From a4124ddf481bfc56859007b34dea646ecb7f8a25 Mon Sep 17 00:00:00 2001 From: lloyd Date: Mon, 11 Jan 2010 22:57:21 +0000 Subject: 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. --- src/ssl/s_kex.cpp | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 src/ssl/s_kex.cpp (limited to 'src/ssl/s_kex.cpp') 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 +#include +#include +#include +#include +#include +#include + +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& c_random, + const MemoryRegion& s_random, + HandshakeHash& hash) + { + const DH_PublicKey* dh_pub = dynamic_cast(kex_key); + const RSA_PublicKey* rsa_pub = dynamic_cast(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(priv_key); + + if(!sign_key) + throw Invalid_Argument("Server Kex: Private key not for signing"); + + PK_Signer* signer = 0; + try { + if(dynamic_cast(sign_key)) + signer = get_pk_signer(*sign_key, "EMSA3(TLS.Digest.0)"); + else if(dynamic_cast(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 Server_Key_Exchange::serialize() const + { + SecureVector 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 Server_Key_Exchange::serialize_params() const + { + SecureVector buf; + for(u32bit j = 0; j != params.size(); j++) + { + SecureVector 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& buf) + { + if(buf.size() < 6) + throw Decoding_Error("Server_Key_Exchange: Packet corrupted"); + + SecureVector 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& c_random, + const MemoryRegion& s_random) const + { + std::auto_ptr key(cert.subject_public_key()); + + DSA_PublicKey* dsa_pub = dynamic_cast(key.get()); + RSA_PublicKey* rsa_pub = dynamic_cast(key.get()); + + std::auto_ptr 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 params_got = serialize_params(); + verifier->update(c_random); + verifier->update(s_random); + verifier->update(params_got); + + return verifier->check_signature(signature, signature.size()); + } + +} -- cgit v1.2.3