diff options
author | lloyd <[email protected]> | 2010-03-30 15:24:36 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2010-03-30 15:24:36 +0000 |
commit | 40d0f36446d5d80dcc1e99c8707e2b84e82c5da0 (patch) | |
tree | f660c5cca710b7098d601c0d77d2a12fd3df2181 | |
parent | 9378baca4d4b2eb1f8d36177ada4dfc4015d46e8 (diff) |
Add a class that knows how to decode a (very small subset of) TLS data
formatting. Particularly useful in the ClientHello, but generally helps
centralize the offset handling, which was particularly unreadable in
the hello messages.
-rw-r--r-- | src/ssl/c_kex.cpp | 11 | ||||
-rw-r--r-- | src/ssl/cert_ver.cpp | 11 | ||||
-rw-r--r-- | src/ssl/hello.cpp | 121 | ||||
-rw-r--r-- | src/ssl/info.txt | 40 | ||||
-rw-r--r-- | src/ssl/tls_messages.h | 3 | ||||
-rw-r--r-- | src/ssl/tls_reader.h | 124 |
6 files changed, 249 insertions, 61 deletions
diff --git a/src/ssl/c_kex.cpp b/src/ssl/c_kex.cpp index 9e59beefc..e09e18ce1 100644 --- a/src/ssl/c_kex.cpp +++ b/src/ssl/c_kex.cpp @@ -6,6 +6,7 @@ */ #include <botan/tls_messages.h> +#include <botan/internal/tls_reader.h> #include <botan/pubkey.h> #include <botan/dh.h> #include <botan/rsa.h> @@ -99,14 +100,8 @@ 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); + TLS_Data_Reader reader(buf); + key_material = reader.get_range<byte>(2, 0, 65535); } else key_material = buf; diff --git a/src/ssl/cert_ver.cpp b/src/ssl/cert_ver.cpp index 7e17dbfab..74f737d7b 100644 --- a/src/ssl/cert_ver.cpp +++ b/src/ssl/cert_ver.cpp @@ -6,6 +6,7 @@ */ #include <botan/tls_messages.h> +#include <botan/internal/tls_reader.h> #include <botan/pubkey.h> #include <botan/rsa.h> #include <botan/dsa.h> @@ -62,14 +63,8 @@ SecureVector<byte> Certificate_Verify::serialize() const */ void Certificate_Verify::deserialize(const MemoryRegion<byte>& buf) { - if(buf.size() < 2) - throw Decoding_Error("Certificate_Verify: Corrupted packet"); - - u32bit sig_len = make_u16bit(buf[0], buf[1]); - if(buf.size() != 2 + sig_len) - throw Decoding_Error("Certificate_Verify: Corrupted packet"); - - signature.set(buf + 2, sig_len); + TLS_Data_Reader reader(buf); + signature = reader.get_range<byte>(2, 0, 65535); } /** diff --git a/src/ssl/hello.cpp b/src/ssl/hello.cpp index 413215eb2..748df7420 100644 --- a/src/ssl/hello.cpp +++ b/src/ssl/hello.cpp @@ -1,12 +1,12 @@ /** * TLS Hello Messages -* (C) 2004-2006 Jack Lloyd +* (C) 2004-2010 Jack Lloyd * * Released under the terms of the Botan license */ #include <botan/tls_messages.h> -#include <botan/loadstor.h> +#include <botan/internal/tls_reader.h> namespace Botan { @@ -93,15 +93,15 @@ SecureVector<byte> Client_Hello::serialize() const buf.append(get_byte(0, suites_size)); buf.append(get_byte(1, suites_size)); - for(u32bit j = 0; j != suites.size(); j++) + for(u32bit i = 0; i != suites.size(); i++) { - buf.append(get_byte(0, suites[j])); - buf.append(get_byte(1, suites[j])); + buf.append(get_byte(0, suites[i])); + buf.append(get_byte(1, suites[i])); } buf.append(static_cast<byte>(comp_algos.size())); - for(u32bit j = 0; j != comp_algos.size(); j++) - buf.append(comp_algos[j]); + for(u32bit i = 0; i != comp_algos.size(); i++) + buf.append(comp_algos[i]); return buf; } @@ -117,35 +117,64 @@ void Client_Hello::deserialize(const MemoryRegion<byte>& buf) if(buf.size() < 41) throw Decoding_Error("Client_Hello: Packet corrupted"); - c_version = static_cast<Version_Code>(make_u16bit(buf[0], buf[1])); - c_random.set(buf + 2, 32); + TLS_Data_Reader reader(buf); - u32bit session_id_len = buf[34]; - if(session_id_len > 32 || session_id_len + 41 > buf.size()) - throw Decoding_Error("Client_Hello: Packet corrupted"); - sess_id.copy(buf + 35, session_id_len); + c_version = static_cast<Version_Code>(reader.get_u16bit()); + c_random = reader.get_fixed<byte>(32); - u32bit offset = 2+32+1+session_id_len; + sess_id = reader.get_range<byte>(1, 0, 32); - u16bit suites_size = make_u16bit(buf[offset], buf[offset+1]); - offset += 2; - if(suites_size % 2 == 1 || offset + suites_size + 2 > buf.size()) - throw Decoding_Error("Client_Hello: Packet corrupted"); + suites = reader.get_range_vector<u16bit>(2, 1, 32767); + + comp_algos = reader.get_range_vector<byte>(1, 1, 255); - for(u32bit j = 0; j != suites_size; j += 2) +#if 0 + if(offset != buf.size()) // extensions? { - u16bit suite = make_u16bit(buf[offset+j], buf[offset+j+1]); - suites.push_back(suite); - } - offset += suites_size; + if(buf.size() - offset < 2) + throw Decoding_Error("Client_Hello: Packet corrupted"); - byte comp_algo_size = buf[offset]; - offset += 1; - if(offset + comp_algo_size > buf.size()) - throw Decoding_Error("Client_Hello: Packet corrupted"); + const u16bit extens_size = make_u16bit(buf[offset], buf[offset+1]); + offset += 2; + + /* + RFC 3546 says if Extensions are present in the Client Hello, + then there is no other data following, and we MUST fail in this + case. + */ + if(buf.size() - offset != extens_size) + throw Decoding_Error("Client_Hello: Packet corrupted"); + + while(offset < buf.size()) + { + if(buf.size() - offset < 4) + throw Decoding_Error("Client_Hello: Packet corrupted"); + + u16bit extn_code = make_u16bit(buf[offset ], buf[offset+1]); + u16bit extn_size = make_u16bit(buf[offset+2], buf[offset+3]); + + offset += 4; + + if(buf.size() - offset < extn_size) + throw Decoding_Error("Client_Hello: Packet corrupted"); - for(u32bit j = 0; j != comp_algo_size; j++) - comp_algos.push_back(buf[offset+j]); + if(extn_code == 0) // server name indication + { + if(extn_size < 2) + throw Decoding_Error("Client_Hello: Packet corrupted"); + + u16bit name_count = make_u16bit(buf[offset], buf[offset+1]); + + for(u32bit i = 0; i != name_count; ++i) + { + + } + } + else + offset += extn_size; // skip it + } + } +#endif } /** @@ -153,8 +182,8 @@ void Client_Hello::deserialize(const MemoryRegion<byte>& buf) */ bool Client_Hello::offered_suite(u16bit ciphersuite) const { - for(u32bit j = 0; j != suites.size(); j++) - if(suites[j] == ciphersuite) + for(u32bit i = 0; i != suites.size(); i++) + if(suites[i] == ciphersuite) return true; return false; } @@ -169,11 +198,15 @@ Server_Hello::Server_Hello(RandomNumberGenerator& rng, HandshakeHash& hash) { bool have_rsa = false, have_dsa = false; - for(u32bit j = 0; j != certs.size(); j++) + + for(u32bit i = 0; i != certs.size(); i++) { - Public_Key* key = certs[j].subject_public_key(); - if(key->algo_name() == "RSA") have_rsa = true; - if(key->algo_name() == "DSA") have_dsa = true; + Public_Key* key = certs[i].subject_public_key(); + if(key->algo_name() == "RSA") + have_rsa = true; + + if(key->algo_name() == "DSA") + have_dsa = true; } suite = policy->choose_suite(c_hello.ciphersuites(), have_rsa, have_dsa); @@ -215,7 +248,9 @@ void Server_Hello::deserialize(const MemoryRegion<byte>& buf) if(buf.size() < 38) throw Decoding_Error("Server_Hello: Packet corrupted"); - s_version = static_cast<Version_Code>(make_u16bit(buf[0], buf[1])); + TLS_Data_Reader reader(buf); + + s_version = static_cast<Version_Code>(reader.get_u16bit()); if(s_version != SSL_V3 && s_version != TLS_V10 && s_version != TLS_V11) { @@ -223,18 +258,14 @@ void Server_Hello::deserialize(const MemoryRegion<byte>& buf) "Server_Hello: Unsupported server version"); } - s_random.set(buf + 2, 32); + s_random = reader.get_fixed<byte>(32); - u32bit session_id_len = buf[2+32]; - if(session_id_len > 32 || session_id_len + 38 != buf.size()) - throw Decoding_Error("Server_Hello: Packet corrupted"); - sess_id.copy(buf + 2 + 32 + 1, session_id_len); + sess_id = reader.get_range<byte>(1, 0, 32); - suite = make_u16bit(buf[2+32+1+session_id_len], - buf[2+32+1+session_id_len+1]); - comp_algo = buf[2+32+1+session_id_len+2]; - } + suite = reader.get_u16bit(); + comp_algo = reader.get_byte(); + } /** * Create a new Server Hello Done message diff --git a/src/ssl/info.txt b/src/ssl/info.txt index 73e4207d8..e7e679a8c 100644 --- a/src/ssl/info.txt +++ b/src/ssl/info.txt @@ -1 +1,41 @@ define SSL_TLS + +<header:public> +handshake_hash.h +socket.h +tls_alerts.h +tls_client.h +tls_connection.h +tls_exceptn.h +tls_magic.h +tls_messages.h +tls_policy.h +tls_queue.h +tls_record.h +tls_server.h +tls_session_key.h +tls_state.h +tls_suites.h +</header:public> + +<header:internal> +tls_reader.h +</header:internal> + +<source> +c_kex.cpp +cert_req.cpp +cert_ver.cpp +finished.cpp +handshake_hash.cpp +handshake_state.cpp +hello.cpp +rec_read.cpp +rec_wri.cpp +s_kex.cpp +tls_client.cpp +tls_policy.cpp +tls_server.cpp +tls_session_key.cpp +tls_suites.cpp +</source> diff --git a/src/ssl/tls_messages.h b/src/ssl/tls_messages.h index 4b512a963..1f72c05f7 100644 --- a/src/ssl/tls_messages.h +++ b/src/ssl/tls_messages.h @@ -49,6 +49,8 @@ class BOTAN_DLL Client_Hello : public HandshakeMessage SecureVector<byte> random() const { return c_random; } + std::string hostname() const { return requested_hostname; } + bool offered_suite(u16bit) const; Client_Hello(RandomNumberGenerator& rng, @@ -63,6 +65,7 @@ class BOTAN_DLL Client_Hello : public HandshakeMessage SecureVector<byte> sess_id, c_random; std::vector<u16bit> suites; std::vector<byte> comp_algos; + std::string requested_hostname; }; /** diff --git a/src/ssl/tls_reader.h b/src/ssl/tls_reader.h new file mode 100644 index 000000000..d2f21a90f --- /dev/null +++ b/src/ssl/tls_reader.h @@ -0,0 +1,124 @@ +/* +* TLS Data Reader +* (C) 2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_READER_H__ +#define BOTAN_TLS_READER_H__ + +#include <botan/secmem.h> +#include <botan/loadstor.h> + +namespace Botan { + +class TLS_Data_Reader + { + public: + TLS_Data_Reader(const MemoryRegion<byte>& buf_in) : + buf(buf_in), offset(0) {} + + u16bit get_u16bit() + { + assert_at_least(2); + u16bit result = make_u16bit(buf[offset], buf[offset+1]); + offset += 2; + return result; + } + + byte get_byte() + { + assert_at_least(1); + byte result = buf[offset]; + offset += 1; + return result; + } + + template<typename T, typename Container> + Container get_elem(u32bit num_elems) + { + assert_at_least(num_elems * sizeof(T)); + + Container result(num_elems); + + for(u32bit i = 0; i != num_elems; ++i) + result[i] = load_be<T>(&buf[offset], i); + + offset += num_elems * sizeof(T); + + return result; + } + + template<typename T> + SecureVector<T> get_range(u32bit len_bytes, + u32bit min_elems, + u32bit max_elems) + { + const u32bit num_elems = + get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); + + return get_elem<T, SecureVector<T> >(num_elems); + } + + template<typename T> + std::vector<T> get_range_vector(u32bit len_bytes, + u32bit min_elems, + u32bit max_elems) + { + const u32bit num_elems = + get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); + + return get_elem<T, std::vector<T> >(num_elems); + } + + template<typename T> + SecureVector<T> get_fixed(u32bit size) + { + return get_elem<T, SecureVector<T> >(size); + } + + private: + u32bit get_length_field(u32bit len_bytes) + { + assert_at_least(len_bytes); + + if(len_bytes == 1) + return get_byte(); + else if(len_bytes == 2) + return get_u16bit(); + + throw Decoding_Error("TLS_Data_Reader: Bad length size"); + } + + u32bit get_num_elems(u32bit len_bytes, + u32bit T_size, + u32bit min_elems, + u32bit max_elems) + { + const u32bit byte_length = get_length_field(len_bytes); + + if(byte_length % T_size != 0) + throw Decoding_Error("TLS_Data_Reader: Size isn't multiple of T"); + + const u32bit num_elems = byte_length / T_size; + + if(num_elems < min_elems || num_elems > max_elems) + throw Decoding_Error("TLS_Data_Reader: Range outside paramaters"); + + return num_elems; + } + + void assert_at_least(u32bit n) + { + if(buf.size() - offset < n) + throw Decoding_Error("TLS_Data_Reader: Corrupt packet"); + } + + const MemoryRegion<byte>& buf; + u32bit offset; + }; + +} + +#endif |