aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRenĂ© Korthaus <[email protected]>2016-09-28 13:06:36 +0200
committerRenĂ© Korthaus <[email protected]>2016-10-03 12:18:24 +0200
commitf38841305ecd3fd0d13285823497a5a9d3b5c19f (patch)
treed01a3263baa7df488cf58fc997d1c9710dbfb0a4
parentab2842d6f28680b1cac18d5ff6b70b395d1ffb65 (diff)
Support encoding of supported point formats extension
-rw-r--r--doc/news.rst2
-rw-r--r--src/lib/pubkey/ecdh/ecdh.h11
-rw-r--r--src/lib/tls/msg_client_hello.cpp16
-rw-r--r--src/lib/tls/msg_client_kex.cpp10
-rw-r--r--src/lib/tls/msg_server_hello.cpp8
-rw-r--r--src/lib/tls/msg_server_kex.cpp10
-rw-r--r--src/lib/tls/tls_extensions.cpp48
-rw-r--r--src/lib/tls/tls_extensions.h32
-rw-r--r--src/lib/tls/tls_messages.h18
-rw-r--r--src/lib/tls/tls_policy.cpp5
-rw-r--r--src/lib/tls/tls_policy.h8
-rw-r--r--src/tests/unit_tls.cpp12
12 files changed, 175 insertions, 5 deletions
diff --git a/doc/news.rst b/doc/news.rst
index a764d75fb..892938aff 100644
--- a/doc/news.rst
+++ b/doc/news.rst
@@ -4,6 +4,8 @@ Release Notes
Version 1.11.33, Not Yet Released
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+* Add support for the TLS Supported Point Formats Extension (RFC 4492).
+
Version 1.11.32, 2016-09-28
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/lib/pubkey/ecdh/ecdh.h b/src/lib/pubkey/ecdh/ecdh.h
index 2f892436c..bdd9ea047 100644
--- a/src/lib/pubkey/ecdh/ecdh.h
+++ b/src/lib/pubkey/ecdh/ecdh.h
@@ -55,6 +55,12 @@ class BOTAN_DLL ECDH_PublicKey : public virtual EC_PublicKey
std::vector<byte> public_value() const
{ return unlock(EC2OSP(public_point(), PointGFp::UNCOMPRESSED)); }
+ /**
+ * @return public point value
+ */
+ std::vector<byte> public_value(PointGFp::Compression_Type type) const
+ { return unlock(EC2OSP(public_point(), type)); }
+
protected:
ECDH_PublicKey();
};
@@ -84,7 +90,10 @@ class BOTAN_DLL ECDH_PrivateKey : public ECDH_PublicKey,
EC_PrivateKey(rng, domain, x) {}
std::vector<byte> public_value() const override
- { return ECDH_PublicKey::public_value(); }
+ { return ECDH_PublicKey::public_value(PointGFp::UNCOMPRESSED); }
+
+ std::vector<byte> public_value(PointGFp::Compression_Type type) const
+ { return ECDH_PublicKey::public_value(type); }
};
}
diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp
index b493fd3ee..36335e7ce 100644
--- a/src/lib/tls/msg_client_hello.cpp
+++ b/src/lib/tls/msg_client_hello.cpp
@@ -98,8 +98,12 @@ Client_Hello::Client_Hello(Handshake_IO& io,
if(reneg_info.empty() && !next_protocols.empty())
m_extensions.add(new Application_Layer_Protocol_Notification(next_protocols));
+ if(m_version.supports_negotiable_signature_algorithms())
+ m_extensions.add(new Signature_Algorithms(policy.allowed_signature_hashes(),
+ policy.allowed_signature_methods()));
+
if(m_version.is_datagram_protocol())
- m_extensions.add(new SRTP_Protection_Profiles(policy.srtp_profiles()));
+ m_extensions.add(new SRTP_Protection_Profiles(policy.srtp_profiles()));
#if defined(BOTAN_HAS_SRP6)
m_extensions.add(new SRP_Identifier(client_settings.srp_identifier()));
@@ -112,6 +116,11 @@ Client_Hello::Client_Hello(Handshake_IO& io,
m_extensions.add(new Supported_Elliptic_Curves(policy.allowed_ecc_curves()));
+ if(!policy.allowed_ecc_curves().empty() && policy.use_ecc_point_compression())
+ {
+ m_extensions.add(new Supported_Point_Formats());
+ }
+
if(m_version.supports_negotiable_signature_algorithms())
m_extensions.add(new Signature_Algorithms(policy.allowed_signature_hashes(),
policy.allowed_signature_methods()));
@@ -156,6 +165,11 @@ Client_Hello::Client_Hello(Handshake_IO& io,
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() && policy.use_ecc_point_compression())
+ {
+ m_extensions.add(new Supported_Point_Formats());
+ }
+
if(m_version.supports_negotiable_signature_algorithms())
m_extensions.add(new Signature_Algorithms(policy.allowed_signature_hashes(),
policy.allowed_signature_methods()));
diff --git a/src/lib/tls/msg_client_kex.cpp b/src/lib/tls/msg_client_kex.cpp
index bc4d33d52..a01830c28 100644
--- a/src/lib/tls/msg_client_kex.cpp
+++ b/src/lib/tls/msg_client_kex.cpp
@@ -172,7 +172,15 @@ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io,
append_tls_length_value(m_pre_master, psk.bits_of(), 2);
}
- append_tls_length_value(m_key_material, priv_key.public_value(), 1);
+ // follow server's preference for point compression
+ if(state.server_hello()->prefers_compressed_ec_points())
+ {
+ append_tls_length_value(m_key_material, priv_key.public_value(PointGFp::COMPRESSED), 1);
+ }
+ else
+ {
+ append_tls_length_value(m_key_material, priv_key.public_value(PointGFp::UNCOMPRESSED), 1);
+ }
}
#if defined(BOTAN_HAS_SRP6)
else if(kex_algo == "SRP_SHA")
diff --git a/src/lib/tls/msg_server_hello.cpp b/src/lib/tls/msg_server_hello.cpp
index ebe8fb085..4f95a5c9d 100644
--- a/src/lib/tls/msg_server_hello.cpp
+++ b/src/lib/tls/msg_server_hello.cpp
@@ -35,12 +35,18 @@ Server_Hello::Server_Hello(Handshake_IO& io,
if(client_hello.supports_extended_master_secret())
m_extensions.add(new Extended_Master_Secret);
+ Ciphersuite c = Ciphersuite::by_id(m_ciphersuite);
+
if(client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac())
{
- Ciphersuite c = Ciphersuite::by_id(m_ciphersuite);
if(c.cbc_ciphersuite())
m_extensions.add(new Encrypt_then_MAC);
}
+
+ if(c.ecc_ciphersuite() && policy.use_ecc_point_compression())
+ {
+ m_extensions.add(new Supported_Point_Formats());
+ }
if(client_hello.secure_renegotiation())
m_extensions.add(new Renegotiation_Extension(reneg_info));
diff --git a/src/lib/tls/msg_server_kex.cpp b/src/lib/tls/msg_server_kex.cpp
index 10581fe45..c44dcb69a 100644
--- a/src/lib/tls/msg_server_kex.cpp
+++ b/src/lib/tls/msg_server_kex.cpp
@@ -85,7 +85,15 @@ Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io,
m_params.push_back(get_byte(0, named_curve_id));
m_params.push_back(get_byte(1, named_curve_id));
- append_tls_length_value(m_params, ecdh->public_value(), 1);
+ // follow client's preference for point compression
+ if(state.client_hello()->prefers_compressed_ec_points())
+ {
+ append_tls_length_value(m_params, ecdh->public_value(PointGFp::COMPRESSED), 1);
+ }
+ else
+ {
+ append_tls_length_value(m_params, ecdh->public_value(PointGFp::UNCOMPRESSED), 1);
+ }
m_kex_key.reset(ecdh.release());
}
diff --git a/src/lib/tls/tls_extensions.cpp b/src/lib/tls/tls_extensions.cpp
index e38e4ccdc..d82df20c5 100644
--- a/src/lib/tls/tls_extensions.cpp
+++ b/src/lib/tls/tls_extensions.cpp
@@ -33,6 +33,9 @@ Extension* make_extension(TLS_Data_Reader& reader,
case TLSEXT_USABLE_ELLIPTIC_CURVES:
return new Supported_Elliptic_Curves(reader, size);
+ case TLSEXT_EC_POINT_FORMATS:
+ return new Supported_Point_Formats(reader, size);
+
case TLSEXT_SAFE_RENEGOTIATION:
return new Renegotiation_Extension(reader, size);
@@ -353,6 +356,51 @@ Supported_Elliptic_Curves::Supported_Elliptic_Curves(TLS_Data_Reader& reader,
}
}
+std::vector<byte> Supported_Point_Formats::serialize() const
+ {
+ std::vector<byte> buf(1);
+
+ // if we send this extension, we prefer compressed points,
+ // otherwise we don't send it (which is equal to supporting only uncompressed)
+ buf.push_back(ANSIX962_COMPRESSED_PRIME);
+
+ // if this extension is sent, it MUST include uncompressed (RFC 4492, section 5.1)
+ buf.push_back(UNCOMPRESSED);
+
+ buf[0] = static_cast<byte>(buf.size()-1);
+
+ return buf;
+ }
+
+Supported_Point_Formats::Supported_Point_Formats(TLS_Data_Reader& reader,
+ u16bit extension_size)
+ {
+ byte len = reader.get_byte();
+
+ if(len + 1 != extension_size)
+ throw Decoding_Error("Inconsistent length field in supported point formats list");
+
+ for(size_t i = 0; i != len; ++i)
+ {
+ byte format = reader.get_byte();
+
+ if(format == UNCOMPRESSED)
+ {
+ m_prefers_compressed = false;
+ reader.discard_next(len-i-1);
+ return;
+ }
+ else if(format == ANSIX962_COMPRESSED_PRIME)
+ {
+ m_prefers_compressed = true;
+ reader.discard_next(len-i-1);
+ return;
+ }
+
+ // ignore ANSIX962_COMPRESSED_CHAR2, we don't support these curves
+ }
+ }
+
std::string Signature_Algorithms::hash_algo_name(byte code)
{
switch(code)
diff --git a/src/lib/tls/tls_extensions.h b/src/lib/tls/tls_extensions.h
index c270bf23a..d69e40a60 100644
--- a/src/lib/tls/tls_extensions.h
+++ b/src/lib/tls/tls_extensions.h
@@ -258,6 +258,38 @@ class Supported_Elliptic_Curves final : public Extension
};
/**
+* Supported Point Formats Extension (RFC 4492)
+*/
+class Supported_Point_Formats final : public Extension
+ {
+ public:
+ enum ECPointFormat : byte {
+ UNCOMPRESSED = 0,
+ ANSIX962_COMPRESSED_PRIME = 1,
+ ANSIX962_COMPRESSED_CHAR2 = 2, // don't support these curves
+ };
+
+ static Handshake_Extension_Type static_type()
+ { return TLSEXT_EC_POINT_FORMATS; }
+
+ Handshake_Extension_Type type() const override { return static_type(); }
+
+ std::vector<byte> serialize() const override;
+
+ explicit Supported_Point_Formats() : m_prefers_compressed(true) {}
+
+ Supported_Point_Formats(TLS_Data_Reader& reader,
+ u16bit extension_size);
+
+ bool empty() const override { return false; }
+
+ bool prefers_compressed() { return m_prefers_compressed; }
+
+ private:
+ bool m_prefers_compressed = false;
+ };
+
+/**
* Signature Algorithms Extension for TLS 1.2 (RFC 5246)
*/
class Signature_Algorithms final : public Extension
diff --git a/src/lib/tls/tls_messages.h b/src/lib/tls/tls_messages.h
index 698dbc99f..25228c865 100644
--- a/src/lib/tls/tls_messages.h
+++ b/src/lib/tls/tls_messages.h
@@ -121,6 +121,15 @@ class BOTAN_DLL Client_Hello final : public Handshake_Message
return std::vector<std::string>();
}
+ bool prefers_compressed_ec_points() const
+ {
+ if(Supported_Point_Formats* ecc_formats = m_extensions.get<Supported_Point_Formats>())
+ {
+ return ecc_formats->prefers_compressed();
+ }
+ return false;
+ }
+
std::string sni_hostname() const
{
if(Server_Name_Indicator* sni = m_extensions.get<Server_Name_Indicator>())
@@ -328,6 +337,15 @@ class BOTAN_DLL Server_Hello final : public Handshake_Message
std::set<Handshake_Extension_Type> extension_types() const
{ return m_extensions.extension_types(); }
+ bool prefers_compressed_ec_points() const
+ {
+ if(auto ecc_formats = m_extensions.get<Supported_Point_Formats>())
+ {
+ return ecc_formats->prefers_compressed();
+ }
+ return false;
+ }
+
Server_Hello(Handshake_IO& io,
Handshake_Hash& hash,
const Policy& policy,
diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp
index 592d4f572..9646aa320 100644
--- a/src/lib/tls/tls_policy.cpp
+++ b/src/lib/tls/tls_policy.cpp
@@ -104,6 +104,11 @@ bool Policy::allowed_ecc_curve(const std::string& curve) const
return value_exists(allowed_ecc_curves(), curve);
}
+bool Policy::use_ecc_point_compression() const
+ {
+ return false;
+ }
+
/*
* Choose an ECC curve to use
*/
diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h
index 76e80ddde..47ac51685 100644
--- a/src/lib/tls/tls_policy.h
+++ b/src/lib/tls/tls_policy.h
@@ -67,6 +67,11 @@ class BOTAN_DLL Policy
bool allowed_ecc_curve(const std::string& curve) const;
/**
+ * Request that ECC curve points are sent compressed
+ */
+ virtual bool use_ecc_point_compression() const;
+
+ /**
* Returns a list of compression algorithms we are willing to use,
* in order of preference. Allowed values any value of
* Compression_Method.
@@ -348,6 +353,9 @@ class BOTAN_DLL Text_Policy : public Policy
std::vector<std::string> allowed_ecc_curves() const override
{ return get_list("ecc_curves", Policy::allowed_ecc_curves()); }
+ bool use_ecc_point_compression() const override
+ { return get_bool("use_ecc_point_compression", Policy::use_ecc_point_compression()); }
+
bool allow_tls10() const override
{ return get_bool("allow_tls10", Policy::allow_tls10()); }
diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp
index de54c9747..5ae24ba81 100644
--- a/src/tests/unit_tls.cpp
+++ b/src/tests/unit_tls.cpp
@@ -868,6 +868,18 @@ class TLS_Unit_Tests : public Test
results.push_back(test_tls_handshake(Botan::TLS::Protocol_Version::TLS_V12, *basic_creds, policy, server_policy));
results.push_back(test_dtls_handshake(Botan::TLS::Protocol_Version::DTLS_V12, *basic_creds, policy, server_policy));
+ policy.set("use_ecc_point_compression", "true");
+ policy.set("key_exchange_methods", "ECDH");
+ policy.set("ciphers", "AES-128");
+ results.push_back(test_tls_handshake(Botan::TLS::Protocol_Version::TLS_V12, *basic_creds, policy));
+ results.push_back(test_dtls_handshake(Botan::TLS::Protocol_Version::DTLS_V12, *basic_creds, policy));
+
+ server_policy.set("use_ecc_point_compression", "true");
+ server_policy.set("key_exchange_methods", "ECDH");
+ server_policy.set("ciphers", "AES-128");
+ results.push_back(test_tls_handshake(Botan::TLS::Protocol_Version::TLS_V12, *basic_creds, policy, server_policy));
+ results.push_back(test_dtls_handshake(Botan::TLS::Protocol_Version::DTLS_V12, *basic_creds, policy, server_policy));
+
return results;
}