aboutsummaryrefslogtreecommitdiffstats
path: root/src/ssl/c_kex.cpp
diff options
context:
space:
mode:
authorlloyd <[email protected]>2010-02-14 05:39:37 +0000
committerlloyd <[email protected]>2010-02-14 05:39:37 +0000
commit1e596a25e32c3106b3d6e2aceb64a270a8b30713 (patch)
tree6f9bc30f3583f81420b69200d5ff1c82b4a00917 /src/ssl/c_kex.cpp
parent12e07d37e9622cfb24b2102090550a0260c6665c (diff)
parent3b980d2fcee997ba262cf7e8d8542eb51a56be3e (diff)
propagate from branch 'net.randombit.botan' (head 5bfc3e699003b86615c584f8ae40bd6e761f96c0)
to branch 'net.randombit.botan.ssl' (head 6865128cf0c5f6ad1987e22cc1d521fd2e38fd21)
Diffstat (limited to 'src/ssl/c_kex.cpp')
-rw-r--r--src/ssl/c_kex.cpp174
1 files changed, 174 insertions, 0 deletions
diff --git a/src/ssl/c_kex.cpp b/src/ssl/c_kex.cpp
new file mode 100644
index 000000000..298b22a89
--- /dev/null
+++ b/src/ssl/c_kex.cpp
@@ -0,0 +1,174 @@
+/**
+* Client Key Exchange Message Source File
+* (C) 2004-2008 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_messages.h>
+#include <botan/dh.h>
+#include <botan/rsa.h>
+#include <botan/rng.h>
+#include <botan/look_pk.h>
+#include <botan/loadstor.h>
+#include <memory>
+
+namespace Botan {
+
+/**
+* Create a new Client Key Exchange message
+*/
+Client_Key_Exchange::Client_Key_Exchange(RandomNumberGenerator& rng,
+ Record_Writer& writer,
+ HandshakeHash& hash,
+ const X509_PublicKey* pub_key,
+ Version_Code using_version,
+ Version_Code pref_version)
+ {
+ const DH_PublicKey* dh_pub = dynamic_cast<const DH_PublicKey*>(pub_key);
+ const RSA_PublicKey* rsa_pub = dynamic_cast<const RSA_PublicKey*>(pub_key);
+
+ include_length = true;
+
+ if(dh_pub)
+ {
+ DH_PrivateKey priv_key(rng, dh_pub->get_domain());
+ pre_master = priv_key.derive_key(dh_pub->get_y());
+ key_material = priv_key.public_value();
+ }
+ else if(rsa_pub)
+ {
+ pre_master.resize(48);
+ rng.randomize(pre_master, 48);
+ pre_master[0] = (pref_version >> 8) & 0xFF;
+ pre_master[1] = (pref_version ) & 0xFF;
+
+ std::auto_ptr<PK_Encryptor> encryptor(get_pk_encryptor(*rsa_pub,
+ "PKCS1v15"));
+
+ key_material = encryptor->encrypt(pre_master, rng);
+
+ if(using_version == SSL_V3)
+ include_length = false;
+ }
+ else
+ throw Invalid_Argument("Client_Key_Exchange: Key not RSA or DH");
+
+ send(writer, hash);
+ }
+
+/**
+* Read a Client Key Exchange message
+*/
+Client_Key_Exchange::Client_Key_Exchange(const MemoryRegion<byte>& contents,
+ const CipherSuite& suite,
+ Version_Code using_version)
+ {
+ include_length = true;
+
+ if(using_version == SSL_V3 &&
+ (suite.kex_type() == CipherSuite::NO_KEX ||
+ suite.kex_type() == CipherSuite::RSA_KEX))
+ include_length = false;
+
+ deserialize(contents);
+ }
+
+/**
+* Serialize a Client Key Exchange message
+*/
+SecureVector<byte> Client_Key_Exchange::serialize() const
+ {
+ SecureVector<byte> buf;
+
+ if(include_length)
+ {
+ u16bit key_size = key_material.size();
+ buf.append(get_byte(0, key_size));
+ buf.append(get_byte(1, key_size));
+ }
+ buf.append(key_material);
+
+ return buf;
+ }
+
+/**
+* Deserialize a Client Key Exchange message
+*/
+void Client_Key_Exchange::deserialize(const MemoryRegion<byte>& buf)
+ {
+ if(include_length)
+ {
+ if(buf.size() < 2)
+ throw Decoding_Error("Client_Key_Exchange: Packet corrupted");
+
+ u32bit size = make_u16bit(buf[0], buf[1]);
+ if(size + 2 != buf.size())
+ throw Decoding_Error("Client_Key_Exchange: Packet corrupted");
+
+ key_material.set(buf + 2, size);
+ }
+ else
+ key_material = buf;
+ }
+
+/**
+* Return the pre_master_secret
+*/
+SecureVector<byte>
+Client_Key_Exchange::pre_master_secret(RandomNumberGenerator& rng,
+ const PKCS8_PrivateKey* priv_key,
+ Version_Code version)
+ {
+ const DH_PrivateKey* dh_priv = dynamic_cast<const DH_PrivateKey*>(priv_key);
+ const RSA_PrivateKey* rsa_priv =
+ dynamic_cast<const RSA_PrivateKey*>(priv_key);
+
+ if(dh_priv)
+ {
+ try {
+ pre_master = dh_priv->derive_key(key_material, key_material.size());
+ }
+ catch(std::exception& e)
+ {
+ pre_master.resize(dh_priv->public_value().size());
+ rng.randomize(pre_master, pre_master.size());
+ }
+
+ return pre_master;
+ }
+ else if(rsa_priv)
+ {
+ std::auto_ptr<PK_Decryptor> decryptor(get_pk_decryptor(*rsa_priv,
+ "PKCS1v15"));
+
+ try {
+ pre_master = decryptor->decrypt(key_material);
+
+ if(pre_master.size() != 48 ||
+ make_u16bit(pre_master[0], pre_master[1]) != version)
+ throw Decoding_Error("Client_Key_Exchange: Secret corrupted");
+ }
+ catch(std::exception)
+ {
+ pre_master.resize(48);
+ rng.randomize(pre_master, pre_master.size());
+ pre_master[0] = (version >> 8) & 0xFF;
+ pre_master[1] = (version ) & 0xFF;
+ }
+
+ return pre_master;
+ }
+ else
+ throw Invalid_Argument("Client_Key_Exchange: Bad key for decrypt");
+ }
+
+/**
+* Return the pre_master_secret
+*/
+SecureVector<byte> Client_Key_Exchange::pre_master_secret() const
+ {
+ return pre_master;
+ }
+
+}