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