diff options
author | Jack Lloyd <[email protected]> | 2017-10-22 11:09:55 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-10-22 11:09:55 -0400 |
commit | 52b2a634cbf95224d3d05035e26fd53eda64ab5a (patch) | |
tree | ad35d007ecbf3672e09314f9dae45b9e4ae05887 /src/lib/tls | |
parent | 8fc068fa337ccae190402984c9234ec5a9ea1f47 (diff) | |
parent | 558b66b0d56879f9b204266d08e661ff90667d20 (diff) |
Merge GH #1263 Support FFDHE negotiation in TLS
Diffstat (limited to 'src/lib/tls')
-rw-r--r-- | src/lib/tls/msg_client_hello.cpp | 16 | ||||
-rw-r--r-- | src/lib/tls/msg_server_kex.cpp | 23 | ||||
-rw-r--r-- | src/lib/tls/tls_extensions.cpp | 81 | ||||
-rw-r--r-- | src/lib/tls/tls_extensions.h | 20 | ||||
-rw-r--r-- | src/lib/tls/tls_messages.h | 2 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.cpp | 51 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.h | 30 | ||||
-rw-r--r-- | src/lib/tls/tls_server.cpp | 6 | ||||
-rw-r--r-- | src/lib/tls/tls_text_policy.cpp | 5 |
9 files changed, 206 insertions, 28 deletions
diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp index bb7d84df8..e804a0cf0 100644 --- a/src/lib/tls/msg_client_hello.cpp +++ b/src/lib/tls/msg_client_hello.cpp @@ -121,9 +121,10 @@ Client_Hello::Client_Hello(Handshake_IO& io, } #endif - m_extensions.add(new Supported_Elliptic_Curves(policy.allowed_ecc_curves())); + Supported_Groups* supported_groups = new Supported_Groups(policy.allowed_groups()); + m_extensions.add(supported_groups); - if(!policy.allowed_ecc_curves().empty()) + if(!supported_groups->curves().empty()) { m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); } @@ -324,8 +325,15 @@ std::set<std::string> Client_Hello::supported_sig_algos() const std::vector<std::string> Client_Hello::supported_ecc_curves() const { - if(Supported_Elliptic_Curves* ecc = m_extensions.get<Supported_Elliptic_Curves>()) - return ecc->curves(); + if(Supported_Groups* groups = m_extensions.get<Supported_Groups>()) + return groups->curves(); + return std::vector<std::string>(); + } + +std::vector<std::string> Client_Hello::supported_dh_groups() const + { + if(Supported_Groups* groups = m_extensions.get<Supported_Groups>()) + return groups->dh_groups(); return std::vector<std::string>(); } diff --git a/src/lib/tls/msg_server_kex.cpp b/src/lib/tls/msg_server_kex.cpp index 97ac4ac8f..ab75d3a9b 100644 --- a/src/lib/tls/msg_server_kex.cpp +++ b/src/lib/tls/msg_server_kex.cpp @@ -56,7 +56,28 @@ Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, if(kex_algo == "DH" || kex_algo == "DHE_PSK") { - std::unique_ptr<DH_PrivateKey> dh(new DH_PrivateKey(rng, DL_Group(policy.dh_group()))); + const std::vector<std::string>& dh_groups = + state.client_hello()->supported_dh_groups(); + + std::string group_name; + + // if the client does not send any DH groups in + // the supported groups extension, but does offer DH ciphersuites, + // we select a group arbitrarily + if (dh_groups.empty()) + { + group_name = policy.dh_group(); + } + else + { + group_name = policy.choose_dh_group(dh_groups); + } + + if (group_name.empty()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Could not agree on a DH group with the client"); + + std::unique_ptr<DH_PrivateKey> dh(new DH_PrivateKey(rng, DL_Group(group_name))); append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_p()), 2); append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_g()), 2); diff --git a/src/lib/tls/tls_extensions.cpp b/src/lib/tls/tls_extensions.cpp index 317d96b8d..8f13b2c6d 100644 --- a/src/lib/tls/tls_extensions.cpp +++ b/src/lib/tls/tls_extensions.cpp @@ -275,7 +275,23 @@ std::vector<uint8_t> Application_Layer_Protocol_Notification::serialize() const return buf; } -std::string Supported_Elliptic_Curves::curve_id_to_name(uint16_t id) +Supported_Groups::Supported_Groups(const std::vector<std::string>& groups) : + m_groups(groups) + { + for(const auto& group : m_groups) + { + if(is_dh_group(group)) + { + m_dh_groups.push_back(group); + } + else + { + m_curves.push_back(group); + } + } + } + +std::string Supported_Groups::curve_id_to_name(uint16_t id) { switch(id) { @@ -302,12 +318,23 @@ std::string Supported_Elliptic_Curves::curve_id_to_name(uint16_t id) return BOTAN_HOUSE_ECC_CURVE_NAME; #endif + case 256: + return "ffdhe/ietf/2048"; + case 257: + return "ffdhe/ietf/3072"; + case 258: + return "ffdhe/ietf/4096"; + case 259: + return "ffdhe/ietf/6144"; + case 260: + return "ffdhe/ietf/8192"; + default: return ""; // something we don't know or support } } -uint16_t Supported_Elliptic_Curves::name_to_curve_id(const std::string& name) +uint16_t Supported_Groups::name_to_curve_id(const std::string& name) { if(name == "secp256r1") return 23; @@ -332,17 +359,39 @@ uint16_t Supported_Elliptic_Curves::name_to_curve_id(const std::string& name) return BOTAN_HOUSE_ECC_CURVE_TLS_ID; #endif - // Unknown/unavailable EC curves are ignored + if(name == "ffdhe/ietf/2048") + return 256; + if(name == "ffdhe/ietf/3072") + return 257; + if(name == "ffdhe/ietf/4096") + return 258; + if(name == "ffdhe/ietf/6144") + return 259; + if(name == "ffdhe/ietf/8192") + return 260; + + // Unknown/unavailable DH groups/EC curves are ignored return 0; } -std::vector<uint8_t> Supported_Elliptic_Curves::serialize() const +bool Supported_Groups::is_dh_group( const std::string& group_name ) + { + if(group_name == "ffdhe/ietf/2048" || group_name == "ffdhe/ietf/3072" + || group_name == "ffdhe/ietf/4096" || group_name == "ffdhe/ietf/6144" + || group_name == "ffdhe/ietf/8192") + { + return true; + } + return false; + } + +std::vector<uint8_t> Supported_Groups::serialize() const { std::vector<uint8_t> buf(2); - for(size_t i = 0; i != m_curves.size(); ++i) + for(size_t i = 0; i != m_groups.size(); ++i) { - const uint16_t id = name_to_curve_id(m_curves[i]); + const uint16_t id = name_to_curve_id(m_groups[i]); if(id > 0) { @@ -357,16 +406,16 @@ std::vector<uint8_t> Supported_Elliptic_Curves::serialize() const return buf; } -Supported_Elliptic_Curves::Supported_Elliptic_Curves(TLS_Data_Reader& reader, - uint16_t extension_size) +Supported_Groups::Supported_Groups(TLS_Data_Reader& reader, + uint16_t extension_size) { uint16_t len = reader.get_uint16_t(); if(len + 2 != extension_size) - throw Decoding_Error("Inconsistent length field in elliptic curve list"); + throw Decoding_Error("Inconsistent length field in supported groups list"); if(len % 2 == 1) - throw Decoding_Error("Elliptic curve list of strange size"); + throw Decoding_Error("Supported groups list of strange size"); len /= 2; @@ -376,7 +425,17 @@ Supported_Elliptic_Curves::Supported_Elliptic_Curves(TLS_Data_Reader& reader, const std::string name = curve_id_to_name(id); if(!name.empty()) - m_curves.push_back(name); + { + m_groups.push_back(name); + if(is_dh_group(name)) + { + m_dh_groups.push_back(name); + } + else + { + m_curves.push_back(name); + } + } } } diff --git a/src/lib/tls/tls_extensions.h b/src/lib/tls/tls_extensions.h index ee3310563..221d8b46f 100644 --- a/src/lib/tls/tls_extensions.h +++ b/src/lib/tls/tls_extensions.h @@ -225,10 +225,11 @@ class Session_Ticket final : public Extension std::vector<uint8_t> m_ticket; }; + /** -* Supported Elliptic Curves Extension (RFC 4492) +* Supported Groups Extension (RFC 7919) */ -class Supported_Elliptic_Curves final : public Extension +class Supported_Groups final : public Extension { public: static Handshake_Extension_Type static_type() @@ -239,21 +240,28 @@ class Supported_Elliptic_Curves final : public Extension static std::string curve_id_to_name(uint16_t id); static uint16_t name_to_curve_id(const std::string& name); + static bool is_dh_group( const std::string& group_name ); + const std::vector<std::string>& curves() const { return m_curves; } + const std::vector<std::string>& dh_groups() const { return m_dh_groups; } std::vector<uint8_t> serialize() const override; - explicit Supported_Elliptic_Curves(const std::vector<std::string>& curves) : - m_curves(curves) {} + explicit Supported_Groups(const std::vector<std::string>& groups); - Supported_Elliptic_Curves(TLS_Data_Reader& reader, + Supported_Groups(TLS_Data_Reader& reader, uint16_t extension_size); - bool empty() const override { return m_curves.empty(); } + bool empty() const override { return m_groups.empty(); } private: + std::vector<std::string> m_groups; std::vector<std::string> m_curves; + std::vector<std::string> m_dh_groups; }; +// previously Supported Elliptic Curves Extension (RFC 4492) +using Supported_Elliptic_Curves = Supported_Groups; + /** * Supported Point Formats Extension (RFC 4492) */ diff --git a/src/lib/tls/tls_messages.h b/src/lib/tls/tls_messages.h index ac6c1e1ad..767635830 100644 --- a/src/lib/tls/tls_messages.h +++ b/src/lib/tls/tls_messages.h @@ -110,6 +110,8 @@ class BOTAN_UNSTABLE_API Client_Hello final : public Handshake_Message std::vector<std::string> supported_ecc_curves() const; + std::vector<std::string> supported_dh_groups() const; + bool prefers_compressed_ec_points() const; std::string sni_hostname() const; diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp index 43926e314..0a7e78e65 100644 --- a/src/lib/tls/tls_policy.cpp +++ b/src/lib/tls/tls_policy.cpp @@ -10,6 +10,7 @@ #include <botan/tls_ciphersuite.h> #include <botan/tls_magic.h> #include <botan/tls_exceptn.h> +#include <botan/tls_extensions.h> #include <botan/internal/stl_util.h> #include <botan/pk_keys.h> #include <sstream> @@ -117,7 +118,11 @@ std::vector<std::string> Policy::allowed_ecc_curves() const bool Policy::allowed_ecc_curve(const std::string& curve) const { - return value_exists(allowed_ecc_curves(), curve); + if(!allowed_ecc_curves().empty()) + { + return value_exists(allowed_ecc_curves(), curve); + } + return value_exists(allowed_groups(), curve); } bool Policy::use_ecc_point_compression() const @@ -130,21 +135,56 @@ bool Policy::use_ecc_point_compression() const */ std::string Policy::choose_curve(const std::vector<std::string>& curve_names) const { - const std::vector<std::string> our_curves = allowed_ecc_curves(); + const std::vector<std::string> our_groups = allowed_groups(); - for(size_t i = 0; i != our_curves.size(); ++i) - if(value_exists(curve_names, our_curves[i])) - return our_curves[i]; + for(size_t i = 0; i != our_groups.size(); ++i) + if(!Supported_Groups::is_dh_group(our_groups[i]) + && value_exists(curve_names, our_groups[i])) + return our_groups[i]; return ""; // no shared curve } +/* +* Choose an FFDHE group to use +*/ +std::string Policy::choose_dh_group(const std::vector<std::string>& dh_groups) const + { + const std::vector<std::string> our_groups = allowed_groups(); + + for(size_t i = 0; i != our_groups.size(); ++i) + if(Supported_Groups::is_dh_group(our_groups[i]) + && value_exists(dh_groups, our_groups[i])) + return our_groups[i]; + + return ""; // no shared ffdhe group + } + std::string Policy::dh_group() const { // We offer 2048 bit DH because we can return "modp/ietf/2048"; } +std::vector<std::string> Policy::allowed_groups() const + { + // Default list is ordered by performance + return { + "x25519", + "secp256r1", + "secp521r1", + "secp384r1", + "brainpool256r1", + "brainpool384r1", + "brainpool512r1", + "ffdhe/ietf/2048", + "ffdhe/ietf/3072", + "ffdhe/ietf/4096", + "ffdhe/ietf/6144", + "ffdhe/ietf/8192" + }; + } + size_t Policy::minimum_dh_group_size() const { return 2048; @@ -502,6 +542,7 @@ void Policy::print(std::ostream& o) const print_vec(o, "signature_methods", allowed_signature_methods()); print_vec(o, "key_exchange_methods", allowed_key_exchange_methods()); print_vec(o, "ecc_curves", allowed_ecc_curves()); + print_vec(o, "groups", allowed_groups()); print_bool(o, "allow_insecure_renegotiation", allow_insecure_renegotiation()); print_bool(o, "include_time_in_hello_random", include_time_in_hello_random()); diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h index 333cf0ee1..499ae91ba 100644 --- a/src/lib/tls/tls_policy.h +++ b/src/lib/tls/tls_policy.h @@ -77,13 +77,25 @@ class BOTAN_PUBLIC_API(2,0) Policy bool allowed_signature_hash(const std::string& hash) const; /** - * Return list of ECC curves we are willing to use in order of preference + * Return list of ECC curves we are willing to use in order of preference. + * Allowed values: x25519, secp256r1, secp384r1, secp521r1, + * brainpool256r1, brainpool384r1, brainpool512r1 */ virtual std::vector<std::string> allowed_ecc_curves() const; bool allowed_ecc_curve(const std::string& curve) const; /** + * Return list of ECC curves and FFDHE groups + * we are willing to use in order of preference. + * Allowed values: x25519, secp256r1, secp384r1, secp521r1, + * brainpool256r1, brainpool384r1, brainpool512r1, + * ffdhe/ietf/2048, ffdhe/ietf/3072, ffdhe/ietf/4096, + * ffdhe/ietf/6144, ffdhe/ietf/8192 + */ + virtual std::vector<std::string> allowed_groups() const; + + /** * Request that ECC curve points are sent compressed */ virtual bool use_ecc_point_compression() const; @@ -103,6 +115,11 @@ class BOTAN_PUBLIC_API(2,0) Policy virtual std::string choose_curve(const std::vector<std::string>& curve_names) const; /** + * Choose an FFHDE group to use + */ + virtual std::string choose_dh_group(const std::vector<std::string>& dh_group_names) const; + + /** * Allow renegotiation even if the counterparty doesn't * support the secure renegotiation extension. * @@ -330,6 +347,9 @@ class BOTAN_PUBLIC_API(2,0) NSA_Suite_B_128 final : public Policy std::vector<std::string> allowed_ecc_curves() const override { return std::vector<std::string>({"secp256r1"}); } + std::vector<std::string> allowed_groups() const override + { return allowed_ecc_curves(); } + size_t minimum_signature_strength() const override { return 128; } bool allow_tls10() const override { return false; } @@ -375,6 +395,12 @@ class BOTAN_PUBLIC_API(2,0) BSI_TR_02102_2 final : public Policy return std::vector<std::string>({"brainpool512r1", "brainpool384r1", "brainpool256r1", "secp384r1", "secp256r1"}); } + std::vector<std::string> allowed_groups() const override + { + return std::vector<std::string>({"brainpool512r1", "brainpool384r1", "brainpool256r1", "secp384r1", + "secp256r1", "ffdhe/ietf/8192", "ffdhe/ietf/6144", "ffdhe/ietf/4096", "ffdhe/ietf/3072", "ffdhe/ietf/2048"}); + } + bool allow_insecure_renegotiation() const override { return false; } bool allow_server_initiated_renegotiation() const override { return true; } bool server_uses_own_ciphersuite_preferences() const override { return true; } @@ -451,6 +477,8 @@ class BOTAN_PUBLIC_API(2,0) Text_Policy : public Policy std::vector<std::string> allowed_ecc_curves() const override; + std::vector<std::string> allowed_groups() const override; + bool use_ecc_point_compression() const override; bool allow_tls10() const override; diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp index c0e853a80..9f1dfe1d1 100644 --- a/src/lib/tls/tls_server.cpp +++ b/src/lib/tls/tls_server.cpp @@ -168,6 +168,9 @@ uint16_t choose_ciphersuite( const bool have_shared_ecc_curve = (policy.choose_curve(client_hello.supported_ecc_curves()) != ""); + const bool have_shared_dh_group = + (policy.choose_dh_group(client_hello.supported_dh_groups()) != ""); + /* Walk down one list in preference order */ @@ -193,6 +196,9 @@ uint16_t choose_ciphersuite( if(suite.ecc_ciphersuite() && have_shared_ecc_curve == false) continue; + if(suite.kex_algo() == "DH" && have_shared_dh_group == false) + continue; + // For non-anon ciphersuites if(suite.sig_algo() != "") { diff --git a/src/lib/tls/tls_text_policy.cpp b/src/lib/tls/tls_text_policy.cpp index ef5799339..345e6005f 100644 --- a/src/lib/tls/tls_text_policy.cpp +++ b/src/lib/tls/tls_text_policy.cpp @@ -108,6 +108,11 @@ std::string Text_Policy::dh_group() const return get_str("dh_group", Policy::dh_group()); } +std::vector<std::string> Text_Policy::allowed_groups() const + { + return get_list("groups", Policy::allowed_groups()); + } + size_t Text_Policy::minimum_ecdh_group_size() const { return get_len("minimum_ecdh_group_size", Policy::minimum_ecdh_group_size()); |