diff options
author | Jack Lloyd <[email protected]> | 2016-10-21 11:25:53 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2016-10-21 16:54:43 -0400 |
commit | f44bd90a3ff9c2928eef825a0ff5394160b1a01c (patch) | |
tree | d5bec5ca3c501122c747fd492c8a16270135b935 /src/lib/tls/msg_client_kex.cpp | |
parent | 6aa855bba613c7b6fedfbe71d15930964acb1633 (diff) |
X25519 key exchange for TLS
Client interops with google.com, server not tested against an
independent client yet.
Diffstat (limited to 'src/lib/tls/msg_client_kex.cpp')
-rw-r--r-- | src/lib/tls/msg_client_kex.cpp | 61 |
1 files changed, 42 insertions, 19 deletions
diff --git a/src/lib/tls/msg_client_kex.cpp b/src/lib/tls/msg_client_kex.cpp index 02ebcc2c8..81b01a704 100644 --- a/src/lib/tls/msg_client_kex.cpp +++ b/src/lib/tls/msg_client_kex.cpp @@ -20,8 +20,12 @@ #include <botan/ecdh.h> #include <botan/rsa.h> +#if defined(BOTAN_HAS_CURVE_25519) + #include <botan/curve25519.h> +#endif + #if defined(BOTAN_HAS_SRP6) -#include <botan/srp6.h> + #include <botan/srp6.h> #endif namespace Botan { @@ -138,31 +142,53 @@ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io, const u16bit curve_id = reader.get_u16bit(); - const std::string name = Supported_Elliptic_Curves::curve_id_to_name(curve_id); + const std::string curve_name = Supported_Elliptic_Curves::curve_id_to_name(curve_id); - if(name == "") + if(curve_name == "") throw Decoding_Error("Server sent unknown named curve " + std::to_string(curve_id)); - if(!policy.allowed_ecc_curve(name)) + if(!policy.allowed_ecc_curve(curve_name)) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Server sent ECC curve prohibited by policy"); } - EC_Group group(name); - - std::vector<byte> ecdh_key = reader.get_range<byte>(1, 1, 255); + const std::vector<byte> ecdh_key = reader.get_range<byte>(1, 1, 255); - ECDH_PublicKey counterparty_key(group, OS2ECP(ecdh_key, group.get_curve())); + std::vector<byte> our_ecdh_public; + secure_vector<byte> ecdh_secret; - policy.check_peer_key_acceptable(counterparty_key); - - ECDH_PrivateKey priv_key(rng, group); - - PK_Key_Agreement ka(priv_key, rng, "Raw"); + 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(); +#else + throw Internal_Error("Negotiated X25519 somehow, but it is disabled"); +#endif - secure_vector<byte> 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 + { + EC_Group group(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); + } if(kex_algo == "ECDH") m_pre_master = ecdh_secret; @@ -172,10 +198,7 @@ Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io, append_tls_length_value(m_pre_master, psk.bits_of(), 2); } - // 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); + append_tls_length_value(m_key_material, our_ecdh_public, 1); } #if defined(BOTAN_HAS_SRP6) else if(kex_algo == "SRP_SHA") |