diff options
author | lloyd <[email protected]> | 2010-01-11 22:57:21 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2010-01-11 22:57:21 +0000 |
commit | a4124ddf481bfc56859007b34dea646ecb7f8a25 (patch) | |
tree | fd842d8a091c5c529d6c32cd300bc195519ceb46 /src/ssl/s_kex.cpp | |
parent | f5fd85b0ea6a5a6975d595130e029f94fddae9a4 (diff) |
Import latest version of Ajisai into src/ssl; once this hits mainline
I'll officially kill off Ajisai (instead of it just lingering as a zombine
as it is currently).
Apparently I broke something (or multiple things) during the import process;
servers crash and clients gets MAC errors on connect.
Diffstat (limited to 'src/ssl/s_kex.cpp')
-rw-r--r-- | src/ssl/s_kex.cpp | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/ssl/s_kex.cpp b/src/ssl/s_kex.cpp new file mode 100644 index 000000000..e1decfe84 --- /dev/null +++ b/src/ssl/s_kex.cpp @@ -0,0 +1,195 @@ +/** +* Server Key Exchange Message Source File +* (C) 2004-2006 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/dsa.h> +#include <botan/look_pk.h> +#include <botan/loadstor.h> +#include <memory> + +namespace Botan { + +/** +* Create a new Server Key Exchange message +*/ +Server_Key_Exchange::Server_Key_Exchange(RandomNumberGenerator& rng, + Record_Writer& writer, + const X509_PublicKey* kex_key, + const PKCS8_PrivateKey* priv_key, + const MemoryRegion<byte>& c_random, + const MemoryRegion<byte>& s_random, + HandshakeHash& hash) + { + const DH_PublicKey* dh_pub = dynamic_cast<const DH_PublicKey*>(kex_key); + const RSA_PublicKey* rsa_pub = dynamic_cast<const RSA_PublicKey*>(kex_key); + + if(dh_pub) + { + params.push_back(dh_pub->get_domain().get_p()); + params.push_back(dh_pub->get_domain().get_g()); + params.push_back(BigInt::decode(dh_pub->public_value())); + } + else if(rsa_pub) + { + params.push_back(rsa_pub->get_n()); + params.push_back(rsa_pub->get_e()); + } + else + throw Invalid_Argument("Bad key for TLS key exchange: not DH or RSA"); + + // FIXME: dup of stuff in cert_ver.cpp + // FIXME: it's OK for the server to be anonymous.... + const PK_Signing_Key* sign_key = + dynamic_cast<const PK_Signing_Key*>(priv_key); + + if(!sign_key) + throw Invalid_Argument("Server Kex: Private key not for signing"); + + PK_Signer* signer = 0; + try { + if(dynamic_cast<const RSA_PrivateKey*>(sign_key)) + signer = get_pk_signer(*sign_key, "EMSA3(TLS.Digest.0)"); + else if(dynamic_cast<const DSA_PrivateKey*>(sign_key)) + { + signer = get_pk_signer(*sign_key, "EMSA1(SHA-1)"); + signer->set_output_format(DER_SEQUENCE); + } + else + throw Invalid_Argument("Bad key for TLS signature: not RSA or DSA"); + + signer->update(c_random); + signer->update(s_random); + signer->update(serialize_params()); + signature = signer->signature(rng); + + delete signer; + } + catch(...) + { + delete signer; + throw; + } + + send(writer, hash); + } + +/** +* Serialize a Server Key Exchange message +*/ +SecureVector<byte> Server_Key_Exchange::serialize() const + { + SecureVector<byte> buf = serialize_params(); + u16bit sig_len = signature.size(); + buf.append(get_byte(0, sig_len)); + buf.append(get_byte(1, sig_len)); + buf.append(signature); + return buf; + } + +/** +* Serialize the ServerParams structure +*/ +SecureVector<byte> Server_Key_Exchange::serialize_params() const + { + SecureVector<byte> buf; + for(u32bit j = 0; j != params.size(); j++) + { + SecureVector<byte> param = BigInt::encode(params[j]); + u16bit param_size = param.size(); + + buf.append(get_byte(0, param_size)); + buf.append(get_byte(1, param_size)); + buf.append(param); + } + return buf; + } + +/** +* Deserialize a Server Key Exchange message +*/ +void Server_Key_Exchange::deserialize(const MemoryRegion<byte>& buf) + { + if(buf.size() < 6) + throw Decoding_Error("Server_Key_Exchange: Packet corrupted"); + + SecureVector<byte> values[4]; + u32bit so_far = 0; + + for(u32bit j = 0; j != 4; j++) + { + u16bit len = make_u16bit(buf[so_far], buf[so_far+1]); + so_far += 2; + + if(len + so_far > buf.size()) + throw Decoding_Error("Server_Key_Exchange: Packet corrupted"); + + values[j].set(buf + so_far, len); + so_far += len; + + if(j == 2 && so_far == buf.size()) + break; + } + + params.push_back(BigInt::decode(values[0])); + params.push_back(BigInt::decode(values[1])); + if(values[3].size()) + { + params.push_back(BigInt::decode(values[2])); + signature = values[3]; + } + else + signature = values[2]; + } + +/** +* Return the public key +*/ +X509_PublicKey* Server_Key_Exchange::key() const + { + if(params.size() == 2) + return new RSA_PublicKey(params[0], params[1]); + else if(params.size() == 3) + return new DH_PublicKey(DL_Group(params[0], params[1]), params[2]); + else + throw Internal_Error("Server_Key_Exchange::key: No key set"); + } + +/** +* Verify a Server Key Exchange message +*/ +bool Server_Key_Exchange::verify(const X509_Certificate& cert, + const MemoryRegion<byte>& c_random, + const MemoryRegion<byte>& s_random) const + { + std::auto_ptr<X509_PublicKey> key(cert.subject_public_key()); + + DSA_PublicKey* dsa_pub = dynamic_cast<DSA_PublicKey*>(key.get()); + RSA_PublicKey* rsa_pub = dynamic_cast<RSA_PublicKey*>(key.get()); + + std::auto_ptr<PK_Verifier> verifier; + + if(dsa_pub) + { + verifier.reset(get_pk_verifier(*dsa_pub, "EMSA1(SHA-1)", DER_SEQUENCE)); + verifier->set_input_format(DER_SEQUENCE); + } + else if(rsa_pub) + verifier.reset(get_pk_verifier(*rsa_pub, "EMSA3(TLS.Digest.0)")); + else + throw Invalid_Argument("Server did not provide a RSA/DSA cert"); + + SecureVector<byte> params_got = serialize_params(); + verifier->update(c_random); + verifier->update(s_random); + verifier->update(params_got); + + return verifier->check_signature(signature, signature.size()); + } + +} |