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.cpp16
-rw-r--r--src/lib/tls/msg_client_kex.cpp29
-rw-r--r--src/lib/tls/msg_server_kex.cpp5
-rw-r--r--src/lib/tls/tls_extensions.cpp81
-rw-r--r--src/lib/tls/tls_extensions.h20
-rw-r--r--src/lib/tls/tls_messages.h2
-rw-r--r--src/lib/tls/tls_policy.cpp51
-rw-r--r--src/lib/tls/tls_policy.h18
-rw-r--r--src/lib/tls/tls_server.cpp7
-rw-r--r--src/lib/tls/tls_text_policy.cpp5
10 files changed, 207 insertions, 27 deletions
diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp
index bb7d84df8..e804a0cf0 100644
--- a/src/lib/tls/msg_client_hello.cpp
+++ b/src/lib/tls/msg_client_hello.cpp
@@ -121,9 +121,10 @@ Client_Hello::Client_Hello(Handshake_IO& io,
}
#endif
- m_extensions.add(new Supported_Elliptic_Curves(policy.allowed_ecc_curves()));
+ Supported_Groups* supported_groups = new Supported_Groups(policy.allowed_groups());
+ m_extensions.add(supported_groups);
- if(!policy.allowed_ecc_curves().empty())
+ if(!supported_groups->curves().empty())
{
m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression()));
}
@@ -324,8 +325,15 @@ std::set<std::string> Client_Hello::supported_sig_algos() const
std::vector<std::string> Client_Hello::supported_ecc_curves() const
{
- if(Supported_Elliptic_Curves* ecc = m_extensions.get<Supported_Elliptic_Curves>())
- return ecc->curves();
+ if(Supported_Groups* groups = m_extensions.get<Supported_Groups>())
+ return groups->curves();
+ return std::vector<std::string>();
+ }
+
+std::vector<std::string> Client_Hello::supported_dh_groups() const
+ {
+ if(Supported_Groups* groups = m_extensions.get<Supported_Groups>())
+ return groups->dh_groups();
return std::vector<std::string>();
}
diff --git a/src/lib/tls/msg_client_kex.cpp b/src/lib/tls/msg_client_kex.cpp
index 3291b6eb5..1c3950a03 100644
--- a/src/lib/tls/msg_client_kex.cpp
+++ b/src/lib/tls/msg_client_kex.cpp
@@ -101,6 +101,35 @@ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io,
throw Decoding_Error("Bad params size for DH key exchange");
/*
+ * If we offer ffdhe groups in the client hello,
+ * p and g must match one of these groups.
+ */
+ std::vector<std::string> allowed_groups = policy.allowed_groups();
+ bool server_sent_requested_group = false;
+
+ if(!allowed_groups.empty())
+ {
+ for(const auto& allowed_group : allowed_groups)
+ {
+ if(Supported_Groups::is_dh_group(allowed_group))
+ {
+ DL_Group client_group(allowed_group);
+ if(client_group.get_p() == p && client_group.get_g() == g)
+ {
+ server_sent_requested_group = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if(!server_sent_requested_group)
+ {
+ throw TLS_Exception(Alert::INSUFFICIENT_SECURITY,
+ "Server sent unexpected DH key for DHE exchange");
+ }
+
+ /*
* A basic check for key validity. As we do not know q here we
* cannot check that Y is in the right subgroup. However since
* our key is ephemeral there does not seem to be any
diff --git a/src/lib/tls/msg_server_kex.cpp b/src/lib/tls/msg_server_kex.cpp
index 97ac4ac8f..0765e1bdc 100644
--- a/src/lib/tls/msg_server_kex.cpp
+++ b/src/lib/tls/msg_server_kex.cpp
@@ -56,7 +56,10 @@ Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io,
if(kex_algo == "DH" || kex_algo == "DHE_PSK")
{
- std::unique_ptr<DH_PrivateKey> dh(new DH_PrivateKey(rng, DL_Group(policy.dh_group())));
+ const std::vector<std::string>& dh_groups =
+ state.client_hello()->supported_dh_groups();
+
+ std::unique_ptr<DH_PrivateKey> dh(new DH_PrivateKey(rng, DL_Group(policy.choose_dh_group(dh_groups))));
append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_p()), 2);
append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_g()), 2);
diff --git a/src/lib/tls/tls_extensions.cpp b/src/lib/tls/tls_extensions.cpp
index 317d96b8d..8f13b2c6d 100644
--- a/src/lib/tls/tls_extensions.cpp
+++ b/src/lib/tls/tls_extensions.cpp
@@ -275,7 +275,23 @@ std::vector<uint8_t> Application_Layer_Protocol_Notification::serialize() const
return buf;
}
-std::string Supported_Elliptic_Curves::curve_id_to_name(uint16_t id)
+Supported_Groups::Supported_Groups(const std::vector<std::string>& groups) :
+ m_groups(groups)
+ {
+ for(const auto& group : m_groups)
+ {
+ if(is_dh_group(group))
+ {
+ m_dh_groups.push_back(group);
+ }
+ else
+ {
+ m_curves.push_back(group);
+ }
+ }
+ }
+
+std::string Supported_Groups::curve_id_to_name(uint16_t id)
{
switch(id)
{
@@ -302,12 +318,23 @@ std::string Supported_Elliptic_Curves::curve_id_to_name(uint16_t id)
return BOTAN_HOUSE_ECC_CURVE_NAME;
#endif
+ case 256:
+ return "ffdhe/ietf/2048";
+ case 257:
+ return "ffdhe/ietf/3072";
+ case 258:
+ return "ffdhe/ietf/4096";
+ case 259:
+ return "ffdhe/ietf/6144";
+ case 260:
+ return "ffdhe/ietf/8192";
+
default:
return ""; // something we don't know or support
}
}
-uint16_t Supported_Elliptic_Curves::name_to_curve_id(const std::string& name)
+uint16_t Supported_Groups::name_to_curve_id(const std::string& name)
{
if(name == "secp256r1")
return 23;
@@ -332,17 +359,39 @@ uint16_t Supported_Elliptic_Curves::name_to_curve_id(const std::string& name)
return BOTAN_HOUSE_ECC_CURVE_TLS_ID;
#endif
- // Unknown/unavailable EC curves are ignored
+ if(name == "ffdhe/ietf/2048")
+ return 256;
+ if(name == "ffdhe/ietf/3072")
+ return 257;
+ if(name == "ffdhe/ietf/4096")
+ return 258;
+ if(name == "ffdhe/ietf/6144")
+ return 259;
+ if(name == "ffdhe/ietf/8192")
+ return 260;
+
+ // Unknown/unavailable DH groups/EC curves are ignored
return 0;
}
-std::vector<uint8_t> Supported_Elliptic_Curves::serialize() const
+bool Supported_Groups::is_dh_group( const std::string& group_name )
+ {
+ if(group_name == "ffdhe/ietf/2048" || group_name == "ffdhe/ietf/3072"
+ || group_name == "ffdhe/ietf/4096" || group_name == "ffdhe/ietf/6144"
+ || group_name == "ffdhe/ietf/8192")
+ {
+ return true;
+ }
+ return false;
+ }
+
+std::vector<uint8_t> Supported_Groups::serialize() const
{
std::vector<uint8_t> buf(2);
- for(size_t i = 0; i != m_curves.size(); ++i)
+ for(size_t i = 0; i != m_groups.size(); ++i)
{
- const uint16_t id = name_to_curve_id(m_curves[i]);
+ const uint16_t id = name_to_curve_id(m_groups[i]);
if(id > 0)
{
@@ -357,16 +406,16 @@ std::vector<uint8_t> Supported_Elliptic_Curves::serialize() const
return buf;
}
-Supported_Elliptic_Curves::Supported_Elliptic_Curves(TLS_Data_Reader& reader,
- uint16_t extension_size)
+Supported_Groups::Supported_Groups(TLS_Data_Reader& reader,
+ uint16_t extension_size)
{
uint16_t len = reader.get_uint16_t();
if(len + 2 != extension_size)
- throw Decoding_Error("Inconsistent length field in elliptic curve list");
+ throw Decoding_Error("Inconsistent length field in supported groups list");
if(len % 2 == 1)
- throw Decoding_Error("Elliptic curve list of strange size");
+ throw Decoding_Error("Supported groups list of strange size");
len /= 2;
@@ -376,7 +425,17 @@ Supported_Elliptic_Curves::Supported_Elliptic_Curves(TLS_Data_Reader& reader,
const std::string name = curve_id_to_name(id);
if(!name.empty())
- m_curves.push_back(name);
+ {
+ m_groups.push_back(name);
+ if(is_dh_group(name))
+ {
+ m_dh_groups.push_back(name);
+ }
+ else
+ {
+ m_curves.push_back(name);
+ }
+ }
}
}
diff --git a/src/lib/tls/tls_extensions.h b/src/lib/tls/tls_extensions.h
index ee3310563..221d8b46f 100644
--- a/src/lib/tls/tls_extensions.h
+++ b/src/lib/tls/tls_extensions.h
@@ -225,10 +225,11 @@ class Session_Ticket final : public Extension
std::vector<uint8_t> m_ticket;
};
+
/**
-* Supported Elliptic Curves Extension (RFC 4492)
+* Supported Groups Extension (RFC 7919)
*/
-class Supported_Elliptic_Curves final : public Extension
+class Supported_Groups final : public Extension
{
public:
static Handshake_Extension_Type static_type()
@@ -239,21 +240,28 @@ class Supported_Elliptic_Curves final : public Extension
static std::string curve_id_to_name(uint16_t id);
static uint16_t name_to_curve_id(const std::string& name);
+ static bool is_dh_group( const std::string& group_name );
+
const std::vector<std::string>& curves() const { return m_curves; }
+ const std::vector<std::string>& dh_groups() const { return m_dh_groups; }
std::vector<uint8_t> serialize() const override;
- explicit Supported_Elliptic_Curves(const std::vector<std::string>& curves) :
- m_curves(curves) {}
+ explicit Supported_Groups(const std::vector<std::string>& groups);
- Supported_Elliptic_Curves(TLS_Data_Reader& reader,
+ Supported_Groups(TLS_Data_Reader& reader,
uint16_t extension_size);
- bool empty() const override { return m_curves.empty(); }
+ bool empty() const override { return m_groups.empty(); }
private:
+ std::vector<std::string> m_groups;
std::vector<std::string> m_curves;
+ std::vector<std::string> m_dh_groups;
};
+// previously Supported Elliptic Curves Extension (RFC 4492)
+using Supported_Elliptic_Curves = Supported_Groups;
+
/**
* Supported Point Formats Extension (RFC 4492)
*/
diff --git a/src/lib/tls/tls_messages.h b/src/lib/tls/tls_messages.h
index ac6c1e1ad..767635830 100644
--- a/src/lib/tls/tls_messages.h
+++ b/src/lib/tls/tls_messages.h
@@ -110,6 +110,8 @@ class BOTAN_UNSTABLE_API Client_Hello final : public Handshake_Message
std::vector<std::string> supported_ecc_curves() const;
+ std::vector<std::string> supported_dh_groups() const;
+
bool prefers_compressed_ec_points() const;
std::string sni_hostname() const;
diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp
index 43926e314..0a7e78e65 100644
--- a/src/lib/tls/tls_policy.cpp
+++ b/src/lib/tls/tls_policy.cpp
@@ -10,6 +10,7 @@
#include <botan/tls_ciphersuite.h>
#include <botan/tls_magic.h>
#include <botan/tls_exceptn.h>
+#include <botan/tls_extensions.h>
#include <botan/internal/stl_util.h>
#include <botan/pk_keys.h>
#include <sstream>
@@ -117,7 +118,11 @@ std::vector<std::string> Policy::allowed_ecc_curves() const
bool Policy::allowed_ecc_curve(const std::string& curve) const
{
- return value_exists(allowed_ecc_curves(), curve);
+ if(!allowed_ecc_curves().empty())
+ {
+ return value_exists(allowed_ecc_curves(), curve);
+ }
+ return value_exists(allowed_groups(), curve);
}
bool Policy::use_ecc_point_compression() const
@@ -130,21 +135,56 @@ bool Policy::use_ecc_point_compression() const
*/
std::string Policy::choose_curve(const std::vector<std::string>& curve_names) const
{
- const std::vector<std::string> our_curves = allowed_ecc_curves();
+ const std::vector<std::string> our_groups = allowed_groups();
- for(size_t i = 0; i != our_curves.size(); ++i)
- if(value_exists(curve_names, our_curves[i]))
- return our_curves[i];
+ for(size_t i = 0; i != our_groups.size(); ++i)
+ if(!Supported_Groups::is_dh_group(our_groups[i])
+ && value_exists(curve_names, our_groups[i]))
+ return our_groups[i];
return ""; // no shared curve
}
+/*
+* Choose an FFDHE group to use
+*/
+std::string Policy::choose_dh_group(const std::vector<std::string>& dh_groups) const
+ {
+ const std::vector<std::string> our_groups = allowed_groups();
+
+ for(size_t i = 0; i != our_groups.size(); ++i)
+ if(Supported_Groups::is_dh_group(our_groups[i])
+ && value_exists(dh_groups, our_groups[i]))
+ return our_groups[i];
+
+ return ""; // no shared ffdhe group
+ }
+
std::string Policy::dh_group() const
{
// We offer 2048 bit DH because we can
return "modp/ietf/2048";
}
+std::vector<std::string> Policy::allowed_groups() const
+ {
+ // Default list is ordered by performance
+ return {
+ "x25519",
+ "secp256r1",
+ "secp521r1",
+ "secp384r1",
+ "brainpool256r1",
+ "brainpool384r1",
+ "brainpool512r1",
+ "ffdhe/ietf/2048",
+ "ffdhe/ietf/3072",
+ "ffdhe/ietf/4096",
+ "ffdhe/ietf/6144",
+ "ffdhe/ietf/8192"
+ };
+ }
+
size_t Policy::minimum_dh_group_size() const
{
return 2048;
@@ -502,6 +542,7 @@ void Policy::print(std::ostream& o) const
print_vec(o, "signature_methods", allowed_signature_methods());
print_vec(o, "key_exchange_methods", allowed_key_exchange_methods());
print_vec(o, "ecc_curves", allowed_ecc_curves());
+ print_vec(o, "groups", allowed_groups());
print_bool(o, "allow_insecure_renegotiation", allow_insecure_renegotiation());
print_bool(o, "include_time_in_hello_random", include_time_in_hello_random());
diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h
index 333cf0ee1..2d90de5c0 100644
--- a/src/lib/tls/tls_policy.h
+++ b/src/lib/tls/tls_policy.h
@@ -103,6 +103,11 @@ class BOTAN_PUBLIC_API(2,0) Policy
virtual std::string choose_curve(const std::vector<std::string>& curve_names) const;
/**
+ * Choose an FFHDE group to use
+ */
+ virtual std::string choose_dh_group(const std::vector<std::string>& dh_group_names) const;
+
+ /**
* Allow renegotiation even if the counterparty doesn't
* support the secure renegotiation extension.
*
@@ -156,6 +161,8 @@ class BOTAN_PUBLIC_API(2,0) Policy
virtual std::string dh_group() const;
+ virtual std::vector<std::string> allowed_groups() const;
+
/**
* Return the minimum DH group size we're willing to use
* Default is currently 1024 (insecure), should be 2048
@@ -330,6 +337,9 @@ class BOTAN_PUBLIC_API(2,0) NSA_Suite_B_128 final : public Policy
std::vector<std::string> allowed_ecc_curves() const override
{ return std::vector<std::string>({"secp256r1"}); }
+ std::vector<std::string> allowed_groups() const override
+ { return allowed_ecc_curves(); }
+
size_t minimum_signature_strength() const override { return 128; }
bool allow_tls10() const override { return false; }
@@ -375,6 +385,12 @@ class BOTAN_PUBLIC_API(2,0) BSI_TR_02102_2 final : public Policy
return std::vector<std::string>({"brainpool512r1", "brainpool384r1", "brainpool256r1", "secp384r1", "secp256r1"});
}
+ std::vector<std::string> allowed_groups() const override
+ {
+ return std::vector<std::string>({"brainpool512r1", "brainpool384r1", "brainpool256r1", "secp384r1",
+ "secp256r1", "ffdhe/ietf/8192", "ffdhe/ietf/6144", "ffdhe/ietf/4096", "ffdhe/ietf/3072", "ffdhe/ietf/2048"});
+ }
+
bool allow_insecure_renegotiation() const override { return false; }
bool allow_server_initiated_renegotiation() const override { return true; }
bool server_uses_own_ciphersuite_preferences() const override { return true; }
@@ -451,6 +467,8 @@ class BOTAN_PUBLIC_API(2,0) Text_Policy : public Policy
std::vector<std::string> allowed_ecc_curves() const override;
+ std::vector<std::string> allowed_groups() const override;
+
bool use_ecc_point_compression() const override;
bool allow_tls10() const override;
diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp
index c0e853a80..fb8317a1c 100644
--- a/src/lib/tls/tls_server.cpp
+++ b/src/lib/tls/tls_server.cpp
@@ -168,6 +168,9 @@ uint16_t choose_ciphersuite(
const bool have_shared_ecc_curve =
(policy.choose_curve(client_hello.supported_ecc_curves()) != "");
+ const bool have_shared_dh_group =
+ (policy.choose_dh_group(client_hello.supported_dh_groups()) != "");
+
/*
Walk down one list in preference order
*/
@@ -190,9 +193,13 @@ uint16_t choose_ciphersuite(
if(suite.valid() == false)
continue;
+ // TODO supported groups SHOULD have preference over ciphersuite list
if(suite.ecc_ciphersuite() && have_shared_ecc_curve == false)
continue;
+ if(suite.kex_algo() == "DH" && have_shared_dh_group == false)
+ continue;
+
// For non-anon ciphersuites
if(suite.sig_algo() != "")
{
diff --git a/src/lib/tls/tls_text_policy.cpp b/src/lib/tls/tls_text_policy.cpp
index ef5799339..345e6005f 100644
--- a/src/lib/tls/tls_text_policy.cpp
+++ b/src/lib/tls/tls_text_policy.cpp
@@ -108,6 +108,11 @@ std::string Text_Policy::dh_group() const
return get_str("dh_group", Policy::dh_group());
}
+std::vector<std::string> Text_Policy::allowed_groups() const
+ {
+ return get_list("groups", Policy::allowed_groups());
+ }
+
size_t Text_Policy::minimum_ecdh_group_size() const
{
return get_len("minimum_ecdh_group_size", Policy::minimum_ecdh_group_size());