diff options
author | Jack Lloyd <[email protected]> | 2018-02-19 12:38:11 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2018-02-19 12:38:11 -0500 |
commit | bf337951e36f1be8f64f4ea2aa3d401cfb591f6d (patch) | |
tree | 1fbf9d5f6a3a56c80124c913b5f3e7a0ad680b69 | |
parent | 9792c0eb8203a4982d28afebb19b027444753f90 (diff) | |
parent | 9abd3b8ac7927c40082e4e2956bdce7f5254fdea (diff) |
Merge GH #1448 Support custom curves in TLS handshake
28 files changed, 348 insertions, 431 deletions
diff --git a/configure.py b/configure.py index c6b9fde64..14f8a7dcc 100755 --- a/configure.py +++ b/configure.py @@ -539,11 +539,6 @@ def process_command_line(args): # pylint: disable=too-many-locals install_group.add_option('--includedir', metavar='DIR', help='set the include file install dir') - misc_group = optparse.OptionGroup(parser, 'Miscellaneous options') - - misc_group.add_option('--house-curve', metavar='STRING', dest='house_curve', - help='a custom in-house curve of the format: curve.pem,NAME,OID,CURVEID') - info_group = optparse.OptionGroup(parser, 'Informational') info_group.add_option('--list-modules', dest='list_modules', @@ -559,7 +554,6 @@ def process_command_line(args): # pylint: disable=too-many-locals parser.add_option_group(docs_group) parser.add_option_group(mods_group) parser.add_option_group(install_group) - parser.add_option_group(misc_group) parser.add_option_group(info_group) # These exist only for autoconf compatibility (requested by zw for mtn) @@ -1641,34 +1635,6 @@ def generate_build_info(build_paths, modules, cc, arch, osinfo): return out -def house_ecc_curve_macros(house_curve): - def _read_pem(filepath): - try: - with open(filepath) as f: - lines = [line.rstrip() for line in f] - except IOError: - raise UserError("Error reading file '%s'" % filepath) - - for ndx, _ in enumerate(lines): - lines[ndx] = ' \"%s\"' % lines[ndx] - return "\\\n" + ' \\\n'.join(lines) - - if house_curve is None: - return [] - else: - p = house_curve.split(",") - if len(p) != 4: - raise UserError('--house-curve must have 4 comma separated parameters. See --help') - # make sure TLS curve id is in reserved for private use range (0xFE00..0xFEFF) - curve_id = int(p[3], 16) - if curve_id < 0xfe00 or curve_id > 0xfeff: - raise UserError('TLS curve ID not in reserved range (see RFC 4492)') - - return ['NAME \"' + p[1] + '\"', - 'OID \"' + p[2] + '\"', - 'PEM ' + _read_pem(filepath=p[0]), - 'TLS_ID ' + hex(curve_id)] - def create_template_vars(source_paths, build_paths, options, modules, cc, arch, osinfo): #pylint: disable=too-many-locals,too-many-branches,too-many-statements @@ -1890,7 +1856,6 @@ def create_template_vars(source_paths, build_paths, options, modules, cc, arch, 'os_features': osinfo.enabled_features(options), 'os_name': osinfo.basename, 'cpu_features': arch.supported_isa_extensions(cc, options), - 'house_ecc_curve_defines': house_ecc_curve_macros(options.house_curve), 'fuzzer_mode': options.unsafe_fuzzer_mode, 'fuzzer_type': options.build_fuzzers.upper() if options.build_fuzzers else '', diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in index 24eae539a..06ae5b598 100644 --- a/src/build-data/buildh.in +++ b/src/build-data/buildh.in @@ -87,10 +87,6 @@ */ %{local_config} -%{for house_ecc_curve_defines} -#define BOTAN_HOUSE_ECC_CURVE_%{i} -%{endfor} - /* * Things you can edit (but probably shouldn't) */ diff --git a/src/lib/asn1/oids.cpp b/src/lib/asn1/oids.cpp index b9ba1f858..59ce08b35 100644 --- a/src/lib/asn1/oids.cpp +++ b/src/lib/asn1/oids.cpp @@ -44,11 +44,6 @@ class OID_Map { const std::string oid_str = oid.as_string(); -#if defined(BOTAN_HOUSE_ECC_CURVE_NAME) - if(oid_str == BOTAN_HOUSE_ECC_CURVE_OID) - return BOTAN_HOUSE_ECC_CURVE_NAME; -#endif - lock_guard_type<mutex_type> lock(m_mutex); auto i = m_oid2str.find(oid_str); @@ -60,11 +55,6 @@ class OID_Map OID lookup(const std::string& str) { -#if defined(BOTAN_HOUSE_ECC_CURVE_NAME) - if(str == BOTAN_HOUSE_ECC_CURVE_NAME) - return OID(BOTAN_HOUSE_ECC_CURVE_OID); -#endif - lock_guard_type<mutex_type> lock(m_mutex); auto i = m_str2oid.find(str); if(i != m_str2oid.end()) diff --git a/src/lib/pubkey/ec_group/ec_named.cpp b/src/lib/pubkey/ec_group/ec_named.cpp index cfab1fafd..ba91b5eaa 100644 --- a/src/lib/pubkey/ec_group/ec_named.cpp +++ b/src/lib/pubkey/ec_group/ec_named.cpp @@ -283,9 +283,6 @@ const std::set<std::string>& EC_Group::known_named_groups() "gost_256A", "frp256v1", "sm2p256v1" -#if defined(BOTAN_HOUSE_ECC_CURVE_NAME) - ,BOTAN_HOUSE_ECC_CURVE_NAME -#endif }; return named_groups; } 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 diff --git a/src/scripts/oids.py b/src/scripts/oids.py index 61a31a6f6..8b9d8ba3e 100755 --- a/src/scripts/oids.py +++ b/src/scripts/oids.py @@ -107,10 +107,6 @@ std::string lookup(const OID& oid) const std::string oid_str = oid.as_string(); %s -#if defined(BOTAN_HOUSE_ECC_CURVE_NAME) - if(oid_str == BOTAN_HOUSE_ECC_CURVE_OID) return BOTAN_HOUSE_ECC_CURVE_NAME; -#endif - return std::string(); } @@ -118,10 +114,6 @@ OID lookup(const std::string& name) { %s -#if defined(BOTAN_HOUSE_ECC_CURVE_NAME) - if(name == BOTAN_HOUSE_ECC_CURVE_NAME) return OID(BOTAN_HOUSE_ECC_CURVE_OID); -#endif - return OID(); } diff --git a/src/tests/data/tls-policy/bsi.txt b/src/tests/data/tls-policy/bsi.txt index 9879b87f5..c62777472 100644 --- a/src/tests/data/tls-policy/bsi.txt +++ b/src/tests/data/tls-policy/bsi.txt @@ -1,23 +1,22 @@ -allow_tls10=false -allow_tls11=false -allow_tls12=true -allow_dtls10=false -allow_dtls12=false +allow_tls10 = false +allow_tls11 = false +allow_tls12 = true +allow_dtls10 = false +allow_dtls12 = false -ciphers=AES-256/GCM AES-128/GCM AES-256 AES-128 -signature_hashes=SHA-384 SHA-256 -macs=AEAD SHA-384 SHA-256 -key_exchange_methods=ECDH DH PSK ECDHE_PSK DHE_PSK -signature_methods=ECDSA RSA DSA -ecc_curves=brainpool512r1 brainpool384r1 brainpool256r1 secp384r1 secp256r1 -groups=brainpool512r1 brainpool384r1 brainpool256r1 secp384r1 secp256r1 ffdhe/ietf/8192 ffdhe/ietf/6144 ffdhe/ietf/4096 ffdhe/ietf/3072 ffdhe/ietf/2048 -minimum_dh_group_size=2000 -minimum_dsa_group_size=2000 -minimum_ecdh_group_size=250 -minimum_ecdsa_group_size=250 -minimum_rsa_bits=2000 +ciphers = AES-256/GCM AES-128/GCM AES-256 AES-128 +signature_hashes = SHA-384 SHA-256 +macs = AEAD SHA-384 SHA-256 +key_exchange_methods = ECDH DH PSK ECDHE_PSK DHE_PSK +signature_methods = ECDSA RSA DSA +key_exchange_groups = brainpool512r1 brainpool384r1 brainpool256r1 secp384r1 secp256r1 ffdhe/ietf/8192 ffdhe/ietf/6144 ffdhe/ietf/4096 ffdhe/ietf/3072 ffdhe/ietf/2048 +minimum_dh_group_size = 2000 +minimum_dsa_group_size = 2000 +minimum_ecdh_group_size = 250 +minimum_ecdsa_group_size = 250 +minimum_rsa_bits = 2000 -allow_insecure_renegotiation=false -allow_server_initiated_renegotiation=true -server_uses_own_ciphersuite_preferences=true -negotiate_encrypt_then_mac=true +allow_insecure_renegotiation = false +allow_server_initiated_renegotiation = true +server_uses_own_ciphersuite_preferences = true +negotiate_encrypt_then_mac = true diff --git a/src/tests/data/tls-policy/compat.txt b/src/tests/data/tls-policy/compat.txt index 473453ab0..cd419e91a 100644 --- a/src/tests/data/tls-policy/compat.txt +++ b/src/tests/data/tls-policy/compat.txt @@ -14,7 +14,7 @@ macs = AEAD SHA-256 SHA-384 SHA-1 signature_hashes = SHA-512 SHA-384 SHA-256 SHA-1 signature_methods = ECDSA RSA IMPLICIT key_exchange_methods = CECPQ1 ECDH DH RSA -ecc_curves = x25519 secp256r1 secp521r1 secp384r1 brainpool256r1 brainpool384r1 brainpool512r1 +key_exchange_groups = x25519 secp256r1 secp521r1 secp384r1 brainpool256r1 brainpool384r1 brainpool512r1 ffdhe/ietf/2048 allow_insecure_renegotiation = false include_time_in_hello_random = true allow_client_initiated_renegotiation = true @@ -23,7 +23,6 @@ hide_unknown_users = false server_uses_own_ciphersuite_preferences = true negotiate_encrypt_then_mac = true session_ticket_lifetime = 86400 -dh_group = modp/ietf/1024 minimum_dh_group_size = 1024 minimum_ecdh_group_size = 255 minimum_rsa_bits = 1024 diff --git a/src/tests/data/tls-policy/datagram.txt b/src/tests/data/tls-policy/datagram.txt index 6a9819aff..d6071a906 100644 --- a/src/tests/data/tls-policy/datagram.txt +++ b/src/tests/data/tls-policy/datagram.txt @@ -8,7 +8,7 @@ macs = AEAD signature_hashes = SHA-512 SHA-384 SHA-256 signature_methods = ECDSA RSA key_exchange_methods = CECPQ1 ECDH DH -ecc_curves = x25519 secp256r1 secp521r1 secp384r1 brainpool256r1 brainpool384r1 brainpool512r1 +key_exchange_groups = x25519 secp256r1 secp521r1 secp384r1 brainpool256r1 brainpool384r1 brainpool512r1 ffdhe/ietf/2048 ffdhe/ietf/3072 ffdhe/ietf/4096 ffdhe/ietf/6144 ffdhe/ietf/8192 allow_insecure_renegotiation = false include_time_in_hello_random = true allow_server_initiated_renegotiation = false diff --git a/src/tests/data/tls-policy/default.txt b/src/tests/data/tls-policy/default.txt index c96f91d96..0cf3dbbf8 100644 --- a/src/tests/data/tls-policy/default.txt +++ b/src/tests/data/tls-policy/default.txt @@ -8,7 +8,7 @@ macs = AEAD SHA-256 SHA-384 SHA-1 signature_hashes = SHA-512 SHA-384 SHA-256 signature_methods = ECDSA RSA key_exchange_methods = CECPQ1 ECDH DH -ecc_curves = x25519 secp256r1 secp521r1 secp384r1 brainpool256r1 brainpool384r1 brainpool512r1 +key_exchange_groups = x25519 secp256r1 secp521r1 secp384r1 brainpool256r1 brainpool384r1 brainpool512r1 ffdhe/ietf/2048 ffdhe/ietf/3072 ffdhe/ietf/4096 ffdhe/ietf/6144 ffdhe/ietf/8192 allow_insecure_renegotiation = false include_time_in_hello_random = true allow_server_initiated_renegotiation = false @@ -16,7 +16,6 @@ hide_unknown_users = false server_uses_own_ciphersuite_preferences = true negotiate_encrypt_then_mac = true session_ticket_lifetime = 86400 -dh_group = modp/ietf/2048 minimum_dh_group_size = 2048 minimum_ecdh_group_size = 255 minimum_rsa_bits = 2048 diff --git a/src/tests/data/tls-policy/strict.txt b/src/tests/data/tls-policy/strict.txt index f59aaf271..7cb55bb83 100644 --- a/src/tests/data/tls-policy/strict.txt +++ b/src/tests/data/tls-policy/strict.txt @@ -8,7 +8,7 @@ macs = AEAD signature_hashes = SHA-512 SHA-384 signature_methods = ECDSA RSA key_exchange_methods = CECPQ1 ECDH -ecc_curves = x25519 secp256r1 secp521r1 secp384r1 brainpool256r1 brainpool384r1 brainpool512r1 +key_exchange_groups = x25519 secp256r1 secp521r1 secp384r1 brainpool256r1 brainpool384r1 brainpool512r1 ffdhe/ietf/2048 ffdhe/ietf/3072 ffdhe/ietf/4096 ffdhe/ietf/6144 ffdhe/ietf/8192 allow_insecure_renegotiation = false include_time_in_hello_random = true allow_server_initiated_renegotiation = false @@ -16,7 +16,6 @@ hide_unknown_users = false server_uses_own_ciphersuite_preferences = true negotiate_encrypt_then_mac = true session_ticket_lifetime = 86400 -dh_group = modp/ietf/2048 minimum_dh_group_size = 2048 minimum_ecdh_group_size = 255 minimum_rsa_bits = 2048 diff --git a/src/tests/data/tls-policy/suiteb.txt b/src/tests/data/tls-policy/suiteb.txt index 7c0b3e7d8..90ef68f4a 100644 --- a/src/tests/data/tls-policy/suiteb.txt +++ b/src/tests/data/tls-policy/suiteb.txt @@ -8,7 +8,7 @@ macs = AEAD signature_hashes = SHA-256 signature_methods = ECDSA key_exchange_methods = ECDH -ecc_curves = secp256r1 +key_exchange_groups = secp256r1 allow_insecure_renegotiation = false include_time_in_hello_random = true allow_server_initiated_renegotiation = false @@ -16,8 +16,6 @@ hide_unknown_users = false server_uses_own_ciphersuite_preferences = true negotiate_encrypt_then_mac = true session_ticket_lifetime = 86400 -dh_group = modp/ietf/2048 -groups = secp256r1 minimum_dh_group_size = 2048 minimum_ecdh_group_size = 255 minimum_rsa_bits = 2048 diff --git a/src/tests/test_tls.cpp b/src/tests/test_tls.cpp index 4762653ac..728c13735 100644 --- a/src/tests/test_tls.cpp +++ b/src/tests/test_tls.cpp @@ -108,7 +108,7 @@ class Test_TLS_Alert_Strings : public Test BOTAN_REGISTER_TEST("tls_alert_strings", Test_TLS_Alert_Strings); -class Test_TLS_Policy_Test : public Test +class Test_TLS_Policy_Text : public Test { public: std::vector<Test::Result> run() override @@ -119,9 +119,10 @@ class Test_TLS_Policy_Test : public Test for(std::string policy : policies) { - result.test_eq("Values for TLS " + policy + " policy", - tls_policy_string(policy), - read_tls_policy(policy)); + const std::string from_policy_obj = tls_policy_string(policy); + const std::string from_file = read_tls_policy(policy); + + result.test_eq("Values for TLS " + policy + " policy", from_file, from_policy_obj); } return {result}; @@ -174,7 +175,7 @@ class Test_TLS_Policy_Test : public Test } }; -BOTAN_REGISTER_TEST("tls_policy_test", Test_TLS_Policy_Test); +BOTAN_REGISTER_TEST("tls_policy_text", Test_TLS_Policy_Text); class Test_TLS_Ciphersuites : public Test { diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index 0a5739c3d..9d95a199a 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -21,6 +21,7 @@ #include <botan/ec_group.h> #include <botan/hex.h> + #include <botan/oids.h> #include <botan/pkcs10.h> #include <botan/rsa.h> #include <botan/ecdsa.h> @@ -443,6 +444,14 @@ class TLS_Handshake_Test final return "test/3"; } + virtual std::string tls_decode_group_param(Botan::TLS::Group_Params group_param) + { + if(static_cast<uint16_t>(group_param) == 0xFEE1) + return "secp112r1"; + + return Botan::TLS::Callbacks::tls_decode_group_param(group_param); + } + private: Test::Result& m_results; const Botan::TLS::Protocol_Version m_expected_version; @@ -686,13 +695,20 @@ class TLS_Unit_Tests final : public Test { Botan::RandomNumberGenerator& rng = Test::rng(); - for(auto const& version : versions) + try { - TLS_Handshake_Test test( - version.to_string() + " " + test_descr, - version, creds, policy, policy, rng, client_ses, server_ses, client_auth); - test.go(); - results.push_back(test.results()); + for(auto const& version : versions) + { + TLS_Handshake_Test test( + version.to_string() + " " + test_descr, + version, creds, policy, policy, rng, client_ses, server_ses, client_auth); + test.go(); + results.push_back(test.results()); + } + } + catch(std::exception& e) + { + results.push_back(Test::Result::Failure(test_descr, e.what())); } } @@ -946,11 +962,28 @@ class TLS_Unit_Tests final : public Test test_modern_versions("AES-128 DHE_PSK", results, *client_ses, *server_ses, *creds, "DHE_PSK", "AES-128", "SHA-1"); #endif -#if defined(BOTAN_HOUSE_ECC_CURVE_NAME) - test_modern_versions("AES-128/GCM house curve", - results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD", - { { "groups", BOTAN_HOUSE_ECC_CURVE_NAME } }); -#endif + // Test with a custom curve + + /* + * First register a curve, in this case secp112r1 + */ + const Botan::BigInt p("0xDB7C2ABF62E35E668076BEAD208B"); + const Botan::BigInt a("0xDB7C2ABF62E35E668076BEAD2088"); + const Botan::BigInt b("0x659EF8BA043916EEDE8911702B22"); + + const Botan::BigInt g_x("0x09487239995A5EE76B55F9C2F098"); + const Botan::BigInt g_y("0xA89CE5AF8724C0A23E0E0FF77500"); + const Botan::BigInt order("0xDB7C2ABF62E35E7628DFAC6561C5"); + + const Botan::OID oid("1.3.132.0.6"); + + // Creating this object implicitly registers the curve for future use ... + Botan::EC_Group reg_secp112r1(p, a, b, g_x, g_y, order, 1, oid); + + Botan::OIDS::add_oid(oid, "secp112r1"); + + test_modern_versions("AES-256/GCM secp112r1", results, *client_ses, *server_ses, *creds, "ECDH", "AES-256/GCM", "AEAD", + { { "groups", "0xFEE1" }, { "minimum_ecdh_group_size", "112" } }); return results; } |