aboutsummaryrefslogtreecommitdiffstats
path: root/src/tls/tls_client.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tls/tls_client.cpp')
-rw-r--r--src/tls/tls_client.cpp530
1 files changed, 0 insertions, 530 deletions
diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp
deleted file mode 100644
index f17247c16..000000000
--- a/src/tls/tls_client.cpp
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
-* TLS Client
-* (C) 2004-2011,2012 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/tls_client.h>
-#include <botan/internal/tls_handshake_state.h>
-#include <botan/internal/tls_messages.h>
-#include <botan/internal/stl_util.h>
-#include <memory>
-
-namespace Botan {
-
-namespace TLS {
-
-namespace {
-
-class Client_Handshake_State : public Handshake_State
- {
- public:
- // using Handshake_State::Handshake_State;
-
- Client_Handshake_State(Handshake_IO* io,
- std::function<void (const Handshake_Message&)> msg_callback =
- std::function<void (const Handshake_Message&)>()) :
- Handshake_State(io, msg_callback) {}
-
- const Public_Key& get_server_public_Key() const
- {
- BOTAN_ASSERT(server_public_key, "Server sent us a certificate");
- return *server_public_key.get();
- }
-
- // Used during session resumption
- secure_vector<byte> resume_master_secret;
-
- std::unique_ptr<Public_Key> server_public_key;
-
- // Used by client using NPN
- std::function<std::string (std::vector<std::string>)> client_npn_cb;
- };
-
-}
-
-/*
-* TLS Client Constructor
-*/
-Client::Client(std::function<void (const byte[], size_t)> output_fn,
- std::function<void (const byte[], size_t)> proc_cb,
- std::function<void (Alert, const byte[], size_t)> alert_cb,
- std::function<bool (const Session&)> handshake_cb,
- Session_Manager& session_manager,
- Credentials_Manager& creds,
- const Policy& policy,
- RandomNumberGenerator& rng,
- const Server_Information& info,
- const Protocol_Version offer_version,
- std::function<std::string (std::vector<std::string>)> next_protocol,
- size_t io_buf_sz) :
- Channel(output_fn, proc_cb, alert_cb, handshake_cb, session_manager, rng, io_buf_sz),
- m_policy(policy),
- m_creds(creds),
- m_info(info)
- {
- const std::string srp_identifier = m_creds.srp_identifier("tls-client", m_info.hostname());
-
- Handshake_State& state = create_handshake_state(offer_version);
- send_client_hello(state, false, offer_version, srp_identifier, next_protocol);
- }
-
-Handshake_State* Client::new_handshake_state(Handshake_IO* io)
- {
- return new Client_Handshake_State(io);
- }
-
-std::vector<X509_Certificate>
-Client::get_peer_cert_chain(const Handshake_State& state) const
- {
- if(state.server_certs())
- return state.server_certs()->cert_chain();
- return std::vector<X509_Certificate>();
- }
-
-/*
-* Send a new client hello to renegotiate
-*/
-void Client::initiate_handshake(Handshake_State& state,
- bool force_full_renegotiation)
- {
- send_client_hello(state,
- force_full_renegotiation,
- state.version());
- }
-
-void Client::send_client_hello(Handshake_State& state_base,
- bool force_full_renegotiation,
- Protocol_Version version,
- const std::string& srp_identifier,
- std::function<std::string (std::vector<std::string>)> next_protocol)
- {
- Client_Handshake_State& state = dynamic_cast<Client_Handshake_State&>(state_base);
-
- if(state.version().is_datagram_protocol())
- state.set_expected_next(HELLO_VERIFY_REQUEST); // optional
- state.set_expected_next(SERVER_HELLO);
-
- state.client_npn_cb = next_protocol;
-
- const bool send_npn_request = static_cast<bool>(next_protocol);
-
- if(!force_full_renegotiation && !m_info.empty())
- {
- Session session_info;
- if(session_manager().load_from_server_info(m_info, session_info))
- {
- if(srp_identifier == "" || session_info.srp_identifier() == srp_identifier)
- {
- state.client_hello(new Client_Hello(
- state.handshake_io(),
- state.hash(),
- m_policy,
- rng(),
- secure_renegotiation_data_for_client_hello(),
- session_info,
- send_npn_request));
-
- state.resume_master_secret = session_info.master_secret();
- }
- }
- }
-
- if(!state.client_hello()) // not resuming
- {
- state.client_hello(new Client_Hello(
- state.handshake_io(),
- state.hash(),
- version,
- m_policy,
- rng(),
- secure_renegotiation_data_for_client_hello(),
- send_npn_request,
- m_info.hostname(),
- srp_identifier));
- }
-
- secure_renegotiation_check(state.client_hello());
- }
-
-/*
-* Process a handshake message
-*/
-void Client::process_handshake_msg(const Handshake_State* active_state,
- Handshake_State& state_base,
- Handshake_Type type,
- const std::vector<byte>& contents)
- {
- Client_Handshake_State& state = dynamic_cast<Client_Handshake_State&>(state_base);
-
- if(type == HELLO_REQUEST && active_state)
- {
- Hello_Request hello_request(contents);
-
- // Ignore request entirely if we are currently negotiating a handshake
- if(state.client_hello())
- return;
-
- if(!m_policy.allow_server_initiated_renegotiation() ||
- (!m_policy.allow_insecure_renegotiation() && !secure_renegotiation_supported()))
- {
- // RFC 5746 section 4.2
- send_warning_alert(Alert::NO_RENEGOTIATION);
- return;
- }
-
- this->initiate_handshake(state, false);
-
- return;
- }
-
- state.confirm_transition_to(type);
-
- if(type != HANDSHAKE_CCS && type != FINISHED && type != HELLO_VERIFY_REQUEST)
- state.hash().update(state.handshake_io().format(contents, type));
-
- if(type == HELLO_VERIFY_REQUEST)
- {
- state.set_expected_next(SERVER_HELLO);
- state.set_expected_next(HELLO_VERIFY_REQUEST); // might get it again
-
- Hello_Verify_Request hello_verify_request(contents);
-
- state.hello_verify_request(hello_verify_request);
- }
- else if(type == SERVER_HELLO)
- {
- state.server_hello(new Server_Hello(contents));
-
- if(!state.client_hello()->offered_suite(state.server_hello()->ciphersuite()))
- {
- throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
- "Server replied with ciphersuite we didn't send");
- }
-
- if(!value_exists(state.client_hello()->compression_methods(),
- state.server_hello()->compression_method()))
- {
- throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
- "Server replied with compression method we didn't send");
- }
-
- if(!state.client_hello()->next_protocol_notification() &&
- state.server_hello()->next_protocol_notification())
- {
- throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
- "Server sent next protocol but we didn't request it");
- }
-
- 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());
-
- secure_renegotiation_check(state.server_hello());
-
- 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
-
- /*
- * In this case, we offered the version used in the original
- * session, and the server must resume with the same version.
- */
- if(state.server_hello()->version() != state.client_hello()->version())
- throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
- "Server resumed session but with wrong version");
-
- state.compute_session_keys(state.resume_master_secret);
-
- 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.client_hello()->version().is_datagram_protocol() !=
- state.server_hello()->version().is_datagram_protocol())
- {
- throw TLS_Exception(Alert::PROTOCOL_VERSION,
- "Server replied with different protocol type than we offered");
- }
-
- if(state.version() > state.client_hello()->version())
- {
- throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
- "Server replied with later version than in hello");
- }
-
- if(!m_policy.acceptable_protocol_version(state.version()))
- {
- throw TLS_Exception(Alert::PROTOCOL_VERSION,
- "Server version is unacceptable by policy");
- }
-
- if(state.ciphersuite().sig_algo() != "")
- {
- state.set_expected_next(CERTIFICATE);
- }
- else if(state.ciphersuite().kex_algo() == "PSK")
- {
- /* PSK is anonymous so no certificate/cert req message is
- ever sent. The server may or may not send a server kex,
- depending on if it has an identity hint for us.
-
- (EC)DHE_PSK always sends a server key exchange for the
- DH exchange portion.
- */
-
- state.set_expected_next(SERVER_KEX);
- state.set_expected_next(SERVER_HELLO_DONE);
- }
- else if(state.ciphersuite().kex_algo() != "RSA")
- {
- state.set_expected_next(SERVER_KEX);
- }
- else
- {
- state.set_expected_next(CERTIFICATE_REQUEST); // optional
- state.set_expected_next(SERVER_HELLO_DONE);
- }
- }
- }
- else if(type == CERTIFICATE)
- {
- if(state.ciphersuite().kex_algo() != "RSA")
- {
- state.set_expected_next(SERVER_KEX);
- }
- else
- {
- state.set_expected_next(CERTIFICATE_REQUEST); // optional
- state.set_expected_next(SERVER_HELLO_DONE);
- }
-
- state.server_certs(new Certificate(contents));
-
- const std::vector<X509_Certificate>& server_certs =
- state.server_certs()->cert_chain();
-
- if(server_certs.empty())
- throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
- "Client: No certificates sent by server");
-
- try
- {
- m_creds.verify_certificate_chain("tls-client", m_info.hostname(), server_certs);
- }
- catch(std::exception& e)
- {
- throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what());
- }
-
- std::unique_ptr<Public_Key> peer_key(server_certs[0].subject_public_key());
-
- if(peer_key->algo_name() != state.ciphersuite().sig_algo())
- throw TLS_Exception(Alert::ILLEGAL_PARAMETER,
- "Certificate key type did not match ciphersuite");
-
- state.server_public_key.reset(peer_key.release());
- }
- else if(type == SERVER_KEX)
- {
- state.set_expected_next(CERTIFICATE_REQUEST); // optional
- state.set_expected_next(SERVER_HELLO_DONE);
-
- state.server_kex(
- new Server_Key_Exchange(contents,
- state.ciphersuite().kex_algo(),
- state.ciphersuite().sig_algo(),
- state.version())
- );
-
- if(state.ciphersuite().sig_algo() != "")
- {
- const Public_Key& server_key = state.get_server_public_Key();
-
- if(!state.server_kex()->verify(server_key, state))
- {
- throw TLS_Exception(Alert::DECRYPT_ERROR,
- "Bad signature on server key exchange");
- }
- }
- }
- else if(type == CERTIFICATE_REQUEST)
- {
- state.set_expected_next(SERVER_HELLO_DONE);
- state.cert_req(
- new Certificate_Req(contents, state.version())
- );
- }
- else if(type == SERVER_HELLO_DONE)
- {
- state.server_hello_done(
- new Server_Hello_Done(contents)
- );
-
- if(state.received_handshake_msg(CERTIFICATE_REQUEST))
- {
- const std::vector<std::string>& types =
- state.cert_req()->acceptable_cert_types();
-
- std::vector<X509_Certificate> client_certs =
- m_creds.cert_chain(types,
- "tls-client",
- m_info.hostname());
-
- state.client_certs(
- new Certificate(state.handshake_io(),
- state.hash(),
- client_certs)
- );
- }
-
- state.client_kex(
- new Client_Key_Exchange(state.handshake_io(),
- state,
- m_policy,
- m_creds,
- state.server_public_key.get(),
- m_info.hostname(),
- rng())
- );
-
- state.compute_session_keys();
-
- if(state.received_handshake_msg(CERTIFICATE_REQUEST) &&
- !state.client_certs()->empty())
- {
- Private_Key* private_key =
- m_creds.private_key_for(state.client_certs()->cert_chain()[0],
- "tls-client",
- m_info.hostname());
-
- state.client_verify(
- new Certificate_Verify(state.handshake_io(),
- state,
- m_policy,
- rng(),
- private_key)
- );
- }
-
- state.handshake_io().send(Change_Cipher_Spec());
-
- change_cipher_spec_writer(CLIENT);
-
- if(state.server_hello()->next_protocol_notification())
- {
- const std::string protocol = state.client_npn_cb(
- state.server_hello()->next_protocols());
-
- state.next_protocol(
- new Next_Protocol(state.handshake_io(), state.hash(), protocol)
- );
- }
-
- state.client_finished(
- new Finished(state.handshake_io(), 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)
- {
- state.set_expected_next(FINISHED);
-
- change_cipher_spec_reader(CLIENT);
- }
- else if(type == FINISHED)
- {
- state.server_finished(new Finished(contents));
-
- if(!state.server_finished()->verify(state, SERVER))
- throw TLS_Exception(Alert::DECRYPT_ERROR,
- "Finished message didn't verify");
-
- state.hash().update(state.handshake_io().format(contents, type));
-
- if(!state.client_finished()) // session resume case
- {
- state.handshake_io().send(Change_Cipher_Spec());
-
- change_cipher_spec_writer(CLIENT);
-
- if(state.server_hello()->next_protocol_notification())
- {
- const std::string protocol = state.client_npn_cb(
- state.server_hello()->next_protocols());
-
- state.next_protocol(
- new Next_Protocol(state.handshake_io(), state.hash(), protocol)
- );
- }
-
- state.client_finished(
- new Finished(state.handshake_io(), state, CLIENT)
- );
- }
-
- std::vector<byte> session_id = state.server_hello()->session_id();
-
- const std::vector<byte>& session_ticket = state.session_ticket();
-
- if(session_id.empty() && !session_ticket.empty())
- session_id = make_hello_random(rng());
-
- Session session_info(
- session_id,
- state.session_keys().master_secret(),
- state.server_hello()->version(),
- state.server_hello()->ciphersuite(),
- state.server_hello()->compression_method(),
- CLIENT,
- state.server_hello()->fragment_size(),
- get_peer_cert_chain(state),
- session_ticket,
- m_info,
- ""
- );
-
- const bool should_save = save_session(session_info);
-
- if(!session_id.empty())
- {
- if(should_save)
- session_manager().save(session_info);
- else
- session_manager().remove_entry(session_info.session_id());
- }
-
- activate_session();
- }
- else
- throw Unexpected_Message("Unknown handshake message received");
- }
-
-}
-
-}