aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-12-04 12:08:01 -0500
committerJack Lloyd <[email protected]>2017-12-04 12:08:01 -0500
commitd3c1f3ba1a9d03ff8e84f0044ee3854804fac86b (patch)
tree95221f8edfda1f8ed4495449be9a78e8d61cb487 /src
parent683e105ad25fd862857eee51cd0ac757c45a86f8 (diff)
parent4477a88dcfa49075fa49a520c429fc1a6c0a3849 (diff)
Merge #1332 Add callbacks to make it easier to offload TLS pk operations
Diffstat (limited to 'src')
-rw-r--r--src/lib/tls/msg_cert_verify.cpp12
-rw-r--r--src/lib/tls/msg_client_hello.cpp4
-rw-r--r--src/lib/tls/msg_client_kex.cpp95
-rw-r--r--src/lib/tls/msg_server_hello.cpp10
-rw-r--r--src/lib/tls/msg_server_kex.cpp24
-rw-r--r--src/lib/tls/tls_callbacks.cpp117
-rw-r--r--src/lib/tls/tls_callbacks.h86
-rw-r--r--src/lib/tls/tls_client.cpp25
-rw-r--r--src/lib/tls/tls_handshake_state.cpp2
-rw-r--r--src/lib/tls/tls_handshake_state.h4
-rw-r--r--src/lib/tls/tls_policy.cpp3
-rw-r--r--src/lib/tls/tls_policy.h8
-rw-r--r--src/lib/tls/tls_text_policy.cpp6
-rw-r--r--src/tests/unit_tls.cpp4
14 files changed, 294 insertions, 106 deletions
diff --git a/src/lib/tls/msg_cert_verify.cpp b/src/lib/tls/msg_cert_verify.cpp
index 4b7ba5662..ce7a30374 100644
--- a/src/lib/tls/msg_cert_verify.cpp
+++ b/src/lib/tls/msg_cert_verify.cpp
@@ -1,6 +1,7 @@
/*
* Certificate Verify Message
* (C) 2004,2006,2011,2012 Jack Lloyd
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -29,9 +30,9 @@ Certificate_Verify::Certificate_Verify(Handshake_IO& io,
std::pair<std::string, Signature_Format> format =
state.choose_sig_format(*priv_key, m_hash_algo, m_sig_algo, true, policy);
- PK_Signer signer(*priv_key, rng, format.first, format.second);
-
- m_signature = signer.sign_message(state.hash().get_contents(), rng);
+ m_signature =
+ state.callbacks().tls_sign_message(*priv_key, rng, format.first, format.second,
+ state.hash().get_contents());
state.hash().update(io.send(*this));
}
@@ -89,10 +90,9 @@ bool Certificate_Verify::verify(const X509_Certificate& cert,
state.parse_sig_format(*key.get(), m_hash_algo, m_sig_algo,
true, policy);
- PK_Verifier verifier(*key, format.first, format.second);
-
const bool signature_valid =
- verifier.verify_message(state.hash().get_contents(), m_signature);
+ state.callbacks().tls_verify_message(*key, format.first, format.second,
+ state.hash().get_contents(), m_signature);
#if defined(BOTAN_UNSAFE_FUZZER_MODE)
return true;
diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp
index 3b13cf21d..cde2b737a 100644
--- a/src/lib/tls/msg_client_hello.cpp
+++ b/src/lib/tls/msg_client_hello.cpp
@@ -2,6 +2,7 @@
* TLS Hello Request and Client Hello Messages
* (C) 2004-2011,2015,2016 Jack Lloyd
* 2016 Matthias Gierlings
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -105,7 +106,8 @@ Client_Hello::Client_Hello(Handshake_IO& io,
m_extensions.add(new Renegotiation_Extension(reneg_info));
m_extensions.add(new Server_Name_Indicator(client_settings.hostname()));
- m_extensions.add(new Certificate_Status_Request({}, {}));
+ if(policy.support_cert_status_message())
+ m_extensions.add(new Certificate_Status_Request({}, {}));
if(reneg_info.empty() && !next_protocols.empty())
m_extensions.add(new Application_Layer_Protocol_Notification(next_protocols));
diff --git a/src/lib/tls/msg_client_kex.cpp b/src/lib/tls/msg_client_kex.cpp
index 51040e479..0ff99462c 100644
--- a/src/lib/tls/msg_client_kex.cpp
+++ b/src/lib/tls/msg_client_kex.cpp
@@ -1,13 +1,13 @@
/*
* Client Key Exchange Message
* (C) 2004-2010,2016 Jack Lloyd
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/tls_messages.h>
#include <botan/tls_extensions.h>
-#include <botan/oids.h>
#include <botan/rng.h>
#include <botan/internal/tls_reader.h>
@@ -17,16 +17,8 @@
#include <botan/credentials_manager.h>
#include <botan/internal/ct_utils.h>
-#include <botan/pubkey.h>
-
-#include <botan/dh.h>
-#include <botan/ecdh.h>
#include <botan/rsa.h>
-#if defined(BOTAN_HAS_CURVE_25519)
- #include <botan/curve25519.h>
-#endif
-
#if defined(BOTAN_HAS_CECPQ1)
#include <botan/cecpq1.h>
#endif
@@ -94,49 +86,25 @@ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io,
if(kex_algo == "DH" || kex_algo == "DHE_PSK")
{
- BigInt p = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
- BigInt g = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
- BigInt Y = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
+ const std::vector<uint8_t> modulus = reader.get_range<uint8_t>(2, 1, 65535);
+ const std::vector<uint8_t> generator = reader.get_range<uint8_t>(2, 1, 65535);
+ const std::vector<uint8_t> peer_public_value = reader.get_range<uint8_t>(2, 1, 65535);
if(reader.remaining_bytes())
throw Decoding_Error("Bad params size for DH key 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
- * advantage to bogus keys anyway.
- */
- if(Y <= 1 || Y >= p - 1)
- throw TLS_Exception(Alert::INSUFFICIENT_SECURITY,
- "Server sent bad DH key for DHE exchange");
-
- DL_Group group(p, g);
-
- if(!group.verify_group(rng, false))
- throw TLS_Exception(Alert::INSUFFICIENT_SECURITY,
- "DH group validation failed");
-
- DH_PublicKey counterparty_key(group, Y);
-
- policy.check_peer_key_acceptable(counterparty_key);
-
- DH_PrivateKey priv_key(rng, group);
-
- PK_Key_Agreement ka(priv_key, rng, "Raw");
-
- secure_vector<uint8_t> dh_secret = CT::strip_leading_zeros(
- ka.derive_key(0, counterparty_key.public_value()).bits_of());
+ const std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> dh_result =
+ state.callbacks().tls_dh_agree(modulus, generator, peer_public_value, policy, rng);
if(kex_algo == "DH")
- m_pre_master = dh_secret;
+ m_pre_master = dh_result.first;
else
{
- append_tls_length_value(m_pre_master, dh_secret, 2);
+ append_tls_length_value(m_pre_master, dh_result.first, 2);
append_tls_length_value(m_pre_master, psk.bits_of(), 2);
}
- append_tls_length_value(m_key_material, priv_key.public_value(), 2);
+ append_tls_length_value(m_key_material, dh_result.second, 2);
}
else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK")
{
@@ -158,51 +126,20 @@ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io,
"Server sent ECC curve prohibited by policy");
}
- const std::vector<uint8_t> ecdh_key = reader.get_range<uint8_t>(1, 1, 255);
- std::vector<uint8_t> our_ecdh_public;
- secure_vector<uint8_t> ecdh_secret;
-
- if(curve_name == "x25519")
- {
-#if defined(BOTAN_HAS_CURVE_25519)
- if(ecdh_key.size() != 32)
- throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Invalid X25519 key size");
-
- Curve25519_PublicKey counterparty_key(ecdh_key);
- policy.check_peer_key_acceptable(counterparty_key);
- Curve25519_PrivateKey priv_key(rng);
- PK_Key_Agreement ka(priv_key, rng, "Raw");
- ecdh_secret = ka.derive_key(0, counterparty_key.public_value()).bits_of();
-
- // X25519 is always compressed but sent as "uncompressed" in TLS
- our_ecdh_public = priv_key.public_value();
-#else
- throw Internal_Error("Negotiated X25519 somehow, but it is disabled");
-#endif
- }
- else
- {
- EC_Group group(OIDS::lookup(curve_name));
- ECDH_PublicKey counterparty_key(group, OS2ECP(ecdh_key, group.get_curve()));
- policy.check_peer_key_acceptable(counterparty_key);
- ECDH_PrivateKey priv_key(rng, group);
- PK_Key_Agreement ka(priv_key, rng, "Raw");
- ecdh_secret = ka.derive_key(0, counterparty_key.public_value()).bits_of();
-
- // follow server's preference for point compression
- our_ecdh_public = priv_key.public_value(
- state.server_hello()->prefers_compressed_ec_points() ? PointGFp::COMPRESSED : PointGFp::UNCOMPRESSED);
- }
+ const std::vector<uint8_t> peer_public_value = reader.get_range<uint8_t>(1, 1, 255);
+ 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 == "ECDH")
- m_pre_master = ecdh_secret;
+ m_pre_master = ecdh_result.first;
else
{
- append_tls_length_value(m_pre_master, ecdh_secret, 2);
+ append_tls_length_value(m_pre_master, ecdh_result.first, 2);
append_tls_length_value(m_pre_master, psk.bits_of(), 2);
}
- append_tls_length_value(m_key_material, our_ecdh_public, 1);
+ append_tls_length_value(m_key_material, ecdh_result.second, 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 67c3d530f..9eb33645b 100644
--- a/src/lib/tls/msg_server_hello.cpp
+++ b/src/lib/tls/msg_server_hello.cpp
@@ -2,6 +2,7 @@
* TLS Server Hello and Server Hello Done
* (C) 2004-2011,2015,2016 Jack Lloyd
* 2016 Matthias Gierlings
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -37,7 +38,7 @@ Server_Hello::Server_Hello(Handshake_IO& io,
m_extensions.add(new Extended_Master_Secret);
// Sending the extension back does not commit us to sending a stapled response
- if(client_hello.supports_cert_status_message())
+ if(client_hello.supports_cert_status_message() && policy.support_cert_status_message())
m_extensions.add(new Certificate_Status_Request);
Ciphersuite c = Ciphersuite::by_id(m_ciphersuite);
@@ -105,7 +106,7 @@ Server_Hello::Server_Hello(Handshake_IO& io,
m_extensions.add(new Extended_Master_Secret);
// Sending the extension back does not commit us to sending a stapled response
- if(client_hello.supports_cert_status_message())
+ if(client_hello.supports_cert_status_message() && policy.support_cert_status_message())
m_extensions.add(new Certificate_Status_Request);
if(client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac())
@@ -115,11 +116,6 @@ Server_Hello::Server_Hello(Handshake_IO& io,
m_extensions.add(new Encrypt_then_MAC);
}
- if(client_hello.supports_cert_status_message())
- {
- m_extensions.add(new Certificate_Status_Request);
- }
-
if(resumed_session.ciphersuite().ecc_ciphersuite())
{
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 ab75d3a9b..631273eb7 100644
--- a/src/lib/tls/msg_server_kex.cpp
+++ b/src/lib/tls/msg_server_kex.cpp
@@ -1,6 +1,7 @@
/*
* Server Key Exchange Message
* (C) 2004-2010,2012,2015,2016 Jack Lloyd
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -185,12 +186,14 @@ Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io,
std::pair<std::string, Signature_Format> format =
state.choose_sig_format(*signing_key, m_hash_algo, m_sig_algo, false, policy);
- PK_Signer signer(*signing_key, rng, format.first, format.second);
+ std::vector<uint8_t> buf = state.client_hello()->random();
- signer.update(state.client_hello()->random());
- signer.update(state.server_hello()->random());
- signer.update(params());
- m_signature = signer.signature(rng);
+ buf += state.server_hello()->random();
+ buf += params();
+
+ m_signature =
+ state.callbacks().tls_sign_message(*signing_key, rng,
+ format.first, format.second, buf);
}
state.hash().update(io.send(*this));
@@ -300,13 +303,14 @@ bool Server_Key_Exchange::verify(const Public_Key& server_key,
state.parse_sig_format(server_key, m_hash_algo, m_sig_algo,
false, policy);
- PK_Verifier verifier(server_key, format.first, format.second);
+ std::vector<uint8_t> buf = state.client_hello()->random();
- verifier.update(state.client_hello()->random());
- verifier.update(state.server_hello()->random());
- verifier.update(params());
+ buf += state.server_hello()->random();
+ buf += params();
- const bool signature_valid = verifier.check_signature(m_signature);
+ const bool signature_valid =
+ state.callbacks().tls_verify_message(server_key, format.first, format.second,
+ buf, m_signature);
#if defined(BOTAN_UNSAFE_FUZZER_MODE)
return true;
diff --git a/src/lib/tls/tls_callbacks.cpp b/src/lib/tls/tls_callbacks.cpp
index 59620aec2..b8f38589e 100644
--- a/src/lib/tls/tls_callbacks.cpp
+++ b/src/lib/tls/tls_callbacks.cpp
@@ -1,6 +1,7 @@
/*
* TLS Callbacks
* (C) 2016 Jack Lloyd
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -9,6 +10,15 @@
#include <botan/tls_policy.h>
#include <botan/x509path.h>
#include <botan/ocsp.h>
+#include <botan/dh.h>
+#include <botan/ecdh.h>
+#include <botan/oids.h>
+#include <botan/tls_exceptn.h>
+#include <botan/internal/ct_utils.h>
+
+#if defined(BOTAN_HAS_CURVE_25519)
+ #include <botan/curve25519.h>
+#endif
namespace Botan {
@@ -50,4 +60,111 @@ void TLS::Callbacks::tls_verify_cert_chain(
throw Exception("Certificate validation failure: " + result.result_string());
}
+std::vector<uint8_t> TLS::Callbacks::tls_sign_message(
+ const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& emsa,
+ Signature_Format format,
+ const std::vector<uint8_t>& msg)
+ {
+ PK_Signer signer(key, rng, emsa, format);
+
+ return signer.sign_message(msg, rng);
+ }
+
+bool TLS::Callbacks::tls_verify_message(
+ const Public_Key& key,
+ const std::string& emsa,
+ Signature_Format format,
+ const std::vector<uint8_t>& msg,
+ const std::vector<uint8_t>& sig)
+ {
+ PK_Verifier verifier(key, emsa, format);
+
+ return verifier.verify_message(msg, sig);
+ }
+
+std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> TLS::Callbacks::tls_dh_agree(
+ const std::vector<uint8_t>& modulus,
+ const std::vector<uint8_t>& generator,
+ const std::vector<uint8_t>& peer_public_value,
+ const Policy& policy,
+ RandomNumberGenerator& rng)
+ {
+ BigInt p = BigInt::decode(modulus);
+ BigInt g = BigInt::decode(generator);
+ BigInt Y = BigInt::decode(peer_public_value);
+
+ /*
+ * 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
+ * advantage to bogus keys anyway.
+ */
+ if(Y <= 1 || Y >= p - 1)
+ throw TLS_Exception(Alert::INSUFFICIENT_SECURITY,
+ "Server sent bad DH key for DHE exchange");
+
+ DL_Group group(p, g);
+
+ if(!group.verify_group(rng, false))
+ throw TLS_Exception(Alert::INSUFFICIENT_SECURITY,
+ "DH group validation failed");
+
+ DH_PublicKey peer_key(group, Y);
+
+ policy.check_peer_key_acceptable(peer_key);
+
+ DH_PrivateKey priv_key(rng, group);
+ PK_Key_Agreement ka(priv_key, rng, "Raw");
+ secure_vector<uint8_t> dh_secret = CT::strip_leading_zeros(
+ ka.derive_key(0, peer_key.public_value()).bits_of());
+
+ return std::make_pair(dh_secret, priv_key.public_value());
+ }
+
+std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> TLS::Callbacks::tls_ecdh_agree(
+ const std::string& curve_name,
+ const std::vector<uint8_t>& peer_public_value,
+ const Policy& policy,
+ RandomNumberGenerator& rng,
+ bool compressed)
+ {
+ secure_vector<uint8_t> ecdh_secret;
+ std::vector<uint8_t> our_public_value;
+
+ if(curve_name == "x25519")
+ {
+#if defined(BOTAN_HAS_CURVE_25519)
+ if(peer_public_value.size() != 32)
+ {
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Invalid X25519 key size");
+ }
+
+ Curve25519_PublicKey peer_key(peer_public_value);
+ policy.check_peer_key_acceptable(peer_key);
+ Curve25519_PrivateKey priv_key(rng);
+ PK_Key_Agreement ka(priv_key, rng, "Raw");
+ ecdh_secret = ka.derive_key(0, peer_key.public_value()).bits_of();
+
+ // X25519 is always compressed but sent as "uncompressed" in TLS
+ our_public_value = priv_key.public_value();
+#else
+ throw Internal_Error("Negotiated X25519 somehow, but it is disabled");
+#endif
+ }
+ else
+ {
+ EC_Group group(OIDS::lookup(curve_name));
+ ECDH_PublicKey peer_key(group, OS2ECP(peer_public_value, group.get_curve()));
+ policy.check_peer_key_acceptable(peer_key);
+ ECDH_PrivateKey priv_key(rng, group);
+ PK_Key_Agreement ka(priv_key, rng, "Raw");
+ ecdh_secret = ka.derive_key(0, peer_key.public_value()).bits_of();
+ our_public_value = priv_key.public_value(compressed ? PointGFp::COMPRESSED : PointGFp::UNCOMPRESSED);
+ }
+
+ return std::make_pair(ecdh_secret, our_public_value);
+ }
+
}
diff --git a/src/lib/tls/tls_callbacks.h b/src/lib/tls/tls_callbacks.h
index 962bb2489..4437a222a 100644
--- a/src/lib/tls/tls_callbacks.h
+++ b/src/lib/tls/tls_callbacks.h
@@ -2,6 +2,7 @@
* TLS Callbacks
* (C) 2016 Matthias Gierlings
* 2016 Jack Lloyd
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -11,6 +12,7 @@
#include <botan/tls_session.h>
#include <botan/tls_alert.h>
+#include <botan/pubkey.h>
#include <functional>
namespace Botan {
@@ -140,6 +142,90 @@ class BOTAN_PUBLIC_API(2,0) Callbacks
}
/**
+ * Optional callback with default impl: sign a message
+ *
+ * Default implementation uses PK_Signer::sign_message().
+ * Override to provide a different approach, e.g. using an external device.
+ *
+ * @param key the private key of the signer
+ * @param rng a random number generator
+ * @param emsa the encoding method to be applied to the message
+ * @param format the signature format
+ * @param msg the input data for the signature
+ *
+ * @return the signature
+ */
+ virtual std::vector<uint8_t> tls_sign_message(
+ const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& emsa,
+ Signature_Format format,
+ const std::vector<uint8_t>& msg);
+
+ /**
+ * Optional callback with default impl: verify a message signature
+ *
+ * Default implementation uses PK_Verifier::verify_message().
+ * Override to provide a different approach, e.g. using an external device.
+ *
+ * @param key the public key of the signer
+ * @param emsa the encoding method to be applied to the message
+ * @param format the signature format
+ * @param msg the input data for the signature
+ * @param sig the signature to be checked
+ *
+ * @return true if the signature is valid, false otherwise
+ */
+ virtual bool tls_verify_message(
+ const Public_Key& key,
+ const std::string& emsa,
+ Signature_Format format,
+ const std::vector<uint8_t>& msg,
+ const std::vector<uint8_t>& sig);
+
+ /**
+ * Optional callback with default impl: client side DH agreement
+ *
+ * Default implementation uses PK_Key_Agreement::derive_key().
+ * Override to provide a different approach, e.g. using an external device.
+ *
+ * @param modulus the modulus p of the discrete logarithm group
+ * @param generator the generator of the DH subgroup
+ * @param peer_public_value the public value of the peer
+ * @param policy the TLS policy associated with the session being established
+ * @param rng a random number generator
+ *
+ * @return a pair consisting of the agreed raw secret and our public value
+ */
+ virtual std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> tls_dh_agree(
+ const std::vector<uint8_t>& modulus,
+ const std::vector<uint8_t>& generator,
+ const std::vector<uint8_t>& peer_public_value,
+ const Policy& policy,
+ RandomNumberGenerator& rng);
+
+ /**
+ * Optional callback with default impl: client side ECDH agreement
+ *
+ * Default implementation uses PK_Key_Agreement::derive_key().
+ * Override to provide a different approach, e.g. using an external device.
+ *
+ * @param curve_name the name of the elliptic curve
+ * @param peer_public_value the public value of the peer
+ * @param policy the TLS policy associated with the session being established
+ * @param rng a random number generator
+ * @param compressed the compression preference for our public value
+ *
+ * @return a pair consisting of the agreed raw secret and our public value
+ */
+ virtual std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> tls_ecdh_agree(
+ const std::string& curve_name,
+ const std::vector<uint8_t>& peer_public_value,
+ const Policy& policy,
+ RandomNumberGenerator& rng,
+ bool compressed);
+
+ /**
* Optional callback: inspect handshake message
* Throw an exception to abort the handshake.
* Default simply ignores the message.
diff --git a/src/lib/tls/tls_client.cpp b/src/lib/tls/tls_client.cpp
index 0e620a279..ad8fdfa2d 100644
--- a/src/lib/tls/tls_client.cpp
+++ b/src/lib/tls/tls_client.cpp
@@ -2,6 +2,7 @@
* TLS Client
* (C) 2004-2011,2012,2015,2016 Jack Lloyd
* 2016 Matthias Gierlings
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -386,7 +387,8 @@ void Client::process_handshake_msg(const Handshake_State* active_state,
"Client: No certificates sent by server");
/*
- Certificate verification happens after we receive the server hello done,
+ If the server supports certificate status messages,
+ certificate verification happens after we receive the server hello done,
in case an OCSP response was also available
*/
@@ -412,6 +414,24 @@ void Client::process_handshake_msg(const Handshake_State* active_state,
{
state.set_expected_next(CERTIFICATE_STATUS); // optional
}
+ else
+ {
+ try
+ {
+ auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-client", m_info.hostname());
+
+ callbacks().tls_verify_cert_chain(server_certs,
+ {},
+ trusted_CAs,
+ Usage_Type::TLS_SERVER_AUTH,
+ m_info.hostname(),
+ policy());
+ }
+ catch(std::exception& e)
+ {
+ throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what());
+ }
+ }
}
else if(type == CERTIFICATE_STATUS)
{
@@ -459,7 +479,8 @@ void Client::process_handshake_msg(const Handshake_State* active_state,
{
state.server_hello_done(new Server_Hello_Done(contents));
- if(state.server_certs() != nullptr)
+ if(state.server_certs() != nullptr &&
+ state.server_hello()->supports_certificate_status_message())
{
try
{
diff --git a/src/lib/tls/tls_handshake_state.cpp b/src/lib/tls/tls_handshake_state.cpp
index 442d499d1..0fcf0d2ab 100644
--- a/src/lib/tls/tls_handshake_state.cpp
+++ b/src/lib/tls/tls_handshake_state.cpp
@@ -1,6 +1,7 @@
/*
* TLS Handshaking
* (C) 2004-2006,2011,2012,2015,2016 Jack Lloyd
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -8,7 +9,6 @@
#include <botan/internal/tls_handshake_state.h>
#include <botan/internal/tls_record.h>
#include <botan/tls_messages.h>
-#include <botan/tls_callbacks.h>
#include <botan/kdf.h>
#include <sstream>
diff --git a/src/lib/tls/tls_handshake_state.h b/src/lib/tls/tls_handshake_state.h
index e15e3a92f..437625ced 100644
--- a/src/lib/tls/tls_handshake_state.h
+++ b/src/lib/tls/tls_handshake_state.h
@@ -1,6 +1,7 @@
/*
* TLS Handshake State
* (C) 2004-2006,2011,2012 Jack Lloyd
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -14,6 +15,7 @@
#include <botan/tls_ciphersuite.h>
#include <botan/tls_exceptn.h>
#include <botan/tls_handshake_msg.h>
+#include <botan/tls_callbacks.h>
#include <botan/pk_keys.h>
#include <botan/pubkey.h>
#include <functional>
@@ -160,6 +162,8 @@ class Handshake_State
const Session_Keys& session_keys() const { return m_session_keys; }
+ Callbacks& callbacks() const { return m_callbacks; }
+
void compute_session_keys();
void compute_session_keys(const secure_vector<uint8_t>& resume_master_secret);
diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp
index 5d82eee0c..d849faf9d 100644
--- a/src/lib/tls/tls_policy.cpp
+++ b/src/lib/tls/tls_policy.cpp
@@ -2,6 +2,7 @@
* Policies for TLS
* (C) 2004-2010,2012,2015,2016 Jack Lloyd
* 2016 Christian Mainka
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -341,6 +342,7 @@ bool Policy::include_time_in_hello_random() const { return true; }
bool Policy::hide_unknown_users() const { return false; }
bool Policy::server_uses_own_ciphersuite_preferences() const { return true; }
bool Policy::negotiate_encrypt_then_mac() const { return true; }
+bool Policy::support_cert_status_message() const { return true; }
// 1 second initial timeout, 60 second max - see RFC 6347 sec 4.2.4.1
size_t Policy::dtls_initial_timeout() const { return 1*1000; }
@@ -552,6 +554,7 @@ void Policy::print(std::ostream& o) const
print_bool(o, "hide_unknown_users", hide_unknown_users());
print_bool(o, "server_uses_own_ciphersuite_preferences", server_uses_own_ciphersuite_preferences());
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';
diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h
index db2cbb3bb..786cdeea8 100644
--- a/src/lib/tls/tls_policy.h
+++ b/src/lib/tls/tls_policy.h
@@ -1,6 +1,7 @@
/*
* Hooks for application level policies on TLS connections
* (C) 2004-2006,2013 Jack Lloyd
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -288,6 +289,11 @@ class BOTAN_PUBLIC_API(2,0) Policy
virtual bool negotiate_encrypt_then_mac() const;
/**
+ * Indicates whether certificate status messages should be supported
+ */
+ virtual bool support_cert_status_message() const;
+
+ /**
* Return allowed ciphersuites, in order of preference
*/
virtual std::vector<uint16_t> ciphersuite_list(Protocol_Version version,
@@ -502,6 +508,8 @@ class BOTAN_PUBLIC_API(2,0) Text_Policy : public Policy
bool negotiate_encrypt_then_mac() const override;
+ bool support_cert_status_message() const override;
+
std::string dh_group() const override;
size_t minimum_ecdh_group_size() const override;
diff --git a/src/lib/tls/tls_text_policy.cpp b/src/lib/tls/tls_text_policy.cpp
index 345e6005f..97a6da31a 100644
--- a/src/lib/tls/tls_text_policy.cpp
+++ b/src/lib/tls/tls_text_policy.cpp
@@ -1,6 +1,7 @@
/*
* Text-Based TLS Policy
* (C) 2016,2017 Jack Lloyd
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -103,6 +104,11 @@ bool Text_Policy::negotiate_encrypt_then_mac() const
return get_bool("negotiate_encrypt_then_mac", Policy::negotiate_encrypt_then_mac());
}
+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
{
return get_str("dh_group", Policy::dh_group());
diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp
index b22028a0e..a154d2e18 100644
--- a/src/tests/unit_tls.cpp
+++ b/src/tests/unit_tls.cpp
@@ -2,6 +2,7 @@
* (C) 2014,2015 Jack Lloyd
* 2016 Matthias Gierlings
* 2017 René Korthaus, Rohde & Schwarz Cybersecurity
+* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -1308,6 +1309,9 @@ class TLS_Unit_Tests final : public Test
test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
{ { "signature_methods", "RSA" } });
+ test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
+ { { "support_cert_status_message", "false" } });
+
#if defined(BOTAN_HAS_DSA)
test_modern_versions(results, *client_ses, *server_ses, *creds, "DH", "AES-128/GCM", "AEAD",
{ { "signature_methods", "DSA" } });