diff options
author | René Korthaus <[email protected]> | 2016-09-28 13:06:36 +0200 |
---|---|---|
committer | René Korthaus <[email protected]> | 2016-10-03 12:18:24 +0200 |
commit | f38841305ecd3fd0d13285823497a5a9d3b5c19f (patch) | |
tree | d01a3263baa7df488cf58fc997d1c9710dbfb0a4 | |
parent | ab2842d6f28680b1cac18d5ff6b70b395d1ffb65 (diff) |
Support encoding of supported point formats extension
-rw-r--r-- | doc/news.rst | 2 | ||||
-rw-r--r-- | src/lib/pubkey/ecdh/ecdh.h | 11 | ||||
-rw-r--r-- | src/lib/tls/msg_client_hello.cpp | 16 | ||||
-rw-r--r-- | src/lib/tls/msg_client_kex.cpp | 10 | ||||
-rw-r--r-- | src/lib/tls/msg_server_hello.cpp | 8 | ||||
-rw-r--r-- | src/lib/tls/msg_server_kex.cpp | 10 | ||||
-rw-r--r-- | src/lib/tls/tls_extensions.cpp | 48 | ||||
-rw-r--r-- | src/lib/tls/tls_extensions.h | 32 | ||||
-rw-r--r-- | src/lib/tls/tls_messages.h | 18 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.cpp | 5 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.h | 8 | ||||
-rw-r--r-- | src/tests/unit_tls.cpp | 12 |
12 files changed, 175 insertions, 5 deletions
diff --git a/doc/news.rst b/doc/news.rst index a764d75fb..892938aff 100644 --- a/doc/news.rst +++ b/doc/news.rst @@ -4,6 +4,8 @@ Release Notes Version 1.11.33, Not Yet Released ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +* Add support for the TLS Supported Point Formats Extension (RFC 4492). + Version 1.11.32, 2016-09-28 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/lib/pubkey/ecdh/ecdh.h b/src/lib/pubkey/ecdh/ecdh.h index 2f892436c..bdd9ea047 100644 --- a/src/lib/pubkey/ecdh/ecdh.h +++ b/src/lib/pubkey/ecdh/ecdh.h @@ -55,6 +55,12 @@ class BOTAN_DLL ECDH_PublicKey : public virtual EC_PublicKey std::vector<byte> public_value() const { return unlock(EC2OSP(public_point(), PointGFp::UNCOMPRESSED)); } + /** + * @return public point value + */ + std::vector<byte> public_value(PointGFp::Compression_Type type) const + { return unlock(EC2OSP(public_point(), type)); } + protected: ECDH_PublicKey(); }; @@ -84,7 +90,10 @@ class BOTAN_DLL ECDH_PrivateKey : public ECDH_PublicKey, EC_PrivateKey(rng, domain, x) {} std::vector<byte> public_value() const override - { return ECDH_PublicKey::public_value(); } + { return ECDH_PublicKey::public_value(PointGFp::UNCOMPRESSED); } + + std::vector<byte> public_value(PointGFp::Compression_Type type) const + { return ECDH_PublicKey::public_value(type); } }; } diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp index b493fd3ee..36335e7ce 100644 --- a/src/lib/tls/msg_client_hello.cpp +++ b/src/lib/tls/msg_client_hello.cpp @@ -98,8 +98,12 @@ Client_Hello::Client_Hello(Handshake_IO& io, if(reneg_info.empty() && !next_protocols.empty()) m_extensions.add(new Application_Layer_Protocol_Notification(next_protocols)); + if(m_version.supports_negotiable_signature_algorithms()) + m_extensions.add(new Signature_Algorithms(policy.allowed_signature_hashes(), + policy.allowed_signature_methods())); + if(m_version.is_datagram_protocol()) - m_extensions.add(new SRTP_Protection_Profiles(policy.srtp_profiles())); + m_extensions.add(new SRTP_Protection_Profiles(policy.srtp_profiles())); #if defined(BOTAN_HAS_SRP6) m_extensions.add(new SRP_Identifier(client_settings.srp_identifier())); @@ -112,6 +116,11 @@ Client_Hello::Client_Hello(Handshake_IO& io, m_extensions.add(new Supported_Elliptic_Curves(policy.allowed_ecc_curves())); + if(!policy.allowed_ecc_curves().empty() && policy.use_ecc_point_compression()) + { + m_extensions.add(new Supported_Point_Formats()); + } + if(m_version.supports_negotiable_signature_algorithms()) m_extensions.add(new Signature_Algorithms(policy.allowed_signature_hashes(), policy.allowed_signature_methods())); @@ -156,6 +165,11 @@ Client_Hello::Client_Hello(Handshake_IO& io, m_extensions.add(new Session_Ticket(session.session_ticket())); m_extensions.add(new Supported_Elliptic_Curves(policy.allowed_ecc_curves())); + if(!policy.allowed_ecc_curves().empty() && policy.use_ecc_point_compression()) + { + m_extensions.add(new Supported_Point_Formats()); + } + if(m_version.supports_negotiable_signature_algorithms()) m_extensions.add(new Signature_Algorithms(policy.allowed_signature_hashes(), policy.allowed_signature_methods())); diff --git a/src/lib/tls/msg_client_kex.cpp b/src/lib/tls/msg_client_kex.cpp index bc4d33d52..a01830c28 100644 --- a/src/lib/tls/msg_client_kex.cpp +++ b/src/lib/tls/msg_client_kex.cpp @@ -172,7 +172,15 @@ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io, append_tls_length_value(m_pre_master, psk.bits_of(), 2); } - append_tls_length_value(m_key_material, priv_key.public_value(), 1); + // follow server's preference for point compression + if(state.server_hello()->prefers_compressed_ec_points()) + { + append_tls_length_value(m_key_material, priv_key.public_value(PointGFp::COMPRESSED), 1); + } + else + { + append_tls_length_value(m_key_material, priv_key.public_value(PointGFp::UNCOMPRESSED), 1); + } } #if defined(BOTAN_HAS_SRP6) else if(kex_algo == "SRP_SHA") diff --git a/src/lib/tls/msg_server_hello.cpp b/src/lib/tls/msg_server_hello.cpp index ebe8fb085..4f95a5c9d 100644 --- a/src/lib/tls/msg_server_hello.cpp +++ b/src/lib/tls/msg_server_hello.cpp @@ -35,12 +35,18 @@ Server_Hello::Server_Hello(Handshake_IO& io, if(client_hello.supports_extended_master_secret()) m_extensions.add(new Extended_Master_Secret); + Ciphersuite c = Ciphersuite::by_id(m_ciphersuite); + if(client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac()) { - Ciphersuite c = Ciphersuite::by_id(m_ciphersuite); if(c.cbc_ciphersuite()) m_extensions.add(new Encrypt_then_MAC); } + + if(c.ecc_ciphersuite() && policy.use_ecc_point_compression()) + { + m_extensions.add(new Supported_Point_Formats()); + } if(client_hello.secure_renegotiation()) m_extensions.add(new Renegotiation_Extension(reneg_info)); diff --git a/src/lib/tls/msg_server_kex.cpp b/src/lib/tls/msg_server_kex.cpp index 10581fe45..c44dcb69a 100644 --- a/src/lib/tls/msg_server_kex.cpp +++ b/src/lib/tls/msg_server_kex.cpp @@ -85,7 +85,15 @@ Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, m_params.push_back(get_byte(0, named_curve_id)); m_params.push_back(get_byte(1, named_curve_id)); - append_tls_length_value(m_params, ecdh->public_value(), 1); + // follow client's preference for point compression + if(state.client_hello()->prefers_compressed_ec_points()) + { + append_tls_length_value(m_params, ecdh->public_value(PointGFp::COMPRESSED), 1); + } + else + { + append_tls_length_value(m_params, ecdh->public_value(PointGFp::UNCOMPRESSED), 1); + } m_kex_key.reset(ecdh.release()); } diff --git a/src/lib/tls/tls_extensions.cpp b/src/lib/tls/tls_extensions.cpp index e38e4ccdc..d82df20c5 100644 --- a/src/lib/tls/tls_extensions.cpp +++ b/src/lib/tls/tls_extensions.cpp @@ -33,6 +33,9 @@ Extension* make_extension(TLS_Data_Reader& reader, case TLSEXT_USABLE_ELLIPTIC_CURVES: return new Supported_Elliptic_Curves(reader, size); + case TLSEXT_EC_POINT_FORMATS: + return new Supported_Point_Formats(reader, size); + case TLSEXT_SAFE_RENEGOTIATION: return new Renegotiation_Extension(reader, size); @@ -353,6 +356,51 @@ Supported_Elliptic_Curves::Supported_Elliptic_Curves(TLS_Data_Reader& reader, } } +std::vector<byte> Supported_Point_Formats::serialize() const + { + std::vector<byte> buf(1); + + // if we send this extension, we prefer compressed points, + // otherwise we don't send it (which is equal to supporting only uncompressed) + buf.push_back(ANSIX962_COMPRESSED_PRIME); + + // if this extension is sent, it MUST include uncompressed (RFC 4492, section 5.1) + buf.push_back(UNCOMPRESSED); + + buf[0] = static_cast<byte>(buf.size()-1); + + return buf; + } + +Supported_Point_Formats::Supported_Point_Formats(TLS_Data_Reader& reader, + u16bit extension_size) + { + byte 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) + { + byte format = reader.get_byte(); + + if(format == UNCOMPRESSED) + { + m_prefers_compressed = false; + reader.discard_next(len-i-1); + return; + } + else if(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::string Signature_Algorithms::hash_algo_name(byte code) { switch(code) diff --git a/src/lib/tls/tls_extensions.h b/src/lib/tls/tls_extensions.h index c270bf23a..d69e40a60 100644 --- a/src/lib/tls/tls_extensions.h +++ b/src/lib/tls/tls_extensions.h @@ -258,6 +258,38 @@ class Supported_Elliptic_Curves final : public Extension }; /** +* Supported Point Formats Extension (RFC 4492) +*/ +class Supported_Point_Formats final : public Extension + { + public: + enum ECPointFormat : byte { + UNCOMPRESSED = 0, + ANSIX962_COMPRESSED_PRIME = 1, + ANSIX962_COMPRESSED_CHAR2 = 2, // don't support these curves + }; + + static Handshake_Extension_Type static_type() + { return TLSEXT_EC_POINT_FORMATS; } + + Handshake_Extension_Type type() const override { return static_type(); } + + std::vector<byte> serialize() const override; + + explicit Supported_Point_Formats() : m_prefers_compressed(true) {} + + Supported_Point_Formats(TLS_Data_Reader& reader, + u16bit extension_size); + + bool empty() const override { return false; } + + bool prefers_compressed() { return m_prefers_compressed; } + + private: + bool m_prefers_compressed = false; + }; + +/** * Signature Algorithms Extension for TLS 1.2 (RFC 5246) */ class Signature_Algorithms final : public Extension diff --git a/src/lib/tls/tls_messages.h b/src/lib/tls/tls_messages.h index 698dbc99f..25228c865 100644 --- a/src/lib/tls/tls_messages.h +++ b/src/lib/tls/tls_messages.h @@ -121,6 +121,15 @@ class BOTAN_DLL Client_Hello final : public Handshake_Message return std::vector<std::string>(); } + bool prefers_compressed_ec_points() const + { + if(Supported_Point_Formats* ecc_formats = m_extensions.get<Supported_Point_Formats>()) + { + return ecc_formats->prefers_compressed(); + } + return false; + } + std::string sni_hostname() const { if(Server_Name_Indicator* sni = m_extensions.get<Server_Name_Indicator>()) @@ -328,6 +337,15 @@ class BOTAN_DLL Server_Hello final : public Handshake_Message std::set<Handshake_Extension_Type> extension_types() const { return m_extensions.extension_types(); } + bool prefers_compressed_ec_points() const + { + if(auto ecc_formats = m_extensions.get<Supported_Point_Formats>()) + { + return ecc_formats->prefers_compressed(); + } + return false; + } + Server_Hello(Handshake_IO& io, Handshake_Hash& hash, const Policy& policy, diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp index 592d4f572..9646aa320 100644 --- a/src/lib/tls/tls_policy.cpp +++ b/src/lib/tls/tls_policy.cpp @@ -104,6 +104,11 @@ bool Policy::allowed_ecc_curve(const std::string& curve) const return value_exists(allowed_ecc_curves(), curve); } +bool Policy::use_ecc_point_compression() const + { + return false; + } + /* * Choose an ECC curve to use */ diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h index 76e80ddde..47ac51685 100644 --- a/src/lib/tls/tls_policy.h +++ b/src/lib/tls/tls_policy.h @@ -67,6 +67,11 @@ class BOTAN_DLL Policy bool allowed_ecc_curve(const std::string& curve) const; /** + * Request that ECC curve points are sent compressed + */ + virtual bool use_ecc_point_compression() const; + + /** * Returns a list of compression algorithms we are willing to use, * in order of preference. Allowed values any value of * Compression_Method. @@ -348,6 +353,9 @@ class BOTAN_DLL Text_Policy : public Policy std::vector<std::string> allowed_ecc_curves() const override { return get_list("ecc_curves", Policy::allowed_ecc_curves()); } + bool use_ecc_point_compression() const override + { return get_bool("use_ecc_point_compression", Policy::use_ecc_point_compression()); } + bool allow_tls10() const override { return get_bool("allow_tls10", Policy::allow_tls10()); } diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index de54c9747..5ae24ba81 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -868,6 +868,18 @@ class TLS_Unit_Tests : public Test results.push_back(test_tls_handshake(Botan::TLS::Protocol_Version::TLS_V12, *basic_creds, policy, server_policy)); results.push_back(test_dtls_handshake(Botan::TLS::Protocol_Version::DTLS_V12, *basic_creds, policy, server_policy)); + policy.set("use_ecc_point_compression", "true"); + policy.set("key_exchange_methods", "ECDH"); + policy.set("ciphers", "AES-128"); + results.push_back(test_tls_handshake(Botan::TLS::Protocol_Version::TLS_V12, *basic_creds, policy)); + results.push_back(test_dtls_handshake(Botan::TLS::Protocol_Version::DTLS_V12, *basic_creds, policy)); + + server_policy.set("use_ecc_point_compression", "true"); + server_policy.set("key_exchange_methods", "ECDH"); + server_policy.set("ciphers", "AES-128"); + results.push_back(test_tls_handshake(Botan::TLS::Protocol_Version::TLS_V12, *basic_creds, policy, server_policy)); + results.push_back(test_dtls_handshake(Botan::TLS::Protocol_Version::DTLS_V12, *basic_creds, policy, server_policy)); + return results; } |