aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/tls/tls_callbacks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/tls/tls_callbacks.cpp')
-rw-r--r--src/lib/tls/tls_callbacks.cpp116
1 files changed, 116 insertions, 0 deletions
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 <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 +59,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);
+ }
+
}