diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/tls/tls_server.cpp | 372 |
1 files changed, 179 insertions, 193 deletions
diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp index 66a0e0e1d..5bc5410f5 100644 --- a/src/lib/tls/tls_server.cpp +++ b/src/lib/tls/tls_server.cpp @@ -131,16 +131,14 @@ bool check_for_resume(Session& session_info, } // Checking encrypt_then_mac on resume (RFC 7366 section 3.1) - if( !client_hello->supports_encrypt_then_mac() && session_info.supports_encrypt_then_mac()) + if(!client_hello->supports_encrypt_then_mac() && session_info.supports_encrypt_then_mac()) { - /* Client previously negotiated session with Encrypt-then-MAC, but has now attempted to resume without the extension: abort */ throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Client resumed Encrypt-then-MAC session without sending extension"); - } return true; @@ -511,153 +509,147 @@ void Server::process_client_hello_msg(const Handshake_State* active_state, { this->session_create(pending_state, have_session_ticket_key); } -} + } void Server::process_certificate_msg(Server_Handshake_State& pending_state, const std::vector<uint8_t>& contents) -{ + { pending_state.client_certs(new Certificate(contents, policy())); pending_state.set_expected_next(CLIENT_KEX); -} + } void Server::process_client_key_exchange_msg(Server_Handshake_State& pending_state, const std::vector<uint8_t>& contents) -{ + { if(pending_state.received_handshake_msg(CERTIFICATE) && !pending_state.client_certs()->empty()) pending_state.set_expected_next(CERTIFICATE_VERIFY); else pending_state.set_expected_next(HANDSHAKE_CCS); - pending_state.client_kex( - new Client_Key_Exchange(contents, pending_state, - pending_state.server_rsa_kex_key(), - m_creds, policy(), rng()) - ); + pending_state.client_kex(new Client_Key_Exchange(contents, pending_state, + pending_state.server_rsa_kex_key(), + m_creds, policy(), rng())); pending_state.compute_session_keys(); -} + } void Server::process_change_cipher_spec_msg(Server_Handshake_State& pending_state) -{ + { pending_state.set_expected_next(FINISHED); change_cipher_spec_reader(SERVER); -} + } void Server::process_certificate_verify_msg(Server_Handshake_State& pending_state, Handshake_Type type, const std::vector<uint8_t>& contents) -{ - pending_state.client_verify ( new Certificate_Verify ( contents, pending_state.version() ) ); - - const std::vector<X509_Certificate>& client_certs = - pending_state.client_certs()->cert_chain(); - - const bool sig_valid = - pending_state.client_verify()->verify ( client_certs[0], pending_state, policy() ); - - pending_state.hash().update ( pending_state.handshake_io().format ( contents, type ) ); - - /* - * Using DECRYPT_ERROR looks weird here, but per RFC 4346 is for - * "A handshake cryptographic operation failed, including being - * unable to correctly verify a signature, ..." - */ - if ( !sig_valid ) - throw TLS_Exception ( Alert::DECRYPT_ERROR, "Client cert verify failed" ); - - try - { - const std::string sni_hostname = pending_state.client_hello()->sni_hostname(); - auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-server", sni_hostname); - - callbacks().tls_verify_cert_chain(client_certs, - {}, // ocsp - trusted_CAs, - Usage_Type::TLS_CLIENT_AUTH, - sni_hostname, - policy()); - } - catch ( std::exception& e ) - { - throw TLS_Exception ( Alert::BAD_CERTIFICATE, e.what() ); - } - - pending_state.set_expected_next ( HANDSHAKE_CCS ); -} + { + pending_state.client_verify(new Certificate_Verify(contents, pending_state.version())); + + const std::vector<X509_Certificate>& client_certs = + pending_state.client_certs()->cert_chain(); + + const bool sig_valid = + pending_state.client_verify()->verify(client_certs[0], pending_state, policy()); + + pending_state.hash().update(pending_state.handshake_io().format(contents, type)); + + /* + * Using DECRYPT_ERROR looks weird here, but per RFC 4346 is for + * "A handshake cryptographic operation failed, including being + * unable to correctly verify a signature, ..." + */ + if(!sig_valid) + throw TLS_Exception(Alert::DECRYPT_ERROR, "Client cert verify failed"); + + try + { + const std::string sni_hostname = pending_state.client_hello()->sni_hostname(); + auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-server", sni_hostname); + + callbacks().tls_verify_cert_chain(client_certs, + {}, // ocsp + trusted_CAs, + Usage_Type::TLS_CLIENT_AUTH, + sni_hostname, + policy()); + } + catch(std::exception& e) + { + throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what()); + } + + pending_state.set_expected_next(HANDSHAKE_CCS); + } void Server::process_finished_msg(Server_Handshake_State& pending_state, Handshake_Type type, const std::vector<uint8_t>& contents) -{ - pending_state.set_expected_next ( HANDSHAKE_NONE ); - - pending_state.client_finished ( new Finished ( contents ) ); - - if ( !pending_state.client_finished()->verify ( pending_state, CLIENT ) ) - throw TLS_Exception ( Alert::DECRYPT_ERROR, - "Finished message didn't verify" ); - - if ( !pending_state.server_finished() ) - { - // already sent finished if resuming, so this is a new session - - pending_state.hash().update ( pending_state.handshake_io().format ( contents, type ) ); - - Session session_info( - pending_state.server_hello()->session_id(), - pending_state.session_keys().master_secret(), - pending_state.server_hello()->version(), - pending_state.server_hello()->ciphersuite(), - pending_state.server_hello()->compression_method(), - SERVER, - pending_state.server_hello()->supports_extended_master_secret(), - pending_state.server_hello()->supports_encrypt_then_mac(), - get_peer_cert_chain ( pending_state ), - std::vector<uint8_t>(), - Server_Information(pending_state.client_hello()->sni_hostname()), - pending_state.srp_identifier(), - pending_state.server_hello()->srtp_profile() - ); - - if ( save_session ( session_info ) ) - { - if ( pending_state.server_hello()->supports_session_ticket() ) - { - try - { - const SymmetricKey ticket_key = m_creds.psk ( "tls-server", "session-ticket", "" ); - - pending_state.new_session_ticket ( - new New_Session_Ticket ( pending_state.handshake_io(), - pending_state.hash(), - session_info.encrypt ( ticket_key, rng() ), - policy().session_ticket_lifetime() ) - ); - } - catch ( ... ) {} - } - else - session_manager().save ( session_info ); - } + { + pending_state.set_expected_next(HANDSHAKE_NONE); + + pending_state.client_finished(new Finished(contents)); - if ( !pending_state.new_session_ticket() && - pending_state.server_hello()->supports_session_ticket() ) + if(!pending_state.client_finished()->verify(pending_state, CLIENT)) + throw TLS_Exception(Alert::DECRYPT_ERROR, + "Finished message didn't verify"); + + if(!pending_state.server_finished()) + { + // already sent finished if resuming, so this is a new session + + pending_state.hash().update(pending_state.handshake_io().format(contents, type)); + + Session session_info( + pending_state.server_hello()->session_id(), + pending_state.session_keys().master_secret(), + pending_state.server_hello()->version(), + pending_state.server_hello()->ciphersuite(), + pending_state.server_hello()->compression_method(), + SERVER, + pending_state.server_hello()->supports_extended_master_secret(), + pending_state.server_hello()->supports_encrypt_then_mac(), + get_peer_cert_chain(pending_state), + std::vector<uint8_t>(), + Server_Information(pending_state.client_hello()->sni_hostname()), + pending_state.srp_identifier(), + pending_state.server_hello()->srtp_profile()); + + if(save_session(session_info)) + { + if(pending_state.server_hello()->supports_session_ticket()) { - pending_state.new_session_ticket ( - new New_Session_Ticket ( pending_state.handshake_io(), pending_state.hash() ) - ); + try + { + const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); + + pending_state.new_session_ticket( + new New_Session_Ticket(pending_state.handshake_io(), + pending_state.hash(), + session_info.encrypt(ticket_key, rng()), + policy().session_ticket_lifetime())); + } + catch(...) {} } + else + session_manager().save(session_info); + } - pending_state.handshake_io().send ( Change_Cipher_Spec() ); + if(!pending_state.new_session_ticket() && + pending_state.server_hello()->supports_session_ticket()) + { + pending_state.new_session_ticket( + new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash())); + } - change_cipher_spec_writer ( SERVER ); + pending_state.handshake_io().send(Change_Cipher_Spec()); - pending_state.server_finished ( new Finished ( pending_state.handshake_io(), pending_state, SERVER ) ); - } + change_cipher_spec_writer(SERVER); - activate_session(); + pending_state.server_finished(new Finished(pending_state.handshake_io(), pending_state, SERVER)); + } -} + activate_session(); + } /* * Process a handshake message @@ -711,72 +703,68 @@ void Server::session_resume(Server_Handshake_State& pending_state, bool have_session_ticket_key, Session& session_info) { - // Only offer a resuming client a new ticket if they didn't send one this time, - // ie, resumed via server-side resumption. TODO: also send one if expiring soon? - - const bool offer_new_session_ticket = - (pending_state.client_hello()->supports_session_ticket() && - pending_state.client_hello()->session_ticket().empty() && - have_session_ticket_key); - - pending_state.server_hello(new Server_Hello( - pending_state.handshake_io(), - pending_state.hash(), - policy(), - rng(), - secure_renegotiation_data_for_server_hello(), - *pending_state.client_hello(), - session_info, - offer_new_session_ticket, - m_next_protocol - )); - - secure_renegotiation_check(pending_state.server_hello()); - - pending_state.compute_session_keys(session_info.master_secret()); - - if(!save_session(session_info)) - { - session_manager().remove_entry(session_info.session_id()); + // Only offer a resuming client a new ticket if they didn't send one this time, + // ie, resumed via server-side resumption. TODO: also send one if expiring soon? - if(pending_state.server_hello()->supports_session_ticket()) // send an empty ticket - { - pending_state.new_session_ticket( - new New_Session_Ticket(pending_state.handshake_io(), - pending_state.hash()) - ); - } + const bool offer_new_session_ticket = + (pending_state.client_hello()->supports_session_ticket() && + pending_state.client_hello()->session_ticket().empty() && + have_session_ticket_key); + + pending_state.server_hello(new Server_Hello( + pending_state.handshake_io(), + pending_state.hash(), + policy(), + rng(), + secure_renegotiation_data_for_server_hello(), + *pending_state.client_hello(), + session_info, + offer_new_session_ticket, + m_next_protocol)); + + secure_renegotiation_check(pending_state.server_hello()); + + pending_state.compute_session_keys(session_info.master_secret()); + + if(!save_session(session_info)) + { + session_manager().remove_entry(session_info.session_id()); + + if(pending_state.server_hello()->supports_session_ticket()) // send an empty ticket + { + pending_state.new_session_ticket( + new New_Session_Ticket(pending_state.handshake_io(), + pending_state.hash())); } + } - if(pending_state.server_hello()->supports_session_ticket() && !pending_state.new_session_ticket()) + if(pending_state.server_hello()->supports_session_ticket() && !pending_state.new_session_ticket()) + { + try { - try - { - const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); - - pending_state.new_session_ticket( - new New_Session_Ticket(pending_state.handshake_io(), - pending_state.hash(), - session_info.encrypt(ticket_key, rng()), - policy().session_ticket_lifetime()) - ); - } - catch(...) {} + const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); - if(!pending_state.new_session_ticket()) - { - pending_state.new_session_ticket( - new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash()) - ); - } + pending_state.new_session_ticket( + new New_Session_Ticket(pending_state.handshake_io(), + pending_state.hash(), + session_info.encrypt(ticket_key, rng()), + policy().session_ticket_lifetime())); } + catch(...) {} - pending_state.handshake_io().send(Change_Cipher_Spec()); + if(!pending_state.new_session_ticket()) + { + pending_state.new_session_ticket( + new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash())); + } + } - change_cipher_spec_writer(SERVER); + pending_state.handshake_io().send(Change_Cipher_Spec()); - pending_state.server_finished(new Finished(pending_state.handshake_io(), pending_state, SERVER)); - pending_state.set_expected_next(HANDSHAKE_CCS); + change_cipher_spec_writer(SERVER); + + pending_state.server_finished(new Finished(pending_state.handshake_io(), pending_state, SERVER)); + pending_state.set_expected_next(HANDSHAKE_CCS); } void Server::session_create(Server_Handshake_State& pending_state, @@ -803,28 +791,26 @@ void Server::session_create(Server_Handshake_State& pending_state, send_alert(Alert(Alert::UNRECOGNIZED_NAME)); } - Server_Hello::Settings srv_settings( - make_hello_random(rng(), policy()), // new session ID - pending_state.version(), - choose_ciphersuite(policy(), - pending_state.version(), - m_creds, - cert_chains, - *pending_state.client_hello()), - choose_compression(policy(), - pending_state.client_hello()->compression_methods()), - have_session_ticket_key); + const uint16_t ciphersuite = choose_ciphersuite(policy(), pending_state.version(), + m_creds, cert_chains, + *pending_state.client_hello()); + + Server_Hello::Settings srv_settings( + make_hello_random(rng(), policy()), // new session ID + pending_state.version(), + ciphersuite, + choose_compression(policy(), pending_state.client_hello()->compression_methods()), + have_session_ticket_key); pending_state.server_hello(new Server_Hello( - pending_state.handshake_io(), - pending_state.hash(), - policy(), - rng(), - secure_renegotiation_data_for_server_hello(), - *pending_state.client_hello(), - srv_settings, - m_next_protocol) - ); + pending_state.handshake_io(), + pending_state.hash(), + policy(), + rng(), + secure_renegotiation_data_for_server_hello(), + *pending_state.client_hello(), + srv_settings, + m_next_protocol)); secure_renegotiation_check(pending_state.server_hello()); @@ -834,7 +820,7 @@ void Server::session_create(Server_Handshake_State& pending_state, if(sig_algo != "") { BOTAN_ASSERT(!cert_chains[sig_algo].empty(), - "Attempting to send empty certificate chain"); + "Attempting to send empty certificate chain"); pending_state.server_certs(new Certificate(pending_state.handshake_io(), pending_state.hash(), |