aboutsummaryrefslogtreecommitdiffstats
path: root/src/ssl/tls_client.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssl/tls_client.cpp')
-rw-r--r--src/ssl/tls_client.cpp586
1 files changed, 0 insertions, 586 deletions
diff --git a/src/ssl/tls_client.cpp b/src/ssl/tls_client.cpp
deleted file mode 100644
index a136752fd..000000000
--- a/src/ssl/tls_client.cpp
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
-* TLS Client
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/tls_client.h>
-#include <botan/internal/tls_alerts.h>
-#include <botan/internal/tls_state.h>
-#include <botan/loadstor.h>
-#include <botan/rsa.h>
-#include <botan/dsa.h>
-#include <botan/dh.h>
-
-namespace Botan {
-
-namespace {
-
-/**
-* Verify the state transition is allowed
-* FIXME: checks are wrong for session reuse (add a flag for that)
-*/
-void client_check_state(Handshake_Type new_msg, Handshake_State* state)
- {
- class State_Transition_Error : public Unexpected_Message
- {
- public:
- State_Transition_Error(const std::string& err) :
- Unexpected_Message("State transition error from " + err) {}
- };
-
- if(new_msg == HELLO_REQUEST)
- {
- if(state->client_hello)
- throw State_Transition_Error("HelloRequest");
- }
- else if(new_msg == SERVER_HELLO)
- {
- if(!state->client_hello || state->server_hello)
- throw State_Transition_Error("ServerHello");
- }
- else if(new_msg == CERTIFICATE)
- {
- if(!state->server_hello || state->server_kex ||
- state->cert_req || state->server_hello_done)
- throw State_Transition_Error("ServerCertificate");
- }
- else if(new_msg == SERVER_KEX)
- {
- if(!state->server_hello || state->server_kex ||
- state->cert_req || state->server_hello_done)
- throw State_Transition_Error("ServerKeyExchange");
- }
- else if(new_msg == CERTIFICATE_REQUEST)
- {
- if(!state->server_certs || state->cert_req || state->server_hello_done)
- throw State_Transition_Error("CertificateRequest");
- }
- else if(new_msg == SERVER_HELLO_DONE)
- {
- if(!state->server_hello || state->server_hello_done)
- throw State_Transition_Error("ServerHelloDone");
- }
- else if(new_msg == HANDSHAKE_CCS)
- {
- if(!state->client_finished || state->server_finished)
- throw State_Transition_Error("ServerChangeCipherSpec");
- }
- else if(new_msg == FINISHED)
- {
- if(!state->got_server_ccs)
- throw State_Transition_Error("ServerFinished");
- }
- else
- throw Unexpected_Message("Unexpected message in handshake");
- }
-
-}
-
-/**
-* TLS Client Constructor
-*/
-TLS_Client::TLS_Client(std::tr1::function<size_t (byte[], size_t)> input_fn,
- std::tr1::function<void (const byte[], size_t)> output_fn,
- const TLS_Policy& policy,
- RandomNumberGenerator& rng) :
- input_fn(input_fn),
- policy(policy),
- rng(rng),
- writer(output_fn)
- {
- initialize();
- }
-
-void TLS_Client::add_client_cert(const X509_Certificate& cert,
- Private_Key* cert_key)
- {
- certs.push_back(std::make_pair(cert, cert_key));
- }
-
-/**
-* TLS Client Destructor
-*/
-TLS_Client::~TLS_Client()
- {
- close();
- for(size_t i = 0; i != certs.size(); i++)
- delete certs[i].second;
- delete state;
- }
-
-/**
-* Initialize a TLS client connection
-*/
-void TLS_Client::initialize()
- {
- std::string error_str;
- Alert_Type error_type = NO_ALERT_TYPE;
-
- try {
- state = 0;
- active = false;
- writer.set_version(policy.pref_version());
- do_handshake();
- }
- catch(TLS_Exception& e)
- {
- error_str = e.what();
- error_type = e.type();
- }
- catch(std::exception& e)
- {
- error_str = e.what();
- error_type = HANDSHAKE_FAILURE;
- }
-
- if(error_type != NO_ALERT_TYPE)
- {
- if(active)
- {
- active = false;
- reader.reset();
-
- writer.alert(FATAL, error_type);
- writer.reset();
- }
-
- if(state)
- {
- delete state;
- state = 0;
- }
-
- throw Stream_IO_Error("TLS_Client: Handshake failed: " + error_str);
- }
- }
-
-/**
-* Return the peer's certificate chain
-*/
-std::vector<X509_Certificate> TLS_Client::peer_cert_chain() const
- {
- return peer_certs;
- }
-
-/**
-* Write to a TLS connection
-*/
-void TLS_Client::write(const byte buf[], size_t length)
- {
- if(!active)
- throw TLS_Exception(INTERNAL_ERROR,
- "TLS_Client::write called while closed");
-
- writer.send(APPLICATION_DATA, buf, length);
- }
-
-/**
-* Read from a TLS connection
-*/
-size_t TLS_Client::read(byte out[], size_t length)
- {
- if(!active)
- return 0;
-
- writer.flush();
-
- while(read_buf.size() == 0)
- {
- state_machine();
- if(active == false)
- break;
- }
-
- size_t got = std::min<size_t>(read_buf.size(), length);
- read_buf.read(out, got);
- return got;
- }
-
-/**
-* Close a TLS connection
-*/
-void TLS_Client::close()
- {
- close(WARNING, CLOSE_NOTIFY);
- }
-
-/**
-* Check connection status
-*/
-bool TLS_Client::is_closed() const
- {
- if(!active)
- return true;
- return false;
- }
-
-/**
-* Close a TLS connection
-*/
-void TLS_Client::close(Alert_Level level, Alert_Type alert_code)
- {
- if(active)
- {
- try {
- writer.alert(level, alert_code);
- writer.flush();
- }
- catch(...) {}
-
- active = false;
- }
- }
-
-/**
-* Iterate the TLS state machine
-*/
-void TLS_Client::state_machine()
- {
- byte rec_type = CONNECTION_CLOSED;
- SecureVector<byte> record(1024);
-
- size_t bytes_needed = reader.get_record(rec_type, record);
-
- while(bytes_needed)
- {
- size_t to_get = std::min<size_t>(record.size(), bytes_needed);
- size_t got = input_fn(&record[0], to_get);
-
- if(got == 0)
- {
- rec_type = CONNECTION_CLOSED;
- break;
- }
-
- reader.add_input(&record[0], got);
-
- bytes_needed = reader.get_record(rec_type, record);
- }
-
- if(rec_type == CONNECTION_CLOSED)
- {
- active = false;
- reader.reset();
- writer.reset();
- }
- else if(rec_type == APPLICATION_DATA)
- {
- if(active)
- read_buf.write(&record[0], record.size());
- else
- throw Unexpected_Message("Application data before handshake done");
- }
- else if(rec_type == HANDSHAKE || rec_type == CHANGE_CIPHER_SPEC)
- read_handshake(rec_type, record);
- else if(rec_type == ALERT)
- {
- Alert alert(record);
-
- if(alert.is_fatal() || alert.type() == CLOSE_NOTIFY)
- {
- if(alert.type() == CLOSE_NOTIFY)
- writer.alert(WARNING, CLOSE_NOTIFY);
-
- reader.reset();
- writer.reset();
- active = false;
- if(state)
- {
- delete state;
- state = 0;
- }
- }
- }
- else
- throw Unexpected_Message("Unknown message type received");
- }
-
-/**
-* Split up and process handshake messages
-*/
-void TLS_Client::read_handshake(byte rec_type,
- const MemoryRegion<byte>& rec_buf)
- {
- if(rec_type == HANDSHAKE)
- state->queue.write(&rec_buf[0], rec_buf.size());
-
- while(true)
- {
- Handshake_Type type = HANDSHAKE_NONE;
- SecureVector<byte> contents;
-
- if(rec_type == HANDSHAKE)
- {
- if(state->queue.size() >= 4)
- {
- byte head[4] = { 0 };
- state->queue.peek(head, 4);
-
- const size_t length = make_u32bit(0, head[1], head[2], head[3]);
-
- if(state->queue.size() >= length + 4)
- {
- type = static_cast<Handshake_Type>(head[0]);
- contents.resize(length);
- state->queue.read(head, 4);
- state->queue.read(&contents[0], contents.size());
- }
- }
- }
- else if(rec_type == CHANGE_CIPHER_SPEC)
- {
- if(state->queue.size() == 0 && rec_buf.size() == 1 && rec_buf[0] == 1)
- type = HANDSHAKE_CCS;
- else
- throw Decoding_Error("Malformed ChangeCipherSpec message");
- }
- else
- throw Decoding_Error("Unknown message type in handshake processing");
-
- if(type == HANDSHAKE_NONE)
- break;
-
- process_handshake_msg(type, contents);
-
- if(type == HANDSHAKE_CCS || !state)
- break;
- }
- }
-
-/**
-* Process a handshake message
-*/
-void TLS_Client::process_handshake_msg(Handshake_Type type,
- const MemoryRegion<byte>& contents)
- {
- rng.add_entropy(&contents[0], contents.size());
-
- if(type == HELLO_REQUEST)
- {
- if(state == 0)
- state = new Handshake_State();
- else
- return;
- }
-
- if(state == 0)
- throw Unexpected_Message("Unexpected handshake message");
-
- if(type != HANDSHAKE_CCS && type != HELLO_REQUEST && type != FINISHED)
- {
- state->hash.update(static_cast<byte>(type));
- const size_t record_length = contents.size();
- for(size_t i = 0; i != 3; i++)
- state->hash.update(get_byte<u32bit>(i+1, record_length));
- state->hash.update(contents);
- }
-
- if(type == HELLO_REQUEST)
- {
- client_check_state(type, state);
-
- Hello_Request hello_request(contents);
- state->client_hello = new Client_Hello(rng, writer, policy, state->hash);
- }
- else if(type == SERVER_HELLO)
- {
- client_check_state(type, state);
-
- state->server_hello = new Server_Hello(contents);
-
- if(!state->client_hello->offered_suite(
- state->server_hello->ciphersuite()
- )
- )
- throw TLS_Exception(HANDSHAKE_FAILURE,
- "TLS_Client: Server replied with bad ciphersuite");
-
- state->version = state->server_hello->version();
-
- if(state->version > state->client_hello->version())
- throw TLS_Exception(HANDSHAKE_FAILURE,
- "TLS_Client: Server replied with bad version");
-
- if(state->version < policy.min_version())
- throw TLS_Exception(PROTOCOL_VERSION,
- "TLS_Client: Server is too old for specified policy");
-
- writer.set_version(state->version);
- reader.set_version(state->version);
-
- state->suite = CipherSuite(state->server_hello->ciphersuite());
- }
- else if(type == CERTIFICATE)
- {
- client_check_state(type, state);
-
- if(state->suite.sig_type() == TLS_ALGO_SIGNER_ANON)
- throw Unexpected_Message("Recived certificate from anonymous server");
-
- state->server_certs = new Certificate(contents);
-
- peer_certs = state->server_certs->cert_chain();
- if(peer_certs.size() == 0)
- throw TLS_Exception(HANDSHAKE_FAILURE,
- "TLS_Client: No certificates sent by server");
-
- if(!policy.check_cert(peer_certs))
- throw TLS_Exception(BAD_CERTIFICATE,
- "TLS_Client: Server certificate is not valid");
-
- state->kex_pub = peer_certs[0].subject_public_key();
-
- bool is_dsa = false, is_rsa = false;
-
- if(dynamic_cast<DSA_PublicKey*>(state->kex_pub))
- is_dsa = true;
- else if(dynamic_cast<RSA_PublicKey*>(state->kex_pub))
- is_rsa = true;
- else
- throw TLS_Exception(UNSUPPORTED_CERTIFICATE,
- "Unknown key type received in server kex");
-
- if((is_dsa && state->suite.sig_type() != TLS_ALGO_SIGNER_DSA) ||
- (is_rsa && state->suite.sig_type() != TLS_ALGO_SIGNER_RSA))
- throw TLS_Exception(ILLEGAL_PARAMETER,
- "Certificate key type did not match ciphersuite");
- }
- else if(type == SERVER_KEX)
- {
- client_check_state(type, state);
-
- if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_NOKEX)
- throw Unexpected_Message("Unexpected key exchange from server");
-
- state->server_kex = new Server_Key_Exchange(contents);
-
- if(state->kex_pub)
- delete state->kex_pub;
-
- state->kex_pub = state->server_kex->key();
-
- bool is_dh = false, is_rsa = false;
-
- if(dynamic_cast<DH_PublicKey*>(state->kex_pub))
- is_dh = true;
- else if(dynamic_cast<RSA_PublicKey*>(state->kex_pub))
- is_rsa = true;
- else
- throw TLS_Exception(HANDSHAKE_FAILURE,
- "Unknown key type received in server kex");
-
- if((is_dh && state->suite.kex_type() != TLS_ALGO_KEYEXCH_DH) ||
- (is_rsa && state->suite.kex_type() != TLS_ALGO_KEYEXCH_RSA))
- throw TLS_Exception(ILLEGAL_PARAMETER,
- "Certificate key type did not match ciphersuite");
-
- if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON)
- {
- if(!state->server_kex->verify(peer_certs[0],
- state->client_hello->random(),
- state->server_hello->random()))
- throw TLS_Exception(DECRYPT_ERROR,
- "Bad signature on server key exchange");
- }
- }
- else if(type == CERTIFICATE_REQUEST)
- {
- client_check_state(type, state);
-
- state->cert_req = new Certificate_Req(contents);
- state->do_client_auth = true;
- }
- else if(type == SERVER_HELLO_DONE)
- {
- client_check_state(type, state);
-
- state->server_hello_done = new Server_Hello_Done(contents);
-
- if(state->do_client_auth)
- {
- std::vector<X509_Certificate> send_certs;
-
- std::vector<Certificate_Type> types =
- state->cert_req->acceptable_types();
-
- // FIXME: Fill in useful certs here, if any
- state->client_certs = new Certificate(writer, send_certs,
- state->hash);
- }
-
- state->client_kex =
- new Client_Key_Exchange(rng, writer, state->hash,
- state->kex_pub, state->version,
- state->client_hello->version());
-
- if(state->do_client_auth)
- {
- Private_Key* key_matching_cert = 0; // FIXME
- state->client_verify = new Certificate_Verify(rng,
- writer, state->hash,
- key_matching_cert);
- }
-
- state->keys = SessionKeys(state->suite, state->version,
- state->client_kex->pre_master_secret(),
- state->client_hello->random(),
- state->server_hello->random());
-
- writer.send(CHANGE_CIPHER_SPEC, 1);
- writer.flush();
-
- writer.set_keys(state->suite, state->keys, CLIENT);
-
- state->client_finished = new Finished(writer, state->version, CLIENT,
- state->keys.master_secret(),
- state->hash);
- }
- else if(type == HANDSHAKE_CCS)
- {
- client_check_state(type, state);
-
- reader.set_keys(state->suite, state->keys, CLIENT);
- state->got_server_ccs = true;
- }
- else if(type == FINISHED)
- {
- client_check_state(type, state);
-
- state->server_finished = new Finished(contents);
-
- if(!state->server_finished->verify(state->keys.master_secret(),
- state->version, state->hash, SERVER))
- throw TLS_Exception(DECRYPT_ERROR,
- "Finished message didn't verify");
-
- delete state;
- state = 0;
- active = true;
- }
- else
- throw Unexpected_Message("Unknown handshake message received");
- }
-
-/**
-* Perform a client-side TLS handshake
-*/
-void TLS_Client::do_handshake()
- {
- state = new Handshake_State;
-
- state->client_hello = new Client_Hello(rng, writer, policy, state->hash);
-
- while(true)
- {
- if(active && !state)
- break;
- if(!active && !state)
- throw TLS_Exception(HANDSHAKE_FAILURE, "TLS_Client: Handshake failed (do_handshake)");
-
- state_machine();
- }
- }
-
-}