diff options
Diffstat (limited to 'src/lib/tls')
-rw-r--r-- | src/lib/tls/msg_client_hello.cpp | 24 | ||||
-rw-r--r-- | src/lib/tls/msg_client_kex.cpp | 20 | ||||
-rw-r--r-- | src/lib/tls/msg_server_hello.cpp | 2 | ||||
-rw-r--r-- | src/lib/tls/msg_server_kex.cpp | 47 | ||||
-rw-r--r-- | src/lib/tls/tls_algos.cpp | 42 | ||||
-rw-r--r-- | src/lib/tls/tls_algos.h | 8 | ||||
-rw-r--r-- | src/lib/tls/tls_callbacks.cpp | 6 | ||||
-rw-r--r-- | src/lib/tls/tls_callbacks.h | 11 | ||||
-rw-r--r-- | src/lib/tls/tls_extensions.cpp | 144 | ||||
-rw-r--r-- | src/lib/tls/tls_extensions.h | 29 | ||||
-rw-r--r-- | src/lib/tls/tls_messages.h | 4 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.cpp | 132 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.h | 69 | ||||
-rw-r--r-- | src/lib/tls/tls_server.cpp | 2 | ||||
-rw-r--r-- | src/lib/tls/tls_text_policy.cpp | 57 |
15 files changed, 273 insertions, 324 deletions
diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp index 158238de2..a9da82f07 100644 --- a/src/lib/tls/msg_client_hello.cpp +++ b/src/lib/tls/msg_client_hello.cpp @@ -129,14 +129,15 @@ Client_Hello::Client_Hello(Handshake_IO& io, } #endif - Supported_Groups* supported_groups = new Supported_Groups(policy.allowed_groups()); - m_extensions.add(supported_groups); + std::unique_ptr<Supported_Groups> supported_groups(new Supported_Groups(policy.key_exchange_groups())); - if(!supported_groups->curves().empty()) + if(supported_groups->ec_groups().size() > 0) { m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); } + m_extensions.add(supported_groups.release()); + cb.tls_modify_extensions(m_extensions, CLIENT); if(policy.send_fallback_scsv(client_settings.protocol_version())) @@ -175,13 +176,16 @@ Client_Hello::Client_Hello(Handshake_IO& io, m_extensions.add(new Renegotiation_Extension(reneg_info)); m_extensions.add(new Server_Name_Indicator(session.server_info().hostname())); 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()) + std::unique_ptr<Supported_Groups> supported_groups(new Supported_Groups(policy.key_exchange_groups())); + + if(supported_groups->ec_groups().size() > 0) { m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); } + m_extensions.add(supported_groups.release()); + if(session.supports_encrypt_then_mac()) m_extensions.add(new Encrypt_then_MAC); @@ -324,18 +328,18 @@ std::vector<Signature_Scheme> Client_Hello::signature_schemes() const return schemes; } -std::vector<std::string> Client_Hello::supported_ecc_curves() const +std::vector<Group_Params> Client_Hello::supported_ecc_curves() const { if(Supported_Groups* groups = m_extensions.get<Supported_Groups>()) - return groups->curves(); - return std::vector<std::string>(); + return groups->ec_groups(); + return std::vector<Group_Params>(); } -std::vector<std::string> Client_Hello::supported_dh_groups() const +std::vector<Group_Params> Client_Hello::supported_dh_groups() const { if(Supported_Groups* groups = m_extensions.get<Supported_Groups>()) return groups->dh_groups(); - return std::vector<std::string>(); + return std::vector<Group_Params>(); } bool Client_Hello::prefers_compressed_ec_points() const diff --git a/src/lib/tls/msg_client_kex.cpp b/src/lib/tls/msg_client_kex.cpp index 6e767d4d6..b3dff072e 100644 --- a/src/lib/tls/msg_client_kex.cpp +++ b/src/lib/tls/msg_client_kex.cpp @@ -112,30 +112,32 @@ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io, kex_algo == Kex_Algo::ECDHE_PSK) { const uint8_t curve_type = reader.get_byte(); - if(curve_type != 3) throw Decoding_Error("Server sent non-named ECC curve"); - const uint16_t curve_id = reader.get_uint16_t(); - - const std::string curve_name = Supported_Elliptic_Curves::curve_id_to_name(curve_id); - - if(curve_name == "") - throw Decoding_Error("Server sent unknown named curve " + std::to_string(curve_id)); + const Group_Params curve_id = static_cast<Group_Params>(reader.get_uint16_t()); + const std::vector<uint8_t> peer_public_value = reader.get_range<uint8_t>(1, 1, 255); - if(!policy.allowed_ecc_curve(curve_name)) + if(policy.choose_key_exchange_group({curve_id}) != curve_id) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server sent ECC curve prohibited by policy"); } - const std::vector<uint8_t> peer_public_value = reader.get_range<uint8_t>(1, 1, 255); + const std::string curve_name = state.callbacks().tls_decode_group_param(curve_id); + + if(curve_name == "") + throw Decoding_Error("Server sent unknown named curve " + + std::to_string(static_cast<uint16_t>(curve_id))); + const std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> ecdh_result = state.callbacks().tls_ecdh_agree(curve_name, peer_public_value, policy, rng, state.server_hello()->prefers_compressed_ec_points()); if(kex_algo == Kex_Algo::ECDH) + { m_pre_master = ecdh_result.first; + } else { append_tls_length_value(m_pre_master, ecdh_result.first, 2); diff --git a/src/lib/tls/msg_server_hello.cpp b/src/lib/tls/msg_server_hello.cpp index 2d5a185f0..223bddde5 100644 --- a/src/lib/tls/msg_server_hello.cpp +++ b/src/lib/tls/msg_server_hello.cpp @@ -121,7 +121,7 @@ Server_Hello::Server_Hello(Handshake_IO& io, m_extensions.add(new Encrypt_then_MAC); } - if(resumed_session.ciphersuite().ecc_ciphersuite()) + if(resumed_session.ciphersuite().ecc_ciphersuite() && client_hello.extension_types().count(TLSEXT_EC_POINT_FORMATS)) { m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); } diff --git a/src/lib/tls/msg_server_kex.cpp b/src/lib/tls/msg_server_kex.cpp index 56ff3017f..1b42cba99 100644 --- a/src/lib/tls/msg_server_kex.cpp +++ b/src/lib/tls/msg_server_kex.cpp @@ -57,27 +57,31 @@ Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, if(kex_algo == Kex_Algo::DH || kex_algo == Kex_Algo::DHE_PSK) { - const std::vector<std::string>& dh_groups = - state.client_hello()->supported_dh_groups(); + const std::vector<Group_Params> dh_groups = state.client_hello()->supported_dh_groups(); - std::string group_name; + Group_Params shared_group = Group_Params::NONE; - // 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()) + /* + 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(); + shared_group = policy.default_dh_group(); } else { - group_name = policy.choose_dh_group(dh_groups); + shared_group = policy.choose_key_exchange_group(dh_groups); } - if (group_name.empty()) + if(shared_group == Group_Params::NONE) throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Could not agree on a DH group with the client"); + BOTAN_ASSERT(group_param_is_dh(shared_group), "DH groups for the DH ciphersuites god"); + + const std::string group_name = state.callbacks().tls_decode_group_param(shared_group); 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); @@ -87,25 +91,19 @@ Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) { - const std::vector<std::string>& curves = - state.client_hello()->supported_ecc_curves(); + const std::vector<Group_Params> ec_groups = state.client_hello()->supported_ecc_curves(); - if(curves.empty()) + if(ec_groups.empty()) throw Internal_Error("Client sent no ECC extension but we negotiated ECDH"); - const std::string curve_name = policy.choose_curve(curves); - - if(curve_name == "") - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Could not agree on an ECC curve with the client"); + Group_Params shared_group = policy.choose_key_exchange_group(ec_groups); - const uint16_t named_curve_id = Supported_Elliptic_Curves::name_to_curve_id(curve_name); - if(named_curve_id == 0) - throw Internal_Error("TLS does not support ECC with " + curve_name); + if(shared_group == Group_Params::NONE) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "No shared ECC group with client"); std::vector<uint8_t> ecdh_public_val; - if(curve_name == "x25519") + if(shared_group == Group_Params::X25519) { #if defined(BOTAN_HAS_CURVE_25519) std::unique_ptr<Curve25519_PrivateKey> x25519(new Curve25519_PrivateKey(rng)); @@ -117,6 +115,10 @@ Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, } else { + Group_Params curve = policy.choose_key_exchange_group(ec_groups); + + const std::string curve_name = state.callbacks().tls_decode_group_param(curve); + EC_Group ec_group(curve_name); std::unique_ptr<ECDH_PrivateKey> ecdh(new ECDH_PrivateKey(rng, ec_group)); @@ -128,6 +130,7 @@ Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, m_kex_key.reset(ecdh.release()); } + const uint16_t named_curve_id = static_cast<uint16_t>(shared_group); m_params.push_back(3); // named curve m_params.push_back(get_byte(0, named_curve_id)); m_params.push_back(get_byte(1, named_curve_id)); diff --git a/src/lib/tls/tls_algos.cpp b/src/lib/tls/tls_algos.cpp index 33b00d519..db75bf14e 100644 --- a/src/lib/tls/tls_algos.cpp +++ b/src/lib/tls/tls_algos.cpp @@ -115,6 +115,43 @@ Auth_Method auth_method_from_string(const std::string& str) throw Invalid_Argument("Bad signature method " + str); } +bool group_param_is_dh(Group_Params group) + { + uint16_t group_id = static_cast<uint16_t>(group); + return (group_id >= 256 && group_id < 512); + } + +Group_Params group_param_from_string(const std::string& group_name) + { + if(group_name == "secp256r1") + return Group_Params::SECP256R1; + if(group_name == "secp384r1") + return Group_Params::SECP384R1; + if(group_name == "secp521r1") + return Group_Params::SECP521R1; + if(group_name == "brainpool256r1") + return Group_Params::BRAINPOOL256R1; + if(group_name == "brainpool384r1") + return Group_Params::BRAINPOOL384R1; + if(group_name == "brainpool512r1") + return Group_Params::BRAINPOOL512R1; + if(group_name == "x25519") + return Group_Params::X25519; + + if(group_name == "ffdhe/ietf/2048") + return Group_Params::FFDHE_2048; + if(group_name == "ffdhe/ietf/3072") + return Group_Params::FFDHE_3072; + if(group_name == "ffdhe/ietf/4096") + return Group_Params::FFDHE_4096; + if(group_name == "ffdhe/ietf/6144") + return Group_Params::FFDHE_6144; + if(group_name == "ffdhe/ietf/8192") + return Group_Params::FFDHE_8192; + + return Group_Params::NONE; // unknown + } + std::string group_param_to_string(Group_Params group) { switch(group) @@ -145,11 +182,6 @@ std::string group_param_to_string(Group_Params group) case Group_Params::FFDHE_8192: return "ffdhe/ietf/8192"; -#if defined(BOTAN_HOUSE_ECC_CURVE_NAME) - case BOTAN_HOUSE_ECC_CURVE_TLS_ID: - return BOTAN_HOUSE_ECC_CURVE_NAME; -#endif - default: return ""; } diff --git a/src/lib/tls/tls_algos.h b/src/lib/tls/tls_algos.h index 4f7a35ec8..e0b2dabc2 100644 --- a/src/lib/tls/tls_algos.h +++ b/src/lib/tls/tls_algos.h @@ -118,6 +118,8 @@ std::string signature_algorithm_of_scheme(Signature_Scheme scheme); * Matches with wire encoding */ enum class Group_Params : uint16_t { + NONE = 0, + SECP256R1 = 23, SECP384R1 = 24, SECP521R1 = 25, @@ -132,13 +134,11 @@ enum class Group_Params : uint16_t { FFDHE_4096 = 258, FFDHE_6144 = 259, FFDHE_8192 = 260, - -#if defined(BOTAN_HOUSE_ECC_CURVE_NAME) - HOUSE_CURVE = BOTAN_HOUSE_ECC_CURVE_TLS_ID, -#endif }; std::string group_param_to_string(Group_Params group); +Group_Params group_param_from_string(const std::string& group_name); +bool group_param_is_dh(Group_Params group); enum class Kex_Algo { STATIC_RSA, diff --git a/src/lib/tls/tls_callbacks.cpp b/src/lib/tls/tls_callbacks.cpp index b3b1b79bb..6919c36ca 100644 --- a/src/lib/tls/tls_callbacks.cpp +++ b/src/lib/tls/tls_callbacks.cpp @@ -8,6 +8,7 @@ #include <botan/tls_callbacks.h> #include <botan/tls_policy.h> +#include <botan/tls_algos.h> #include <botan/x509path.h> #include <botan/ocsp.h> #include <botan/dh.h> @@ -40,6 +41,11 @@ void TLS::Callbacks::tls_examine_extensions(const Extensions&, Connection_Side) { } +std::string TLS::Callbacks::tls_decode_group_param(Group_Params group_param) + { + return group_param_to_string(group_param); + } + void TLS::Callbacks::tls_verify_cert_chain( const std::vector<X509_Certificate>& cert_chain, const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses, diff --git a/src/lib/tls/tls_callbacks.h b/src/lib/tls/tls_callbacks.h index dd6ad2d4b..88e502e89 100644 --- a/src/lib/tls/tls_callbacks.h +++ b/src/lib/tls/tls_callbacks.h @@ -284,6 +284,17 @@ class BOTAN_PUBLIC_API(2,0) Callbacks virtual void tls_examine_extensions(const Extensions& extn, Connection_Side which_side); /** + * Optional callback: decode TLS group ID + * + * TLS uses a 16-bit field to identify ECC and DH groups. This callback + * handles the decoding. You only need to implement this if you are using + * a custom ECC or DH group (this is extremely uncommon). + * + * Default implementation uses the standard (IETF-defined) mappings. + */ + virtual std::string tls_decode_group_param(Group_Params group_param); + + /** * Optional callback: error logging. (not currently called) * @param err An error message related to this connection. */ diff --git a/src/lib/tls/tls_extensions.cpp b/src/lib/tls/tls_extensions.cpp index 6d69d7b45..e77de9c5e 100644 --- a/src/lib/tls/tls_extensions.cpp +++ b/src/lib/tls/tls_extensions.cpp @@ -28,8 +28,8 @@ Extension* make_extension(TLS_Data_Reader& reader, uint16_t code, uint16_t size) return new SRP_Identifier(reader, size); #endif - case TLSEXT_USABLE_ELLIPTIC_CURVES: - return new Supported_Elliptic_Curves(reader, size); + case TLSEXT_SUPPORTED_GROUPS: + return new Supported_Groups(reader, size); case TLSEXT_CERT_STATUS_REQUEST: return new Certificate_Status_Request(reader, size); @@ -295,123 +295,39 @@ std::vector<uint8_t> Application_Layer_Protocol_Notification::serialize() const return buf; } -Supported_Groups::Supported_Groups(const std::vector<std::string>& groups) : - m_groups(groups) +Supported_Groups::Supported_Groups(const std::vector<Group_Params>& 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) +std::vector<Group_Params> Supported_Groups::ec_groups() const { - switch(id) + std::vector<Group_Params> ec; + for(auto g : m_groups) { - case 23: - return "secp256r1"; - case 24: - return "secp384r1"; - case 25: - return "secp521r1"; - case 26: - return "brainpool256r1"; - case 27: - return "brainpool384r1"; - case 28: - return "brainpool512r1"; - -#if defined(BOTAN_HAS_CURVE_25519) - case 29: - return "x25519"; -#endif - -#if defined(BOTAN_HOUSE_ECC_CURVE_NAME) - case BOTAN_HOUSE_ECC_CURVE_TLS_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 + if(group_param_is_dh(g) == false) + ec.push_back(g); } + return ec; } -uint16_t Supported_Groups::name_to_curve_id(const std::string& name) - { - if(name == "secp256r1") - return 23; - if(name == "secp384r1") - return 24; - if(name == "secp521r1") - return 25; - if(name == "brainpool256r1") - return 26; - if(name == "brainpool384r1") - return 27; - if(name == "brainpool512r1") - return 28; - -#if defined(BOTAN_HAS_CURVE_25519) - if(name == "x25519") - return 29; -#endif - -#if defined(BOTAN_HOUSE_ECC_CURVE_NAME) - if(name == BOTAN_HOUSE_ECC_CURVE_NAME) - return BOTAN_HOUSE_ECC_CURVE_TLS_ID; -#endif - - 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; - } - -bool Supported_Groups::is_dh_group( const std::string& group_name ) +std::vector<Group_Params> Supported_Groups::dh_groups() const { - 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") + std::vector<Group_Params> dh; + for(auto g : m_groups) { - return true; + if(group_param_is_dh(g) == true) + dh.push_back(g); } - return false; + return dh; } std::vector<uint8_t> Supported_Groups::serialize() const { std::vector<uint8_t> buf(2); - for(size_t i = 0; i != m_groups.size(); ++i) + for(auto g : m_groups) { - const uint16_t id = name_to_curve_id(m_groups[i]); + const uint16_t id = static_cast<uint16_t>(g); if(id > 0) { @@ -427,9 +343,9 @@ std::vector<uint8_t> Supported_Groups::serialize() const } Supported_Groups::Supported_Groups(TLS_Data_Reader& reader, - uint16_t extension_size) + uint16_t extension_size) { - uint16_t len = reader.get_uint16_t(); + const uint16_t len = reader.get_uint16_t(); if(len + 2 != extension_size) throw Decoding_Error("Inconsistent length field in supported groups list"); @@ -437,28 +353,10 @@ Supported_Groups::Supported_Groups(TLS_Data_Reader& reader, if(len % 2 == 1) throw Decoding_Error("Supported groups list of strange size"); - len /= 2; - - for(size_t i = 0; i != len; ++i) + for(size_t i = 0; i != len / 2; ++i) { const uint16_t id = reader.get_uint16_t(); - const Group_Params group_id = static_cast<Group_Params>(id); - - const bool is_dh = (id >= 256 && id <= 511); - const std::string name = group_param_to_string(group_id); - - if(!name.empty()) - { - m_groups.push_back(name); - if(is_dh) - { - m_dh_groups.push_back(name); - } - else - { - m_curves.push_back(name); - } - } + m_groups.push_back(static_cast<Group_Params>(id)); } } diff --git a/src/lib/tls/tls_extensions.h b/src/lib/tls/tls_extensions.h index a1ed3f858..f87c07f2e 100644 --- a/src/lib/tls/tls_extensions.h +++ b/src/lib/tls/tls_extensions.h @@ -1,8 +1,8 @@ /* * TLS Extensions -* (C) 2011,2012,2016 Jack Lloyd -* 2016 Juraj Somorovsky -* 2016 Matthias Gierlings +* (C) 2011,2012,2016,2018 Jack Lloyd +* (C) 2016 Juraj Somorovsky +* (C) 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -29,7 +29,7 @@ enum Handshake_Extension_Type { TLSEXT_CERT_STATUS_REQUEST = 5, TLSEXT_CERTIFICATE_TYPES = 9, - TLSEXT_USABLE_ELLIPTIC_CURVES = 10, + TLSEXT_SUPPORTED_GROUPS = 10, TLSEXT_EC_POINT_FORMATS = 11, TLSEXT_SRP_IDENTIFIER = 12, TLSEXT_SIGNATURE_ALGORITHMS = 13, @@ -234,34 +234,27 @@ class Supported_Groups final : public Extension { public: static Handshake_Extension_Type static_type() - { return TLSEXT_USABLE_ELLIPTIC_CURVES; } + { return TLSEXT_SUPPORTED_GROUPS; } Handshake_Extension_Type type() const override { return static_type(); } - 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<Group_Params> ec_groups() const; + std::vector<Group_Params> dh_groups() const; std::vector<uint8_t> serialize() const override; - explicit Supported_Groups(const std::vector<std::string>& groups); + explicit Supported_Groups(const std::vector<Group_Params>& groups); Supported_Groups(TLS_Data_Reader& reader, - uint16_t extension_size); + uint16_t extension_size); 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; + std::vector<Group_Params> m_groups; }; // previously Supported Elliptic Curves Extension (RFC 4492) -using Supported_Elliptic_Curves = Supported_Groups; +//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 03b07fe27..98c46dfa8 100644 --- a/src/lib/tls/tls_messages.h +++ b/src/lib/tls/tls_messages.h @@ -106,9 +106,9 @@ class BOTAN_UNSTABLE_API Client_Hello final : public Handshake_Message std::vector<Signature_Scheme> signature_schemes() const; - std::vector<std::string> supported_ecc_curves() const; + std::vector<Group_Params> supported_ecc_curves() const; - std::vector<std::string> supported_dh_groups() const; + std::vector<Group_Params> supported_dh_groups() const; bool prefers_compressed_ec_points() const; diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp index 2c63aa840..7fd7af235 100644 --- a/src/lib/tls/tls_policy.cpp +++ b/src/lib/tls/tls_policy.cpp @@ -9,9 +9,8 @@ #include <botan/tls_policy.h> #include <botan/tls_ciphersuite.h> -#include <botan/tls_magic.h> +#include <botan/tls_algos.h> #include <botan/tls_exceptn.h> -#include <botan/tls_extensions.h> #include <botan/internal/stl_util.h> #include <botan/pk_keys.h> #include <sstream> @@ -123,90 +122,58 @@ bool Policy::allowed_signature_hash(const std::string& sig_hash) const return value_exists(allowed_signature_hashes(), sig_hash); } -std::vector<std::string> Policy::allowed_ecc_curves() const - { - // Default list is ordered by performance - - return { - "x25519", - "secp256r1", - "secp521r1", - "secp384r1", - "brainpool256r1", - "brainpool384r1", - "brainpool512r1", - }; - } - -bool Policy::allowed_ecc_curve(const std::string& curve) const - { - 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 { return false; } -/* -* Choose an ECC curve to use -*/ -std::string Policy::choose_curve(const std::vector<std::string>& curve_names) const +Group_Params Policy::choose_key_exchange_group(const std::vector<Group_Params>& peer_groups) const { - const std::vector<std::string> our_groups = allowed_groups(); + if(peer_groups.empty()) + return Group_Params::NONE; - 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]; + const std::vector<Group_Params> our_groups = key_exchange_groups(); - return ""; // no shared curve - } - -/* -* Choose an FFDHE group to use -*/ -std::string Policy::choose_dh_group(const std::vector<std::string>& dh_groups) const - { - if(dh_groups.empty()) - return dh_group(); - - 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]; + for(auto g : our_groups) + { + if(value_exists(peer_groups, g)) + return g; + } - return ""; // no shared ffdhe group + return Group_Params::NONE; } -std::string Policy::dh_group() const +Group_Params Policy::default_dh_group() const { - // We offer 2048 bit DH because we can - return "modp/ietf/2048"; + /* + * Return the first listed or just default to 2048 + */ + for(auto g : key_exchange_groups()) + { + if(group_param_is_dh(g)) + return g; + } + + return Group_Params::FFDHE_2048; } -std::vector<std::string> Policy::allowed_groups() const +std::vector<Group_Params> Policy::key_exchange_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" + Group_Params::X25519, + Group_Params::SECP256R1, + Group_Params::SECP521R1, + Group_Params::SECP384R1, + Group_Params::BRAINPOOL256R1, + Group_Params::BRAINPOOL384R1, + Group_Params::BRAINPOOL512R1, + + Group_Params::FFDHE_2048, + Group_Params::FFDHE_3072, + Group_Params::FFDHE_4096, + Group_Params::FFDHE_6144, + Group_Params::FFDHE_8192, }; } @@ -448,7 +415,7 @@ class Ciphersuite_Preference_Ordering final } std::vector<uint16_t> Policy::ciphersuite_list(Protocol_Version version, - bool have_srp) const + bool have_srp) const { const std::vector<std::string> ciphers = allowed_ciphers(); const std::vector<std::string> macs = allowed_macs(); @@ -503,8 +470,11 @@ std::vector<uint16_t> Policy::ciphersuite_list(Protocol_Version version, removal of x25519 from the ECC curve list as equivalent to saying they do not trust CECPQ1 */ - if(suite.kex_method() == Kex_Algo::CECPQ1 && allowed_ecc_curve("x25519") == false) - continue; + if(suite.kex_method() == Kex_Algo::CECPQ1) + { + if(value_exists(key_exchange_groups(), Group_Params::X25519) == false) + continue; + } // OK, consider it ciphersuites.push_back(suite); @@ -540,6 +510,20 @@ void print_vec(std::ostream& o, o << '\n'; } +void print_vec(std::ostream& o, + const char* key, + const std::vector<Group_Params>& v) + { + o << key << " = "; + for(size_t i = 0; i != v.size(); ++i) + { + o << group_param_to_string(v[i]); + if(i != v.size() - 1) + o << ' '; + } + o << '\n'; + } + void print_bool(std::ostream& o, const char* key, bool b) { @@ -560,8 +544,7 @@ void Policy::print(std::ostream& o) const print_vec(o, "signature_hashes", allowed_signature_hashes()); 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_vec(o, "key_exchange_groups", key_exchange_groups()); print_bool(o, "allow_insecure_renegotiation", allow_insecure_renegotiation()); print_bool(o, "include_time_in_hello_random", include_time_in_hello_random()); @@ -571,7 +554,6 @@ void Policy::print(std::ostream& o) const print_bool(o, "negotiate_encrypt_then_mac", negotiate_encrypt_then_mac()); print_bool(o, "support_cert_status_message", support_cert_status_message()); o << "session_ticket_lifetime = " << session_ticket_lifetime() << '\n'; - o << "dh_group = " << dh_group() << '\n'; o << "minimum_dh_group_size = " << minimum_dh_group_size() << '\n'; o << "minimum_ecdh_group_size = " << minimum_ecdh_group_size() << '\n'; o << "minimum_rsa_bits = " << minimum_rsa_bits() << '\n'; diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h index a3d175201..615e1674b 100644 --- a/src/lib/tls/tls_policy.h +++ b/src/lib/tls/tls_policy.h @@ -81,23 +81,10 @@ 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. - * Allowed values: x25519, secp256r1, secp384r1, secp521r1, - * brainpool256r1, brainpool384r1, brainpool512r1 + * Return list of ECC curves and FFDHE groups we are willing to + * use in order of preference. */ - 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; + virtual std::vector<Group_Params> key_exchange_groups() const; /** * Request that ECC curve points are sent compressed @@ -105,14 +92,10 @@ class BOTAN_PUBLIC_API(2,0) Policy virtual bool use_ecc_point_compression() const; /** - * Choose an elliptic curve to use - */ - virtual std::string choose_curve(const std::vector<std::string>& curve_names) const; - - /** - * Choose an FFHDE group to use + * Select a key exchange group to use, from the list of groups sent by the + * peer. If none are acceptable, return Group_Params::NONE */ - virtual std::string choose_dh_group(const std::vector<std::string>& dh_group_names) const; + virtual Group_Params choose_key_exchange_group(const std::vector<Group_Params>& peer_groups) const; /** * Allow renegotiation even if the counterparty doesn't @@ -166,7 +149,7 @@ class BOTAN_PUBLIC_API(2,0) Policy */ virtual bool allow_dtls12() const; - virtual std::string dh_group() const; + virtual Group_Params default_dh_group() const; /** * Return the minimum DH group size we're willing to use @@ -291,7 +274,7 @@ class BOTAN_PUBLIC_API(2,0) Policy * Return allowed ciphersuites, in order of preference */ virtual std::vector<uint16_t> ciphersuite_list(Protocol_Version version, - bool have_srp) const; + bool have_srp) const; /** * @return the default MTU for DTLS @@ -323,6 +306,8 @@ class BOTAN_PUBLIC_API(2,0) Policy virtual ~Policy() = default; }; +typedef Policy Default_Policy; + /** * NSA Suite B 128-bit security level (RFC 6460) */ @@ -344,11 +329,8 @@ class BOTAN_PUBLIC_API(2,0) NSA_Suite_B_128 : public Policy std::vector<std::string> allowed_signature_methods() const override { return std::vector<std::string>({"ECDSA"}); } - 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(); } + std::vector<Group_Params> key_exchange_groups() const override + { return {Group_Params::SECP256R1}; } size_t minimum_signature_strength() const override { return 128; } @@ -390,15 +372,20 @@ class BOTAN_PUBLIC_API(2,0) BSI_TR_02102_2 : public Policy return std::vector<std::string>({"ECDSA", "RSA", "DSA"}); } - std::vector<std::string> allowed_ecc_curves() const override + std::vector<Group_Params> key_exchange_groups() const override { - 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"}); + return std::vector<Group_Params>({ + Group_Params::BRAINPOOL512R1, + Group_Params::BRAINPOOL384R1, + Group_Params::BRAINPOOL256R1, + Group_Params::SECP384R1, + Group_Params::SECP256R1, + Group_Params::FFDHE_8192, + Group_Params::FFDHE_6144, + Group_Params::FFDHE_4096, + Group_Params::FFDHE_3072, + Group_Params::FFDHE_2048 + }); } bool allow_insecure_renegotiation() const override { return false; } @@ -475,9 +462,7 @@ class BOTAN_PUBLIC_API(2,0) Text_Policy : public Policy std::vector<std::string> allowed_signature_methods() const override; - std::vector<std::string> allowed_ecc_curves() const override; - - std::vector<std::string> allowed_groups() const override; + std::vector<Group_Params> key_exchange_groups() const; bool use_ecc_point_compression() const override; @@ -504,8 +489,6 @@ class BOTAN_PUBLIC_API(2,0) Text_Policy : public Policy bool support_cert_status_message() const override; - std::string dh_group() const override; - size_t minimum_ecdh_group_size() const override; size_t minimum_ecdsa_group_size() const override; diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp index 61a360ba9..b4e74c775 100644 --- a/src/lib/tls/tls_server.cpp +++ b/src/lib/tls/tls_server.cpp @@ -166,7 +166,7 @@ uint16_t choose_ciphersuite( "Policy forbids us from negotiating any ciphersuite"); const bool have_shared_ecc_curve = - (policy.choose_curve(client_hello.supported_ecc_curves()) != ""); + (policy.choose_key_exchange_group(client_hello.supported_ecc_curves()) != Group_Params::NONE); /* Walk down one list in preference order diff --git a/src/lib/tls/tls_text_policy.cpp b/src/lib/tls/tls_text_policy.cpp index 97a6da31a..5c7a4b278 100644 --- a/src/lib/tls/tls_text_policy.cpp +++ b/src/lib/tls/tls_text_policy.cpp @@ -40,11 +40,6 @@ std::vector<std::string> Text_Policy::allowed_signature_methods() const return get_list("signature_methods", Policy::allowed_signature_methods()); } -std::vector<std::string> Text_Policy::allowed_ecc_curves() const - { - return get_list("ecc_curves", Policy::allowed_ecc_curves()); - } - bool Text_Policy::use_ecc_point_compression() const { return get_bool("use_ecc_point_compression", Policy::use_ecc_point_compression()); @@ -89,6 +84,7 @@ bool Text_Policy::allow_client_initiated_renegotiation() const { return get_bool("allow_client_initiated_renegotiation", Policy::allow_client_initiated_renegotiation()); } + bool Text_Policy::allow_server_initiated_renegotiation() const { return get_bool("allow_server_initiated_renegotiation", Policy::allow_server_initiated_renegotiation()); @@ -109,14 +105,53 @@ bool Text_Policy::support_cert_status_message() const return get_bool("support_cert_status_message", Policy::support_cert_status_message()); } -std::string Text_Policy::dh_group() const +std::vector<Group_Params> Text_Policy::key_exchange_groups() const { - return get_str("dh_group", Policy::dh_group()); - } + std::string group_str = get_str("key_exchange_groups"); -std::vector<std::string> Text_Policy::allowed_groups() const - { - return get_list("groups", Policy::allowed_groups()); + if(group_str.empty()) + { + // fall back to previously used name + group_str = get_str("groups"); + } + + if(group_str.empty()) + { + return Policy::key_exchange_groups(); + } + + std::vector<Group_Params> groups; + for(std::string group_name : split_on(group_str, ' ')) + { + Group_Params group_id = group_param_from_string(group_name); + + if(group_id == Group_Params::NONE) + { + try + { + size_t consumed = 0; + unsigned long ll_id = std::stoul(group_name, &consumed, 0); + if(consumed != group_name.size()) + continue; // some other cruft + + const uint16_t id = static_cast<uint16_t>(ll_id); + + if(id != ll_id) + continue; // integer too large + + group_id = static_cast<Group_Params>(id); + } + catch(...) + { + continue; + } + } + + if(group_id != Group_Params::NONE) + groups.push_back(group_id); + } + + return groups; } size_t Text_Policy::minimum_ecdh_group_size() const |