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 /src | |
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.
Diffstat (limited to 'src')
-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 |