diff options
-rw-r--r-- | src/tls/c_hello.cpp (renamed from src/tls/hello.cpp) | 180 | ||||
-rw-r--r-- | src/tls/info.txt | 17 | ||||
-rw-r--r-- | src/tls/s_hello.cpp | 201 | ||||
-rw-r--r-- | src/tls/tls_extensions.cpp | 4 | ||||
-rw-r--r-- | src/tls/tls_messages.h | 22 | ||||
-rw-r--r-- | src/tls/tls_server.cpp | 49 | ||||
-rw-r--r-- | src/tls/tls_server.h | 19 | ||||
-rw-r--r-- | src/tls/tls_session_manager.cpp | 2 |
8 files changed, 271 insertions, 223 deletions
diff --git a/src/tls/hello.cpp b/src/tls/c_hello.cpp index 8c13cb8f6..3164f30ee 100644 --- a/src/tls/hello.cpp +++ b/src/tls/c_hello.cpp @@ -1,5 +1,5 @@ ;/* -* TLS Hello Messages +* TLS Hello Request and Client Hello Messages * (C) 2004-2011 Jack Lloyd * * Released under the terms of the Botan license @@ -287,182 +287,4 @@ bool Client_Hello::offered_suite(u16bit ciphersuite) const return false; } -/* -* Create a new Server Hello message -*/ -Server_Hello::Server_Hello(Record_Writer& writer, - TLS_Handshake_Hash& hash, - const TLS_Policy& policy, - RandomNumberGenerator& rng, - bool client_has_secure_renegotiation, - const MemoryRegion<byte>& reneg_info, - const std::vector<X509_Certificate>& certs, - const Client_Hello& c_hello, - Version_Code ver) : - s_version(ver), - m_session_id(rng.random_vec(32)), - s_random(rng.random_vec(32)), - m_fragment_size(c_hello.fragment_size()), - m_secure_renegotiation(client_has_secure_renegotiation), - m_renegotiation_info(reneg_info), - m_next_protocol(false) - { - bool have_rsa = false, have_dsa = false; - - for(size_t i = 0; i != certs.size(); ++i) - { - 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, false); - - if(suite == 0) - throw TLS_Exception(HANDSHAKE_FAILURE, - "Can't agree on a ciphersuite with client"); - - comp_method = policy.choose_compression(c_hello.compression_methods()); - - send(writer, hash); - } - -/* -* Create a new Server Hello message -*/ -Server_Hello::Server_Hello(Record_Writer& writer, - TLS_Handshake_Hash& hash, - RandomNumberGenerator& rng, - bool client_has_secure_renegotiation, - const MemoryRegion<byte>& reneg_info, - const MemoryRegion<byte>& session_id, - size_t fragment_size, - u16bit ciphersuite, - byte compression, - Version_Code ver) : - s_version(ver), - m_session_id(session_id), - s_random(rng.random_vec(32)), - suite(ciphersuite), - comp_method(compression), - m_fragment_size(fragment_size), - m_secure_renegotiation(client_has_secure_renegotiation), - m_renegotiation_info(reneg_info), - m_next_protocol(false) - { - send(writer, hash); - } - -/* -* Serialize a Server Hello message -*/ -MemoryVector<byte> Server_Hello::serialize() const - { - MemoryVector<byte> buf; - - buf.push_back(static_cast<byte>(s_version >> 8)); - buf.push_back(static_cast<byte>(s_version )); - buf += s_random; - - append_tls_length_value(buf, m_session_id, 1); - - buf.push_back(get_byte(0, suite)); - buf.push_back(get_byte(1, suite)); - - buf.push_back(comp_method); - - TLS_Extensions extensions; - - if(m_secure_renegotiation) - extensions.push_back(new Renegotation_Extension(m_renegotiation_info)); - - if(m_fragment_size != 0) - extensions.push_back(new Maximum_Fragment_Length(m_fragment_size)); - - if(m_next_protocol) - extensions.push_back(new Next_Protocol_Negotiation(m_next_protocols)); - - buf += extensions.serialize(); - - return buf; - } - -/* -* Deserialize a Server Hello message -*/ -void Server_Hello::deserialize(const MemoryRegion<byte>& buf) - { - m_secure_renegotiation = false; - m_next_protocol = false; - - if(buf.size() < 38) - throw Decoding_Error("Server_Hello: Packet corrupted"); - - 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) - { - throw TLS_Exception(PROTOCOL_VERSION, - "Server_Hello: Unsupported server version"); - } - - s_random = reader.get_fixed<byte>(32); - - m_session_id = reader.get_range<byte>(1, 0, 32); - - suite = reader.get_u16bit(); - - comp_method = reader.get_byte(); - - TLS_Extensions extensions(reader); - - for(size_t i = 0; i != extensions.count(); ++i) - { - TLS_Extension* extn = extensions.at(i); - - if(Renegotation_Extension* reneg = dynamic_cast<Renegotation_Extension*>(extn)) - { - // checked by TLS_Client / TLS_Server as they know the handshake state - m_secure_renegotiation = true; - m_renegotiation_info = reneg->renegotiation_info(); - } - else if(Next_Protocol_Negotiation* npn = dynamic_cast<Next_Protocol_Negotiation*>(extn)) - { - m_next_protocols = npn->protocols(); - m_next_protocol = true; - } - } - } - -/* -* Create a new Server Hello Done message -*/ -Server_Hello_Done::Server_Hello_Done(Record_Writer& writer, - TLS_Handshake_Hash& hash) - { - send(writer, hash); - } - -/* -* Serialize a Server Hello Done message -*/ -MemoryVector<byte> Server_Hello_Done::serialize() const - { - return MemoryVector<byte>(); - } - -/* -* Deserialize a Server Hello Done message -*/ -void Server_Hello_Done::deserialize(const MemoryRegion<byte>& buf) - { - if(buf.size()) - throw Decoding_Error("Server_Hello_Done: Must be empty, and is not"); - } - } diff --git a/src/tls/info.txt b/src/tls/info.txt index 6654c3b80..9473b0ae2 100644 --- a/src/tls/info.txt +++ b/src/tls/info.txt @@ -22,34 +22,35 @@ tls_suites.h <header:internal> tls_alerts.h -tls_handshake_hash.h tls_extensions.h +tls_handshake_hash.h +tls_handshake_state.h tls_messages.h tls_reader.h tls_session_key.h -tls_handshake_state.h </header:internal> <source> +c_hello.cpp c_kex.cpp cert_req.cpp cert_ver.cpp finished.cpp -tls_handshake_hash.cpp -tls_extensions.cpp -hello.cpp +next_protocol.cpp rec_read.cpp rec_wri.cpp +s_hello.cpp s_kex.cpp -next_protocol.cpp tls_channel.cpp tls_client.cpp +tls_extensions.cpp +tls_handshake_hash.cpp +tls_handshake_state.cpp tls_policy.cpp tls_server.cpp -tls_session_key.cpp tls_session.cpp +tls_session_key.cpp tls_session_manager.cpp -tls_handshake_state.cpp tls_suites.cpp </source> diff --git a/src/tls/s_hello.cpp b/src/tls/s_hello.cpp new file mode 100644 index 000000000..5ffb1e7d4 --- /dev/null +++ b/src/tls/s_hello.cpp @@ -0,0 +1,201 @@ +;/* +* TLS Server Hello and Server Hello Done +* (C) 2004-2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#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 <botan/internal/stl_util.h> + +namespace Botan { + +/* +* Create a new Server Hello message +*/ +Server_Hello::Server_Hello(Record_Writer& writer, + TLS_Handshake_Hash& hash, + Version_Code version, + const Client_Hello& c_hello, + const std::vector<X509_Certificate>& certs, + const TLS_Policy& policy, + bool client_has_secure_renegotiation, + const MemoryRegion<byte>& reneg_info, + bool client_has_npn, + const std::vector<std::string>& next_protocols, + RandomNumberGenerator& rng) : + s_version(version), + m_session_id(rng.random_vec(32)), + s_random(rng.random_vec(32)), + m_fragment_size(c_hello.fragment_size()), + m_secure_renegotiation(client_has_secure_renegotiation), + m_renegotiation_info(reneg_info), + m_next_protocol(client_has_npn), + m_next_protocols(next_protocols) + { + bool have_rsa = false, have_dsa = false; + + for(size_t i = 0; i != certs.size(); ++i) + { + 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, false); + + if(suite == 0) + throw TLS_Exception(HANDSHAKE_FAILURE, + "Can't agree on a ciphersuite with client"); + + comp_method = policy.choose_compression(c_hello.compression_methods()); + + send(writer, hash); + } + +/* +* Create a new Server Hello message +*/ +Server_Hello::Server_Hello(Record_Writer& writer, + TLS_Handshake_Hash& hash, + const MemoryRegion<byte>& session_id, + Version_Code ver, + u16bit ciphersuite, + byte compression, + size_t max_fragment_size, + bool client_has_secure_renegotiation, + const MemoryRegion<byte>& reneg_info, + bool client_has_npn, + const std::vector<std::string>& next_protocols, + RandomNumberGenerator& rng) : + s_version(ver), + m_session_id(session_id), + s_random(rng.random_vec(32)), + suite(ciphersuite), + comp_method(compression), + m_fragment_size(max_fragment_size), + m_secure_renegotiation(client_has_secure_renegotiation), + m_renegotiation_info(reneg_info), + m_next_protocol(client_has_npn), + m_next_protocols(next_protocols) + { + send(writer, hash); + } + +/* +* Serialize a Server Hello message +*/ +MemoryVector<byte> Server_Hello::serialize() const + { + MemoryVector<byte> buf; + + buf.push_back(static_cast<byte>(s_version >> 8)); + buf.push_back(static_cast<byte>(s_version )); + buf += s_random; + + append_tls_length_value(buf, m_session_id, 1); + + buf.push_back(get_byte(0, suite)); + buf.push_back(get_byte(1, suite)); + + buf.push_back(comp_method); + + TLS_Extensions extensions; + + if(m_secure_renegotiation) + extensions.push_back(new Renegotation_Extension(m_renegotiation_info)); + + if(m_fragment_size != 0) + extensions.push_back(new Maximum_Fragment_Length(m_fragment_size)); + + if(m_next_protocol) + extensions.push_back(new Next_Protocol_Negotiation(m_next_protocols)); + + buf += extensions.serialize(); + + return buf; + } + +/* +* Deserialize a Server Hello message +*/ +void Server_Hello::deserialize(const MemoryRegion<byte>& buf) + { + m_secure_renegotiation = false; + m_next_protocol = false; + + if(buf.size() < 38) + throw Decoding_Error("Server_Hello: Packet corrupted"); + + 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) + { + throw TLS_Exception(PROTOCOL_VERSION, + "Server_Hello: Unsupported server version"); + } + + s_random = reader.get_fixed<byte>(32); + + m_session_id = reader.get_range<byte>(1, 0, 32); + + suite = reader.get_u16bit(); + + comp_method = reader.get_byte(); + + TLS_Extensions extensions(reader); + + for(size_t i = 0; i != extensions.count(); ++i) + { + TLS_Extension* extn = extensions.at(i); + + if(Renegotation_Extension* reneg = dynamic_cast<Renegotation_Extension*>(extn)) + { + // checked by TLS_Client / TLS_Server as they know the handshake state + m_secure_renegotiation = true; + m_renegotiation_info = reneg->renegotiation_info(); + } + else if(Next_Protocol_Negotiation* npn = dynamic_cast<Next_Protocol_Negotiation*>(extn)) + { + m_next_protocols = npn->protocols(); + m_next_protocol = true; + } + } + } + +/* +* Create a new Server Hello Done message +*/ +Server_Hello_Done::Server_Hello_Done(Record_Writer& writer, + TLS_Handshake_Hash& hash) + { + send(writer, hash); + } + +/* +* Serialize a Server Hello Done message +*/ +MemoryVector<byte> Server_Hello_Done::serialize() const + { + return MemoryVector<byte>(); + } + +/* +* Deserialize a Server Hello Done message +*/ +void Server_Hello_Done::deserialize(const MemoryRegion<byte>& buf) + { + if(buf.size()) + throw Decoding_Error("Server_Hello_Done: Must be empty, and is not"); + } + +} diff --git a/src/tls/tls_extensions.cpp b/src/tls/tls_extensions.cpp index a6ab13f46..c74790ea1 100644 --- a/src/tls/tls_extensions.cpp +++ b/src/tls/tls_extensions.cpp @@ -9,8 +9,6 @@ #include <botan/internal/tls_reader.h> #include <botan/tls_exceptn.h> -#include <stdio.h> - namespace Botan { namespace { @@ -244,8 +242,6 @@ Next_Protocol_Negotiation::Next_Protocol_Negotiation(TLS_Data_Reader& reader, { const std::string p = reader.get_string(1, 0, 255); - printf("Protocol option %s\n", p.c_str()); - if(bytes_remaining < p.size() + 1) throw Decoding_Error("Bad encoding for next protocol extension"); diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h index 9c61501c9..67647d5a3 100644 --- a/src/tls/tls_messages.h +++ b/src/tls/tls_messages.h @@ -154,24 +154,28 @@ class Server_Hello : public Handshake_Message Server_Hello(Record_Writer& writer, TLS_Handshake_Hash& hash, + Version_Code version, + const Client_Hello& other, + const std::vector<X509_Certificate>& certs, const TLS_Policy& policies, - RandomNumberGenerator& rng, bool client_has_secure_renegotiation, const MemoryRegion<byte>& reneg_info, - const std::vector<X509_Certificate>& certs, - const Client_Hello& other, - Version_Code version); + bool client_has_npn, + const std::vector<std::string>& next_protocols, + RandomNumberGenerator& rng); Server_Hello(Record_Writer& writer, TLS_Handshake_Hash& hash, - RandomNumberGenerator& rng, - bool client_has_secure_renegotiation, - const MemoryRegion<byte>& reneg_info, const MemoryRegion<byte>& session_id, - size_t max_fragment_size, + Version_Code ver, u16bit ciphersuite, byte compression, - Version_Code ver); + size_t max_fragment_size, + bool client_has_secure_renegotiation, + const MemoryRegion<byte>& reneg_info, + bool client_has_npn, + const std::vector<std::string>& next_protocols, + RandomNumberGenerator& rng); Server_Hello(const MemoryRegion<byte>& buf) { deserialize(buf); } private: diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp index 109835e4a..729c185df 100644 --- a/src/tls/tls_server.cpp +++ b/src/tls/tls_server.cpp @@ -12,8 +12,6 @@ #include <botan/rsa.h> #include <botan/dh.h> -#include <stdio.h> - namespace Botan { namespace { @@ -87,12 +85,14 @@ TLS_Server::TLS_Server(std::tr1::function<void (const byte[], size_t)> output_fn TLS_Session_Manager& session_manager, Credentials_Manager& creds, const TLS_Policy& policy, - RandomNumberGenerator& rng) : + RandomNumberGenerator& rng, + const std::vector<std::string>& next_protocols) : TLS_Channel(output_fn, proc_fn, handshake_fn), policy(policy), rng(rng), session_manager(session_manager), - creds(creds) + creds(creds), + m_possible_protocols(next_protocols) { } @@ -154,7 +154,7 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, { state->client_hello = new Client_Hello(contents, type); - client_requested_hostname = state->client_hello->sni_hostname(); + m_hostname = state->client_hello->sni_hostname(); state->version = choose_version(state->client_hello->version(), policy.min_version()); @@ -176,14 +176,16 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, state->server_hello = new Server_Hello( writer, state->hash, - rng, - secure_renegotiation.supported(), - secure_renegotiation.for_server_hello(), session_info.session_id(), + Version_Code(session_info.version()), session_info.ciphersuite(), session_info.compression_method(), session_info.fragment_size(), - Version_Code(session_info.version())); + secure_renegotiation.supported(), + secure_renegotiation.for_server_hello(), + state->client_hello->next_protocol_negotiation(), + m_possible_protocols, + rng); if(session_info.fragment_size()) writer.set_maximum_fragment_size(session_info.fragment_size()); @@ -214,24 +216,26 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, std::vector<X509_Certificate> server_certs = creds.cert_chain("", "tls-server", - client_requested_hostname); + m_hostname); Private_Key* private_key = server_certs.empty() ? 0 : (creds.private_key_for(server_certs[0], "tls-server", - client_requested_hostname)); + m_hostname)); state->server_hello = new Server_Hello( writer, state->hash, + state->version, + *(state->client_hello), + server_certs, policy, - rng, secure_renegotiation.supported(), secure_renegotiation.for_server_hello(), - server_certs, - *(state->client_hello), - state->version); + state->client_hello->next_protocol_negotiation(), + m_possible_protocols, + rng); if(state->client_hello->fragment_size()) writer.set_maximum_fragment_size(state->client_hello->fragment_size()); @@ -347,10 +351,21 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, } else if(type == HANDSHAKE_CCS) { - state->set_expected_next(FINISHED); + if(state->server_hello->next_protocol_negotiation()) + state->set_expected_next(NEXT_PROTOCOL); + else + state->set_expected_next(FINISHED); reader.activate(state->suite, state->keys, SERVER); } + else if(type == NEXT_PROTOCOL) + { + state->set_expected_next(FINISHED); + + state->next_protocol = new Next_Protocol(contents); + + m_next_protocol = state->next_protocol->protocol(); + } else if(type == FINISHED) { state->set_expected_next(HANDSHAKE_NONE); @@ -389,7 +404,7 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, secure_renegotiation.supported(), state->server_hello->fragment_size(), peer_certs, - client_requested_hostname, + m_hostname, "" ); diff --git a/src/tls/tls_server.h b/src/tls/tls_server.h index b08d3f7e8..31e0e9ca4 100644 --- a/src/tls/tls_server.h +++ b/src/tls/tls_server.h @@ -30,15 +30,24 @@ class BOTAN_DLL TLS_Server : public TLS_Channel TLS_Session_Manager& session_manager, Credentials_Manager& creds, const TLS_Policy& policy, - RandomNumberGenerator& rng); + RandomNumberGenerator& rng, + const std::vector<std::string>& protocols = + std::vector<std::string>()); void renegotiate(); /** - * Return the server name indicator, if set by the client + * Return the server name indicator, if sent by the client */ std::string server_name_indicator() const - { return client_requested_hostname; } + { return m_hostname; } + + /** + * Return the protocol negotiated with NPN extension + */ + std::string next_protocol() const + { return m_next_protocol; } + private: void read_handshake(byte, const MemoryRegion<byte>&); @@ -49,7 +58,9 @@ class BOTAN_DLL TLS_Server : public TLS_Channel TLS_Session_Manager& session_manager; Credentials_Manager& creds; - std::string client_requested_hostname; + std::vector<std::string> m_possible_protocols; + std::string m_hostname; + std::string m_next_protocol; }; } diff --git a/src/tls/tls_session_manager.cpp b/src/tls/tls_session_manager.cpp index 4a0126fc0..e5ec75c88 100644 --- a/src/tls/tls_session_manager.cpp +++ b/src/tls/tls_session_manager.cpp @@ -9,8 +9,6 @@ #include <botan/hex.h> #include <botan/time.h> -#include <stdio.h> - namespace Botan { bool TLS_Session_Manager_In_Memory::load_from_session_str( |