aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2018-02-19 12:38:11 -0500
committerJack Lloyd <[email protected]>2018-02-19 12:38:11 -0500
commitbf337951e36f1be8f64f4ea2aa3d401cfb591f6d (patch)
tree1fbf9d5f6a3a56c80124c913b5f3e7a0ad680b69
parent9792c0eb8203a4982d28afebb19b027444753f90 (diff)
parent9abd3b8ac7927c40082e4e2956bdce7f5254fdea (diff)
Merge GH #1448 Support custom curves in TLS handshake
-rwxr-xr-xconfigure.py35
-rw-r--r--src/build-data/buildh.in4
-rw-r--r--src/lib/asn1/oids.cpp10
-rw-r--r--src/lib/pubkey/ec_group/ec_named.cpp3
-rw-r--r--src/lib/tls/msg_client_hello.cpp24
-rw-r--r--src/lib/tls/msg_client_kex.cpp20
-rw-r--r--src/lib/tls/msg_server_hello.cpp2
-rw-r--r--src/lib/tls/msg_server_kex.cpp47
-rw-r--r--src/lib/tls/tls_algos.cpp42
-rw-r--r--src/lib/tls/tls_algos.h8
-rw-r--r--src/lib/tls/tls_callbacks.cpp6
-rw-r--r--src/lib/tls/tls_callbacks.h11
-rw-r--r--src/lib/tls/tls_extensions.cpp144
-rw-r--r--src/lib/tls/tls_extensions.h29
-rw-r--r--src/lib/tls/tls_messages.h4
-rw-r--r--src/lib/tls/tls_policy.cpp132
-rw-r--r--src/lib/tls/tls_policy.h69
-rw-r--r--src/lib/tls/tls_server.cpp2
-rw-r--r--src/lib/tls/tls_text_policy.cpp57
-rwxr-xr-xsrc/scripts/oids.py8
-rw-r--r--src/tests/data/tls-policy/bsi.txt41
-rw-r--r--src/tests/data/tls-policy/compat.txt3
-rw-r--r--src/tests/data/tls-policy/datagram.txt2
-rw-r--r--src/tests/data/tls-policy/default.txt3
-rw-r--r--src/tests/data/tls-policy/strict.txt3
-rw-r--r--src/tests/data/tls-policy/suiteb.txt4
-rw-r--r--src/tests/test_tls.cpp11
-rw-r--r--src/tests/unit_tls.cpp55
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;
}