diff options
author | lloyd <[email protected]> | 2012-01-04 17:11:40 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-01-04 17:11:40 +0000 |
commit | 268b336843cf71f8fcb8c68ed67a622c71e3232a (patch) | |
tree | 1e6da6458693a5c8040edeb05bc3eef40c93cddf /src | |
parent | c926d5e919245f25d1730f4f4d565f691647e99f (diff) |
Split hello.cpp into c_hello.cpp and s_hello.cpp
Add support for NPN on the server side. Server is initialized with the
list of protocols it wants to offer, once the handshake completes the
client requested protocol is available via a getter.
Diffstat (limited to 'src')
-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( |