diff options
author | lloyd <[email protected]> | 2010-04-28 22:31:20 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2010-04-28 22:31:20 +0000 |
commit | 0f47cb60e703ca2de56286f07b4c9d91c7bba071 (patch) | |
tree | 5304fd84516c79f55e213755b2b2b99e6e65c9e0 /src | |
parent | 6eec50d372143afcb3188f21d0991ace3e0d5e9e (diff) | |
parent | 50fc7b15553d888d95bee72972e53eae27a82c1f (diff) |
propagate from branch 'net.randombit.botan' (head a5f25a3b954f24c5d07fa0dab6c4d76f63767165)
to branch 'net.randombit.botan.c++0x' (head a365694b70b4b84ca713272d56d496acca351cb5)
Diffstat (limited to 'src')
27 files changed, 772 insertions, 178 deletions
diff --git a/src/benchmark/benchmark.cpp b/src/benchmark/benchmark.cpp index 348882b2a..2b0ed7cb6 100644 --- a/src/benchmark/benchmark.cpp +++ b/src/benchmark/benchmark.cpp @@ -148,7 +148,7 @@ algorithm_benchmark(const std::string& name, return all_results; const u64bit ns_per_provider = - ((u64bit)milliseconds * 1000 * 1000) / providers.size(); + (static_cast<u64bit>(milliseconds) * 1000 * 1000) / providers.size(); std::vector<byte> buf(16 * 1024); rng.randomize(&buf[0], buf.size()); diff --git a/src/cert/cvc/asn1_eac_tm.cpp b/src/cert/cvc/asn1_eac_tm.cpp index 5a464ba3c..ac18a73ce 100644 --- a/src/cert/cvc/asn1_eac_tm.cpp +++ b/src/cert/cvc/asn1_eac_tm.cpp @@ -37,8 +37,8 @@ SecureVector<byte> enc_two_digit(u32bit in) u32bit dec_two_digit(byte b1, byte b2) { - u32bit upper = (u32bit)b1; - u32bit lower = (u32bit)b2; + u32bit upper = b1; + u32bit lower = b2; if(upper > 9 || lower > 9) throw Invalid_Argument("CVC dec_two_digit value too large"); diff --git a/src/engine/def_engine/lookup_hash.cpp b/src/engine/def_engine/lookup_hash.cpp index 4ce7915d4..1d96d4f3f 100644 --- a/src/engine/def_engine/lookup_hash.cpp +++ b/src/engine/def_engine/lookup_hash.cpp @@ -83,6 +83,10 @@ #include <botan/par_hash.h> #endif +#if defined(BOTAN_HAS_COMB4P) + #include <botan/comb4p.h> +#endif + namespace Botan { /* @@ -185,6 +189,17 @@ Default_Engine::find_hash(const SCAN_Name& request, return new Whirlpool; #endif +#if defined(BOTAN_HAS_COMB4P) + if(request.algo_name() == "Comb4P" && request.arg_count() == 2) + { + const HashFunction* h1 = af.prototype_hash_function(request.arg(0)); + const HashFunction* h2 = af.prototype_hash_function(request.arg(1)); + + if(h1 && h2) + return new Comb4P(h1->clone(), h2->clone()); + } +#endif + #if defined(BOTAN_HAS_PARALLEL_HASH) if(request.algo_name() == "Parallel") diff --git a/src/hash/comb4p/comb4p.cpp b/src/hash/comb4p/comb4p.cpp new file mode 100644 index 000000000..6ae36b9d3 --- /dev/null +++ b/src/hash/comb4p/comb4p.cpp @@ -0,0 +1,105 @@ +/** +* Comb4P hash combiner +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/comb4p.h> +#include <botan/internal/xor_buf.h> +#include <stdexcept> + +namespace Botan { + +namespace { + +u32bit comb4p_block_size(const HashFunction* h1, + const HashFunction* h2) + { + if(h1->HASH_BLOCK_SIZE == h2->HASH_BLOCK_SIZE) + return h1->HASH_BLOCK_SIZE; + + /* + * Return LCM of the block sizes? This would probably be OK for + * HMAC, which is the main thing relying on knowing the block size. + */ + return 0; + } + +void comb4p_round(MemoryRegion<byte>& out, + const MemoryRegion<byte>& in, + byte round_no, + HashFunction* h1, + HashFunction* h2) + { + h1->update(round_no); + h2->update(round_no); + + h1->update(&in[0], in.size()); + h2->update(&in[0], in.size()); + + SecureVector<byte> h_buf = h1->final(); + xor_buf(&out[0], &h_buf[0], std::min(out.size(), h_buf.size())); + + h_buf = h2->final(); + xor_buf(&out[0], &h_buf[0], std::min(out.size(), h_buf.size())); + } + +} + +Comb4P::Comb4P(HashFunction* h1, HashFunction* h2) : + HashFunction(h1->OUTPUT_LENGTH + h2->OUTPUT_LENGTH, + comb4p_block_size(h1, h2)), + hash1(h1), hash2(h2) + { + if(hash1->name() == hash2->name()) + throw std::invalid_argument("Comb4P: Must use two distinct hashes"); + + if(hash1->OUTPUT_LENGTH != hash2->OUTPUT_LENGTH) + throw std::invalid_argument("Comb4P: Incompatible hashes " + + hash1->name() + " and " + + hash2->name()); + + clear(); + } + +void Comb4P::clear() + { + hash1->clear(); + hash2->clear(); + + // Prep for processing next message, if any + hash1->update(0); + hash2->update(0); + } + +void Comb4P::add_data(const byte input[], u32bit length) + { + hash1->update(input, length); + hash2->update(input, length); + } + +void Comb4P::final_result(byte out[]) + { + SecureVector<byte> h1 = hash1->final(); + SecureVector<byte> h2 = hash2->final(); + + // First round + xor_buf(&h1[0], &h2[0], std::min(h1.size(), h2.size())); + + // Second round + comb4p_round(h2, h1, 1, hash1, hash2); + + // Third round + comb4p_round(h1, h2, 2, hash1, hash2); + + copy_mem(out , &h1[0], h1.size()); + copy_mem(out + h1.size(), &h2[0], h2.size()); + + // Prep for processing next message, if any + hash1->update(0); + hash2->update(0); + } + +} + diff --git a/src/hash/comb4p/comb4p.h b/src/hash/comb4p/comb4p.h new file mode 100644 index 000000000..ce66bb9c9 --- /dev/null +++ b/src/hash/comb4p/comb4p.h @@ -0,0 +1,47 @@ +/** +* Comb4P hash combiner +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_COMB4P_H__ +#define BOTAN_COMB4P_H__ + +#include <botan/hash.h> + +namespace Botan { + +/** +* Combines two hash functions using a Feistel scheme. Described in +* "On the Security of Hash Function Combiners", Anja Lehmann +*/ +class Comb4P : public HashFunction + { + public: + Comb4P(HashFunction* h1, HashFunction* h2); + + ~Comb4P() { delete hash1; delete hash2; } + + HashFunction* clone() const + { + return new Comb4P(hash1->clone(), hash2->clone()); + } + + std::string name() const + { + return "Comb4P(" + hash1->name() + "," + hash2->name() + ")"; + } + + void clear(); + private: + void add_data(const byte input[], u32bit length); + void final_result(byte out[]); + + HashFunction* hash1; + HashFunction* hash2; + }; + +} + +#endif diff --git a/src/hash/comb4p/info.txt b/src/hash/comb4p/info.txt new file mode 100644 index 000000000..9ccf0223a --- /dev/null +++ b/src/hash/comb4p/info.txt @@ -0,0 +1 @@ +define COMB4P diff --git a/src/hash/sha1_sse2/sha1_sse2.cpp b/src/hash/sha1_sse2/sha1_sse2.cpp index 9267689e7..00a0752f6 100644 --- a/src/hash/sha1_sse2/sha1_sse2.cpp +++ b/src/hash/sha1_sse2/sha1_sse2.cpp @@ -159,7 +159,7 @@ void SHA_160_SSE2::compress_n(const byte input_bytes[], u32bit blocks) u32bit A = digest[0], B = digest[1], C = digest[2], D = digest[3], E = digest[4]; - const __m128i* input = (const __m128i *)input_bytes; + const __m128i* input = reinterpret_cast<const __m128i*>(input_bytes); for(u32bit i = 0; i != blocks; ++i) { diff --git a/src/kdf/tls_prf/prf_tls.cpp b/src/kdf/tls_prf/prf_tls.cpp index 5e77f831e..7345f11c5 100644 --- a/src/kdf/tls_prf/prf_tls.cpp +++ b/src/kdf/tls_prf/prf_tls.cpp @@ -1,6 +1,6 @@ /* -* TLS PRF -* (C) 2004-2006 Jack Lloyd +* TLS v1.0 and v1.2 PRFs +* (C) 2004-2010 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -18,19 +18,19 @@ namespace { /* * TLS PRF P_hash function */ -SecureVector<byte> P_hash(MessageAuthenticationCode* mac, - u32bit len, - const byte secret[], u32bit secret_len, - const byte seed[], u32bit seed_len) +void P_hash(byte output[], u32bit output_len, + MessageAuthenticationCode* mac, + const byte secret[], u32bit secret_len, + const byte seed[], u32bit seed_len) { - SecureVector<byte> out; - mac->set_key(secret, secret_len); SecureVector<byte> A(seed, seed_len); - while(len) + + while(output_len) { - const u32bit this_block_len = std::min(mac->OUTPUT_LENGTH, len); + const u32bit this_block_len = + std::min(mac->OUTPUT_LENGTH, output_len); A = mac->process(A); @@ -38,10 +38,10 @@ SecureVector<byte> P_hash(MessageAuthenticationCode* mac, mac->update(seed, seed_len); SecureVector<byte> block = mac->final(); - out.append(block, this_block_len); - len -= this_block_len; + xor_buf(output, &block[0], this_block_len); + output_len -= this_block_len; + output += this_block_len; } - return out; } } @@ -68,18 +68,41 @@ SecureVector<byte> TLS_PRF::derive(u32bit key_len, const byte secret[], u32bit secret_len, const byte seed[], u32bit seed_len) const { + SecureVector<byte> output(key_len); + u32bit S1_len = (secret_len + 1) / 2, S2_len = (secret_len + 1) / 2; const byte* S1 = secret; const byte* S2 = secret + (secret_len - S2_len); - SecureVector<byte> key1, key2; - key1 = P_hash(hmac_md5, key_len, S1, S1_len, seed, seed_len); - key2 = P_hash(hmac_sha1, key_len, S2, S2_len, seed, seed_len); + P_hash(output, key_len, hmac_md5, S1, S1_len, seed, seed_len); + P_hash(output, key_len, hmac_sha1, S2, S2_len, seed, seed_len); + + return output; + } + +/* +* TLS v1.2 PRF Constructor and Destructor +*/ +TLS_12_PRF::TLS_12_PRF(HashFunction* hash) + { + hmac = new HMAC(hash); + } + +TLS_12_PRF::~TLS_12_PRF() + { + delete hmac; + } + +SecureVector<byte> TLS_12_PRF::derive(u32bit key_len, + const byte secret[], u32bit secret_len, + const byte seed[], u32bit seed_len) const + { + SecureVector<byte> output(key_len); - xor_buf(key1.begin(), key2.begin(), key2.size()); + P_hash(output, key_len, hmac, secret, secret_len, seed, seed_len); - return key1; + return output; } } diff --git a/src/kdf/tls_prf/prf_tls.h b/src/kdf/tls_prf/prf_tls.h index d21279588..6d1787609 100644 --- a/src/kdf/tls_prf/prf_tls.h +++ b/src/kdf/tls_prf/prf_tls.h @@ -1,6 +1,6 @@ /* -* TLS v1.0 PRF -* (C) 1999-2007 Jack Lloyd +* TLS v1.0 and v1.2 PRFs +* (C) 2004-2010 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -10,6 +10,7 @@ #include <botan/kdf.h> #include <botan/mac.h> +#include <botan/hash.h> namespace Botan { @@ -19,8 +20,9 @@ namespace Botan { class BOTAN_DLL TLS_PRF : public KDF { public: - SecureVector<byte> derive(u32bit, const byte[], u32bit, - const byte[], u32bit) const; + SecureVector<byte> derive(u32bit key_len, + const byte secret[], u32bit secret_len, + const byte seed[], u32bit seed_len) const; TLS_PRF(); ~TLS_PRF(); @@ -29,6 +31,22 @@ class BOTAN_DLL TLS_PRF : public KDF MessageAuthenticationCode* hmac_sha1; }; +/* +* TLS 1.2 PRF +*/ +class BOTAN_DLL TLS_12_PRF : public KDF + { + public: + SecureVector<byte> derive(u32bit key_len, + const byte secret[], u32bit secret_len, + const byte seed[], u32bit seed_len) const; + + TLS_12_PRF(HashFunction* hash); + ~TLS_12_PRF(); + private: + MessageAuthenticationCode* hmac; + }; + } #endif diff --git a/src/libstate/global_rng.cpp b/src/libstate/global_rng.cpp index 725ec2be1..c5dcaab00 100644 --- a/src/libstate/global_rng.cpp +++ b/src/libstate/global_rng.cpp @@ -6,7 +6,7 @@ */ #include <botan/libstate.h> -#include <botan/mutex.h> +#include <botan/internal/mutex.h> #if defined(BOTAN_HAS_RANDPOOL) #include <botan/randpool.h> diff --git a/src/pk_pad/emsa_raw/emsa_raw.cpp b/src/pk_pad/emsa_raw/emsa_raw.cpp index 5dfe20a50..734dc3698 100644 --- a/src/pk_pad/emsa_raw/emsa_raw.cpp +++ b/src/pk_pad/emsa_raw/emsa_raw.cpp @@ -44,7 +44,25 @@ bool EMSA_Raw::verify(const MemoryRegion<byte>& coded, const MemoryRegion<byte>& raw, u32bit) { - return (coded == raw); + if(coded.size() == raw.size()) + return (coded == raw); + + if(coded.size() > raw.size()) + return false; + + // handle zero padding differences + const u32bit leading_zeros_expected = raw.size() - coded.size(); + + bool same_modulo_leading_zeros = true; + + for(u32bit i = 0; i != leading_zeros_expected; ++i) + if(raw[i]) + same_modulo_leading_zeros = false; + + if(!same_mem(&coded[0], &raw[leading_zeros_expected], coded.size())) + same_modulo_leading_zeros = false; + + return same_modulo_leading_zeros; } } diff --git a/src/pubkey/ec_dompar/ec_dompar.cpp b/src/pubkey/ec_dompar/ec_dompar.cpp index b0aa7a87a..512d8d769 100644 --- a/src/pubkey/ec_dompar/ec_dompar.cpp +++ b/src/pubkey/ec_dompar/ec_dompar.cpp @@ -30,12 +30,21 @@ EC_Domain_Params::EC_Domain_Params(const OID& domain_oid) EC_Domain_Params::EC_Domain_Params(const std::string& pem) { - if(pem != "") + if(pem == "") + return; // no initialization / uninitialized + + try { DataSource_Memory input(pem); - *this = EC_Domain_Params( - PEM_Code::decode_check_label(input, "EC PARAMETERS")); + SecureVector<byte> ber = + PEM_Code::decode_check_label(input, "EC PARAMETERS"); + + *this = EC_Domain_Params(ber); + } + catch(Decoding_Error) // hmm, not PEM? + { + *this = EC_Domain_Params(OID(pem)); } } diff --git a/src/pubkey/ec_dompar/ec_dompar.h b/src/pubkey/ec_dompar/ec_dompar.h index 7da2120cc..15143373a 100644 --- a/src/pubkey/ec_dompar/ec_dompar.h +++ b/src/pubkey/ec_dompar/ec_dompar.h @@ -60,10 +60,11 @@ class BOTAN_DLL EC_Domain_Params EC_Domain_Params(const OID& oid); /** - * Create an EC domain from PEM encoding (as from PEM_encode) - * @param pem data + * Create an EC domain from PEM encoding (as from PEM_encode), + * or from an OID name (eg "secp16r1", or "1.3.132.0.8") + * @param pem_or_oid PEM-encoded data, or an OID */ - EC_Domain_Params(const std::string& pem = ""); + EC_Domain_Params(const std::string& pem_or_oid = ""); /** * Create the DER encoding of this domain diff --git a/src/pubkey/ecdh/ecdh.h b/src/pubkey/ecdh/ecdh.h index d670361f6..19621f2ca 100644 --- a/src/pubkey/ecdh/ecdh.h +++ b/src/pubkey/ecdh/ecdh.h @@ -38,7 +38,7 @@ class BOTAN_DLL ECDH_PublicKey : public virtual EC_PublicKey /** * Get this keys algorithm name. - * @result this keys algorithm name + * @return this keys algorithm name */ std::string algo_name() const { return "ECDH"; } @@ -46,9 +46,16 @@ class BOTAN_DLL ECDH_PublicKey : public virtual EC_PublicKey * Get the maximum number of bits allowed to be fed to this key. * This is the bitlength of the order of the base point. - * @result the maximum number of input bits + * @return the maximum number of input bits */ u32bit max_input_bits() const { return domain().get_order().bits(); } + + /** + * @return the public point value + */ + MemoryVector<byte> public_value() const + { return EC2OSP(public_point(), PointGFp::UNCOMPRESSED); } + protected: ECDH_PublicKey() {} }; @@ -75,7 +82,7 @@ class BOTAN_DLL ECDH_PrivateKey : public ECDH_PublicKey, EC_PrivateKey(rng, domain) {} MemoryVector<byte> public_value() const - { return EC2OSP(public_point(), PointGFp::UNCOMPRESSED); } + { return ECDH_PublicKey::public_value(); } }; /** diff --git a/src/rng/hmac_rng/hmac_rng.cpp b/src/rng/hmac_rng/hmac_rng.cpp index 6234a61e7..c185a5643 100644 --- a/src/rng/hmac_rng/hmac_rng.cpp +++ b/src/rng/hmac_rng/hmac_rng.cpp @@ -54,12 +54,11 @@ void HMAC_RNG::randomize(byte out[], u32bit length) } /** -* Reseed the internal state, also accepting user input to include +* Poll for entropy and reset the internal keys */ -void HMAC_RNG::reseed_with_input(u32bit poll_bits, - const byte input[], u32bit input_length) +void HMAC_RNG::reseed(u32bit poll_bits) { - /** + /* Using the terminology of E-t-E, XTR is the MAC function (normally HMAC) seeded with XTS (below) and we form SKM, the key material, by fast polling each source, and then slow polling as many as we think @@ -81,20 +80,16 @@ void HMAC_RNG::reseed_with_input(u32bit poll_bits, } } - // And now add the user-provided input, if any - if(input_length) - accum.add(input, input_length, 1); - /* - It is necessary to feed forward poll data. Otherwise, a good poll - (collecting a large amount of conditional entropy) followed by a - bad one (collecting little) would be unsafe. Do this by generating - new PRF outputs using the previous key and feeding them into the - extractor function. - - Cycle the RNG once (CTXinfo="rng"), then generate a new PRF output - using the CTXinfo "reseed". Provide these values as input to the - extractor function. + * It is necessary to feed forward poll data. Otherwise, a good poll + * (collecting a large amount of conditional entropy) followed by a + * bad one (collecting little) would be unsafe. Do this by + * generating new PRF outputs using the previous key and feeding + * them into the extractor function. + * + * Cycle the RNG once (CTXinfo="rng"), then generate a new PRF + * output using the CTXinfo "reseed". Provide these values as input + * to the extractor function. */ hmac_prf(prf, K, counter, "rng"); extractor->update(K); // K is the CTXinfo=rng PRF output @@ -113,26 +108,27 @@ void HMAC_RNG::reseed_with_input(u32bit poll_bits, // Reset state K.clear(); counter = 0; + user_input_len = 0; - if(input_length > 64 || accum.bits_collected() >= 128) + if(accum.bits_collected() >= 128) seeded = true; } /** -* Reseed the internal state -*/ -void HMAC_RNG::reseed(u32bit poll_bits) - { - reseed_with_input(poll_bits, 0, 0); - } - -/** -* Add user-supplied entropy by reseeding and including this -* input among the poll data +* Add user-supplied entropy to the extractor input */ void HMAC_RNG::add_entropy(const byte input[], u32bit length) { - reseed_with_input(64, input, length); + extractor->update(input, length); + user_input_len += length; + + /* + * After we've accumulated >= 1024 bytes of user input, reseed. + * This input will automatically have been included if reseed was + * called already, as it's just included in the extractor input. + */ + if(user_input_len >= 1024) + reseed(128); } /** @@ -143,7 +139,7 @@ void HMAC_RNG::add_entropy_source(EntropySource* src) entropy_sources.push_back(src); } -/* +/** * Clear memory of sensitive data */ void HMAC_RNG::clear() @@ -152,6 +148,7 @@ void HMAC_RNG::clear() prf->clear(); K.clear(); counter = 0; + user_input_len = 0; seeded = false; } @@ -178,7 +175,9 @@ HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac, // First PRF inputs are all zero, as specified in section 2 K.resize(prf->OUTPUT_LENGTH); + counter = 0; + user_input_len = 0; seeded = false; /* @@ -187,7 +186,7 @@ HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac, RNG, but obviously that is meaningless to do on the first poll. We will want to use the PRF before we set the first key (in - reseed_with_input), and it is a pain to keep track if it is set or + reseed), and it is a pain to keep track if it is set or not. Since the first time it doesn't matter anyway, just set the PRF key to constant zero: randomize() will not produce output unless is_seeded() returns true, and that will only be the case if diff --git a/src/rng/hmac_rng/hmac_rng.h b/src/rng/hmac_rng/hmac_rng.h index 97b0baf15..452357130 100644 --- a/src/rng/hmac_rng/hmac_rng.h +++ b/src/rng/hmac_rng/hmac_rng.h @@ -41,9 +41,6 @@ class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator ~HMAC_RNG(); private: - void reseed_with_input(u32bit poll_bits, - const byte input[], u32bit length); - MessageAuthenticationCode* extractor; MessageAuthenticationCode* prf; @@ -51,7 +48,7 @@ class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator bool seeded; SecureVector<byte> K, io_buffer; - u32bit counter, source_index; + u32bit counter, user_input_len; }; } diff --git a/src/ssl/c_kex.cpp b/src/ssl/c_kex.cpp index e09e18ce1..db2198627 100644 --- a/src/ssl/c_kex.cpp +++ b/src/ssl/c_kex.cpp @@ -67,9 +67,7 @@ Client_Key_Exchange::Client_Key_Exchange(const MemoryRegion<byte>& contents, { include_length = true; - if(using_version == SSL_V3 && - (suite.kex_type() == CipherSuite::NO_KEX || - suite.kex_type() == CipherSuite::RSA_KEX)) + if(using_version == SSL_V3 && (suite.kex_type() == TLS_ALGO_KEYEXCH_RSA)) include_length = false; deserialize(contents); diff --git a/src/ssl/hello.cpp b/src/ssl/hello.cpp index a23d51c24..5b3c32278 100644 --- a/src/ssl/hello.cpp +++ b/src/ssl/hello.cpp @@ -106,6 +106,40 @@ SecureVector<byte> Client_Hello::serialize() const return buf; } +void Client_Hello::deserialize_sslv2(const MemoryRegion<byte>& buf) + { + if(buf.size() < 12 || buf[0] != 1) + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + + const u32bit cipher_spec_len = make_u16bit(buf[3], buf[4]); + const u32bit sess_id_len = make_u16bit(buf[5], buf[6]); + const u32bit challenge_len = make_u16bit(buf[7], buf[8]); + + const u32bit expected_size = + (9 + sess_id_len + cipher_spec_len + challenge_len); + + if(buf.size() != expected_size) + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + + if(sess_id_len != 0 || cipher_spec_len % 3 != 0 || + (challenge_len < 16 || challenge_len > 32)) + { + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + } + + for(u32bit i = 9; i != 9 + cipher_spec_len; i += 3) + { + if(buf[i] != 0) // a SSLv2 cipherspec; ignore it + continue; + + suites.push_back(make_u16bit(buf[i+1], buf[i+2])); + } + + c_version = static_cast<Version_Code>(make_u16bit(buf[1], buf[2])); + + c_random.set(&buf[9+cipher_spec_len+sess_id_len], challenge_len); + } + /** * Deserialize a Client Hello message */ @@ -207,6 +241,11 @@ Server_Hello::Server_Hello(RandomNumberGenerator& rng, } suite = policy->choose_suite(c_hello.ciphersuites(), have_rsa, have_dsa); + + if(suite == 0) + throw TLS_Exception(PROTOCOL_VERSION, + "Can't agree on a ciphersuite with client"); + comp_algo = policy->choose_compression(c_hello.compression_algos()); s_version = ver; diff --git a/src/ssl/rec_read.cpp b/src/ssl/rec_read.cpp index 8f8e5dc1e..f07744c2a 100644 --- a/src/ssl/rec_read.cpp +++ b/src/ssl/rec_read.cpp @@ -124,6 +124,35 @@ u32bit Record_Reader::get_record(byte& msg_type, */ input_queue.peek(header, sizeof(header)); + // SSLv2-format client hello? + if(header[0] & 0x80 && header[2] == 1 && header[3] == 3) + { + u32bit record_len = make_u16bit(header[0], header[1]) & 0x7FFF; + + if(have_in_queue < record_len + 2) + return (record_len + 2 - have_in_queue); + + msg_type = HANDSHAKE; + output.resize(record_len + 4); + + input_queue.read(&output[2], record_len + 2); + output[0] = CLIENT_HELLO_SSLV2; + output[1] = 0; + output[2] = header[0] & 0x7F; + output[3] = header[1]; + + return 0; + } + + if(header[0] != CHANGE_CIPHER_SPEC && + header[0] != ALERT && + header[0] != HANDSHAKE && + header[0] != APPLICATION_DATA) + { + throw TLS_Exception(UNEXPECTED_MESSAGE, + "Record_Reader: Unknown record type"); + } + const u16bit version = make_u16bit(header[1], header[2]); const u16bit record_len = make_u16bit(header[3], header[4]); diff --git a/src/ssl/tls_client.cpp b/src/ssl/tls_client.cpp index fbad1f838..8a4275d93 100644 --- a/src/ssl/tls_client.cpp +++ b/src/ssl/tls_client.cpp @@ -123,6 +123,7 @@ TLS_Client::~TLS_Client() */ void TLS_Client::initialize() { + std::string error_str; Alert_Type error_type = NO_ALERT_TYPE; try { @@ -133,10 +134,12 @@ void TLS_Client::initialize() } catch(TLS_Exception& e) { + error_str = e.what(); error_type = e.type(); } catch(std::exception& e) { + error_str = e.what(); error_type = HANDSHAKE_FAILURE; } @@ -157,7 +160,7 @@ void TLS_Client::initialize() state = 0; } - throw Stream_IO_Error("TLS_Client: Handshake failed"); + throw Stream_IO_Error("TLS_Client: Handshake failed: " + error_str); } } @@ -360,6 +363,8 @@ void TLS_Client::read_handshake(byte rec_type, void TLS_Client::process_handshake_msg(Handshake_Type type, const MemoryRegion<byte>& contents) { + rng.add_entropy(&contents[0], contents.size()); + if(type == HELLO_REQUEST) { if(state == 0) @@ -419,7 +424,7 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, { client_check_state(type, state); - if(state->suite.sig_type() == CipherSuite::NO_SIG) + if(state->suite.sig_type() == TLS_ALGO_SIGNER_ANON) throw Unexpected_Message("Recived certificate from anonymous server"); state->server_certs = new Certificate(contents); @@ -445,8 +450,8 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, throw TLS_Exception(UNSUPPORTED_CERTIFICATE, "Unknown key type recieved in server kex"); - if((is_dsa && state->suite.sig_type() != CipherSuite::DSA_SIG) || - (is_rsa && state->suite.sig_type() != CipherSuite::RSA_SIG)) + if((is_dsa && state->suite.sig_type() != TLS_ALGO_SIGNER_DSA) || + (is_rsa && state->suite.sig_type() != TLS_ALGO_SIGNER_RSA)) throw TLS_Exception(ILLEGAL_PARAMETER, "Certificate key type did not match ciphersuite"); } @@ -454,7 +459,7 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, { client_check_state(type, state); - if(state->suite.kex_type() == CipherSuite::NO_KEX) + if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_NOKEX) throw Unexpected_Message("Unexpected key exchange from server"); state->server_kex = new Server_Key_Exchange(contents); @@ -474,12 +479,12 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, throw TLS_Exception(HANDSHAKE_FAILURE, "Unknown key type recieved in server kex"); - if((is_dh && state->suite.kex_type() != CipherSuite::DH_KEX) || - (is_rsa && state->suite.kex_type() != CipherSuite::RSA_KEX)) + if((is_dh && state->suite.kex_type() != TLS_ALGO_KEYEXCH_DH) || + (is_rsa && state->suite.kex_type() != TLS_ALGO_KEYEXCH_RSA)) throw TLS_Exception(ILLEGAL_PARAMETER, "Certificate key type did not match ciphersuite"); - if(state->suite.sig_type() != CipherSuite::NO_SIG) + if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON) { if(!state->server_kex->verify(peer_certs[0], state->client_hello->random(), diff --git a/src/ssl/tls_magic.h b/src/ssl/tls_magic.h index a6ca1f8d6..93b56d96d 100644 --- a/src/ssl/tls_magic.h +++ b/src/ssl/tls_magic.h @@ -1,6 +1,6 @@ /** -* SSL/TLS Protocol Constants -* (C) 2004-2006 Jack Lloyd +* SSL/TLS Protocol Constants +* (C) 2004-2010 Jack Lloyd * * Released under the terms of the Botan license */ @@ -40,6 +40,7 @@ enum Record_Type { enum Handshake_Type { HELLO_REQUEST = 0, CLIENT_HELLO = 1, + CLIENT_HELLO_SSLV2 = 255, // not a wire value SERVER_HELLO = 2, CERTIFICATE = 11, SERVER_KEX = 12, @@ -96,19 +97,75 @@ enum Certificate_Type { }; enum Ciphersuite_Code { - RSA_RC4_MD5 = 0x0004, - RSA_RC4_SHA = 0x0005, - RSA_3DES_SHA = 0x000A, - RSA_AES128_SHA = 0x002F, - RSA_AES256_SHA = 0x0035, - - DHE_RSA_3DES_SHA = 0x0016, - DHE_RSA_AES128_SHA = 0x0033, - DHE_RSA_AES256_SHA = 0x0039, - - DHE_DSS_3DES_SHA = 0x0013, - DHE_DSS_AES128_SHA = 0x0032, - DHE_DSS_AES256_SHA = 0x0038 + TLS_RSA_WITH_RC4_128_MD5 = 0x0004, + TLS_RSA_WITH_RC4_128_SHA = 0x0005, + + TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A, + + TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F, + TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035, + TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C, + TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D, + TLS_RSA_WITH_SEED_CBC_SHA = 0x0096, + + TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032, + TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040, + TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A, + TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099, + + TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B, + TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A, + + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007, + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024, + + TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011, + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028 +}; + +/* +* Form of the ciphersuites broken down by field instead of +* being randomly assigned codepoints. +*/ +enum TLS_Ciphersuite_Algos { + TLS_ALGO_SIGNER_MASK = 0xFF000000, + TLS_ALGO_SIGNER_ANON = 0x01000000, + TLS_ALGO_SIGNER_RSA = 0x02000000, + TLS_ALGO_SIGNER_DSA = 0x03000000, + TLS_ALGO_SIGNER_ECDSA = 0x04000000, + + TLS_ALGO_KEYEXCH_MASK = 0x00FF0000, + TLS_ALGO_KEYEXCH_NOKEX = 0x00010000, + TLS_ALGO_KEYEXCH_RSA = 0x00020000, + TLS_ALGO_KEYEXCH_DH = 0x00030000, + TLS_ALGO_KEYEXCH_ECDH = 0x00040000, + + TLS_ALGO_MAC_MASK = 0x0000FF00, + TLS_ALGO_MAC_MD5 = 0x00000100, + TLS_ALGO_MAC_SHA1 = 0x00000200, + TLS_ALGO_MAC_SHA256 = 0x00000300, + TLS_ALGO_MAC_SHA384 = 0x00000400, + + TLS_ALGO_CIPHER_MASK = 0x000000FF, + TLS_ALGO_CIPHER_RC4_128 = 0x00000001, + TLS_ALGO_CIPHER_3DES_CBC = 0x00000002, + TLS_ALGO_CIPHER_AES128_CBC = 0x00000003, + TLS_ALGO_CIPHER_AES256_CBC = 0x00000004, + TLS_ALGO_CIPHER_SEED_CBC = 0x00000005 }; enum Compression_Algo { @@ -122,6 +179,9 @@ enum TLS_Handshake_Extension_Type { TLSEXT_TRUSTED_CA_KEYS = 3, TLSEXT_TRUNCATED_HMAC = 4, + TLSEXT_USABLE_ELLIPTIC_CURVES = 10, + TLSEXT_EC_POINT_FORMATS = 11, + TLSEXT_CERTIFICATE_TYPES = 9, TLSEXT_SESSION_TICKET = 35, }; diff --git a/src/ssl/tls_messages.h b/src/ssl/tls_messages.h index 1f72c05f7..5c0c06c88 100644 --- a/src/ssl/tls_messages.h +++ b/src/ssl/tls_messages.h @@ -43,11 +43,11 @@ class BOTAN_DLL Client_Hello : public HandshakeMessage public: Handshake_Type type() const { return CLIENT_HELLO; } Version_Code version() const { return c_version; } - SecureVector<byte> session_id() const { return sess_id; } + const SecureVector<byte>& session_id() const { return sess_id; } std::vector<u16bit> ciphersuites() const { return suites; } std::vector<byte> compression_algos() const { return comp_algos; } - SecureVector<byte> random() const { return c_random; } + const SecureVector<byte>& random() const { return c_random; } std::string hostname() const { return requested_hostname; } @@ -56,10 +56,19 @@ class BOTAN_DLL Client_Hello : public HandshakeMessage Client_Hello(RandomNumberGenerator& rng, Record_Writer&, const TLS_Policy*, HandshakeHash&); - Client_Hello(const MemoryRegion<byte>& buf) { deserialize(buf); } + Client_Hello(const MemoryRegion<byte>& buf, + Handshake_Type type) + { + if(type == CLIENT_HELLO) + deserialize(buf); + else + deserialize_sslv2(buf); + } + private: SecureVector<byte> serialize() const; void deserialize(const MemoryRegion<byte>&); + void deserialize_sslv2(const MemoryRegion<byte>&); Version_Code c_version; SecureVector<byte> sess_id, c_random; @@ -216,11 +225,11 @@ class BOTAN_DLL Server_Hello : public HandshakeMessage public: Handshake_Type type() const { return SERVER_HELLO; } Version_Code version() { return s_version; } - SecureVector<byte> session_id() const { return sess_id; } + const SecureVector<byte>& session_id() const { return sess_id; } u16bit ciphersuite() const { return suite; } byte compression_algo() const { return comp_algo; } - SecureVector<byte> random() const { return s_random; } + const SecureVector<byte>& random() const { return s_random; } Server_Hello(RandomNumberGenerator& rng, Record_Writer&, const TLS_Policy*, diff --git a/src/ssl/tls_policy.cpp b/src/ssl/tls_policy.cpp index 6138ae193..57fcdb5cc 100644 --- a/src/ssl/tls_policy.cpp +++ b/src/ssl/tls_policy.cpp @@ -1,6 +1,6 @@ /** -* Policies -* (C) 2004-2006 Jack Lloyd +* Policies for TLS +* (C) 2004-2010 Jack Lloyd * * Released under the terms of the Botan license */ @@ -29,25 +29,28 @@ std::vector<u16bit> TLS_Policy::suite_list(bool use_rsa, if(use_edh_dsa) { - suites.push_back(DHE_DSS_AES256_SHA); - suites.push_back(DHE_DSS_AES128_SHA); - suites.push_back(DHE_DSS_3DES_SHA); + suites.push_back(TLS_DHE_DSS_WITH_AES_256_CBC_SHA); + suites.push_back(TLS_DHE_DSS_WITH_AES_128_CBC_SHA); + suites.push_back(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA); + suites.push_back(TLS_DHE_DSS_WITH_SEED_CBC_SHA); } if(use_edh_rsa) { - suites.push_back(DHE_RSA_AES256_SHA); - suites.push_back(DHE_RSA_AES128_SHA); - suites.push_back(DHE_RSA_3DES_SHA); + suites.push_back(TLS_DHE_RSA_WITH_AES_256_CBC_SHA); + suites.push_back(TLS_DHE_RSA_WITH_AES_128_CBC_SHA); + suites.push_back(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA); + suites.push_back(TLS_DHE_RSA_WITH_SEED_CBC_SHA); } if(use_rsa) { - suites.push_back(RSA_AES256_SHA); - suites.push_back(RSA_AES128_SHA); - suites.push_back(RSA_3DES_SHA); - suites.push_back(RSA_RC4_SHA); - suites.push_back(RSA_RC4_MD5); + suites.push_back(TLS_RSA_WITH_AES_256_CBC_SHA); + suites.push_back(TLS_RSA_WITH_AES_128_CBC_SHA); + suites.push_back(TLS_RSA_WITH_3DES_EDE_CBC_SHA); + suites.push_back(TLS_RSA_WITH_SEED_CBC_SHA); + suites.push_back(TLS_RSA_WITH_RC4_128_SHA); + suites.push_back(TLS_RSA_WITH_RC4_128_MD5); } if(suites.size() == 0) diff --git a/src/ssl/tls_server.cpp b/src/ssl/tls_server.cpp index 47902a71c..a4cfcf7de 100644 --- a/src/ssl/tls_server.cpp +++ b/src/ssl/tls_server.cpp @@ -43,7 +43,7 @@ void server_check_state(Handshake_Type new_msg, Handshake_State* state) Unexpected_Message("State transition error from " + err) {} }; - if(new_msg == CLIENT_HELLO) + if(new_msg == CLIENT_HELLO || new_msg == CLIENT_HELLO_SSLV2) { if(state->server_hello) throw State_Transition_Error("ClientHello"); @@ -325,23 +325,30 @@ void TLS_Server::read_handshake(byte rec_type, void TLS_Server::process_handshake_msg(Handshake_Type type, const MemoryRegion<byte>& contents) { + rng.add_entropy(&contents[0], contents.size()); + if(state == 0) throw Unexpected_Message("Unexpected handshake message"); if(type != HANDSHAKE_CCS && type != FINISHED) { - state->hash.update(static_cast<byte>(type)); - u32bit record_length = contents.size(); - for(u32bit j = 0; j != 3; j++) - state->hash.update(get_byte(j+1, record_length)); + + if(type != CLIENT_HELLO_SSLV2) + { + state->hash.update(static_cast<byte>(type)); + u32bit record_length = contents.size(); + for(u32bit j = 0; j != 3; j++) + state->hash.update(get_byte(j+1, record_length)); + } + state->hash.update(contents); } - if(type == CLIENT_HELLO) + if(type == CLIENT_HELLO || type == CLIENT_HELLO_SSLV2) { server_check_state(type, state); - state->client_hello = new Client_Hello(contents); + state->client_hello = new Client_Hello(contents, type); client_requested_hostname = state->client_hello->hostname(); @@ -358,7 +365,7 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, state->suite = CipherSuite(state->server_hello->ciphersuite()); - if(state->suite.sig_type() != CipherSuite::NO_SIG) + if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON) { // FIXME: should choose certs based on sig type state->server_certs = new Certificate(writer, cert_chain, @@ -366,14 +373,14 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, } state->kex_priv = PKCS8::copy_key(*private_key, rng); - if(state->suite.kex_type() != CipherSuite::NO_KEX) + if(state->suite.kex_type() != TLS_ALGO_KEYEXCH_NOKEX) { - if(state->suite.kex_type() == CipherSuite::RSA_KEX) + if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_RSA) { state->kex_priv = new RSA_PrivateKey(rng, policy->rsa_export_keysize()); } - else if(state->suite.kex_type() == CipherSuite::DH_KEX) + else if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_DH) { state->kex_priv = new DH_PrivateKey(rng, policy->dh_group()); } diff --git a/src/ssl/tls_suites.cpp b/src/ssl/tls_suites.cpp index a168dac0a..ccc4ab502 100644 --- a/src/ssl/tls_suites.cpp +++ b/src/ssl/tls_suites.cpp @@ -1,40 +1,254 @@ /** -* TLS Cipher Suites -* (C) 2004-2006 Jack Lloyd +* TLS Cipher Suites +* (C) 2004-2010 Jack Lloyd * * Released under the terms of the Botan license */ #include <botan/tls_suites.h> #include <botan/tls_exceptn.h> -#include <botan/parsing.h> -#include <vector> -#include <string> namespace Botan { -namespace { - /** -* Convert an SSL/TLS ciphersuite to a string +* Convert an SSL/TLS ciphersuite to algorithm fields */ -std::string lookup_ciphersuite(u16bit suite) +TLS_Ciphersuite_Algos CipherSuite::lookup_ciphersuite(u16bit suite) { - if(suite == RSA_RC4_MD5) return "RSA/NONE/ARC4/16/MD5"; - if(suite == RSA_RC4_SHA) return "RSA/NONE/ARC4/16/SHA1"; - if(suite == RSA_3DES_SHA) return "RSA/NONE/3DES/24/SHA1"; - if(suite == RSA_AES128_SHA) return "RSA/NONE/AES/16/SHA1"; - if(suite == RSA_AES256_SHA) return "RSA/NONE/AES/32/SHA1"; + if(suite == TLS_RSA_WITH_RC4_128_MD5) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_MD5 | + TLS_ALGO_CIPHER_RC4_128); + + if(suite == TLS_RSA_WITH_RC4_128_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_RC4_128); + + if(suite == TLS_RSA_WITH_3DES_EDE_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_3DES_CBC); + + if(suite == TLS_RSA_WITH_AES_128_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_RSA_WITH_AES_256_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_RSA_WITH_SEED_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_SEED_CBC); + + if(suite == TLS_RSA_WITH_AES_128_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_RSA_WITH_AES_256_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_3DES_CBC); + + if(suite == TLS_DHE_DSS_WITH_AES_128_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_DHE_DSS_WITH_SEED_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_SEED_CBC); + + if(suite == TLS_DHE_DSS_WITH_AES_256_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_3DES_CBC); + + if(suite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_DHE_DSS_WITH_SEED_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_SEED_CBC); + + if(suite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_RC4_128); + + if(suite == TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_3DES_CBC); + + if(suite == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES256_CBC); - if(suite == DHE_RSA_3DES_SHA) return "RSA/DH/3DES/24/SHA1"; - if(suite == DHE_RSA_AES128_SHA) return "RSA/DH/AES/16/SHA1"; - if(suite == DHE_RSA_AES256_SHA) return "RSA/DH/AES/32/SHA1"; + if(suite == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES128_CBC); - if(suite == DHE_DSS_3DES_SHA) return "DSA/DH/3DES/24/SHA1"; - if(suite == DHE_DSS_AES128_SHA) return "DSA/DH/AES/16/SHA1"; - if(suite == DHE_DSS_AES256_SHA) return "DSA/DH/AES/32/SHA1"; + if(suite == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA384 | + TLS_ALGO_CIPHER_AES256_CBC); - return ""; + if(suite == TLS_ECDHE_RSA_WITH_RC4_128_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_RC4_128); + + if(suite == TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_3DES_CBC); + + if(suite == TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA384 | + TLS_ALGO_CIPHER_AES256_CBC); + + return TLS_Ciphersuite_Algos(0); + } + +namespace { + +std::pair<std::string, u32bit> cipher_code_to_name(TLS_Ciphersuite_Algos algo) + { + if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_RC4_128) + return std::make_pair("RC4", 128); + + if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_3DES_CBC) + return std::make_pair("3DES", 24); + + if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_AES128_CBC) + return std::make_pair("AES-128", 16); + + if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_AES256_CBC) + return std::make_pair("AES-256", 32); + + if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_SEED_CBC) + return std::make_pair("SEED", 16); + + throw TLS_Exception(INTERNAL_ERROR, + "CipherSuite: Unknown cipher type " + to_string(algo)); + } + +std::string mac_code_to_name(TLS_Ciphersuite_Algos algo) + { + if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_MD5) + return "MD5"; + + if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA1) + return "SHA-1"; + + if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA256) + return "SHA-256"; + + if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA384) + return "SHA-384"; + + throw TLS_Exception(INTERNAL_ERROR, + "CipherSuite: Unknown MAC type " + to_string(algo)); } } @@ -47,31 +261,21 @@ CipherSuite::CipherSuite(u16bit suite_code) if(suite_code == 0) return; - std::string suite_string = lookup_ciphersuite(suite_code); + TLS_Ciphersuite_Algos algos = lookup_ciphersuite(suite_code); + + if(algos == 0) + throw Invalid_Argument("Unknown ciphersuite: " + to_string(suite_code)); - if(suite_string == "") - throw Invalid_Argument("Unknown ciphersuite: " + - std::to_string(suite_code)); + sig_algo = TLS_Ciphersuite_Algos(algos & TLS_ALGO_SIGNER_MASK); - std::vector<std::string> suite_info = split_on(suite_string, '/'); + kex_algo = TLS_Ciphersuite_Algos(algos & TLS_ALGO_KEYEXCH_MASK); - if(suite_info[0] == "RSA") sig_algo = RSA_SIG; - else if(suite_info[0] == "DSA") sig_algo = DSA_SIG; - else if(suite_info[0] == "NONE") sig_algo = NO_SIG; - else - throw TLS_Exception(INTERNAL_ERROR, - "CipherSuite: Unknown sig type " + suite_info[0]); + std::pair<std::string, u32bit> cipher_info = cipher_code_to_name(algos); - if(suite_info[1] == "DH") kex_algo = DH_KEX; - else if(suite_info[1] == "RSA") kex_algo = RSA_KEX; - else if(suite_info[1] == "NONE") kex_algo = NO_KEX; - else - throw TLS_Exception(INTERNAL_ERROR, - "CipherSuite: Unknown kex type " + suite_info[1]); + cipher = cipher_info.first; + cipher_key_length = cipher_info.second; - cipher = suite_info[2]; - cipher_key_length = to_u32bit(suite_info[3]); - mac = suite_info[4]; + mac = mac_code_to_name(algos); } } diff --git a/src/ssl/tls_suites.h b/src/ssl/tls_suites.h index b7008e8db..fa015c28f 100644 --- a/src/ssl/tls_suites.h +++ b/src/ssl/tls_suites.h @@ -1,6 +1,6 @@ /** -* Cipher Suites -* (C) 2004-2006 Jack Lloyd +* Cipher Suites +* (C) 2004-2010 Jack Lloyd * * Released under the terms of the Botan license */ @@ -9,6 +9,7 @@ #define BOTAN_TLS_CIPHERSUITES_H__ #include <botan/types.h> +#include <botan/tls_magic.h> #include <string> namespace Botan { @@ -19,20 +20,19 @@ namespace Botan { class BOTAN_DLL CipherSuite { public: - enum Kex_Type { NO_KEX, RSA_KEX, DH_KEX }; - enum Sig_Type { NO_SIG, RSA_SIG, DSA_SIG }; + static TLS_Ciphersuite_Algos lookup_ciphersuite(u16bit suite); std::string cipher_algo() const { return cipher; } std::string mac_algo() const { return mac; } u32bit cipher_keylen() const { return cipher_key_length; } - Kex_Type kex_type() const { return kex_algo; } - Sig_Type sig_type() const { return sig_algo; } + + TLS_Ciphersuite_Algos kex_type() const { return kex_algo; } + TLS_Ciphersuite_Algos sig_type() const { return sig_algo; } CipherSuite(u16bit = 0); private: - Kex_Type kex_algo; - Sig_Type sig_algo; + TLS_Ciphersuite_Algos kex_algo, sig_algo; std::string cipher, mac; u32bit cipher_key_length; }; diff --git a/src/utils/bswap.h b/src/utils/bswap.h index fcb0fa7ea..49962f076 100644 --- a/src/utils/bswap.h +++ b/src/utils/bswap.h @@ -83,14 +83,14 @@ inline void bswap_4(T x[4]) template<> inline void bswap_4(u32bit x[4]) { - __m128i T = _mm_loadu_si128((const __m128i*)x); + __m128i T = _mm_loadu_si128(reinterpret_cast<const __m128i*>(x)); T = _mm_shufflehi_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); T = _mm_shufflelo_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); T = _mm_or_si128(_mm_srli_epi16(T, 8), _mm_slli_epi16(T, 8)); - _mm_storeu_si128((__m128i*)x, T); + _mm_storeu_si128(reinterpret_cast<__m128i*>(x), T); } #endif |