diff options
Diffstat (limited to 'comm/third_party/botan/src/lib/tls/tls_extensions.cpp')
-rw-r--r-- | comm/third_party/botan/src/lib/tls/tls_extensions.cpp | 660 |
1 files changed, 660 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/tls/tls_extensions.cpp b/comm/third_party/botan/src/lib/tls/tls_extensions.cpp new file mode 100644 index 0000000000..631868703f --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_extensions.cpp @@ -0,0 +1,660 @@ +/* +* TLS Extensions +* (C) 2011,2012,2015,2016 Jack Lloyd +* 2016 Juraj Somorovsky +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/tls_extensions.h> +#include <botan/internal/tls_reader.h> +#include <botan/tls_exceptn.h> +#include <botan/tls_policy.h> + +namespace Botan { + +namespace TLS { + +namespace { + +Extension* make_extension(TLS_Data_Reader& reader, uint16_t code, uint16_t size, Connection_Side from) + { + switch(code) + { + case TLSEXT_SERVER_NAME_INDICATION: + return new Server_Name_Indicator(reader, size); + +#if defined(BOTAN_HAS_SRP6) + case TLSEXT_SRP_IDENTIFIER: + return new SRP_Identifier(reader, size); +#endif + + case TLSEXT_SUPPORTED_GROUPS: + return new Supported_Groups(reader, size); + + case TLSEXT_CERT_STATUS_REQUEST: + return new Certificate_Status_Request(reader, size, from); + + case TLSEXT_EC_POINT_FORMATS: + return new Supported_Point_Formats(reader, size); + + case TLSEXT_SAFE_RENEGOTIATION: + return new Renegotiation_Extension(reader, size); + + case TLSEXT_SIGNATURE_ALGORITHMS: + return new Signature_Algorithms(reader, size); + + case TLSEXT_USE_SRTP: + return new SRTP_Protection_Profiles(reader, size); + + case TLSEXT_ALPN: + return new Application_Layer_Protocol_Notification(reader, size); + + case TLSEXT_EXTENDED_MASTER_SECRET: + return new Extended_Master_Secret(reader, size); + + case TLSEXT_ENCRYPT_THEN_MAC: + return new Encrypt_then_MAC(reader, size); + + case TLSEXT_SESSION_TICKET: + return new Session_Ticket(reader, size); + + case TLSEXT_SUPPORTED_VERSIONS: + return new Supported_Versions(reader, size, from); + } + + return new Unknown_Extension(static_cast<Handshake_Extension_Type>(code), + reader, size); + } + +} + +void Extensions::deserialize(TLS_Data_Reader& reader, Connection_Side from) + { + if(reader.has_remaining()) + { + const uint16_t all_extn_size = reader.get_uint16_t(); + + if(reader.remaining_bytes() != all_extn_size) + throw Decoding_Error("Bad extension size"); + + while(reader.has_remaining()) + { + const uint16_t extension_code = reader.get_uint16_t(); + const uint16_t extension_size = reader.get_uint16_t(); + + const auto type = static_cast<Handshake_Extension_Type>(extension_code); + + if(m_extensions.find(type) != m_extensions.end()) + throw TLS_Exception(TLS::Alert::DECODE_ERROR, + "Peer sent duplicated extensions"); + + Extension* extn = make_extension( + reader, extension_code, extension_size, from); + + this->add(extn); + } + } + } + +std::vector<uint8_t> Extensions::serialize(Connection_Side whoami) const + { + std::vector<uint8_t> buf(2); // 2 bytes for length field + + for(auto& extn : m_extensions) + { + if(extn.second->empty()) + continue; + + const uint16_t extn_code = static_cast<uint16_t>(extn.second->type()); + + const std::vector<uint8_t> extn_val = extn.second->serialize(whoami); + + buf.push_back(get_byte(0, extn_code)); + buf.push_back(get_byte(1, extn_code)); + + buf.push_back(get_byte(0, static_cast<uint16_t>(extn_val.size()))); + buf.push_back(get_byte(1, static_cast<uint16_t>(extn_val.size()))); + + buf += extn_val; + } + + const uint16_t extn_size = static_cast<uint16_t>(buf.size() - 2); + + buf[0] = get_byte(0, extn_size); + buf[1] = get_byte(1, extn_size); + + // avoid sending a completely empty extensions block + if(buf.size() == 2) + return std::vector<uint8_t>(); + + return buf; + } + +bool Extensions::remove_extension(Handshake_Extension_Type typ) + { + auto i = m_extensions.find(typ); + if(i == m_extensions.end()) + return false; + m_extensions.erase(i); + return true; + } + +std::set<Handshake_Extension_Type> Extensions::extension_types() const + { + std::set<Handshake_Extension_Type> offers; + for(auto i = m_extensions.begin(); i != m_extensions.end(); ++i) + offers.insert(i->first); + return offers; + } + +Unknown_Extension::Unknown_Extension(Handshake_Extension_Type type, + TLS_Data_Reader& reader, + uint16_t extension_size) : + m_type(type), + m_value(reader.get_fixed<uint8_t>(extension_size)) + { + } + +std::vector<uint8_t> Unknown_Extension::serialize(Connection_Side /*whoami*/) const + { + throw Invalid_State("Cannot encode an unknown TLS extension"); + } + +Server_Name_Indicator::Server_Name_Indicator(TLS_Data_Reader& reader, + uint16_t extension_size) + { + /* + * This is used by the server to confirm that it knew the name + */ + if(extension_size == 0) + return; + + uint16_t name_bytes = reader.get_uint16_t(); + + if(name_bytes + 2 != extension_size) + throw Decoding_Error("Bad encoding of SNI extension"); + + while(name_bytes) + { + uint8_t name_type = reader.get_byte(); + name_bytes--; + + if(name_type == 0) // DNS + { + m_sni_host_name = reader.get_string(2, 1, 65535); + name_bytes -= static_cast<uint16_t>(2 + m_sni_host_name.size()); + } + else // some other unknown name type + { + reader.discard_next(name_bytes); + name_bytes = 0; + } + } + } + +std::vector<uint8_t> Server_Name_Indicator::serialize(Connection_Side /*whoami*/) const + { + std::vector<uint8_t> buf; + + size_t name_len = m_sni_host_name.size(); + + buf.push_back(get_byte(0, static_cast<uint16_t>(name_len+3))); + buf.push_back(get_byte(1, static_cast<uint16_t>(name_len+3))); + buf.push_back(0); // DNS + + buf.push_back(get_byte(0, static_cast<uint16_t>(name_len))); + buf.push_back(get_byte(1, static_cast<uint16_t>(name_len))); + + buf += std::make_pair( + cast_char_ptr_to_uint8(m_sni_host_name.data()), + m_sni_host_name.size()); + + return buf; + } + +#if defined(BOTAN_HAS_SRP6) + +SRP_Identifier::SRP_Identifier(TLS_Data_Reader& reader, + uint16_t extension_size) : m_srp_identifier(reader.get_string(1, 1, 255)) + { + if(m_srp_identifier.size() + 1 != extension_size) + throw Decoding_Error("Bad encoding for SRP identifier extension"); + } + +std::vector<uint8_t> SRP_Identifier::serialize(Connection_Side /*whoami*/) const + { + std::vector<uint8_t> buf; + + const uint8_t* srp_bytes = cast_char_ptr_to_uint8(m_srp_identifier.data()); + append_tls_length_value(buf, srp_bytes, m_srp_identifier.size(), 1); + + return buf; + } + +#endif + +Renegotiation_Extension::Renegotiation_Extension(TLS_Data_Reader& reader, + uint16_t extension_size) : m_reneg_data(reader.get_range<uint8_t>(1, 0, 255)) + { + if(m_reneg_data.size() + 1 != extension_size) + throw Decoding_Error("Bad encoding for secure renegotiation extn"); + } + +std::vector<uint8_t> Renegotiation_Extension::serialize(Connection_Side /*whoami*/) const + { + std::vector<uint8_t> buf; + append_tls_length_value(buf, m_reneg_data, 1); + return buf; + } + +Application_Layer_Protocol_Notification::Application_Layer_Protocol_Notification(TLS_Data_Reader& reader, + uint16_t extension_size) + { + if(extension_size == 0) + return; // empty extension + + const uint16_t name_bytes = reader.get_uint16_t(); + + size_t bytes_remaining = extension_size - 2; + + if(name_bytes != bytes_remaining) + throw Decoding_Error("Bad encoding of ALPN extension, bad length field"); + + while(bytes_remaining) + { + const std::string p = reader.get_string(1, 0, 255); + + if(bytes_remaining < p.size() + 1) + throw Decoding_Error("Bad encoding of ALPN, length field too long"); + + if(p.empty()) + throw Decoding_Error("Empty ALPN protocol not allowed"); + + bytes_remaining -= (p.size() + 1); + + m_protocols.push_back(p); + } + } + +const std::string& Application_Layer_Protocol_Notification::single_protocol() const + { + if(m_protocols.size() != 1) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server sent " + std::to_string(m_protocols.size()) + + " protocols in ALPN extension response"); + return m_protocols[0]; + } + +std::vector<uint8_t> Application_Layer_Protocol_Notification::serialize(Connection_Side /*whoami*/) const + { + std::vector<uint8_t> buf(2); + + for(auto&& p: m_protocols) + { + if(p.length() >= 256) + throw TLS_Exception(Alert::INTERNAL_ERROR, "ALPN name too long"); + if(p != "") + append_tls_length_value(buf, + cast_char_ptr_to_uint8(p.data()), + p.size(), + 1); + } + + buf[0] = get_byte(0, static_cast<uint16_t>(buf.size()-2)); + buf[1] = get_byte(1, static_cast<uint16_t>(buf.size()-2)); + + return buf; + } + +Supported_Groups::Supported_Groups(const std::vector<Group_Params>& groups) : m_groups(groups) + { + } + +std::vector<Group_Params> Supported_Groups::ec_groups() const + { + std::vector<Group_Params> ec; + for(auto g : m_groups) + { + if(group_param_is_dh(g) == false) + ec.push_back(g); + } + return ec; + } + +std::vector<Group_Params> Supported_Groups::dh_groups() const + { + std::vector<Group_Params> dh; + for(auto g : m_groups) + { + if(group_param_is_dh(g) == true) + dh.push_back(g); + } + return dh; + } + +std::vector<uint8_t> Supported_Groups::serialize(Connection_Side /*whoami*/) const + { + std::vector<uint8_t> buf(2); + + for(auto g : m_groups) + { + const uint16_t id = static_cast<uint16_t>(g); + + if(id > 0) + { + buf.push_back(get_byte(0, id)); + buf.push_back(get_byte(1, id)); + } + } + + buf[0] = get_byte(0, static_cast<uint16_t>(buf.size()-2)); + buf[1] = get_byte(1, static_cast<uint16_t>(buf.size()-2)); + + return buf; + } + +Supported_Groups::Supported_Groups(TLS_Data_Reader& reader, + uint16_t extension_size) + { + const uint16_t len = reader.get_uint16_t(); + + if(len + 2 != extension_size) + throw Decoding_Error("Inconsistent length field in supported groups list"); + + if(len % 2 == 1) + throw Decoding_Error("Supported groups list of strange size"); + + const size_t elems = len / 2; + + for(size_t i = 0; i != elems; ++i) + { + const uint16_t id = reader.get_uint16_t(); + m_groups.push_back(static_cast<Group_Params>(id)); + } + } + +std::vector<uint8_t> Supported_Point_Formats::serialize(Connection_Side /*whoami*/) const + { + // if this extension is sent, it MUST include uncompressed (RFC 4492, section 5.1) + if(m_prefers_compressed) + { + return std::vector<uint8_t>{2, ANSIX962_COMPRESSED_PRIME, UNCOMPRESSED}; + } + else + { + return std::vector<uint8_t>{1, UNCOMPRESSED}; + } + } + +Supported_Point_Formats::Supported_Point_Formats(TLS_Data_Reader& reader, + uint16_t extension_size) + { + uint8_t len = reader.get_byte(); + + if(len + 1 != extension_size) + throw Decoding_Error("Inconsistent length field in supported point formats list"); + + for(size_t i = 0; i != len; ++i) + { + uint8_t format = reader.get_byte(); + + if(static_cast<ECPointFormat>(format) == UNCOMPRESSED) + { + m_prefers_compressed = false; + reader.discard_next(len-i-1); + return; + } + else if(static_cast<ECPointFormat>(format) == ANSIX962_COMPRESSED_PRIME) + { + m_prefers_compressed = true; + reader.discard_next(len-i-1); + return; + } + + // ignore ANSIX962_COMPRESSED_CHAR2, we don't support these curves + } + } + +std::vector<uint8_t> Signature_Algorithms::serialize(Connection_Side /*whoami*/) const + { + BOTAN_ASSERT(m_schemes.size() < 256, "Too many signature schemes"); + + std::vector<uint8_t> buf; + + const uint16_t len = static_cast<uint16_t>(m_schemes.size() * 2); + + buf.push_back(get_byte(0, len)); + buf.push_back(get_byte(1, len)); + + for(Signature_Scheme scheme : m_schemes) + { + const uint16_t scheme_code = static_cast<uint16_t>(scheme); + + buf.push_back(get_byte(0, scheme_code)); + buf.push_back(get_byte(1, scheme_code)); + } + + return buf; + } + +Signature_Algorithms::Signature_Algorithms(TLS_Data_Reader& reader, + uint16_t extension_size) + { + uint16_t len = reader.get_uint16_t(); + + if(len + 2 != extension_size || len % 2 == 1 || len == 0) + { + throw Decoding_Error("Bad encoding on signature algorithms extension"); + } + + while(len) + { + const uint16_t scheme_code = reader.get_uint16_t(); + m_schemes.push_back(static_cast<Signature_Scheme>(scheme_code)); + len -= 2; + } + } + +Session_Ticket::Session_Ticket(TLS_Data_Reader& reader, + uint16_t extension_size) : m_ticket(reader.get_elem<uint8_t, std::vector<uint8_t>>(extension_size)) + {} + +SRTP_Protection_Profiles::SRTP_Protection_Profiles(TLS_Data_Reader& reader, + uint16_t extension_size) : m_pp(reader.get_range<uint16_t>(2, 0, 65535)) + { + const std::vector<uint8_t> mki = reader.get_range<uint8_t>(1, 0, 255); + + if(m_pp.size() * 2 + mki.size() + 3 != extension_size) + throw Decoding_Error("Bad encoding for SRTP protection extension"); + + if(!mki.empty()) + throw Decoding_Error("Unhandled non-empty MKI for SRTP protection extension"); + } + +std::vector<uint8_t> SRTP_Protection_Profiles::serialize(Connection_Side /*whoami*/) const + { + std::vector<uint8_t> buf; + + const uint16_t pp_len = static_cast<uint16_t>(m_pp.size() * 2); + buf.push_back(get_byte(0, pp_len)); + buf.push_back(get_byte(1, pp_len)); + + for(uint16_t pp : m_pp) + { + buf.push_back(get_byte(0, pp)); + buf.push_back(get_byte(1, pp)); + } + + buf.push_back(0); // srtp_mki, always empty here + + return buf; + } + +Extended_Master_Secret::Extended_Master_Secret(TLS_Data_Reader&, + uint16_t extension_size) + { + if(extension_size != 0) + throw Decoding_Error("Invalid extended_master_secret extension"); + } + +std::vector<uint8_t> Extended_Master_Secret::serialize(Connection_Side /*whoami*/) const + { + return std::vector<uint8_t>(); + } + +Encrypt_then_MAC::Encrypt_then_MAC(TLS_Data_Reader&, + uint16_t extension_size) + { + if(extension_size != 0) + throw Decoding_Error("Invalid encrypt_then_mac extension"); + } + +std::vector<uint8_t> Encrypt_then_MAC::serialize(Connection_Side /*whoami*/) const + { + return std::vector<uint8_t>(); + } + +std::vector<uint8_t> Certificate_Status_Request::serialize(Connection_Side whoami) const + { + std::vector<uint8_t> buf; + + if(whoami == Connection_Side::SERVER) + return buf; // server reply is empty + + /* + opaque ResponderID<1..2^16-1>; + opaque Extensions<0..2^16-1>; + + CertificateStatusType status_type = ocsp(1) + ResponderID responder_id_list<0..2^16-1> + Extensions request_extensions; + */ + + buf.push_back(1); // CertificateStatusType ocsp + + buf.push_back(0); + buf.push_back(0); + buf.push_back(0); + buf.push_back(0); + + return buf; + } + +Certificate_Status_Request::Certificate_Status_Request(TLS_Data_Reader& reader, + uint16_t extension_size, + Connection_Side from) + { + if(from == Connection_Side::SERVER) + { + if(extension_size != 0) + throw Decoding_Error("Server sent non-empty Certificate_Status_Request extension"); + } + else if(extension_size > 0) + { + const uint8_t type = reader.get_byte(); + if(type == 1) + { + const size_t len_resp_id_list = reader.get_uint16_t(); + m_ocsp_names = reader.get_fixed<uint8_t>(len_resp_id_list); + const size_t len_requ_ext = reader.get_uint16_t(); + m_extension_bytes = reader.get_fixed<uint8_t>(len_requ_ext); + } + else + { + reader.discard_next(extension_size - 1); + } + } + } + +Certificate_Status_Request::Certificate_Status_Request(const std::vector<uint8_t>& ocsp_responder_ids, + const std::vector<std::vector<uint8_t>>& ocsp_key_ids) : + m_ocsp_names(ocsp_responder_ids), + m_ocsp_keys(ocsp_key_ids) + { + } + +std::vector<uint8_t> Supported_Versions::serialize(Connection_Side whoami) const + { + std::vector<uint8_t> buf; + + if(whoami == Connection_Side::SERVER) + { + BOTAN_ASSERT_NOMSG(m_versions.size() == 1); + buf.push_back(m_versions[0].major_version()); + buf.push_back(m_versions[0].minor_version()); + } + else + { + BOTAN_ASSERT_NOMSG(m_versions.size() >= 1); + const uint8_t len = static_cast<uint8_t>(m_versions.size() * 2); + + buf.push_back(len); + + for(Protocol_Version version : m_versions) + { + buf.push_back(get_byte(0, version.major_version())); + buf.push_back(get_byte(1, version.minor_version())); + } + } + + return buf; + } + +Supported_Versions::Supported_Versions(Protocol_Version offer, const Policy& policy) + { + if(offer.is_datagram_protocol()) + { + if(offer >= Protocol_Version::DTLS_V12 && policy.allow_dtls12()) + m_versions.push_back(Protocol_Version::DTLS_V12); +#if defined(BOTAN_HAS_TLS_V10) + if(offer >= Protocol_Version::DTLS_V10 && policy.allow_dtls10()) + m_versions.push_back(Protocol_Version::DTLS_V10); +#endif + } + else + { + if(offer >= Protocol_Version::TLS_V12 && policy.allow_tls12()) + m_versions.push_back(Protocol_Version::TLS_V12); +#if defined(BOTAN_HAS_TLS_V10) + if(offer >= Protocol_Version::TLS_V11 && policy.allow_tls11()) + m_versions.push_back(Protocol_Version::TLS_V11); + if(offer >= Protocol_Version::TLS_V10 && policy.allow_tls10()) + m_versions.push_back(Protocol_Version::TLS_V10); +#endif + } + } + +Supported_Versions::Supported_Versions(TLS_Data_Reader& reader, + uint16_t extension_size, + Connection_Side from) + { + if(from == Connection_Side::SERVER) + { + if(extension_size != 2) + throw Decoding_Error("Server sent invalid supported_versions extension"); + m_versions.push_back(Protocol_Version(reader.get_uint16_t())); + } + else + { + auto versions = reader.get_range<uint16_t>(1, 1, 127); + + for(auto v : versions) + m_versions.push_back(Protocol_Version(v)); + + if(extension_size != 1+2*versions.size()) + throw Decoding_Error("Client sent invalid supported_versions extension"); + } + } + +bool Supported_Versions::supports(Protocol_Version version) const + { + for(auto v : m_versions) + if(version == v) + return true; + return false; + } + +} + +} |