From 6299685d6c118bd2125fd532e6f5d2258efd9f0d Mon Sep 17 00:00:00 2001 From: Harry Reimann Date: Thu, 30 Nov 2017 15:22:11 +0100 Subject: Move TLS signature and key exchange code into callbacks Give applications using an external crypto device for signature generation and/or verification and/or (ec)dh key exchange while establishing a TLS session hooks to implement the corresponding functionality. --- src/lib/tls/tls_callbacks.cpp | 116 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) (limited to 'src/lib/tls/tls_callbacks.cpp') diff --git a/src/lib/tls/tls_callbacks.cpp b/src/lib/tls/tls_callbacks.cpp index 59620aec2..b4ffc81a5 100644 --- a/src/lib/tls/tls_callbacks.cpp +++ b/src/lib/tls/tls_callbacks.cpp @@ -9,6 +9,15 @@ #include #include #include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_CURVE_25519) + #include +#endif namespace Botan { @@ -50,4 +59,111 @@ void TLS::Callbacks::tls_verify_cert_chain( throw Exception("Certificate validation failure: " + result.result_string()); } +std::vector TLS::Callbacks::tls_sign_message( + const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& emsa, + Signature_Format format, + const std::vector& 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& msg, + const std::vector& sig) + { + PK_Verifier verifier(key, emsa, format); + + return verifier.verify_message(msg, sig); + } + +std::pair, std::vector> TLS::Callbacks::tls_dh_agree( + const std::vector& modulus, + const std::vector& generator, + const std::vector& 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 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, std::vector> TLS::Callbacks::tls_ecdh_agree( + const std::string& curve_name, + const std::vector& peer_public_value, + const Policy& policy, + RandomNumberGenerator& rng, + bool compressed) + { + secure_vector ecdh_secret; + std::vector 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); + } + } -- cgit v1.2.3