aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/manual/tls.rst13
-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.cpp5
-rw-r--r--src/lib/tls/msg_server_hello.cpp8
-rw-r--r--src/lib/tls/msg_server_kex.cpp5
-rw-r--r--src/lib/tls/tls_extensions.cpp40
-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/data/tls/client_hello.vec4
-rw-r--r--src/tests/data/tls/server_hello.vec4
-rw-r--r--src/tests/unit_tls.cpp12
15 files changed, 174 insertions, 9 deletions
diff --git a/doc/manual/tls.rst b/doc/manual/tls.rst
index 6c1ca42f2..d0e63b9f8 100644
--- a/doc/manual/tls.rst
+++ b/doc/manual/tls.rst
@@ -594,6 +594,19 @@ policy settings from a file.
No other values are currently defined.
+ .. cpp:function:: bool use_ecc_point_compression() const
+
+ Prefer ECC point compression.
+
+ Signals that we prefer ECC points to be compressed when transmitted to us.
+ The other party may not support ECC point compression and therefore may still
+ send points uncompressed.
+
+ Note that the certificate used during authentication must also follow the other
+ party's preference.
+
+ Default: false
+
.. cpp:function:: std::vector<byte> compression() const
Return the list of compression methods we are willing to use, in order of
diff --git a/doc/news.rst b/doc/news.rst
index d831d5b10..f8c2fb393 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).
+
* Fix entropy source selection bug on Windows, which caused the
CryptoAPI entropy source to be not available under its normal name
"win32_cryptoapi" but instead "dev_random". GH #644
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..0eceadb3b 100644
--- a/src/lib/tls/msg_client_kex.cpp
+++ b/src/lib/tls/msg_client_kex.cpp
@@ -172,7 +172,10 @@ 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
+ append_tls_length_value(m_key_material,
+ priv_key.public_value(state.server_hello()->prefers_compressed_ec_points() ?
+ PointGFp::COMPRESSED : 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..33b980ba9 100644
--- a/src/lib/tls/msg_server_kex.cpp
+++ b/src/lib/tls/msg_server_kex.cpp
@@ -85,7 +85,10 @@ 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
+ append_tls_length_value(m_params,
+ ecdh->public_value(state.client_hello()->prefers_compressed_ec_points() ?
+ PointGFp::COMPRESSED : 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..df265d915 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,43 @@ Supported_Elliptic_Curves::Supported_Elliptic_Curves(TLS_Data_Reader& reader,
}
}
+std::vector<byte> Supported_Point_Formats::serialize() const
+ {
+ // if we send this extension, we prefer compressed points,
+ // otherwise we don't send it (which is equal to supporting only uncompressed)
+ // if this extension is sent, it MUST include uncompressed (RFC 4492, section 5.1)
+ return std::vector<byte>{2, ANSIX962_COMPRESSED_PRIME, UNCOMPRESSED};
+ }
+
+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/data/tls/client_hello.vec b/src/tests/data/tls/client_hello.vec
index d629e3f6e..aa8c03258 100644
--- a/src/tests/data/tls/client_hello.vec
+++ b/src/tests/data/tls/client_hello.vec
@@ -13,13 +13,13 @@ Exception =
# with extensions: point formats, ec curves, session ticket, signature algorithms, heartbeat (point formats and heartbeat not supported, empty renegotiation generated)
Buffer = 0303871e18983024eaee1be8ae6607d5ecad941d33fd7fc1d8554a9e1fbfda8d30880000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff01000055000b000403000102000a001c001a00170019001c001b0018001a0016000e000d000b000c0009000a00230000000d0020001e060106020603050105020503040104020403030103020303020102020203000f000101
Protocol = 0303
-AdditionalData = 000A000D0023FF01
+AdditionalData = 000A000B000D0023FF01
Exception =
# with extensions: point formats, ec curves, session ticket, signature algorithms, heartbeat, Encrypt-then-MAC, Extended Master Secret (point formats and heartbeat not supported, empty renegotiation generated)
Buffer = 0303e00da23523058b5dc9c445d97b2bb6315b019e97838ac4f16c23b2cb031b6a490000e2c0afc0adc030c02cc028c024c014c00ac0a3c09f00a500a300a1009f006b006a006900680039003800370036cca9cca8c077c073ccaa00c400c300c200c10088008700860085c032c02ec02ac026c00fc005c079c075c0a1c09d009d003d003500c00084c0aec0acc02fc02bc027c023c013c009c0a2c09e00a400a200a0009e00670040003f003e0033003200310030c076c07200be00bd00bc00bb009a0099009800970045004400430042c031c02dc029c025c00ec004c078c074c0a0c09c009c003c002f00ba009600410007c012c008001600130010000dc00dc003000a00ff0100005f000b000403000102000a001c001a00170019001c001b0018001a0016000e000d000b000c0009000a00230000000d00220020060106020603050105020503040104020403030103020303020102020203eded000f0001010016000000170000
Protocol = 0303
-AdditionalData = 000A000D001600170023FF01
+AdditionalData = 000A000B000D001600170023FF01
Exception =
# empty
diff --git a/src/tests/data/tls/server_hello.vec b/src/tests/data/tls/server_hello.vec
index 64ec40b80..f3bf889cb 100644
--- a/src/tests/data/tls/server_hello.vec
+++ b/src/tests/data/tls/server_hello.vec
@@ -9,14 +9,14 @@
Buffer = 0303ffea0bcfba564a4ce177c6a444b0ebdff5629b277293c618c1125f231e8628dd00c030000016ff01000100000b00040300010200230000000f000101
Protocol = 0303
Ciphersuite = C030
-AdditionalData = 0023FF01
+AdditionalData = 000B0023FF01
Exception =
# correct, with session ticket, extended master secret, and renegotiation info
Buffer = 03019f9cafa88664d9095f85dd64a39e5dd5c09f5a4a5362938af3718ee4e818af6a00c03000001aff01000100000b00040300010200230000000f00010100170000
Protocol = 0301
Ciphersuite = C030
-AdditionalData = 00170023FF01
+AdditionalData = 000B00170023FF01
Exception =
# incorrect, corrupted
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;
}