diff options
-rw-r--r-- | doc/examples/tls_client.cpp | 4 | ||||
-rw-r--r-- | doc/examples/tls_server.cpp | 9 | ||||
-rw-r--r-- | src/tls/hello.cpp | 91 | ||||
-rw-r--r-- | src/tls/info.txt | 2 | ||||
-rw-r--r-- | src/tls/tls_client.cpp | 20 | ||||
-rw-r--r-- | src/tls/tls_client.h | 4 | ||||
-rw-r--r-- | src/tls/tls_extensions.cpp | 150 | ||||
-rw-r--r-- | src/tls/tls_extensions.h | 109 | ||||
-rw-r--r-- | src/tls/tls_magic.h | 11 | ||||
-rw-r--r-- | src/tls/tls_messages.h | 6 | ||||
-rw-r--r-- | src/tls/tls_reader.h | 16 | ||||
-rw-r--r-- | src/tls/tls_session_key.h | 2 | ||||
-rw-r--r-- | src/tls/tls_suites.cpp | 38 |
13 files changed, 387 insertions, 75 deletions
diff --git a/doc/examples/tls_client.cpp b/doc/examples/tls_client.cpp index b44dbf7d5..1d62bbc20 100644 --- a/doc/examples/tls_client.cpp +++ b/doc/examples/tls_client.cpp @@ -35,7 +35,9 @@ class HTTPS_Client std::tr1::bind(&HTTPS_Client::proc_data, std::tr1::ref(*this), _1, _2, _3), sessions, policy, - rng) + rng, + host, + host + "_username") { SecureVector<byte> socket_buf(1024); size_t desired = 0; diff --git a/doc/examples/tls_server.cpp b/doc/examples/tls_server.cpp index e63565fc0..f43af1dcf 100644 --- a/doc/examples/tls_server.cpp +++ b/doc/examples/tls_server.cpp @@ -77,6 +77,7 @@ class Blocking_TLS_Server if(socket_got == 0) // eof? { close(); + printf("got eof on socket\n"); exit = true; } @@ -88,8 +89,8 @@ class Blocking_TLS_Server { if(buf_len == 0 && alert_code != NULL_ALERT) { - printf("Alert: %d, quitting\n", alert_code); - exit = true; + printf("Alert: %d\n", alert_code); + //exit = true; } printf("Got %d bytes: ", (int)buf_len); @@ -141,8 +142,8 @@ int main(int argc, char* argv[]) AutoSeeded_RNG rng; - //RSA_PrivateKey key(rng, 1024); - DSA_PrivateKey key(rng, DL_Group("dsa/jce/1024")); + RSA_PrivateKey key(rng, 1024); + //DSA_PrivateKey key(rng, DL_Group("dsa/jce/1024")); X509_Cert_Options options( "localhost/US/Syn Ack Labs/Mathematical Munitions Dept"); 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 | |