aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2010-03-30 15:24:36 +0000
committerlloyd <[email protected]>2010-03-30 15:24:36 +0000
commit40d0f36446d5d80dcc1e99c8707e2b84e82c5da0 (patch)
treef660c5cca710b7098d601c0d77d2a12fd3df2181
parent9378baca4d4b2eb1f8d36177ada4dfc4015d46e8 (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.cpp11
-rw-r--r--src/ssl/cert_ver.cpp11
-rw-r--r--src/ssl/hello.cpp121
-rw-r--r--src/ssl/info.txt40
-rw-r--r--src/ssl/tls_messages.h3
-rw-r--r--src/ssl/tls_reader.h124
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