aboutsummaryrefslogtreecommitdiffstats
path: root/src/tls
diff options
context:
space:
mode:
Diffstat (limited to 'src/tls')
-rw-r--r--src/tls/hello.cpp91
-rw-r--r--src/tls/info.txt2
-rw-r--r--src/tls/tls_client.cpp20
-rw-r--r--src/tls/tls_client.h4
-rw-r--r--src/tls/tls_extensions.cpp150
-rw-r--r--src/tls/tls_extensions.h109
-rw-r--r--src/tls/tls_magic.h11
-rw-r--r--src/tls/tls_messages.h6
-rw-r--r--src/tls/tls_reader.h16
-rw-r--r--src/tls/tls_session_key.h2
-rw-r--r--src/tls/tls_suites.cpp38
11 files changed, 379 insertions, 70 deletions
diff --git a/src/tls/hello.cpp b/src/tls/hello.cpp
index 0343b649e..59e7c68d4 100644
--- a/src/tls/hello.cpp
+++ b/src/tls/hello.cpp
@@ -1,6 +1,6 @@
/*
* TLS Hello Messages
-* (C) 2004-2010 Jack Lloyd
+* (C) 2004-2011 Jack Lloyd
*
* Released under the terms of the Botan license
*/
@@ -8,8 +8,11 @@
#include <botan/internal/tls_messages.h>
#include <botan/internal/tls_reader.h>
#include <botan/internal/tls_session_key.h>
+#include <botan/internal/tls_extensions.h>
#include <botan/tls_record.h>
+#include <stdio.h>
+
namespace Botan {
/*
@@ -66,14 +69,16 @@ void Hello_Request::deserialize(const MemoryRegion<byte>& buf)
Client_Hello::Client_Hello(Record_Writer& writer,
TLS_Handshake_Hash& hash,
const TLS_Policy& policy,
- RandomNumberGenerator& rng)
+ RandomNumberGenerator& rng,
+ const std::string& hostname,
+ const std::string& srp_identifier) :
+ c_version(policy.pref_version()),
+ c_random(rng.random_vec(32)),
+ suites(policy.ciphersuites()),
+ comp_methods(policy.compression()),
+ requested_hostname(hostname),
+ requested_srp_id(srp_identifier)
{
- c_random = rng.random_vec(32);
-
- suites = policy.ciphersuites();
- comp_methods = policy.compression();
- c_version = policy.pref_version();
-
send(writer, hash);
}
@@ -92,6 +97,13 @@ MemoryVector<byte> Client_Hello::serialize() const
append_tls_length_value(buf, suites, 2);
append_tls_length_value(buf, comp_methods, 1);
+ printf("Requesting hostname '%s'\n", requested_hostname.c_str());
+
+ TLS_Extensions extensions;
+ extensions.push_back(new Server_Name_Indicator(requested_hostname));
+ extensions.push_back(new SRP_Identifier(requested_srp_id));
+ buf += extensions.serialize();
+
return buf;
}
@@ -152,59 +164,20 @@ void Client_Hello::deserialize(const MemoryRegion<byte>& buf)
comp_methods = reader.get_range_vector<byte>(1, 1, 255);
- if(reader.has_remaining())
+ TLS_Extensions extensions(reader);
+
+ for(size_t i = 0; i != extensions.count(); ++i)
{
- const u16bit all_extn_size = reader.get_u16bit();
-
- if(reader.remaining_bytes() != all_extn_size)
- throw Decoding_Error("Client_Hello: Bad extension size");
-
- while(reader.has_remaining())
- {
- const u16bit extension_code = reader.get_u16bit();
- const u16bit extension_size = reader.get_u16bit();
-
- if(extension_code == TLSEXT_SERVER_NAME_INDICATION)
- {
- u16bit name_bytes = reader.get_u16bit();
-
- while(name_bytes)
- {
- byte name_type = reader.get_byte();
- name_bytes--;
-
- if(name_type == 0) // DNS
- {
- std::vector<byte> name =
- reader.get_range_vector<byte>(2, 1, 65535);
-
- requested_hostname.assign(
- reinterpret_cast<const char*>(&name[0]),
- name.size());
-
- name_bytes -= (2 + name.size());
- }
- else
- {
- reader.discard_next(name_bytes);
- name_bytes = 0;
- }
- }
- }
- else if(extension_code == TLSEXT_SRP_IDENTIFIER)
- {
- std::vector<byte> name = reader.get_range_vector<byte>(1, 1, 255);
-
- requested_srp_id.assign(
- reinterpret_cast<char*>(&name[0]),
- name.size());
- }
- else
- {
- reader.discard_next(extension_size);
- }
- }
+ TLS_Extension* extn = extensions.at(i);
+
+ if(Server_Name_Indicator* sni = dynamic_cast<Server_Name_Indicator*>(extn))
+ requested_hostname = sni->host_name();
+ else if(SRP_Identifier* srp = dynamic_cast<SRP_Identifier*>(extn))
+ requested_srp_id = srp->identifier();
}
+
+ printf("hostname %s srp id %s\n", requested_hostname.c_str(),
+ requested_srp_id.c_str());
}
/*
diff --git a/src/tls/info.txt b/src/tls/info.txt
index 43bf244c6..857a5bc2a 100644
--- a/src/tls/info.txt
+++ b/src/tls/info.txt
@@ -22,6 +22,7 @@ tls_suites.h
<header:internal>
tls_alerts.h
tls_handshake_hash.h
+tls_extensions.h
tls_messages.h
tls_reader.h
tls_session_key.h
@@ -34,6 +35,7 @@ cert_req.cpp
cert_ver.cpp
finished.cpp
tls_handshake_hash.cpp
+tls_extensions.cpp
hello.cpp
rec_read.cpp
rec_wri.cpp
diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp
index 19ae44ace..3fe93b846 100644
--- a/src/tls/tls_client.cpp
+++ b/src/tls/tls_client.cpp
@@ -21,7 +21,9 @@ TLS_Client::TLS_Client(std::tr1::function<void (const byte[], size_t)> output_fn
std::tr1::function<void (const byte[], size_t, u16bit)> proc_fn,
TLS_Session_Manager& session_manager,
const TLS_Policy& policy,
- RandomNumberGenerator& rng) :
+ RandomNumberGenerator& rng,
+ const std::string& hostname,
+ const std::string& srp_username) :
TLS_Channel(output_fn, proc_fn),
policy(policy),
rng(rng),
@@ -31,7 +33,12 @@ TLS_Client::TLS_Client(std::tr1::function<void (const byte[], size_t)> output_fn
state = new Handshake_State;
state->set_expected_next(SERVER_HELLO);
- state->client_hello = new Client_Hello(writer, state->hash, policy, rng);
+ state->client_hello = new Client_Hello(writer,
+ state->hash,
+ policy,
+ rng,
+ hostname,
+ srp_username);
}
void TLS_Client::add_client_cert(const X509_Certificate& cert,
@@ -74,7 +81,7 @@ void TLS_Client::process_handshake_msg(Handshake_Type type,
if(type == HELLO_REQUEST)
{
Hello_Request hello_request(contents);
- state->client_hello = new Client_Hello( writer, state->hash, policy, rng);
+ state->client_hello = new Client_Hello(writer, state->hash, policy, rng);
}
else if(type == SERVER_HELLO)
{
@@ -205,10 +212,10 @@ void TLS_Client::process_handshake_msg(Handshake_Type type,
state->server_hello_done = new Server_Hello_Done(contents);
+ std::vector<X509_Certificate> send_certs;
+
if(state->received_handshake_msg(CERTIFICATE_REQUEST))
{
- std::vector<X509_Certificate> send_certs;
-
std::vector<Certificate_Type> types =
state->cert_req->acceptable_types();
@@ -223,7 +230,8 @@ void TLS_Client::process_handshake_msg(Handshake_Type type,
state->kex_pub, state->version,
state->client_hello->version());
- if(state->received_handshake_msg(CERTIFICATE_REQUEST))
+ if(state->received_handshake_msg(CERTIFICATE_REQUEST) &&
+ !send_certs.empty())
{
Private_Key* key_matching_cert = 0; // FIXME
state->client_verify = new Certificate_Verify(writer, state->hash,
diff --git a/src/tls/tls_client.h b/src/tls/tls_client.h
index 295eb0364..e80051460 100644
--- a/src/tls/tls_client.h
+++ b/src/tls/tls_client.h
@@ -27,7 +27,9 @@ class BOTAN_DLL TLS_Client : public TLS_Channel
std::tr1::function<void (const byte[], size_t, u16bit)> proc_fn,
TLS_Session_Manager& session_manager,
const TLS_Policy& policy,
- RandomNumberGenerator& rng);
+ RandomNumberGenerator& rng,
+ const std::string& servername = "",
+ const std::string& srp_username = "");
void add_client_cert(const X509_Certificate& cert,
Private_Key* cert_key);
diff --git a/src/tls/tls_extensions.cpp b/src/tls/tls_extensions.cpp
new file mode 100644
index 000000000..b9881ea3a
--- /dev/null
+++ b/src/tls/tls_extensions.cpp
@@ -0,0 +1,150 @@
+/*
+* TLS Extensions
+* (C) 2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_extensions.h>
+#include <botan/internal/tls_reader.h>
+
+#include <stdio.h>
+
+namespace Botan {
+
+TLS_Extensions::TLS_Extensions(class TLS_Data_Reader& reader)
+ {
+ if(reader.has_remaining())
+ {
+ const u16bit all_extn_size = reader.get_u16bit();
+
+ if(reader.remaining_bytes() != all_extn_size)
+ throw Decoding_Error("Bad extension size");
+
+ while(reader.has_remaining())
+ {
+ const u16bit extension_code = reader.get_u16bit();
+ const u16bit extension_size = reader.get_u16bit();
+
+ if(extension_code == TLSEXT_SERVER_NAME_INDICATION)
+ extensions.push_back(new Server_Name_Indicator(reader));
+ else if(extension_code == TLSEXT_SRP_IDENTIFIER)
+ extensions.push_back(new SRP_Identifier(reader));
+ else // unknown/unhandled extension
+ {
+ printf("Unknown extension code %d\n", extension_code);
+ reader.discard_next(extension_size);
+ }
+ }
+ }
+ }
+
+MemoryVector<byte> TLS_Extensions::serialize() const
+ {
+ MemoryVector<byte> buf(2); // allocate length
+
+ for(size_t i = 0; i != extensions.size(); ++i)
+ {
+ if(extensions[i]->empty())
+ continue;
+
+ const u16bit extn_code = extensions[i]->type();
+
+ MemoryVector<byte> extn_val = extensions[i]->serialize();
+
+ printf("serializing extn %d of %d bytes\n", extn_code, extn_val.size());
+
+ buf.push_back(get_byte(0, extn_code));
+ buf.push_back(get_byte(1, extn_code));
+
+ buf.push_back(get_byte<u16bit>(0, extn_val.size()));
+ buf.push_back(get_byte<u16bit>(1, extn_val.size()));
+
+ buf += extn_val;
+ }
+
+ const u16bit extn_size = buf.size() - 2;
+
+ buf[0] = get_byte(0, extn_size);
+ buf[1] = get_byte(1, extn_size);
+
+ printf("%d bytes of extensions\n", buf.size());
+
+ // avoid sending an empty extensions block
+ if(buf.size() == 2)
+ return MemoryVector<byte>();
+
+ return buf;
+ }
+
+TLS_Extensions::~TLS_Extensions()
+ {
+ for(size_t i = 0; i != extensions.size(); ++i)
+ delete extensions[i];
+ extensions.clear();
+ }
+
+Server_Name_Indicator::Server_Name_Indicator(TLS_Data_Reader& reader)
+ {
+ u16bit name_bytes = reader.get_u16bit();
+
+ while(name_bytes)
+ {
+ byte name_type = reader.get_byte();
+ name_bytes--;
+
+ if(name_type == 0) // DNS
+ {
+ sni_host_name = reader.get_string(2, 1, 65535);
+ name_bytes -= (2 + sni_host_name.size());
+ }
+ else // some other unknown name type
+ {
+ reader.discard_next(name_bytes);
+ name_bytes = 0;
+ }
+ }
+ }
+
+MemoryVector<byte> Server_Name_Indicator::serialize() const
+ {
+ MemoryVector<byte> buf;
+
+ size_t name_len = sni_host_name.size();
+
+ buf.push_back(get_byte<u16bit>(0, name_len+3));
+ buf.push_back(get_byte<u16bit>(1, name_len+3));
+ buf.push_back(0); // DNS
+
+ buf.push_back(get_byte<u16bit>(0, name_len));
+ buf.push_back(get_byte<u16bit>(1, name_len));
+
+
+ buf += std::make_pair(
+ reinterpret_cast<const byte*>(sni_host_name.data()),
+ sni_host_name.size());
+
+ printf("serializing %d bytes %s\n", buf.size(),
+ sni_host_name.c_str());
+ return buf;
+ }
+
+SRP_Identifier::SRP_Identifier(TLS_Data_Reader& reader)
+ {
+ srp_identifier = reader.get_string(1, 1, 255);
+ }
+
+MemoryVector<byte> SRP_Identifier::serialize() const
+ {
+ MemoryVector<byte> buf;
+
+ const byte* srp_bytes =
+ reinterpret_cast<const byte*>(srp_identifier.data());
+
+ append_tls_length_value(buf, srp_bytes, srp_identifier.size(), 1);
+
+ return buf;
+ }
+
+
+}
diff --git a/src/tls/tls_extensions.h b/src/tls/tls_extensions.h
new file mode 100644
index 000000000..01a4253b3
--- /dev/null
+++ b/src/tls/tls_extensions.h
@@ -0,0 +1,109 @@
+/*
+* TLS Extensions
+* (C) 2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_EXTENSIONS_H__
+#define BOTAN_TLS_EXTENSIONS_H__
+
+#include <botan/secmem.h>
+#include <botan/tls_magic.h>
+#include <vector>
+#include <string>
+
+namespace Botan {
+
+class TLS_Data_Reader;
+
+/**
+* Base class representing a TLS extension of some kind
+*/
+class TLS_Extension
+ {
+ public:
+ virtual TLS_Handshake_Extension_Type type() const = 0;
+ virtual MemoryVector<byte> serialize() const = 0;
+
+ virtual bool empty() const = 0;
+
+ virtual ~TLS_Extension() {}
+ };
+
+/**
+* Server Name Indicator extension (RFC 3546)
+*/
+class Server_Name_Indicator : public TLS_Extension
+ {
+ public:
+ TLS_Handshake_Extension_Type type() const
+ { return TLSEXT_SERVER_NAME_INDICATION; }
+
+ Server_Name_Indicator(const std::string& host_name) :
+ sni_host_name(host_name) {}
+
+ Server_Name_Indicator(TLS_Data_Reader& reader);
+
+ std::string host_name() const { return sni_host_name; }
+
+ MemoryVector<byte> serialize() const;
+
+ bool empty() const { return sni_host_name == ""; }
+ private:
+ std::string sni_host_name;
+ };
+
+/**
+* SRP identifier extension (RFC 5054)
+*/
+class SRP_Identifier : public TLS_Extension
+ {
+ public:
+ TLS_Handshake_Extension_Type type() const
+ { return TLSEXT_SRP_IDENTIFIER; }
+
+ SRP_Identifier(const std::string& identifier) :
+ srp_identifier(identifier) {}
+
+ SRP_Identifier(TLS_Data_Reader& reader);
+
+ std::string identifier() const { return srp_identifier; }
+
+ MemoryVector<byte> serialize() const;
+
+ bool empty() const { return srp_identifier == ""; }
+ private:
+ std::string srp_identifier;
+ };
+
+/**
+* Represents a block of extensions in a hello message
+*/
+class TLS_Extensions
+ {
+ public:
+ size_t count() const { return extensions.size(); }
+
+ TLS_Extension* at(size_t idx) { return extensions.at(idx); }
+
+ void push_back(TLS_Extension* extn)
+ { extensions.push_back(extn); }
+
+ MemoryVector<byte> serialize() const;
+
+ TLS_Extensions() {}
+
+ TLS_Extensions(TLS_Data_Reader& reader); // deserialize
+
+ ~TLS_Extensions();
+ private:
+ TLS_Extensions(const TLS_Extensions&) {}
+ TLS_Extensions& operator=(const TLS_Extensions&) { return (*this); }
+
+ std::vector<TLS_Extension*> extensions;
+ };
+
+}
+
+#endif
diff --git a/src/tls/tls_magic.h b/src/tls/tls_magic.h
index 9583d28fe..bddbab3ce 100644
--- a/src/tls/tls_magic.h
+++ b/src/tls/tls_magic.h
@@ -126,6 +126,16 @@ enum Ciphersuite_Code {
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B,
TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A,
+ TLS_SRP_SHA_WITH_3DES_EDE_SHA = 0xC01A,
+ TLS_SRP_SHA_RSA_WITH_3DES_EDE_SHA = 0xC01B,
+ TLS_SRP_SHA_DSS_WITH_3DES_EDE_SHA = 0xC01C,
+ TLS_SRP_SHA_WITH_AES_128_SHA = 0xC01D,
+ TLS_SRP_SHA_RSA_WITH_AES_128_SHA = 0xC01E,
+ TLS_SRP_SHA_DSS_WITH_AES_128_SHA = 0xC01F,
+ TLS_SRP_SHA_WITH_AES_256_SHA = 0xC020,
+ TLS_SRP_SHA_RSA_WITH_AES_256_SHA = 0xC021,
+ TLS_SRP_SHA_DSS_WITH_AES_256_SHA = 0xC022,
+
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,
@@ -157,6 +167,7 @@ enum TLS_Ciphersuite_Algos {
TLS_ALGO_KEYEXCH_RSA = 0x00020000,
TLS_ALGO_KEYEXCH_DH = 0x00030000,
TLS_ALGO_KEYEXCH_ECDH = 0x00040000,
+ TLS_ALGO_KEYEXCH_SRP = 0x00050000,
TLS_ALGO_MAC_MASK = 0x0000FF00,
TLS_ALGO_MAC_MD5 = 0x00000100,
diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h
index 68d564fff..eeaf77a39 100644
--- a/src/tls/tls_messages.h
+++ b/src/tls/tls_messages.h
@@ -1,6 +1,6 @@
/*
* TLS Messages
-* (C) 2004-2010 Jack Lloyd
+* (C) 2004-2011 Jack Lloyd
*
* Released under the terms of the Botan license
*/
@@ -70,7 +70,9 @@ class Client_Hello : public HandshakeMessage
Client_Hello(Record_Writer& writer,
TLS_Handshake_Hash& hash,
const TLS_Policy& policy,
- RandomNumberGenerator& rng);
+ RandomNumberGenerator& rng,
+ const std::string& hostname = "",
+ const std::string& srp_identifier = "");
Client_Hello(const MemoryRegion<byte>& buf,
Handshake_Type type)
diff --git a/src/tls/tls_reader.h b/src/tls/tls_reader.h
index a7ef512e9..9f40bb457 100644
--- a/src/tls/tls_reader.h
+++ b/src/tls/tls_reader.h
@@ -1,6 +1,6 @@
/*
* TLS Data Reader
-* (C) 2010 Jack Lloyd
+* (C) 2010-2011 Jack Lloyd
*
* Released under the terms of the Botan license
*/
@@ -8,8 +8,12 @@
#ifndef BOTAN_TLS_READER_H__
#define BOTAN_TLS_READER_H__
+#include <botan/exceptn.h>
#include <botan/secmem.h>
#include <botan/loadstor.h>
+#include <string>
+#include <vector>
+#include <stdexcept>
namespace Botan {
@@ -97,6 +101,16 @@ class TLS_Data_Reader
return get_elem<T, std::vector<T> >(num_elems);
}
+ std::string get_string(size_t len_bytes,
+ size_t min_bytes,
+ size_t max_bytes)
+ {
+ std::vector<byte> v =
+ get_range_vector<byte>(len_bytes, min_bytes, max_bytes);
+
+ return std::string(reinterpret_cast<char*>(&v[0]), v.size());
+ }
+
template<typename T>
SecureVector<T> get_fixed(size_t size)
{
diff --git a/src/tls/tls_session_key.h b/src/tls/tls_session_key.h
index c967eaf22..76cb7e3e1 100644
--- a/src/tls/tls_session_key.h
+++ b/src/tls/tls_session_key.h
@@ -17,7 +17,7 @@ namespace Botan {
/**
* TLS Session Keys
*/
-class BOTAN_DLL SessionKeys
+class SessionKeys
{
public:
SymmetricKey client_cipher_key() const { return c_cipher; }
diff --git a/src/tls/tls_suites.cpp b/src/tls/tls_suites.cpp
index a8a56c626..8dbd74e4e 100644
--- a/src/tls/tls_suites.cpp
+++ b/src/tls/tls_suites.cpp
@@ -141,6 +141,44 @@ TLS_Ciphersuite_Algos CipherSuite::lookup_ciphersuite(u16bit suite)
TLS_ALGO_MAC_SHA256 |
TLS_ALGO_CIPHER_AES256_CBC);
+ // SRP ciphersuites
+ if(suite == TLS_SRP_SHA_RSA_WITH_3DES_EDE_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_SRP |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_3DES_CBC);
+
+ if(suite == TLS_SRP_SHA_DSS_WITH_3DES_EDE_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
+ TLS_ALGO_KEYEXCH_SRP |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_3DES_CBC);
+
+ if(suite == TLS_SRP_SHA_RSA_WITH_AES_128_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_SRP |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES128_CBC);
+
+ if(suite == TLS_SRP_SHA_DSS_WITH_AES_128_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
+ TLS_ALGO_KEYEXCH_SRP |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES128_CBC);
+
+ if(suite == TLS_SRP_SHA_RSA_WITH_AES_256_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_SRP |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES256_CBC);
+
+ if(suite == TLS_SRP_SHA_DSS_WITH_AES_256_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
+ TLS_ALGO_KEYEXCH_SRP |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES256_CBC);
+
+ // ECC ciphersuites
if(suite == TLS_ECDHE_ECDSA_WITH_RC4_128_SHA)
return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
TLS_ALGO_KEYEXCH_ECDH |