diff options
Diffstat (limited to 'src/tls/tls_client.cpp')
-rw-r--r-- | src/tls/tls_client.cpp | 87 |
1 files changed, 59 insertions, 28 deletions
diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp index 2dd30819f..77e87e9bc 100644 --- a/src/tls/tls_client.cpp +++ b/src/tls/tls_client.cpp @@ -19,14 +19,14 @@ namespace TLS { * TLS Client Constructor */ Client::Client(std::function<void (const byte[], size_t)> output_fn, - std::function<void (const byte[], size_t, Alert)> proc_fn, - std::function<bool (const Session&)> handshake_fn, - Session_Manager& session_manager, - Credentials_Manager& creds, - const Policy& policy, - RandomNumberGenerator& rng, - const std::string& hostname, - std::function<std::string (std::vector<std::string>)> next_protocol) : + std::function<void (const byte[], size_t, Alert)> proc_fn, + std::function<bool (const Session&)> handshake_fn, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const std::string& hostname, + std::function<std::string (std::vector<std::string>)> next_protocol) : Channel(output_fn, proc_fn, handshake_fn), policy(policy), rng(rng), @@ -35,7 +35,7 @@ Client::Client(std::function<void (const byte[], size_t)> output_fn, { writer.set_version(Protocol_Version::SSL_V3); - state = new Handshake_State; + state = new Handshake_State(new Stream_Handshake_Reader); state->set_expected_next(SERVER_HELLO); state->client_npn_cb = next_protocol; @@ -54,6 +54,7 @@ Client::Client(std::function<void (const byte[], size_t)> output_fn, state->client_hello = new Client_Hello( writer, state->hash, + policy, rng, session_info, send_npn_request); @@ -87,7 +88,7 @@ void Client::renegotiate() if(state) return; // currently in handshake - state = new Handshake_State; + state = new Handshake_State(new Stream_Handshake_Reader); state->set_expected_next(SERVER_HELLO); state->client_hello = new Client_Hello(writer, state->hash, policy, rng, @@ -112,7 +113,7 @@ void Client::alert_notify(const Alert& alert) * Process a handshake message */ void Client::process_handshake_msg(Handshake_Type type, - const MemoryRegion<byte>& contents) + const MemoryRegion<byte>& contents) { if(state == 0) throw Unexpected_Message("Unexpected handshake message from server"); @@ -135,12 +136,12 @@ void Client::process_handshake_msg(Handshake_Type type, return; } - state->set_expected_next(SERVER_HELLO); state->client_hello = new Client_Hello(writer, state->hash, policy, rng, secure_renegotiation.for_client_hello()); - secure_renegotiation.update(state->client_hello); + state->set_expected_next(SERVER_HELLO); + return; } @@ -173,17 +174,27 @@ void Client::process_handshake_msg(Handshake_Type type, "Server sent next protocol but we didn't request it"); } - state->version = state->server_hello->version(); + if(state->server_hello->supports_session_ticket()) + { + if(!state->client_hello->supports_session_ticket()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server sent session ticket extension but we did not"); + } + + state->set_version(state->server_hello->version()); - writer.set_version(state->version); - reader.set_version(state->version); + writer.set_version(state->version()); + reader.set_version(state->version()); secure_renegotiation.update(state->server_hello); state->suite = Ciphersuite::by_id(state->server_hello->ciphersuite()); - if(!state->server_hello->session_id().empty() && - (state->server_hello->session_id() == state->client_hello->session_id())) + const bool server_returned_same_session_id = + !state->server_hello->session_id().empty() && + (state->server_hello->session_id() == state->client_hello->session_id()); + + if(server_returned_same_session_id) { // successful resumption @@ -199,19 +210,22 @@ void Client::process_handshake_msg(Handshake_Type type, state->resume_master_secret, true); - state->set_expected_next(HANDSHAKE_CCS); + if(state->server_hello->supports_session_ticket()) + state->set_expected_next(NEW_SESSION_TICKET); + else + state->set_expected_next(HANDSHAKE_CCS); } else { // new session - if(state->version > state->client_hello->version()) + if(state->version() > state->client_hello->version()) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Client: Server replied with bad version"); } - if(state->version < policy.min_version()) + if(state->version() < policy.min_version()) { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Client: Server is too old for specified policy"); @@ -288,7 +302,7 @@ void Client::process_handshake_msg(Handshake_Type type, state->server_kex = new Server_Key_Exchange(contents, state->suite.kex_algo(), state->suite.sig_algo(), - state->version); + state->version()); if(state->suite.sig_algo() != "") { @@ -302,12 +316,10 @@ void Client::process_handshake_msg(Handshake_Type type, else if(type == CERTIFICATE_REQUEST) { state->set_expected_next(SERVER_HELLO_DONE); - state->cert_req = new Certificate_Req(contents, state->version); + state->cert_req = new Certificate_Req(contents, state->version()); } else if(type == SERVER_HELLO_DONE) { - state->set_expected_next(HANDSHAKE_CCS); - state->server_hello_done = new Server_Hello_Done(contents); if(state->received_handshake_msg(CERTIFICATE_REQUEST)) @@ -364,6 +376,17 @@ void Client::process_handshake_msg(Handshake_Type type, } state->client_finished = new Finished(writer, state, CLIENT); + + if(state->server_hello->supports_session_ticket()) + state->set_expected_next(NEW_SESSION_TICKET); + else + state->set_expected_next(HANDSHAKE_CCS); + } + else if(type == NEW_SESSION_TICKET) + { + state->new_session_ticket = new New_Session_Ticket(contents); + + state->set_expected_next(HANDSHAKE_CCS); } else if(type == HANDSHAKE_CCS) { @@ -394,8 +417,17 @@ void Client::process_handshake_msg(Handshake_Type type, state->client_finished = new Finished(writer, state, CLIENT); } + secure_renegotiation.update(state->client_finished, state->server_finished); + + MemoryVector<byte> session_id = state->server_hello->session_id(); + + const MemoryRegion<byte>& session_ticket = state->session_ticket(); + + if(session_id.empty() && !session_ticket.empty()) + session_id = make_hello_random(rng); + Session session_info( - state->server_hello->session_id(), + session_id, state->keys.master_secret(), state->server_hello->version(), state->server_hello->ciphersuite(), @@ -404,6 +436,7 @@ void Client::process_handshake_msg(Handshake_Type type, secure_renegotiation.supported(), state->server_hello->fragment_size(), peer_certs, + session_ticket, state->client_hello->sni_hostname(), "" ); @@ -413,8 +446,6 @@ void Client::process_handshake_msg(Handshake_Type type, else session_manager.remove_entry(session_info.session_id()); - secure_renegotiation.update(state->client_finished, state->server_finished); - delete state; state = 0; handshake_completed = true; |