diff options
Diffstat (limited to 'src/tls')
57 files changed, 0 insertions, 11634 deletions
diff --git a/src/tls/info.txt b/src/tls/info.txt deleted file mode 100644 index adae12cb2..000000000 --- a/src/tls/info.txt +++ /dev/null @@ -1,90 +0,0 @@ -define TLS 20131128 - -load_on auto - -<header:public> -tls_alert.h -tls_blocking.h -tls_channel.h -tls_ciphersuite.h -tls_client.h -tls_exceptn.h -tls_handshake_msg.h -tls_magic.h -tls_server_info.h -tls_policy.h -tls_server.h -tls_session.h -tls_session_manager.h -tls_version.h -</header:public> - -<header:internal> -tls_extensions.h -tls_handshake_hash.h -tls_handshake_io.h -tls_handshake_state.h -tls_heartbeats.h -tls_messages.h -tls_reader.h -tls_record.h -tls_seq_numbers.h -tls_session_key.h -</header:internal> - -<source> -msg_cert_req.cpp -msg_cert_verify.cpp -msg_certificate.cpp -msg_client_hello.cpp -msg_client_kex.cpp -msg_finished.cpp -msg_hello_verify.cpp -msg_next_protocol.cpp -msg_server_hello.cpp -msg_server_kex.cpp -msg_session_ticket.cpp -tls_alert.cpp -tls_blocking.cpp -tls_channel.cpp -tls_ciphersuite.cpp -tls_client.cpp -tls_extensions.cpp -tls_handshake_hash.cpp -tls_handshake_io.cpp -tls_handshake_state.cpp -tls_heartbeats.cpp -tls_policy.cpp -tls_server.cpp -tls_session.cpp -tls_session_key.cpp -tls_session_manager_memory.cpp -tls_suite_info.cpp -tls_record.cpp -tls_version.cpp -</source> - -<requires> -aead -aes -asn1 -cbc -credentials -cryptobox_psk -dh -ecdh -eme_pkcs -emsa3 -hmac -kdf2 -md5 -prf_ssl3 -prf_tls -rng -rsa -sha1 -sha2_32 -srp6 -ssl3mac -x509 -</requires> diff --git a/src/tls/msg_cert_req.cpp b/src/tls/msg_cert_req.cpp deleted file mode 100644 index 23d59c6d4..000000000 --- a/src/tls/msg_cert_req.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* -* Certificate Request Message -* (C) 2004-2006,2012 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_extensions.h> -#include <botan/internal/tls_handshake_io.h> -#include <botan/der_enc.h> -#include <botan/ber_dec.h> -#include <botan/loadstor.h> - -namespace Botan { - -namespace TLS { - -namespace { - -std::string cert_type_code_to_name(byte code) - { - switch(code) - { - case 1: - return "RSA"; - case 2: - return "DSA"; - case 64: - return "ECDSA"; - default: - return ""; // DH or something else - } - } - -byte cert_type_name_to_code(const std::string& name) - { - if(name == "RSA") - return 1; - if(name == "DSA") - return 2; - if(name == "ECDSA") - return 64; - - throw Invalid_Argument("Unknown cert type " + name); - } - -} - -/** -* Create a new Certificate Request message -*/ -Certificate_Req::Certificate_Req(Handshake_IO& io, - Handshake_Hash& hash, - const Policy& policy, - const std::vector<X509_DN>& ca_certs, - Protocol_Version version) : - m_names(ca_certs), - m_cert_key_types({ "RSA", "DSA", "ECDSA" }) - { - if(version.supports_negotiable_signature_algorithms()) - { - std::vector<std::string> hashes = policy.allowed_signature_hashes(); - std::vector<std::string> sigs = policy.allowed_signature_methods(); - - for(size_t i = 0; i != hashes.size(); ++i) - for(size_t j = 0; j != sigs.size(); ++j) - m_supported_algos.push_back(std::make_pair(hashes[i], sigs[j])); - } - - hash.update(io.send(*this)); - } - -/** -* Deserialize a Certificate Request message -*/ -Certificate_Req::Certificate_Req(const std::vector<byte>& buf, - Protocol_Version version) - { - if(buf.size() < 4) - throw Decoding_Error("Certificate_Req: Bad certificate request"); - - TLS_Data_Reader reader(buf); - - std::vector<byte> cert_type_codes = reader.get_range_vector<byte>(1, 1, 255); - - for(size_t i = 0; i != cert_type_codes.size(); ++i) - { - const std::string cert_type_name = cert_type_code_to_name(cert_type_codes[i]); - - if(cert_type_name == "") // something we don't know - continue; - - m_cert_key_types.push_back(cert_type_name); - } - - if(version.supports_negotiable_signature_algorithms()) - { - std::vector<byte> sig_hash_algs = reader.get_range_vector<byte>(2, 2, 65534); - - if(sig_hash_algs.size() % 2 != 0) - throw Decoding_Error("Bad length for signature IDs in certificate request"); - - for(size_t i = 0; i != sig_hash_algs.size(); i += 2) - { - std::string hash = Signature_Algorithms::hash_algo_name(sig_hash_algs[i]); - std::string sig = Signature_Algorithms::sig_algo_name(sig_hash_algs[i+1]); - m_supported_algos.push_back(std::make_pair(hash, sig)); - } - } - - const u16bit purported_size = reader.get_u16bit(); - - if(reader.remaining_bytes() != purported_size) - throw Decoding_Error("Inconsistent length in certificate request"); - - while(reader.has_remaining()) - { - std::vector<byte> name_bits = reader.get_range_vector<byte>(2, 0, 65535); - - BER_Decoder decoder(&name_bits[0], name_bits.size()); - X509_DN name; - decoder.decode(name); - m_names.push_back(name); - } - } - -/** -* Serialize a Certificate Request message -*/ -std::vector<byte> Certificate_Req::serialize() const - { - std::vector<byte> buf; - - std::vector<byte> cert_types; - - for(size_t i = 0; i != m_cert_key_types.size(); ++i) - cert_types.push_back(cert_type_name_to_code(m_cert_key_types[i])); - - append_tls_length_value(buf, cert_types, 1); - - if(!m_supported_algos.empty()) - buf += Signature_Algorithms(m_supported_algos).serialize(); - - std::vector<byte> encoded_names; - - for(size_t i = 0; i != m_names.size(); ++i) - { - DER_Encoder encoder; - encoder.encode(m_names[i]); - - append_tls_length_value(encoded_names, encoder.get_contents(), 2); - } - - append_tls_length_value(buf, encoded_names, 2); - - return buf; - } - -} - -} diff --git a/src/tls/msg_cert_verify.cpp b/src/tls/msg_cert_verify.cpp deleted file mode 100644 index 436b84c24..000000000 --- a/src/tls/msg_cert_verify.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* -* Certificate Verify Message -* (C) 2004,2006,2011,2012 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_extensions.h> -#include <botan/internal/tls_handshake_io.h> -#include <memory> - -namespace Botan { - -namespace TLS { - -/* -* Create a new Certificate Verify message -*/ -Certificate_Verify::Certificate_Verify(Handshake_IO& io, - Handshake_State& state, - const Policy& policy, - RandomNumberGenerator& rng, - const Private_Key* priv_key) - { - BOTAN_ASSERT_NONNULL(priv_key); - - std::pair<std::string, Signature_Format> format = - state.choose_sig_format(*priv_key, m_hash_algo, m_sig_algo, true, policy); - - PK_Signer signer(*priv_key, format.first, format.second); - - if(state.version() == Protocol_Version::SSL_V3) - { - secure_vector<byte> md5_sha = state.hash().final_ssl3( - state.session_keys().master_secret()); - - if(priv_key->algo_name() == "DSA") - m_signature = signer.sign_message(&md5_sha[16], md5_sha.size()-16, rng); - else - m_signature = signer.sign_message(md5_sha, rng); - } - else - { - m_signature = signer.sign_message(state.hash().get_contents(), rng); - } - - state.hash().update(io.send(*this)); - } - -/* -* Deserialize a Certificate Verify message -*/ -Certificate_Verify::Certificate_Verify(const std::vector<byte>& buf, - Protocol_Version version) - { - TLS_Data_Reader reader(buf); - - if(version.supports_negotiable_signature_algorithms()) - { - m_hash_algo = Signature_Algorithms::hash_algo_name(reader.get_byte()); - m_sig_algo = Signature_Algorithms::sig_algo_name(reader.get_byte()); - } - - m_signature = reader.get_range<byte>(2, 0, 65535); - } - -/* -* Serialize a Certificate Verify message -*/ -std::vector<byte> Certificate_Verify::serialize() const - { - std::vector<byte> buf; - - if(m_hash_algo != "" && m_sig_algo != "") - { - buf.push_back(Signature_Algorithms::hash_algo_code(m_hash_algo)); - buf.push_back(Signature_Algorithms::sig_algo_code(m_sig_algo)); - } - - const u16bit sig_len = m_signature.size(); - buf.push_back(get_byte(0, sig_len)); - buf.push_back(get_byte(1, sig_len)); - buf += m_signature; - - return buf; - } - -/* -* Verify a Certificate Verify message -*/ -bool Certificate_Verify::verify(const X509_Certificate& cert, - const Handshake_State& state) const - { - std::unique_ptr<Public_Key> key(cert.subject_public_key()); - - std::pair<std::string, Signature_Format> format = - state.understand_sig_format(*key.get(), m_hash_algo, m_sig_algo, true); - - PK_Verifier verifier(*key, format.first, format.second); - - if(state.version() == Protocol_Version::SSL_V3) - { - secure_vector<byte> md5_sha = state.hash().final_ssl3( - state.session_keys().master_secret()); - - return verifier.verify_message(&md5_sha[16], md5_sha.size()-16, - &m_signature[0], m_signature.size()); - } - - return verifier.verify_message(state.hash().get_contents(), m_signature); - } - -} - -} diff --git a/src/tls/msg_certificate.cpp b/src/tls/msg_certificate.cpp deleted file mode 100644 index 417ad34ce..000000000 --- a/src/tls/msg_certificate.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* -* Certificate Message -* (C) 2004-2006,2012 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_extensions.h> -#include <botan/internal/tls_handshake_io.h> -#include <botan/der_enc.h> -#include <botan/ber_dec.h> -#include <botan/loadstor.h> - -namespace Botan { - -namespace TLS { - -/** -* Create a new Certificate message -*/ -Certificate::Certificate(Handshake_IO& io, - Handshake_Hash& hash, - const std::vector<X509_Certificate>& cert_list) : - m_certs(cert_list) - { - hash.update(io.send(*this)); - } - -/** -* Deserialize a Certificate message -*/ -Certificate::Certificate(const std::vector<byte>& buf) - { - if(buf.size() < 3) - throw Decoding_Error("Certificate: Message malformed"); - - const size_t total_size = make_u32bit(0, buf[0], buf[1], buf[2]); - - if(total_size != buf.size() - 3) - throw Decoding_Error("Certificate: Message malformed"); - - const byte* certs = &buf[3]; - - while(size_t remaining_bytes = &buf[buf.size()] - certs) - { - if(remaining_bytes < 3) - throw Decoding_Error("Certificate: Message malformed"); - - const size_t cert_size = make_u32bit(0, certs[0], certs[1], certs[2]); - - if(remaining_bytes < (3 + cert_size)) - throw Decoding_Error("Certificate: Message malformed"); - - DataSource_Memory cert_buf(&certs[3], cert_size); - m_certs.push_back(X509_Certificate(cert_buf)); - - certs += cert_size + 3; - } - } - -/** -* Serialize a Certificate message -*/ -std::vector<byte> Certificate::serialize() const - { - std::vector<byte> buf(3); - - for(size_t i = 0; i != m_certs.size(); ++i) - { - std::vector<byte> raw_cert = m_certs[i].BER_encode(); - const size_t cert_size = raw_cert.size(); - for(size_t i = 0; i != 3; ++i) - buf.push_back(get_byte<u32bit>(i+1, cert_size)); - buf += raw_cert; - } - - const size_t buf_size = buf.size() - 3; - for(size_t i = 0; i != 3; ++i) - buf[i] = get_byte<u32bit>(i+1, buf_size); - - return buf; - } - -} - -} diff --git a/src/tls/msg_client_hello.cpp b/src/tls/msg_client_hello.cpp deleted file mode 100644 index 0d91af472..000000000 --- a/src/tls/msg_client_hello.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* -* TLS Hello Request and Client Hello Messages -* (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_handshake_io.h> -#include <botan/internal/stl_util.h> -#include <chrono> - -namespace Botan { - -namespace TLS { - -enum { - TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF -}; - -std::vector<byte> make_hello_random(RandomNumberGenerator& rng) - { - std::vector<byte> buf(32); - - const u32bit time32 = static_cast<u32bit>( - std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); - - store_be(time32, &buf[0]); - rng.randomize(&buf[4], buf.size() - 4); - return buf; - } - -/* -* Create a new Hello Request message -*/ -Hello_Request::Hello_Request(Handshake_IO& io) - { - io.send(*this); - } - -/* -* Deserialize a Hello Request message -*/ -Hello_Request::Hello_Request(const std::vector<byte>& buf) - { - if(buf.size()) - throw Decoding_Error("Bad Hello_Request, has non-zero size"); - } - -/* -* Serialize a Hello Request message -*/ -std::vector<byte> Hello_Request::serialize() const - { - return std::vector<byte>(); - } - -/* -* Create a new Client Hello message -*/ -Client_Hello::Client_Hello(Handshake_IO& io, - Handshake_Hash& hash, - Protocol_Version version, - const Policy& policy, - RandomNumberGenerator& rng, - const std::vector<byte>& reneg_info, - bool next_protocol, - const std::string& hostname, - const std::string& srp_identifier) : - m_version(version), - m_random(make_hello_random(rng)), - m_suites(policy.ciphersuite_list(m_version, (srp_identifier != ""))), - m_comp_methods(policy.compression()) - { - m_extensions.add(new Renegotiation_Extension(reneg_info)); - m_extensions.add(new SRP_Identifier(srp_identifier)); - m_extensions.add(new Server_Name_Indicator(hostname)); - m_extensions.add(new Session_Ticket()); - m_extensions.add(new Supported_Elliptic_Curves(policy.allowed_ecc_curves())); - - if(policy.negotiate_heartbeat_support()) - m_extensions.add(new Heartbeat_Support_Indicator(true)); - - if(m_version.supports_negotiable_signature_algorithms()) - m_extensions.add(new Signature_Algorithms(policy.allowed_signature_hashes(), - policy.allowed_signature_methods())); - - if(reneg_info.empty() && next_protocol) - m_extensions.add(new Next_Protocol_Notification()); - - hash.update(io.send(*this)); - } - -/* -* Create a new Client Hello message (session resumption case) -*/ -Client_Hello::Client_Hello(Handshake_IO& io, - Handshake_Hash& hash, - const Policy& policy, - RandomNumberGenerator& rng, - const std::vector<byte>& reneg_info, - const Session& session, - bool next_protocol) : - m_version(session.version()), - m_session_id(session.session_id()), - m_random(make_hello_random(rng)), - m_suites(policy.ciphersuite_list(m_version, (session.srp_identifier() != ""))), - m_comp_methods(policy.compression()) - { - if(!value_exists(m_suites, session.ciphersuite_code())) - m_suites.push_back(session.ciphersuite_code()); - - if(!value_exists(m_comp_methods, session.compression_method())) - m_comp_methods.push_back(session.compression_method()); - - m_extensions.add(new Renegotiation_Extension(reneg_info)); - m_extensions.add(new SRP_Identifier(session.srp_identifier())); - m_extensions.add(new Server_Name_Indicator(session.server_info().hostname())); - m_extensions.add(new Session_Ticket(session.session_ticket())); - m_extensions.add(new Supported_Elliptic_Curves(policy.allowed_ecc_curves())); - - if(policy.negotiate_heartbeat_support()) - m_extensions.add(new Heartbeat_Support_Indicator(true)); - - if(session.fragment_size() != 0) - m_extensions.add(new Maximum_Fragment_Length(session.fragment_size())); - - if(m_version.supports_negotiable_signature_algorithms()) - m_extensions.add(new Signature_Algorithms(policy.allowed_signature_hashes(), - policy.allowed_signature_methods())); - - if(reneg_info.empty() && next_protocol) - m_extensions.add(new Next_Protocol_Notification()); - - hash.update(io.send(*this)); - } - -/* -* Read a counterparty client hello -*/ -Client_Hello::Client_Hello(const std::vector<byte>& buf, Handshake_Type type) - { - if(type == CLIENT_HELLO) - deserialize(buf); - else - deserialize_sslv2(buf); - } - -void Client_Hello::update_hello_cookie(const Hello_Verify_Request& hello_verify) - { - if(!m_version.is_datagram_protocol()) - throw std::runtime_error("Cannot use hello cookie with stream protocol"); - - m_hello_cookie = hello_verify.cookie(); - } - -/* -* Serialize a Client Hello message -*/ -std::vector<byte> Client_Hello::serialize() const - { - std::vector<byte> buf; - - buf.push_back(m_version.major_version()); - buf.push_back(m_version.minor_version()); - buf += m_random; - - append_tls_length_value(buf, m_session_id, 1); - - if(m_version.is_datagram_protocol()) - append_tls_length_value(buf, m_hello_cookie, 1); - - append_tls_length_value(buf, m_suites, 2); - append_tls_length_value(buf, m_comp_methods, 1); - - /* - * May not want to send extensions at all in some cases. If so, - * should include SCSV value (if reneg info is empty, if not we are - * renegotiating with a modern server) - */ - - buf += m_extensions.serialize(); - - return buf; - } - -void Client_Hello::deserialize_sslv2(const std::vector<byte>& buf) - { - if(buf.size() < 12 || buf[0] != 1) - throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); - - const size_t cipher_spec_len = make_u16bit(buf[3], buf[4]); - const size_t m_session_id_len = make_u16bit(buf[5], buf[6]); - const size_t challenge_len = make_u16bit(buf[7], buf[8]); - - const size_t expected_size = - (9 + m_session_id_len + cipher_spec_len + challenge_len); - - if(buf.size() != expected_size) - throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); - - if(m_session_id_len != 0 || cipher_spec_len % 3 != 0 || - (challenge_len < 16 || challenge_len > 32)) - { - throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); - } - - m_version = Protocol_Version(buf[1], buf[2]); - - for(size_t i = 9; i != 9 + cipher_spec_len; i += 3) - { - if(buf[i] != 0) // a SSLv2 cipherspec; ignore it - continue; - - m_suites.push_back(make_u16bit(buf[i+1], buf[i+2])); - } - - m_random.resize(challenge_len); - copy_mem(&m_random[0], &buf[9+cipher_spec_len+m_session_id_len], challenge_len); - - if(offered_suite(static_cast<u16bit>(TLS_EMPTY_RENEGOTIATION_INFO_SCSV))) - m_extensions.add(new Renegotiation_Extension()); - } - -/* -* Deserialize a Client Hello message -*/ -void Client_Hello::deserialize(const std::vector<byte>& buf) - { - if(buf.size() == 0) - throw Decoding_Error("Client_Hello: Packet corrupted"); - - if(buf.size() < 41) - throw Decoding_Error("Client_Hello: Packet corrupted"); - - TLS_Data_Reader reader(buf); - - const byte major_version = reader.get_byte(); - const byte minor_version = reader.get_byte(); - - m_version = Protocol_Version(major_version, minor_version); - - m_random = reader.get_fixed<byte>(32); - - if(m_version.is_datagram_protocol()) - m_hello_cookie = reader.get_range<byte>(1, 0, 255); - - m_session_id = reader.get_range<byte>(1, 0, 32); - - m_suites = reader.get_range_vector<u16bit>(2, 1, 32767); - - m_comp_methods = reader.get_range_vector<byte>(1, 1, 255); - - m_extensions.deserialize(reader); - - if(offered_suite(static_cast<u16bit>(TLS_EMPTY_RENEGOTIATION_INFO_SCSV))) - { - if(Renegotiation_Extension* reneg = m_extensions.get<Renegotiation_Extension>()) - { - if(!reneg->renegotiation_info().empty()) - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Client send renegotiation SCSV and non-empty extension"); - } - else - { - // add fake extension - m_extensions.add(new Renegotiation_Extension()); - } - } - } - -/* -* Check if we offered this ciphersuite -*/ -bool Client_Hello::offered_suite(u16bit ciphersuite) const - { - for(size_t i = 0; i != m_suites.size(); ++i) - if(m_suites[i] == ciphersuite) - return true; - return false; - } - -} - -} diff --git a/src/tls/msg_client_kex.cpp b/src/tls/msg_client_kex.cpp deleted file mode 100644 index ae8b82fd4..000000000 --- a/src/tls/msg_client_kex.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* -* Client Key Exchange Message -* (C) 2004-2010 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_extensions.h> -#include <botan/internal/tls_handshake_io.h> -#include <botan/credentials_manager.h> -#include <botan/pubkey.h> -#include <botan/dh.h> -#include <botan/ecdh.h> -#include <botan/rsa.h> -#include <botan/srp6.h> -#include <botan/rng.h> -#include <botan/loadstor.h> -#include <memory> - -namespace Botan { - -namespace TLS { - -namespace { - -secure_vector<byte> strip_leading_zeros(const secure_vector<byte>& input) - { - size_t leading_zeros = 0; - - for(size_t i = 0; i != input.size(); ++i) - { - if(input[i] != 0) - break; - ++leading_zeros; - } - - secure_vector<byte> output(&input[leading_zeros], - &input[input.size()]); - return output; - } - -} - -/* -* Create a new Client Key Exchange message -*/ -Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io, - Handshake_State& state, - const Policy& policy, - Credentials_Manager& creds, - const Public_Key* server_public_key, - const std::string& hostname, - RandomNumberGenerator& rng) - { - const std::string kex_algo = state.ciphersuite().kex_algo(); - - if(kex_algo == "PSK") - { - std::string identity_hint = ""; - - if(state.server_kex()) - { - TLS_Data_Reader reader(state.server_kex()->params()); - identity_hint = reader.get_string(2, 0, 65535); - } - - const std::string hostname = state.client_hello()->sni_hostname(); - - const std::string psk_identity = creds.psk_identity("tls-client", - hostname, - identity_hint); - - append_tls_length_value(m_key_material, psk_identity, 2); - - SymmetricKey psk = creds.psk("tls-client", hostname, psk_identity); - - std::vector<byte> zeros(psk.length()); - - append_tls_length_value(m_pre_master, zeros, 2); - append_tls_length_value(m_pre_master, psk.bits_of(), 2); - } - else if(state.server_kex()) - { - TLS_Data_Reader reader(state.server_kex()->params()); - - SymmetricKey psk; - - if(kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") - { - std::string identity_hint = reader.get_string(2, 0, 65535); - - const std::string hostname = state.client_hello()->sni_hostname(); - - const std::string psk_identity = creds.psk_identity("tls-client", - hostname, - identity_hint); - - append_tls_length_value(m_key_material, psk_identity, 2); - - psk = creds.psk("tls-client", hostname, psk_identity); - } - - if(kex_algo == "DH" || kex_algo == "DHE_PSK") - { - BigInt p = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); - BigInt g = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); - BigInt Y = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); - - if(reader.remaining_bytes()) - throw Decoding_Error("Bad params size for DH key exchange"); - - if(p.bits() < policy.minimum_dh_group_size()) - throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, - "Server sent DH group of " + - std::to_string(p.bits()) + - " bits, policy requires at least " + - std::to_string(policy.minimum_dh_group_size())); - - /* - * A basic check for key validity. As we do not know q here we - * cannot check that Y is in the right subgroup. However since - * our key is ephemeral there does not seem to be any - * advantage to bogus keys anyway. - */ - if(Y <= 1 || Y >= p - 1) - throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, - "Server sent bad DH key for DHE exchange"); - - DL_Group group(p, g); - - if(!group.verify_group(rng, true)) - throw Internal_Error("DH group failed validation, possible attack"); - - DH_PublicKey counterparty_key(group, Y); - - DH_PrivateKey priv_key(rng, group); - - PK_Key_Agreement ka(priv_key, "Raw"); - - secure_vector<byte> dh_secret = strip_leading_zeros( - ka.derive_key(0, counterparty_key.public_value()).bits_of()); - - if(kex_algo == "DH") - m_pre_master = dh_secret; - else - { - append_tls_length_value(m_pre_master, dh_secret, 2); - append_tls_length_value(m_pre_master, psk.bits_of(), 2); - } - - append_tls_length_value(m_key_material, priv_key.public_value(), 2); - } - else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK") - { - const byte curve_type = reader.get_byte(); - - if(curve_type != 3) - throw Decoding_Error("Server sent non-named ECC curve"); - - const u16bit curve_id = reader.get_u16bit(); - - const std::string name = Supported_Elliptic_Curves::curve_id_to_name(curve_id); - - if(name == "") - throw Decoding_Error("Server sent unknown named curve " + std::to_string(curve_id)); - - EC_Group group(name); - - std::vector<byte> ecdh_key = reader.get_range<byte>(1, 1, 255); - - ECDH_PublicKey counterparty_key(group, OS2ECP(ecdh_key, group.get_curve())); - - ECDH_PrivateKey priv_key(rng, group); - - PK_Key_Agreement ka(priv_key, "Raw"); - - secure_vector<byte> ecdh_secret = - ka.derive_key(0, counterparty_key.public_value()).bits_of(); - - if(kex_algo == "ECDH") - m_pre_master = ecdh_secret; - else - { - append_tls_length_value(m_pre_master, ecdh_secret, 2); - append_tls_length_value(m_pre_master, psk.bits_of(), 2); - } - - append_tls_length_value(m_key_material, priv_key.public_value(), 1); - } - else if(kex_algo == "SRP_SHA") - { - const BigInt N = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); - const BigInt g = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); - std::vector<byte> salt = reader.get_range<byte>(1, 1, 255); - const BigInt B = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); - - const std::string srp_group = srp6_group_identifier(N, g); - - const std::string srp_identifier = - creds.srp_identifier("tls-client", hostname); - - const std::string srp_password = - creds.srp_password("tls-client", hostname, srp_identifier); - - std::pair<BigInt, SymmetricKey> srp_vals = - srp6_client_agree(srp_identifier, - srp_password, - srp_group, - "SHA-1", - salt, - B, - rng); - - append_tls_length_value(m_key_material, BigInt::encode(srp_vals.first), 2); - m_pre_master = srp_vals.second.bits_of(); - } - else - { - throw Internal_Error("Client_Key_Exchange: Unknown kex " + - kex_algo); - } - - reader.assert_done(); - } - else - { - // No server key exchange msg better mean RSA kex + RSA key in cert - - if(kex_algo != "RSA") - throw Unexpected_Message("No server kex but negotiated kex " + kex_algo); - - if(!server_public_key) - throw Internal_Error("No server public key for RSA exchange"); - - if(auto rsa_pub = dynamic_cast<const RSA_PublicKey*>(server_public_key)) - { - const Protocol_Version offered_version = state.client_hello()->version(); - - m_pre_master = rng.random_vec(48); - m_pre_master[0] = offered_version.major_version(); - m_pre_master[1] = offered_version.minor_version(); - - PK_Encryptor_EME encryptor(*rsa_pub, "PKCS1v15"); - - std::vector<byte> encrypted_key = encryptor.encrypt(m_pre_master, rng); - - if(state.version() == Protocol_Version::SSL_V3) - m_key_material = encrypted_key; // no length field - else - append_tls_length_value(m_key_material, encrypted_key, 2); - } - else - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Expected a RSA key in server cert but got " + - server_public_key->algo_name()); - } - - state.hash().update(io.send(*this)); - } - -/* -* Read a Client Key Exchange message -*/ -Client_Key_Exchange::Client_Key_Exchange(const std::vector<byte>& contents, - const Handshake_State& state, - const Private_Key* server_rsa_kex_key, - Credentials_Manager& creds, - const Policy& policy, - RandomNumberGenerator& rng) - { - const std::string kex_algo = state.ciphersuite().kex_algo(); - - if(kex_algo == "RSA") - { - BOTAN_ASSERT(state.server_certs() && !state.server_certs()->cert_chain().empty(), - "RSA key exchange negotiated so server sent a certificate"); - - if(!server_rsa_kex_key) - throw Internal_Error("Expected RSA kex but no server kex key set"); - - if(!dynamic_cast<const RSA_PrivateKey*>(server_rsa_kex_key)) - throw Internal_Error("Expected RSA key but got " + server_rsa_kex_key->algo_name()); - - PK_Decryptor_EME decryptor(*server_rsa_kex_key, "PKCS1v15"); - - Protocol_Version client_version = state.client_hello()->version(); - - /* - * This is used as the pre-master if RSA decryption fails. - * Otherwise we can be used as an oracle. See Bleichenbacher - * "Chosen Ciphertext Attacks against Protocols Based on RSA - * Encryption Standard PKCS #1", Crypto 98 - * - * Create it here instead if in the catch clause as otherwise we - * expose a timing channel WRT the generation of the fake value. - * Some timing channel likely remains due to exception handling - * and the like. - */ - secure_vector<byte> fake_pre_master = rng.random_vec(48); - fake_pre_master[0] = client_version.major_version(); - fake_pre_master[1] = client_version.minor_version(); - - try - { - if(state.version() == Protocol_Version::SSL_V3) - { - m_pre_master = decryptor.decrypt(contents); - } - else - { - TLS_Data_Reader reader(contents); - m_pre_master = decryptor.decrypt(reader.get_range<byte>(2, 0, 65535)); - } - - if(m_pre_master.size() != 48 || - client_version.major_version() != m_pre_master[0] || - client_version.minor_version() != m_pre_master[1]) - { - throw Decoding_Error("Client_Key_Exchange: Secret corrupted"); - } - } - catch(...) - { - m_pre_master = fake_pre_master; - } - } - else - { - TLS_Data_Reader reader(contents); - - SymmetricKey psk; - - if(kex_algo == "PSK" || kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") - { - const std::string psk_identity = reader.get_string(2, 0, 65535); - - psk = creds.psk("tls-server", - state.client_hello()->sni_hostname(), - psk_identity); - - if(psk.length() == 0) - { - if(policy.hide_unknown_users()) - psk = SymmetricKey(rng, 16); - else - throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, - "No PSK for identifier " + psk_identity); - } - } - - if(kex_algo == "PSK") - { - std::vector<byte> zeros(psk.length()); - append_tls_length_value(m_pre_master, zeros, 2); - append_tls_length_value(m_pre_master, psk.bits_of(), 2); - } - else if(kex_algo == "SRP_SHA") - { - SRP6_Server_Session& srp = state.server_kex()->server_srp_params(); - - m_pre_master = srp.step2(BigInt::decode(reader.get_range<byte>(2, 0, 65535))).bits_of(); - } - else if(kex_algo == "DH" || kex_algo == "DHE_PSK" || - kex_algo == "ECDH" || kex_algo == "ECDHE_PSK") - { - const Private_Key& private_key = state.server_kex()->server_kex_key(); - - const PK_Key_Agreement_Key* ka_key = - dynamic_cast<const PK_Key_Agreement_Key*>(&private_key); - - if(!ka_key) - throw Internal_Error("Expected key agreement key type but got " + - private_key.algo_name()); - - try - { - PK_Key_Agreement ka(*ka_key, "Raw"); - - std::vector<byte> client_pubkey; - - if(ka_key->algo_name() == "DH") - client_pubkey = reader.get_range<byte>(2, 0, 65535); - else - client_pubkey = reader.get_range<byte>(1, 0, 255); - - secure_vector<byte> shared_secret = ka.derive_key(0, client_pubkey).bits_of(); - - if(ka_key->algo_name() == "DH") - shared_secret = strip_leading_zeros(shared_secret); - - if(kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") - { - append_tls_length_value(m_pre_master, shared_secret, 2); - append_tls_length_value(m_pre_master, psk.bits_of(), 2); - } - else - m_pre_master = shared_secret; - } - catch(std::exception &e) - { - /* - * Something failed in the DH computation. To avoid possible - * timing attacks, randomize the pre-master output and carry - * on, allowing the protocol to fail later in the finished - * checks. - */ - m_pre_master = rng.random_vec(ka_key->public_value().size()); - } - } - else - throw Internal_Error("Client_Key_Exchange: Unknown kex type " + kex_algo); - } - } - -} - -} diff --git a/src/tls/msg_finished.cpp b/src/tls/msg_finished.cpp deleted file mode 100644 index c018497c8..000000000 --- a/src/tls/msg_finished.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* -* Finished Message -* (C) 2004-2006,2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/internal/tls_messages.h> -#include <botan/internal/tls_handshake_io.h> -#include <memory> - -namespace Botan { - -namespace TLS { - -namespace { - -/* -* Compute the verify_data -*/ -std::vector<byte> finished_compute_verify(const Handshake_State& state, - Connection_Side side) - { - if(state.version() == Protocol_Version::SSL_V3) - { - const byte SSL_CLIENT_LABEL[] = { 0x43, 0x4C, 0x4E, 0x54 }; - const byte SSL_SERVER_LABEL[] = { 0x53, 0x52, 0x56, 0x52 }; - - Handshake_Hash hash = state.hash(); // don't modify state - - std::vector<byte> ssl3_finished; - - if(side == CLIENT) - hash.update(SSL_CLIENT_LABEL, sizeof(SSL_CLIENT_LABEL)); - else - hash.update(SSL_SERVER_LABEL, sizeof(SSL_SERVER_LABEL)); - - return unlock(hash.final_ssl3(state.session_keys().master_secret())); - } - else - { - const byte TLS_CLIENT_LABEL[] = { - 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x69, - 0x73, 0x68, 0x65, 0x64 }; - - const byte TLS_SERVER_LABEL[] = { - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6E, 0x69, - 0x73, 0x68, 0x65, 0x64 }; - - std::unique_ptr<KDF> prf(state.protocol_specific_prf()); - - std::vector<byte> input; - if(side == CLIENT) - input += std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL)); - else - input += std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL)); - - input += state.hash().final(state.version(), state.ciphersuite().prf_algo()); - - return unlock(prf->derive_key(12, state.session_keys().master_secret(), input)); - } - } - -} - -/* -* Create a new Finished message -*/ -Finished::Finished(Handshake_IO& io, - Handshake_State& state, - Connection_Side side) - { - m_verification_data = finished_compute_verify(state, side); - state.hash().update(io.send(*this)); - } - -/* -* Serialize a Finished message -*/ -std::vector<byte> Finished::serialize() const - { - return m_verification_data; - } - -/* -* Deserialize a Finished message -*/ -Finished::Finished(const std::vector<byte>& buf) - { - m_verification_data = buf; - } - -/* -* Verify a Finished message -*/ -bool Finished::verify(const Handshake_State& state, - Connection_Side side) const - { - return (m_verification_data == finished_compute_verify(state, side)); - } - -} - -} diff --git a/src/tls/msg_hello_verify.cpp b/src/tls/msg_hello_verify.cpp deleted file mode 100644 index f8a117c03..000000000 --- a/src/tls/msg_hello_verify.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* -* DTLS Hello Verify Request -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/internal/tls_messages.h> -#include <botan/lookup.h> -#include <memory> - -namespace Botan { - -namespace TLS { - -Hello_Verify_Request::Hello_Verify_Request(const std::vector<byte>& buf) - { - if(buf.size() < 3) - throw Decoding_Error("Hello verify request too small"); - - Protocol_Version version(buf[0], buf[1]); - - if(version != Protocol_Version::DTLS_V10 && - version != Protocol_Version::DTLS_V12) - { - throw Decoding_Error("Unknown version from server in hello verify request"); - } - - if(static_cast<size_t>(buf[2]) + 3 != buf.size()) - throw Decoding_Error("Bad length in hello verify request"); - - m_cookie.assign(&buf[3], &buf[buf.size()]); - } - -Hello_Verify_Request::Hello_Verify_Request(const std::vector<byte>& client_hello_bits, - const std::string& client_identity, - const SymmetricKey& secret_key) - { - std::unique_ptr<MessageAuthenticationCode> hmac(get_mac("HMAC(SHA-256)")); - hmac->set_key(secret_key); - - hmac->update_be(client_hello_bits.size()); - hmac->update(client_hello_bits); - hmac->update_be(client_identity.size()); - hmac->update(client_identity); - - m_cookie = unlock(hmac->final()); - } - -std::vector<byte> Hello_Verify_Request::serialize() const - { - /* DTLS 1.2 server implementations SHOULD use DTLS version 1.0 - regardless of the version of TLS that is expected to be - negotiated (RFC 6347, section 4.2.1) - */ - - Protocol_Version format_version(Protocol_Version::DTLS_V10); - - std::vector<byte> bits; - bits.push_back(format_version.major_version()); - bits.push_back(format_version.minor_version()); - bits.push_back(static_cast<byte>(m_cookie.size())); - bits += m_cookie; - return bits; - } - -} - -} diff --git a/src/tls/msg_next_protocol.cpp b/src/tls/msg_next_protocol.cpp deleted file mode 100644 index a09fd02d1..000000000 --- a/src/tls/msg_next_protocol.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* -* Next Protocol Negotiation -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/internal/tls_messages.h> -#include <botan/internal/tls_extensions.h> -#include <botan/internal/tls_reader.h> -#include <botan/internal/tls_handshake_io.h> - -namespace Botan { - -namespace TLS { - -Next_Protocol::Next_Protocol(Handshake_IO& io, - Handshake_Hash& hash, - const std::string& protocol) : - m_protocol(protocol) - { - hash.update(io.send(*this)); - } - -Next_Protocol::Next_Protocol(const std::vector<byte>& buf) - { - TLS_Data_Reader reader(buf); - - m_protocol = reader.get_string(1, 0, 255); - - reader.get_range_vector<byte>(1, 0, 255); // padding, ignored - } - -std::vector<byte> Next_Protocol::serialize() const - { - std::vector<byte> buf; - - append_tls_length_value(buf, - reinterpret_cast<const byte*>(m_protocol.data()), - m_protocol.size(), - 1); - - const byte padding_len = 32 - ((m_protocol.size() + 2) % 32); - - buf.push_back(padding_len); - - for(size_t i = 0; i != padding_len; ++i) - buf.push_back(0); - - return buf; - } - -} - -} diff --git a/src/tls/msg_server_hello.cpp b/src/tls/msg_server_hello.cpp deleted file mode 100644 index a775e0b4b..000000000 --- a/src/tls/msg_server_hello.cpp +++ /dev/null @@ -1,142 +0,0 @@ -;/* -* 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/internal/tls_handshake_io.h> -#include <botan/internal/stl_util.h> - -namespace Botan { - -namespace TLS { - -/* -* Create a new Server Hello message -*/ -Server_Hello::Server_Hello(Handshake_IO& io, - Handshake_Hash& hash, - const Policy& policy, - const std::vector<byte>& session_id, - Protocol_Version ver, - u16bit ciphersuite, - byte compression, - size_t max_fragment_size, - bool client_has_secure_renegotiation, - const std::vector<byte>& reneg_info, - bool offer_session_ticket, - bool client_has_npn, - const std::vector<std::string>& next_protocols, - bool client_has_heartbeat, - RandomNumberGenerator& rng) : - m_version(ver), - m_session_id(session_id), - m_random(make_hello_random(rng)), - m_ciphersuite(ciphersuite), - m_comp_method(compression) - { - if(client_has_heartbeat && policy.negotiate_heartbeat_support()) - m_extensions.add(new Heartbeat_Support_Indicator(true)); - - /* - * Even a client that offered SSLv3 and sent the SCSV will get an - * extension back. This is probably the right thing to do. - */ - if(client_has_secure_renegotiation) - m_extensions.add(new Renegotiation_Extension(reneg_info)); - - if(max_fragment_size) - m_extensions.add(new Maximum_Fragment_Length(max_fragment_size)); - - if(client_has_npn) - m_extensions.add(new Next_Protocol_Notification(next_protocols)); - - if(offer_session_ticket) - m_extensions.add(new Session_Ticket()); - - hash.update(io.send(*this)); - } - -/* -* Deserialize a Server Hello message -*/ -Server_Hello::Server_Hello(const std::vector<byte>& buf) - { - if(buf.size() < 38) - throw Decoding_Error("Server_Hello: Packet corrupted"); - - TLS_Data_Reader reader(buf); - - const byte major_version = reader.get_byte(); - const byte minor_version = reader.get_byte(); - - m_version = Protocol_Version(major_version, minor_version); - - m_random = reader.get_fixed<byte>(32); - - m_session_id = reader.get_range<byte>(1, 0, 32); - - m_ciphersuite = reader.get_u16bit(); - - m_comp_method = reader.get_byte(); - - m_extensions.deserialize(reader); - } - -/* -* Serialize a Server Hello message -*/ -std::vector<byte> Server_Hello::serialize() const - { - std::vector<byte> buf; - - buf.push_back(m_version.major_version()); - buf.push_back(m_version.minor_version()); - buf += m_random; - - append_tls_length_value(buf, m_session_id, 1); - - buf.push_back(get_byte(0, m_ciphersuite)); - buf.push_back(get_byte(1, m_ciphersuite)); - - buf.push_back(m_comp_method); - - buf += m_extensions.serialize(); - - return buf; - } - -/* -* Create a new Server Hello Done message -*/ -Server_Hello_Done::Server_Hello_Done(Handshake_IO& io, - Handshake_Hash& hash) - { - hash.update(io.send(*this)); - } - -/* -* Deserialize a Server Hello Done message -*/ -Server_Hello_Done::Server_Hello_Done(const std::vector<byte>& buf) - { - if(buf.size()) - throw Decoding_Error("Server_Hello_Done: Must be empty, and is not"); - } - -/* -* Serialize a Server Hello Done message -*/ -std::vector<byte> Server_Hello_Done::serialize() const - { - return std::vector<byte>(); - } - -} - -} diff --git a/src/tls/msg_server_kex.cpp b/src/tls/msg_server_kex.cpp deleted file mode 100644 index b8293d3e8..000000000 --- a/src/tls/msg_server_kex.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/* -* Server Key Exchange Message -* (C) 2004-2010,2012 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_extensions.h> -#include <botan/internal/tls_handshake_io.h> -#include <botan/credentials_manager.h> -#include <botan/loadstor.h> -#include <botan/pubkey.h> -#include <botan/dh.h> -#include <botan/ecdh.h> -#include <botan/rsa.h> -#include <botan/srp6.h> -#include <botan/oids.h> -#include <memory> - -namespace Botan { - -namespace TLS { - -/** -* Create a new Server Key Exchange message -*/ -Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, - Handshake_State& state, - const Policy& policy, - Credentials_Manager& creds, - RandomNumberGenerator& rng, - const Private_Key* signing_key) - { - const std::string hostname = state.client_hello()->sni_hostname(); - const std::string kex_algo = state.ciphersuite().kex_algo(); - - if(kex_algo == "PSK" || kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") - { - std::string identity_hint = - creds.psk_identity_hint("tls-server", hostname); - - append_tls_length_value(m_params, identity_hint, 2); - } - - if(kex_algo == "DH" || kex_algo == "DHE_PSK") - { - std::unique_ptr<DH_PrivateKey> dh(new DH_PrivateKey(rng, policy.dh_group())); - - append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_p()), 2); - append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_g()), 2); - append_tls_length_value(m_params, dh->public_value(), 2); - m_kex_key.reset(dh.release()); - } - else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK") - { - const std::vector<std::string>& curves = - state.client_hello()->supported_ecc_curves(); - - if(curves.empty()) - throw Internal_Error("Client sent no ECC extension but we negotiated ECDH"); - - const std::string curve_name = policy.choose_curve(curves); - - if(curve_name == "") - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Could not agree on an ECC curve with the client"); - - EC_Group ec_group(curve_name); - - std::unique_ptr<ECDH_PrivateKey> ecdh(new ECDH_PrivateKey(rng, ec_group)); - - const std::string ecdh_domain_oid = ecdh->domain().get_oid(); - const std::string domain = OIDS::lookup(OID(ecdh_domain_oid)); - - if(domain == "") - throw Internal_Error("Could not find name of ECDH domain " + ecdh_domain_oid); - - const u16bit named_curve_id = Supported_Elliptic_Curves::name_to_curve_id(domain); - - m_params.push_back(3); // named curve - m_params.push_back(get_byte(0, named_curve_id)); - m_params.push_back(get_byte(1, named_curve_id)); - - append_tls_length_value(m_params, ecdh->public_value(), 1); - - m_kex_key.reset(ecdh.release()); - } - else if(kex_algo == "SRP_SHA") - { - const std::string srp_identifier = state.client_hello()->srp_identifier(); - - std::string group_id; - BigInt v; - std::vector<byte> salt; - - const bool found = creds.srp_verifier("tls-server", hostname, - srp_identifier, - group_id, v, salt, - policy.hide_unknown_users()); - - if(!found) - throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, - "Unknown SRP user " + srp_identifier); - - m_srp_params.reset(new SRP6_Server_Session); - - BigInt B = m_srp_params->step1(v, group_id, - "SHA-1", rng); - - DL_Group group(group_id); - - append_tls_length_value(m_params, BigInt::encode(group.get_p()), 2); - append_tls_length_value(m_params, BigInt::encode(group.get_g()), 2); - append_tls_length_value(m_params, salt, 1); - append_tls_length_value(m_params, BigInt::encode(B), 2); - } - else if(kex_algo != "PSK") - throw Internal_Error("Server_Key_Exchange: Unknown kex type " + kex_algo); - - if(state.ciphersuite().sig_algo() != "") - { - BOTAN_ASSERT(signing_key, "Signing key was set"); - - std::pair<std::string, Signature_Format> format = - state.choose_sig_format(*signing_key, m_hash_algo, m_sig_algo, false, policy); - - PK_Signer signer(*signing_key, format.first, format.second); - - signer.update(state.client_hello()->random()); - signer.update(state.server_hello()->random()); - signer.update(params()); - m_signature = signer.signature(rng); - } - - state.hash().update(io.send(*this)); - } - -/** -* Deserialize a Server Key Exchange message -*/ -Server_Key_Exchange::Server_Key_Exchange(const std::vector<byte>& buf, - const std::string& kex_algo, - const std::string& sig_algo, - Protocol_Version version) : - m_kex_key(nullptr), m_srp_params(nullptr) - { - if(buf.size() < 6) - throw Decoding_Error("Server_Key_Exchange: Packet corrupted"); - - TLS_Data_Reader reader(buf); - - /* - * We really are just serializing things back to what they were - * before, but unfortunately to know where the signature is we need - * to be able to parse the whole thing anyway. - */ - - if(kex_algo == "PSK" || kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") - { - const std::string identity_hint = reader.get_string(2, 0, 65535); - append_tls_length_value(m_params, identity_hint, 2); - } - - if(kex_algo == "DH" || kex_algo == "DHE_PSK") - { - // 3 bigints, DH p, g, Y - - for(size_t i = 0; i != 3; ++i) - { - BigInt v = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); - append_tls_length_value(m_params, BigInt::encode(v), 2); - } - } - else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK") - { - const byte curve_type = reader.get_byte(); - - if(curve_type != 3) - throw Decoding_Error("Server_Key_Exchange: Server sent non-named ECC curve"); - - const u16bit curve_id = reader.get_u16bit(); - - const std::string name = Supported_Elliptic_Curves::curve_id_to_name(curve_id); - - std::vector<byte> ecdh_key = reader.get_range<byte>(1, 1, 255); - - if(name == "") - throw Decoding_Error("Server_Key_Exchange: Server sent unknown named curve " + - std::to_string(curve_id)); - - m_params.push_back(curve_type); - m_params.push_back(get_byte(0, curve_id)); - m_params.push_back(get_byte(1, curve_id)); - append_tls_length_value(m_params, ecdh_key, 1); - } - else if(kex_algo == "SRP_SHA") - { - // 2 bigints (N,g) then salt, then server B - - const BigInt N = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); - const BigInt g = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); - std::vector<byte> salt = reader.get_range<byte>(1, 1, 255); - const BigInt B = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); - - append_tls_length_value(m_params, BigInt::encode(N), 2); - append_tls_length_value(m_params, BigInt::encode(g), 2); - append_tls_length_value(m_params, salt, 1); - append_tls_length_value(m_params, BigInt::encode(B), 2); - } - else if(kex_algo != "PSK") - throw Decoding_Error("Server_Key_Exchange: Unsupported kex type " + kex_algo); - - if(sig_algo != "") - { - if(version.supports_negotiable_signature_algorithms()) - { - m_hash_algo = Signature_Algorithms::hash_algo_name(reader.get_byte()); - m_sig_algo = Signature_Algorithms::sig_algo_name(reader.get_byte()); - } - - m_signature = reader.get_range<byte>(2, 0, 65535); - } - - reader.assert_done(); - } - -Server_Key_Exchange::~Server_Key_Exchange() {} - -/** -* Serialize a Server Key Exchange message -*/ -std::vector<byte> Server_Key_Exchange::serialize() const - { - std::vector<byte> buf = params(); - - if(m_signature.size()) - { - // This should be an explicit version check - if(m_hash_algo != "" && m_sig_algo != "") - { - buf.push_back(Signature_Algorithms::hash_algo_code(m_hash_algo)); - buf.push_back(Signature_Algorithms::sig_algo_code(m_sig_algo)); - } - - append_tls_length_value(buf, m_signature, 2); - } - - return buf; - } - -/** -* Verify a Server Key Exchange message -*/ -bool Server_Key_Exchange::verify(const Public_Key& server_key, - const Handshake_State& state) const - { - std::pair<std::string, Signature_Format> format = - state.understand_sig_format(server_key, m_hash_algo, m_sig_algo, false); - - PK_Verifier verifier(server_key, format.first, format.second); - - verifier.update(state.client_hello()->random()); - verifier.update(state.server_hello()->random()); - verifier.update(params()); - - return verifier.check_signature(m_signature); - } - -const Private_Key& Server_Key_Exchange::server_kex_key() const - { - BOTAN_ASSERT_NONNULL(m_kex_key); - return *m_kex_key; - } - -// Only valid for SRP negotiation -SRP6_Server_Session& Server_Key_Exchange::server_srp_params() const - { - BOTAN_ASSERT_NONNULL(m_srp_params); - return *m_srp_params; - } -} - -} diff --git a/src/tls/msg_session_ticket.cpp b/src/tls/msg_session_ticket.cpp deleted file mode 100644 index 2bb9987a9..000000000 --- a/src/tls/msg_session_ticket.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* -* Session Tickets -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/internal/tls_messages.h> -#include <botan/internal/tls_extensions.h> -#include <botan/internal/tls_reader.h> -#include <botan/internal/tls_handshake_io.h> -#include <botan/loadstor.h> - -namespace Botan { - -namespace TLS { - -New_Session_Ticket::New_Session_Ticket(Handshake_IO& io, - Handshake_Hash& hash, - const std::vector<byte>& ticket, - u32bit lifetime) : - m_ticket_lifetime_hint(lifetime), - m_ticket(ticket) - { - hash.update(io.send(*this)); - } - -New_Session_Ticket::New_Session_Ticket(Handshake_IO& io, - Handshake_Hash& hash) : - m_ticket_lifetime_hint(0) - { - hash.update(io.send(*this)); - } - -New_Session_Ticket::New_Session_Ticket(const std::vector<byte>& buf) : - m_ticket_lifetime_hint(0) - { - if(buf.size() < 6) - throw Decoding_Error("Session ticket message too short to be valid"); - - TLS_Data_Reader reader(buf); - - m_ticket_lifetime_hint = reader.get_u32bit(); - m_ticket = reader.get_range<byte>(2, 0, 65535); - } - -std::vector<byte> New_Session_Ticket::serialize() const - { - std::vector<byte> buf(4); - store_be(m_ticket_lifetime_hint, &buf[0]); - append_tls_length_value(buf, m_ticket, 2); - return buf; - } - -} - -} diff --git a/src/tls/sessions_sqlite/info.txt b/src/tls/sessions_sqlite/info.txt deleted file mode 100644 index 76d53f995..000000000 --- a/src/tls/sessions_sqlite/info.txt +++ /dev/null @@ -1,6 +0,0 @@ -define TLS_SQLITE3_SESSION_MANAGER 20131128 - -<requires> -pbkdf2 -sqlite3 -</requires> diff --git a/src/tls/sessions_sqlite/tls_session_manager_sqlite.cpp b/src/tls/sessions_sqlite/tls_session_manager_sqlite.cpp deleted file mode 100644 index d4f286a8d..000000000 --- a/src/tls/sessions_sqlite/tls_session_manager_sqlite.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/* -* SQLite TLS Session Manager -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/tls_session_manager_sqlite.h> -#include <botan/internal/sqlite3.h> -#include <botan/lookup.h> -#include <botan/hex.h> -#include <botan/loadstor.h> -#include <memory> -#include <chrono> - -namespace Botan { - -namespace TLS { - -namespace { - -SymmetricKey derive_key(const std::string& passphrase, - const byte salt[], - size_t salt_len, - size_t iterations, - size_t& check_val) - { - std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(SHA-512)")); - - secure_vector<byte> x = pbkdf->derive_key(32 + 2, - passphrase, - salt, salt_len, - iterations).bits_of(); - - check_val = make_u16bit(x[0], x[1]); - return SymmetricKey(&x[2], x.size() - 2); - } - -} - -Session_Manager_SQLite::Session_Manager_SQLite(const std::string& passphrase, - RandomNumberGenerator& rng, - const std::string& db_filename, - size_t max_sessions, - std::chrono::seconds session_lifetime) : - m_rng(rng), - m_max_sessions(max_sessions), - m_session_lifetime(session_lifetime) - { - m_db = new sqlite3_database(db_filename); - - m_db->create_table( - "create table if not exists tls_sessions " - "(" - "session_id TEXT PRIMARY KEY, " - "session_start INTEGER, " - "hostname TEXT, " - "hostport INTEGER, " - "session BLOB" - ")"); - - m_db->create_table( - "create table if not exists tls_sessions_metadata " - "(" - "passphrase_salt BLOB, " - "passphrase_iterations INTEGER, " - "passphrase_check INTEGER " - ")"); - - const size_t salts = m_db->row_count("tls_sessions_metadata"); - - if(salts == 1) - { - // existing db - sqlite3_statement stmt(m_db, "select * from tls_sessions_metadata"); - - if(stmt.step()) - { - std::pair<const byte*, size_t> salt = stmt.get_blob(0); - const size_t iterations = stmt.get_size_t(1); - const size_t check_val_db = stmt.get_size_t(2); - - size_t check_val_created; - m_session_key = derive_key(passphrase, - salt.first, - salt.second, - iterations, - check_val_created); - - if(check_val_created != check_val_db) - throw std::runtime_error("Session database password not valid"); - } - } - else - { - // maybe just zap the salts + sessions tables in this case? - if(salts != 0) - throw std::runtime_error("Seemingly corrupted database, multiple salts found"); - - // new database case - - std::vector<byte> salt = unlock(rng.random_vec(16)); - const size_t iterations = 256 * 1024; - size_t check_val = 0; - - m_session_key = derive_key(passphrase, &salt[0], salt.size(), - iterations, check_val); - - sqlite3_statement stmt(m_db, "insert into tls_sessions_metadata" - " values(?1, ?2, ?3)"); - - stmt.bind(1, salt); - stmt.bind(2, iterations); - stmt.bind(3, check_val); - - stmt.spin(); - } - } - -Session_Manager_SQLite::~Session_Manager_SQLite() - { - delete m_db; - } - -bool Session_Manager_SQLite::load_from_session_id(const std::vector<byte>& session_id, - Session& session) - { - sqlite3_statement stmt(m_db, "select session from tls_sessions where session_id = ?1"); - - stmt.bind(1, hex_encode(session_id)); - - while(stmt.step()) - { - std::pair<const byte*, size_t> blob = stmt.get_blob(0); - - try - { - session = Session::decrypt(blob.first, blob.second, m_session_key); - return true; - } - catch(...) - { - } - } - - return false; - } - -bool Session_Manager_SQLite::load_from_server_info(const Server_Information& server, - Session& session) - { - sqlite3_statement stmt(m_db, "select session from tls_sessions" - " where hostname = ?1 and hostport = ?2" - " order by session_start desc"); - - stmt.bind(1, server.hostname()); - stmt.bind(2, server.port()); - - while(stmt.step()) - { - std::pair<const byte*, size_t> blob = stmt.get_blob(0); - - try - { - session = Session::decrypt(blob.first, blob.second, m_session_key); - return true; - } - catch(...) - { - } - } - - return false; - } - -void Session_Manager_SQLite::remove_entry(const std::vector<byte>& session_id) - { - sqlite3_statement stmt(m_db, "delete from tls_sessions where session_id = ?1"); - - stmt.bind(1, hex_encode(session_id)); - - stmt.spin(); - } - -void Session_Manager_SQLite::save(const Session& session) - { - sqlite3_statement stmt(m_db, "insert or replace into tls_sessions" - " values(?1, ?2, ?3, ?4, ?5)"); - - stmt.bind(1, hex_encode(session.session_id())); - stmt.bind(2, session.start_time()); - stmt.bind(3, session.server_info().hostname()); - stmt.bind(4, session.server_info().port()); - stmt.bind(5, session.encrypt(m_session_key, m_rng)); - - stmt.spin(); - - prune_session_cache(); - } - -void Session_Manager_SQLite::prune_session_cache() - { - sqlite3_statement remove_expired(m_db, "delete from tls_sessions where session_start <= ?1"); - - remove_expired.bind(1, std::chrono::system_clock::now() - m_session_lifetime); - - remove_expired.spin(); - - const size_t sessions = m_db->row_count("tls_sessions"); - - if(sessions > m_max_sessions) - { - sqlite3_statement remove_some(m_db, "delete from tls_sessions where session_id in " - "(select session_id from tls_sessions limit ?1)"); - - remove_some.bind(1, sessions - m_max_sessions); - remove_some.spin(); - } - } - -} - -} diff --git a/src/tls/sessions_sqlite/tls_session_manager_sqlite.h b/src/tls/sessions_sqlite/tls_session_manager_sqlite.h deleted file mode 100644 index 7892ccd6a..000000000 --- a/src/tls/sessions_sqlite/tls_session_manager_sqlite.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -* SQLite3 TLS Session Manager -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_SQLITE3_SESSION_MANAGER_H__ -#define BOTAN_TLS_SQLITE3_SESSION_MANAGER_H__ - -#include <botan/tls_session_manager.h> -#include <botan/rng.h> - -namespace Botan { - -class sqlite3_database; - -namespace TLS { - -/** -* An implementation of Session_Manager that saves values in a SQLite3 -* database file, with the session data encrypted using a passphrase. -* -* @warning For clients, the hostnames associated with the saved -* sessions are stored in the database in plaintext. This may be a -* serious privacy risk in some situations. -*/ -class BOTAN_DLL Session_Manager_SQLite : public Session_Manager - { - public: - /** - * @param passphrase used to encrypt the session data - * @param rng a random number generator - * @param db_filename filename of the SQLite database file. - The table names tls_sessions and tls_sessions_metadata - will be used - * @param max_sessions a hint on the maximum number of sessions - * to keep in memory at any one time. (If zero, don't cap) - * @param session_lifetime sessions are expired after this many - * seconds have elapsed from initial handshake. - */ - Session_Manager_SQLite(const std::string& passphrase, - RandomNumberGenerator& rng, - const std::string& db_filename, - size_t max_sessions = 1000, - std::chrono::seconds session_lifetime = std::chrono::seconds(7200)); - - ~Session_Manager_SQLite(); - - bool load_from_session_id(const std::vector<byte>& session_id, - Session& session) override; - - bool load_from_server_info(const Server_Information& info, - Session& session) override; - - void remove_entry(const std::vector<byte>& session_id) override; - - void save(const Session& session_data) override; - - std::chrono::seconds session_lifetime() const override - { return m_session_lifetime; } - - private: - Session_Manager_SQLite(const Session_Manager_SQLite&); - Session_Manager_SQLite& operator=(const Session_Manager_SQLite&); - - void prune_session_cache(); - - SymmetricKey m_session_key; - RandomNumberGenerator& m_rng; - size_t m_max_sessions; - std::chrono::seconds m_session_lifetime; - sqlite3_database* m_db; - }; - -} - -} - -#endif diff --git a/src/tls/tls_alert.cpp b/src/tls/tls_alert.cpp deleted file mode 100644 index 15bb2a2dc..000000000 --- a/src/tls/tls_alert.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* -* Alert Message -* (C) 2004-2006,2011 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/tls_alert.h> -#include <botan/exceptn.h> - -namespace Botan { - -namespace TLS { - -Alert::Alert(const secure_vector<byte>& buf) - { - if(buf.size() != 2) - throw Decoding_Error("Alert: Bad size " + std::to_string(buf.size()) + - " for alert message"); - - if(buf[0] == 1) m_fatal = false; - else if(buf[0] == 2) m_fatal = true; - else - throw Decoding_Error("Alert: Bad code for alert level"); - - const byte dc = buf[1]; - - m_type_code = static_cast<Type>(dc); - } - -std::vector<byte> Alert::serialize() const - { - return std::vector<byte>({ - static_cast<byte>(is_fatal() ? 2 : 1), - static_cast<byte>(type()) - }); - } - -std::string Alert::type_string() const - { - switch(type()) - { - case CLOSE_NOTIFY: - return "close_notify"; - case UNEXPECTED_MESSAGE: - return "unexpected_message"; - case BAD_RECORD_MAC: - return "bad_record_mac"; - case DECRYPTION_FAILED: - return "decryption_failed"; - case RECORD_OVERFLOW: - return "record_overflow"; - case DECOMPRESSION_FAILURE: - return "decompression_failure"; - case HANDSHAKE_FAILURE: - return "handshake_failure"; - case NO_CERTIFICATE: - return "no_certificate"; - case BAD_CERTIFICATE: - return "bad_certificate"; - case UNSUPPORTED_CERTIFICATE: - return "unsupported_certificate"; - case CERTIFICATE_REVOKED: - return "certificate_revoked"; - case CERTIFICATE_EXPIRED: - return "certificate_expired"; - case CERTIFICATE_UNKNOWN: - return "certificate_unknown"; - case ILLEGAL_PARAMETER: - return "illegal_parameter"; - case UNKNOWN_CA: - return "unknown_ca"; - case ACCESS_DENIED: - return "access_denied"; - case DECODE_ERROR: - return "decode_error"; - case DECRYPT_ERROR: - return "decrypt_error"; - case EXPORT_RESTRICTION: - return "export_restriction"; - case PROTOCOL_VERSION: - return "protocol_version"; - case INSUFFICIENT_SECURITY: - return "insufficient_security"; - case INTERNAL_ERROR: - return "internal_error"; - case USER_CANCELED: - return "user_canceled"; - case NO_RENEGOTIATION: - return "no_renegotiation"; - - case UNSUPPORTED_EXTENSION: - return "unsupported_extension"; - case CERTIFICATE_UNOBTAINABLE: - return "certificate_unobtainable"; - case UNRECOGNIZED_NAME: - return "unrecognized_name"; - case BAD_CERTIFICATE_STATUS_RESPONSE: - return "bad_certificate_status_response"; - case BAD_CERTIFICATE_HASH_VALUE: - return "bad_certificate_hash_value"; - case UNKNOWN_PSK_IDENTITY: - return "unknown_psk_identity"; - - case NULL_ALERT: - return "none"; - - case HEARTBEAT_PAYLOAD: - return "heartbeat_payload"; - } - - /* - * This is effectively the default case for the switch above, but we - * leave it out so that when an alert type is added to the enum the - * compiler can warn us that it is not included in the switch - * statement. - */ - return "unrecognized_alert_" + std::to_string(type()); - } - -} - -} diff --git a/src/tls/tls_alert.h b/src/tls/tls_alert.h deleted file mode 100644 index bf32178ee..000000000 --- a/src/tls/tls_alert.h +++ /dev/null @@ -1,113 +0,0 @@ -/* -* Alert Message -* (C) 2004-2006,2011,2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_ALERT_H__ -#define BOTAN_TLS_ALERT_H__ - -#include <botan/secmem.h> -#include <string> - -namespace Botan { - -namespace TLS { - -/** -* SSL/TLS Alert Message -*/ -class BOTAN_DLL Alert - { - public: - /** - * Type codes for TLS alerts - */ - enum Type { - CLOSE_NOTIFY = 0, - UNEXPECTED_MESSAGE = 10, - BAD_RECORD_MAC = 20, - DECRYPTION_FAILED = 21, - RECORD_OVERFLOW = 22, - DECOMPRESSION_FAILURE = 30, - HANDSHAKE_FAILURE = 40, - NO_CERTIFICATE = 41, // SSLv3 only - BAD_CERTIFICATE = 42, - UNSUPPORTED_CERTIFICATE = 43, - CERTIFICATE_REVOKED = 44, - CERTIFICATE_EXPIRED = 45, - CERTIFICATE_UNKNOWN = 46, - ILLEGAL_PARAMETER = 47, - UNKNOWN_CA = 48, - ACCESS_DENIED = 49, - DECODE_ERROR = 50, - DECRYPT_ERROR = 51, - EXPORT_RESTRICTION = 60, - PROTOCOL_VERSION = 70, - INSUFFICIENT_SECURITY = 71, - INTERNAL_ERROR = 80, - USER_CANCELED = 90, - NO_RENEGOTIATION = 100, - UNSUPPORTED_EXTENSION = 110, - CERTIFICATE_UNOBTAINABLE = 111, - UNRECOGNIZED_NAME = 112, - BAD_CERTIFICATE_STATUS_RESPONSE = 113, - BAD_CERTIFICATE_HASH_VALUE = 114, - UNKNOWN_PSK_IDENTITY = 115, - - // pseudo alert values - NULL_ALERT = 256, - HEARTBEAT_PAYLOAD = 257 - }; - - /** - * @return true iff this alert is non-empty - */ - bool is_valid() const { return (m_type_code != NULL_ALERT); } - - /** - * @return if this alert is a fatal one or not - */ - bool is_fatal() const { return m_fatal; } - - /** - * @return type of alert - */ - Type type() const { return m_type_code; } - - /** - * @return type of alert - */ - std::string type_string() const; - - /** - * Serialize an alert - */ - std::vector<byte> serialize() const; - - /** - * Deserialize an Alert message - * @param buf the serialized alert - */ - Alert(const secure_vector<byte>& buf); - - /** - * Create a new Alert - * @param type_code the type of alert - * @param fatal specifies if this is a fatal alert - */ - Alert(Type type_code, bool fatal = false) : - m_fatal(fatal), m_type_code(type_code) {} - - Alert() : m_fatal(false), m_type_code(NULL_ALERT) {} - private: - bool m_fatal; - Type m_type_code; - }; - -} - -} - -#endif diff --git a/src/tls/tls_blocking.cpp b/src/tls/tls_blocking.cpp deleted file mode 100644 index 4b33ba926..000000000 --- a/src/tls/tls_blocking.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* -* TLS Blocking API -* (C) 2013 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/tls_blocking.h> - -namespace Botan { - -namespace TLS { - -using namespace std::placeholders; - -Blocking_Client::Blocking_Client(std::function<size_t (byte[], size_t)> read_fn, - std::function<void (const byte[], size_t)> write_fn, - Session_Manager& session_manager, - Credentials_Manager& creds, - const Policy& policy, - RandomNumberGenerator& rng, - const Server_Information& server_info, - const Protocol_Version offer_version, - std::function<std::string (std::vector<std::string>)> next_protocol) : - m_read_fn(read_fn), - m_channel(write_fn, - std::bind(&Blocking_Client::data_cb, this, _1, _2), - std::bind(&Blocking_Client::alert_cb, this, _1, _2, _3), - std::bind(&Blocking_Client::handshake_cb, this, _1), - session_manager, - creds, - policy, - rng, - server_info, - offer_version, - next_protocol) - { - } - -bool Blocking_Client::handshake_cb(const Session& session) - { - return this->handshake_complete(session); - } - -void Blocking_Client::alert_cb(const Alert alert, const byte[], size_t) - { - this->alert_notification(alert); - } - -void Blocking_Client::data_cb(const byte data[], size_t data_len) - { - m_plaintext.insert(m_plaintext.end(), data, data + data_len); - } - -void Blocking_Client::do_handshake() - { - std::vector<byte> readbuf(4096); - - while(!m_channel.is_closed() && !m_channel.is_active()) - { - const size_t from_socket = m_read_fn(&readbuf[0], readbuf.size()); - m_channel.received_data(&readbuf[0], from_socket); - } - } - -size_t Blocking_Client::read(byte buf[], size_t buf_len) - { - std::vector<byte> readbuf(4096); - - while(m_plaintext.empty() && !m_channel.is_closed()) - { - const size_t from_socket = m_read_fn(&readbuf[0], readbuf.size()); - m_channel.received_data(&readbuf[0], from_socket); - } - - const size_t returned = std::min(buf_len, m_plaintext.size()); - - for(size_t i = 0; i != returned; ++i) - buf[i] = m_plaintext[i]; - m_plaintext.erase(m_plaintext.begin(), m_plaintext.begin() + returned); - - BOTAN_ASSERT_IMPLICATION(returned == 0, m_channel.is_closed(), - "Only return zero if channel is closed"); - - return returned; - } - -} - -} diff --git a/src/tls/tls_blocking.h b/src/tls/tls_blocking.h deleted file mode 100644 index cfa96ce8d..000000000 --- a/src/tls/tls_blocking.h +++ /dev/null @@ -1,97 +0,0 @@ -/* -* TLS Blocking API -* (C) 2013 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_BLOCKING_CHANNELS_H__ -#define BOTAN_TLS_BLOCKING_CHANNELS_H__ - -#include <botan/tls_client.h> -#include <botan/tls_server.h> -#include <deque> - -namespace Botan { - -template<typename T> using secure_deque = std::vector<T, secure_allocator<T>>; - -namespace TLS { - -/** -* Blocking TLS Client -*/ -class BOTAN_DLL Blocking_Client - { - public: - - Blocking_Client(std::function<size_t (byte[], size_t)> read_fn, - std::function<void (const byte[], size_t)> write_fn, - Session_Manager& session_manager, - Credentials_Manager& creds, - const Policy& policy, - RandomNumberGenerator& rng, - const Server_Information& server_info = Server_Information(), - const Protocol_Version offer_version = Protocol_Version::latest_tls_version(), - std::function<std::string (std::vector<std::string>)> next_protocol = - std::function<std::string (std::vector<std::string>)>()); - - /** - * Completes full handshake then returns - */ - void do_handshake(); - - /** - * Number of bytes pending read in the plaintext buffer (bytes - * readable without blocking) - */ - size_t pending() const { return m_plaintext.size(); } - - /** - * Blocking read, will return at least 1 byte or 0 on connection close - */ - size_t read(byte buf[], size_t buf_len); - - void write(const byte buf[], size_t buf_len) { m_channel.send(buf, buf_len); } - - const TLS::Channel& underlying_channel() const { return m_channel; } - TLS::Channel& underlying_channel() { return m_channel; } - - void close() { m_channel.close(); } - - bool is_closed() const { return m_channel.is_closed(); } - - std::vector<X509_Certificate> peer_cert_chain() const - { return m_channel.peer_cert_chain(); } - - virtual ~Blocking_Client() {} - - protected: - /** - * Can override to get the handshake complete notification - */ - virtual bool handshake_complete(const Session&) { return true; } - - /** - * Can override to get notification of alerts - */ - virtual void alert_notification(const Alert&) {} - - private: - - bool handshake_cb(const Session&); - - void data_cb(const byte data[], size_t data_len); - - void alert_cb(const Alert alert, const byte data[], size_t data_len); - - std::function<size_t (byte[], size_t)> m_read_fn; - TLS::Client m_channel; - secure_deque<byte> m_plaintext; - }; - -} - -} - -#endif diff --git a/src/tls/tls_channel.cpp b/src/tls/tls_channel.cpp deleted file mode 100644 index 8ed876b3f..000000000 --- a/src/tls/tls_channel.cpp +++ /dev/null @@ -1,668 +0,0 @@ -/* -* TLS Channels -* (C) 2011-2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/tls_channel.h> -#include <botan/internal/tls_handshake_state.h> -#include <botan/internal/tls_messages.h> -#include <botan/internal/tls_heartbeats.h> -#include <botan/internal/tls_record.h> -#include <botan/internal/tls_seq_numbers.h> -#include <botan/internal/rounding.h> -#include <botan/internal/stl_util.h> -#include <botan/loadstor.h> - -namespace Botan { - -namespace TLS { - -Channel::Channel(std::function<void (const byte[], size_t)> output_fn, - std::function<void (const byte[], size_t)> data_cb, - std::function<void (Alert, const byte[], size_t)> alert_cb, - std::function<bool (const Session&)> handshake_cb, - Session_Manager& session_manager, - RandomNumberGenerator& rng, - size_t reserved_io_buffer_size) : - m_handshake_cb(handshake_cb), - m_data_cb(data_cb), - m_alert_cb(alert_cb), - m_output_fn(output_fn), - m_rng(rng), - m_session_manager(session_manager) - { - m_writebuf.reserve(reserved_io_buffer_size); - m_readbuf.reserve(reserved_io_buffer_size); - } - -void Channel::reset_state() - { - m_active_state.reset(); - m_pending_state.reset(); - m_readbuf.clear(); - m_write_cipher_states.clear(); - m_read_cipher_states.clear(); - } - -Channel::~Channel() - { - // So unique_ptr destructors run correctly - } - -Connection_Sequence_Numbers& Channel::sequence_numbers() const - { - BOTAN_ASSERT(m_sequence_numbers, "Have a sequence numbers object"); - return *m_sequence_numbers; - } - -std::shared_ptr<Connection_Cipher_State> Channel::read_cipher_state_epoch(u16bit epoch) const - { - auto i = m_read_cipher_states.find(epoch); - - BOTAN_ASSERT(i != m_read_cipher_states.end(), - "Have a cipher state for the specified epoch"); - - return i->second; - } - -std::shared_ptr<Connection_Cipher_State> Channel::write_cipher_state_epoch(u16bit epoch) const - { - auto i = m_write_cipher_states.find(epoch); - - BOTAN_ASSERT(i != m_write_cipher_states.end(), - "Have a cipher state for the specified epoch"); - - return i->second; - } - -std::vector<X509_Certificate> Channel::peer_cert_chain() const - { - if(auto active = active_state()) - return get_peer_cert_chain(*active); - return std::vector<X509_Certificate>(); - } - -Handshake_State& Channel::create_handshake_state(Protocol_Version version) - { - if(pending_state()) - throw Internal_Error("create_handshake_state called during handshake"); - - if(auto active = active_state()) - { - Protocol_Version active_version = active->version(); - - if(active_version.is_datagram_protocol() != version.is_datagram_protocol()) - throw std::runtime_error("Active state using version " + - active_version.to_string() + - " cannot change to " + - version.to_string() + - " in pending"); - } - - if(!m_sequence_numbers) - { - if(version.is_datagram_protocol()) - m_sequence_numbers.reset(new Datagram_Sequence_Numbers); - else - m_sequence_numbers.reset(new Stream_Sequence_Numbers); - } - - std::unique_ptr<Handshake_IO> io; - if(version.is_datagram_protocol()) - io.reset(new Datagram_Handshake_IO( - sequence_numbers(), - std::bind(&Channel::send_record_under_epoch, this, - std::placeholders::_1, - std::placeholders::_2, - std::placeholders::_3))); - else - io.reset(new Stream_Handshake_IO( - std::bind(&Channel::send_record, this, - std::placeholders::_1, - std::placeholders::_2))); - - m_pending_state.reset(new_handshake_state(io.release())); - - if(auto active = active_state()) - m_pending_state->set_version(active->version()); - - return *m_pending_state.get(); - } - -void Channel::renegotiate(bool force_full_renegotiation) - { - if(pending_state()) // currently in handshake? - return; - - if(auto active = active_state()) - initiate_handshake(create_handshake_state(active->version()), - force_full_renegotiation); - else - throw std::runtime_error("Cannot renegotiate on inactive connection"); - } - -size_t Channel::maximum_fragment_size() const - { - // should we be caching this value? - - if(auto pending = pending_state()) - if(auto server_hello = pending->server_hello()) - if(size_t frag = server_hello->fragment_size()) - return frag; - - if(auto active = active_state()) - if(size_t frag = active->server_hello()->fragment_size()) - return frag; - - return MAX_PLAINTEXT_SIZE; - } - -void Channel::change_cipher_spec_reader(Connection_Side side) - { - auto pending = pending_state(); - - BOTAN_ASSERT(pending && pending->server_hello(), - "Have received server hello"); - - if(pending->server_hello()->compression_method() != NO_COMPRESSION) - throw Internal_Error("Negotiated unknown compression algorithm"); - - sequence_numbers().new_read_cipher_state(); - - const u16bit epoch = sequence_numbers().current_read_epoch(); - - BOTAN_ASSERT(m_read_cipher_states.count(epoch) == 0, - "No read cipher state currently set for next epoch"); - - // flip side as we are reading - std::shared_ptr<Connection_Cipher_State> read_state( - new Connection_Cipher_State(pending->version(), - (side == CLIENT) ? SERVER : CLIENT, - false, - pending->ciphersuite(), - pending->session_keys())); - - m_read_cipher_states[epoch] = read_state; - } - -void Channel::change_cipher_spec_writer(Connection_Side side) - { - auto pending = pending_state(); - - BOTAN_ASSERT(pending && pending->server_hello(), - "Have received server hello"); - - if(pending->server_hello()->compression_method() != NO_COMPRESSION) - throw Internal_Error("Negotiated unknown compression algorithm"); - - sequence_numbers().new_write_cipher_state(); - - const u16bit epoch = sequence_numbers().current_write_epoch(); - - BOTAN_ASSERT(m_write_cipher_states.count(epoch) == 0, - "No write cipher state currently set for next epoch"); - - std::shared_ptr<Connection_Cipher_State> write_state( - new Connection_Cipher_State(pending->version(), - side, - true, - pending->ciphersuite(), - pending->session_keys())); - - m_write_cipher_states[epoch] = write_state; - } - -bool Channel::is_active() const - { - return (active_state() != nullptr); - } - -bool Channel::is_closed() const - { - if(active_state() || pending_state()) - return false; - - /* - * If no active or pending state, then either we had a connection - * and it has been closed, or we are a server which has never - * received a connection. This case is detectable by also lacking - * m_sequence_numbers - */ - return (m_sequence_numbers != nullptr); - } - -void Channel::activate_session() - { - std::swap(m_active_state, m_pending_state); - m_pending_state.reset(); - - if(m_active_state->version().is_datagram_protocol()) - { - // FIXME, remove old states when we are sure not needed anymore - } - else - { - // TLS is easy just remove all but the current state - auto current_epoch = sequence_numbers().current_write_epoch(); - - const auto not_current_epoch = - [current_epoch](u16bit epoch) { return (epoch != current_epoch); }; - - map_remove_if(not_current_epoch, m_write_cipher_states); - map_remove_if(not_current_epoch, m_read_cipher_states); - } - } - -bool Channel::peer_supports_heartbeats() const - { - if(auto active = active_state()) - return active->server_hello()->supports_heartbeats(); - return false; - } - -bool Channel::heartbeat_sending_allowed() const - { - if(auto active = active_state()) - return active->server_hello()->peer_can_send_heartbeats(); - return false; - } - -size_t Channel::received_data(const std::vector<byte>& buf) - { - return this->received_data(&buf[0], buf.size()); - } - -size_t Channel::received_data(const byte input[], size_t input_size) - { - const auto get_cipherstate = [this](u16bit epoch) - { return this->read_cipher_state_epoch(epoch).get(); }; - - const size_t max_fragment_size = maximum_fragment_size(); - - try - { - while(!is_closed() && input_size) - { - secure_vector<byte> record; - u64bit record_sequence = 0; - Record_Type record_type = NO_RECORD; - Protocol_Version record_version; - - size_t consumed = 0; - - const size_t needed = - read_record(m_readbuf, - input, - input_size, - consumed, - record, - &record_sequence, - &record_version, - &record_type, - m_sequence_numbers.get(), - get_cipherstate); - - BOTAN_ASSERT(consumed <= input_size, - "Record reader consumed sane amount"); - - input += consumed; - input_size -= consumed; - - BOTAN_ASSERT(input_size == 0 || needed == 0, - "Got a full record or consumed all input"); - - if(input_size == 0 && needed != 0) - return needed; // need more data to complete record - - if(record.size() > max_fragment_size) - throw TLS_Exception(Alert::RECORD_OVERFLOW, - "Plaintext record is too large"); - - if(record_type == HANDSHAKE || record_type == CHANGE_CIPHER_SPEC) - { - if(!m_pending_state) - { - create_handshake_state(record_version); - if(record_version.is_datagram_protocol()) - sequence_numbers().read_accept(record_sequence); - } - - m_pending_state->handshake_io().add_record(unlock(record), - record_type, - record_sequence); - - while(auto pending = m_pending_state.get()) - { - auto msg = pending->get_next_handshake_msg(); - - if(msg.first == HANDSHAKE_NONE) // no full handshake yet - break; - - process_handshake_msg(active_state(), *pending, - msg.first, msg.second); - } - } - else if(record_type == HEARTBEAT && peer_supports_heartbeats()) - { - if(!active_state()) - throw Unexpected_Message("Heartbeat sent before handshake done"); - - Heartbeat_Message heartbeat(unlock(record)); - - const std::vector<byte>& payload = heartbeat.payload(); - - if(heartbeat.is_request()) - { - if(!pending_state()) - { - Heartbeat_Message response(Heartbeat_Message::RESPONSE, - &payload[0], payload.size()); - - send_record(HEARTBEAT, response.contents()); - } - } - else - { - m_alert_cb(Alert(Alert::HEARTBEAT_PAYLOAD), &payload[0], payload.size()); - } - } - else if(record_type == APPLICATION_DATA) - { - if(!active_state()) - throw Unexpected_Message("Application data before handshake done"); - - /* - * OpenSSL among others sends empty records in versions - * before TLS v1.1 in order to randomize the IV of the - * following record. Avoid spurious callbacks. - */ - if(record.size() > 0) - m_data_cb(&record[0], record.size()); - } - else if(record_type == ALERT) - { - Alert alert_msg(record); - - if(alert_msg.type() == Alert::NO_RENEGOTIATION) - m_pending_state.reset(); - - m_alert_cb(alert_msg, nullptr, 0); - - if(alert_msg.is_fatal()) - { - if(auto active = active_state()) - m_session_manager.remove_entry(active->server_hello()->session_id()); - } - - if(alert_msg.type() == Alert::CLOSE_NOTIFY) - send_warning_alert(Alert::CLOSE_NOTIFY); // reply in kind - - if(alert_msg.type() == Alert::CLOSE_NOTIFY || alert_msg.is_fatal()) - { - reset_state(); - return 0; - } - } - else - throw Unexpected_Message("Unexpected record type " + - std::to_string(record_type) + - " from counterparty"); - } - - return 0; // on a record boundary - } - catch(TLS_Exception& e) - { - send_fatal_alert(e.type()); - throw; - } - catch(Integrity_Failure& e) - { - send_fatal_alert(Alert::BAD_RECORD_MAC); - throw; - } - catch(Decoding_Error& e) - { - send_fatal_alert(Alert::DECODE_ERROR); - throw; - } - catch(...) - { - send_fatal_alert(Alert::INTERNAL_ERROR); - throw; - } - } - -void Channel::heartbeat(const byte payload[], size_t payload_size) - { - if(heartbeat_sending_allowed()) - { - Heartbeat_Message heartbeat(Heartbeat_Message::REQUEST, - payload, payload_size); - - send_record(HEARTBEAT, heartbeat.contents()); - } - } - -void Channel::write_record(Connection_Cipher_State* cipher_state, - byte record_type, const byte input[], size_t length) - { - BOTAN_ASSERT(m_pending_state || m_active_state, - "Some connection state exists"); - - Protocol_Version record_version = - (m_pending_state) ? (m_pending_state->version()) : (m_active_state->version()); - - TLS::write_record(m_writebuf, - record_type, - input, - length, - record_version, - sequence_numbers().next_write_sequence(), - cipher_state, - m_rng); - - m_output_fn(&m_writebuf[0], m_writebuf.size()); - } - -void Channel::send_record_array(u16bit epoch, byte type, const byte input[], size_t length) - { - if(length == 0) - return; - - /* - * If using CBC mode without an explicit IV (SSL v3 or TLS v1.0), - * send a single byte of plaintext to randomize the (implicit) IV of - * the following main block. If using a stream cipher, or TLS v1.1 - * or higher, this isn't necessary. - * - * An empty record also works but apparently some implementations do - * not like this (https://bugzilla.mozilla.org/show_bug.cgi?id=665814) - * - * See http://www.openssl.org/~bodo/tls-cbc.txt for background. - */ - - auto cipher_state = write_cipher_state_epoch(epoch); - - if(type == APPLICATION_DATA && cipher_state->cbc_without_explicit_iv()) - { - write_record(cipher_state.get(), type, &input[0], 1); - input += 1; - length -= 1; - } - - const size_t max_fragment_size = maximum_fragment_size(); - - while(length) - { - const size_t sending = std::min(length, max_fragment_size); - write_record(cipher_state.get(), type, &input[0], sending); - - input += sending; - length -= sending; - } - } - -void Channel::send_record(byte record_type, const std::vector<byte>& record) - { - send_record_array(sequence_numbers().current_write_epoch(), - record_type, &record[0], record.size()); - } - -void Channel::send_record_under_epoch(u16bit epoch, byte record_type, - const std::vector<byte>& record) - { - send_record_array(epoch, record_type, &record[0], record.size()); - } - -void Channel::send(const byte buf[], size_t buf_size) - { - if(!is_active()) - throw std::runtime_error("Data cannot be sent on inactive TLS connection"); - - send_record_array(sequence_numbers().current_write_epoch(), - APPLICATION_DATA, buf, buf_size); - } - -void Channel::send(const std::string& string) - { - this->send(reinterpret_cast<const byte*>(string.c_str()), string.size()); - } - -void Channel::send_alert(const Alert& alert) - { - if(alert.is_valid() && !is_closed()) - { - try - { - send_record(ALERT, alert.serialize()); - } - catch(...) { /* swallow it */ } - } - - if(alert.type() == Alert::NO_RENEGOTIATION) - m_pending_state.reset(); - - if(alert.is_fatal()) - if(auto active = active_state()) - m_session_manager.remove_entry(active->server_hello()->session_id()); - - if(alert.type() == Alert::CLOSE_NOTIFY || alert.is_fatal()) - reset_state(); - } - -void Channel::secure_renegotiation_check(const Client_Hello* client_hello) - { - const bool secure_renegotiation = client_hello->secure_renegotiation(); - - if(auto active = active_state()) - { - const bool active_sr = active->client_hello()->secure_renegotiation(); - - if(active_sr != secure_renegotiation) - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Client changed its mind about secure renegotiation"); - } - - if(secure_renegotiation) - { - const std::vector<byte>& data = client_hello->renegotiation_info(); - - if(data != secure_renegotiation_data_for_client_hello()) - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Client sent bad values for secure renegotiation"); - } - } - -void Channel::secure_renegotiation_check(const Server_Hello* server_hello) - { - const bool secure_renegotiation = server_hello->secure_renegotiation(); - - if(auto active = active_state()) - { - const bool active_sr = active->client_hello()->secure_renegotiation(); - - if(active_sr != secure_renegotiation) - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Server changed its mind about secure renegotiation"); - } - - if(secure_renegotiation) - { - const std::vector<byte>& data = server_hello->renegotiation_info(); - - if(data != secure_renegotiation_data_for_server_hello()) - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Server sent bad values for secure renegotiation"); - } - } - -std::vector<byte> Channel::secure_renegotiation_data_for_client_hello() const - { - if(auto active = active_state()) - return active->client_finished()->verify_data(); - return std::vector<byte>(); - } - -std::vector<byte> Channel::secure_renegotiation_data_for_server_hello() const - { - if(auto active = active_state()) - { - std::vector<byte> buf = active->client_finished()->verify_data(); - buf += active->server_finished()->verify_data(); - return buf; - } - - return std::vector<byte>(); - } - -bool Channel::secure_renegotiation_supported() const - { - if(auto active = active_state()) - return active->server_hello()->secure_renegotiation(); - - if(auto pending = pending_state()) - if(auto hello = pending->server_hello()) - return hello->secure_renegotiation(); - - return false; - } - -SymmetricKey Channel::key_material_export(const std::string& label, - const std::string& context, - size_t length) const - { - if(auto active = active_state()) - { - std::unique_ptr<KDF> prf(active->protocol_specific_prf()); - - const secure_vector<byte>& master_secret = - active->session_keys().master_secret(); - - std::vector<byte> salt; - salt += to_byte_vector(label); - salt += active->client_hello()->random(); - salt += active->server_hello()->random(); - - if(context != "") - { - size_t context_size = context.length(); - if(context_size > 0xFFFF) - throw std::runtime_error("key_material_export context is too long"); - salt.push_back(get_byte<u16bit>(0, context_size)); - salt.push_back(get_byte<u16bit>(1, context_size)); - salt += to_byte_vector(context); - } - - return prf->derive_key(length, master_secret, salt); - } - else - throw std::runtime_error("Channel::key_material_export connection not active"); - } - -} - -} - diff --git a/src/tls/tls_channel.h b/src/tls/tls_channel.h deleted file mode 100644 index e7b53f563..000000000 --- a/src/tls/tls_channel.h +++ /dev/null @@ -1,259 +0,0 @@ -/* -* TLS Channel -* (C) 2011,2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_CHANNEL_H__ -#define BOTAN_TLS_CHANNEL_H__ - -#include <botan/tls_policy.h> -#include <botan/tls_session.h> -#include <botan/tls_alert.h> -#include <botan/tls_session_manager.h> -#include <botan/x509cert.h> -#include <vector> -#include <string> -#include <memory> -#include <map> - -namespace Botan { - -namespace TLS { - -class Connection_Cipher_State; -class Connection_Sequence_Numbers; -class Handshake_State; - -/** -* Generic interface for TLS endpoint -*/ -class BOTAN_DLL Channel - { - public: - /** - * Inject TLS traffic received from counterparty - * @return a hint as the how many more bytes we need to process the - * current record (this may be 0 if on a record boundary) - */ - size_t received_data(const byte buf[], size_t buf_size); - - /** - * Inject TLS traffic received from counterparty - * @return a hint as the how many more bytes we need to process the - * current record (this may be 0 if on a record boundary) - */ - size_t received_data(const std::vector<byte>& buf); - - /** - * Inject plaintext intended for counterparty - */ - void send(const byte buf[], size_t buf_size); - - /** - * Inject plaintext intended for counterparty - */ - void send(const std::string& val); - - /** - * Inject plaintext intended for counterparty - */ - template<typename Alloc> - void send(const std::vector<unsigned char, Alloc>& val) - { - send(&val[0], val.size()); - } - - /** - * Send a TLS alert message. If the alert is fatal, the internal - * state (keys, etc) will be reset. - * @param alert the Alert to send - */ - void send_alert(const Alert& alert); - - /** - * Send a warning alert - */ - void send_warning_alert(Alert::Type type) { send_alert(Alert(type, false)); } - - /** - * Send a fatal alert - */ - void send_fatal_alert(Alert::Type type) { send_alert(Alert(type, true)); } - - /** - * Send a close notification alert - */ - void close() { send_warning_alert(Alert::CLOSE_NOTIFY); } - - /** - * @return true iff the connection is active for sending application data - */ - bool is_active() const; - - /** - * @return true iff the connection has been definitely closed - */ - bool is_closed() const; - - /** - * Attempt to renegotiate the session - * @param force_full_renegotiation if true, require a full renegotiation, - * otherwise allow session resumption - */ - void renegotiate(bool force_full_renegotiation = false); - - /** - * @return true iff the peer supports heartbeat messages - */ - bool peer_supports_heartbeats() const; - - /** - * @return true iff we are allowed to send heartbeat messages - */ - bool heartbeat_sending_allowed() const; - - /** - * @return true iff the counterparty supports the secure - * renegotiation extensions. - */ - bool secure_renegotiation_supported() const; - - /** - * Attempt to send a heartbeat message (if negotiated with counterparty) - * @param payload will be echoed back - * @param payload_size size of payload in bytes - */ - void heartbeat(const byte payload[], size_t payload_size); - - /** - * Attempt to send a heartbeat message (if negotiated with counterparty) - */ - void heartbeat() { heartbeat(nullptr, 0); } - - /** - * @return certificate chain of the peer (may be empty) - */ - std::vector<X509_Certificate> peer_cert_chain() const; - - /** - * Key material export (RFC 5705) - * @param label a disambiguating label string - * @param context a per-association context value - * @param length the length of the desired key in bytes - * @return key of length bytes - */ - SymmetricKey key_material_export(const std::string& label, - const std::string& context, - size_t length) const; - - Channel(std::function<void (const byte[], size_t)> socket_output_fn, - std::function<void (const byte[], size_t)> data_cb, - std::function<void (Alert, const byte[], size_t)> alert_cb, - std::function<bool (const Session&)> handshake_cb, - Session_Manager& session_manager, - RandomNumberGenerator& rng, - size_t reserved_io_buffer_size); - - Channel(const Channel&) = delete; - - Channel& operator=(const Channel&) = delete; - - virtual ~Channel(); - protected: - - virtual void process_handshake_msg(const Handshake_State* active_state, - Handshake_State& pending_state, - Handshake_Type type, - const std::vector<byte>& contents) = 0; - - virtual void initiate_handshake(Handshake_State& state, - bool force_full_renegotiation) = 0; - - virtual std::vector<X509_Certificate> - get_peer_cert_chain(const Handshake_State& state) const = 0; - - virtual Handshake_State* new_handshake_state(class Handshake_IO* io) = 0; - - Handshake_State& create_handshake_state(Protocol_Version version); - - void activate_session(); - - void change_cipher_spec_reader(Connection_Side side); - - void change_cipher_spec_writer(Connection_Side side); - - /* secure renegotiation handling */ - - void secure_renegotiation_check(const class Client_Hello* client_hello); - void secure_renegotiation_check(const class Server_Hello* server_hello); - - std::vector<byte> secure_renegotiation_data_for_client_hello() const; - std::vector<byte> secure_renegotiation_data_for_server_hello() const; - - RandomNumberGenerator& rng() { return m_rng; } - - Session_Manager& session_manager() { return m_session_manager; } - - bool save_session(const Session& session) const { return m_handshake_cb(session); } - - private: - size_t maximum_fragment_size() const; - - void send_record(byte record_type, const std::vector<byte>& record); - - void send_record_under_epoch(u16bit epoch, byte record_type, - const std::vector<byte>& record); - - void send_record_array(u16bit epoch, byte record_type, - const byte input[], size_t length); - - void write_record(Connection_Cipher_State* cipher_state, - byte type, const byte input[], size_t length); - - Connection_Sequence_Numbers& sequence_numbers() const; - - std::shared_ptr<Connection_Cipher_State> read_cipher_state_epoch(u16bit epoch) const; - - std::shared_ptr<Connection_Cipher_State> write_cipher_state_epoch(u16bit epoch) const; - - void reset_state(); - - const Handshake_State* active_state() const { return m_active_state.get(); } - - const Handshake_State* pending_state() const { return m_pending_state.get(); } - - /* callbacks */ - std::function<bool (const Session&)> m_handshake_cb; - std::function<void (const byte[], size_t)> m_data_cb; - std::function<void (Alert, const byte[], size_t)> m_alert_cb; - std::function<void (const byte[], size_t)> m_output_fn; - - /* external state */ - RandomNumberGenerator& m_rng; - Session_Manager& m_session_manager; - - /* sequence number state */ - std::unique_ptr<Connection_Sequence_Numbers> m_sequence_numbers; - - /* pending and active connection states */ - std::unique_ptr<Handshake_State> m_active_state; - std::unique_ptr<Handshake_State> m_pending_state; - - /* cipher states for each epoch - epoch 0 is plaintext, thus null cipher state */ - std::map<u16bit, std::shared_ptr<Connection_Cipher_State>> m_write_cipher_states = - { { 0, nullptr } }; - std::map<u16bit, std::shared_ptr<Connection_Cipher_State>> m_read_cipher_states = - { { 0, nullptr } }; - - /* I/O buffers */ - secure_vector<byte> m_writebuf; - secure_vector<byte> m_readbuf; - }; - -} - -} - -#endif diff --git a/src/tls/tls_ciphersuite.cpp b/src/tls/tls_ciphersuite.cpp deleted file mode 100644 index e8c551b01..000000000 --- a/src/tls/tls_ciphersuite.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* -* TLS Cipher Suite -* (C) 2004-2010,2012,2013 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/tls_ciphersuite.h> -#include <botan/libstate.h> -#include <botan/parsing.h> -#include <sstream> -#include <stdexcept> - -namespace Botan { - -namespace TLS { - -namespace { - -/* -* This way all work happens at the constuctor call, and we can -* rely on that happening only once in C++11. -*/ -std::vector<Ciphersuite> gather_known_ciphersuites() - { - std::vector<Ciphersuite> ciphersuites; - - for(size_t i = 0; i <= 0xFFFF; ++i) - { - Ciphersuite suite = Ciphersuite::by_id(i); - - if(suite.valid()) - ciphersuites.push_back(suite); - } - - return ciphersuites; - } - -} - -const std::vector<Ciphersuite>& Ciphersuite::all_known_ciphersuites() - { - static std::vector<Ciphersuite> all_ciphersuites(gather_known_ciphersuites()); - return all_ciphersuites; - } - -Ciphersuite Ciphersuite::by_name(const std::string& name) - { - for(auto suite : all_known_ciphersuites()) - { - if(suite.to_string() == name) - return suite; - } - - return Ciphersuite(); // some unknown ciphersuite - } - -Ciphersuite::Ciphersuite(u16bit ciphersuite_code, - const char* sig_algo, - const char* kex_algo, - const char* cipher_algo, - size_t cipher_keylen, - size_t cipher_ivlen, - const char* mac_algo, - size_t mac_keylen, - const char* prf_algo) : - m_ciphersuite_code(ciphersuite_code), - m_sig_algo(sig_algo), - m_kex_algo(kex_algo), - m_cipher_algo(cipher_algo), - m_mac_algo(mac_algo), - m_prf_algo(prf_algo), - m_cipher_keylen(cipher_keylen), - m_cipher_ivlen(cipher_ivlen), - m_mac_keylen(mac_keylen) - { - } - -bool Ciphersuite::psk_ciphersuite() const - { - return (kex_algo() == "PSK" || - kex_algo() == "DHE_PSK" || - kex_algo() == "ECDHE_PSK"); - } - -bool Ciphersuite::ecc_ciphersuite() const - { - return (sig_algo() == "ECDSA" || kex_algo() == "ECDH" || kex_algo() == "ECDHE_PSK"); - } - -bool Ciphersuite::valid() const - { - if(!m_cipher_keylen) // uninitialized object - return false; - - Algorithm_Factory& af = global_state().algorithm_factory(); - - if(!af.prototype_hash_function(prf_algo())) - return false; - - if(mac_algo() == "AEAD") - { - auto cipher_and_mode = split_on(cipher_algo(), '/'); - BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo"); - if(!af.prototype_block_cipher(cipher_and_mode[0])) - return false; - - const auto mode = cipher_and_mode[1]; - -#if !defined(BOTAN_HAS_AEAD_CCM) - if(mode == "CCM" || mode == "CCM-8") - return false; -#endif - -#if !defined(BOTAN_HAS_AEAD_GCM) - if(mode == "GCM") - return false; -#endif - -#if !defined(BOTAN_HAS_AEAD_OCB) - if(mode == "OCB") - return false; -#endif - } - else - { - if(!af.prototype_block_cipher(cipher_algo()) && - !af.prototype_stream_cipher(cipher_algo())) - return false; - - if(!af.prototype_hash_function(mac_algo())) - return false; - } - - if(kex_algo() == "SRP_SHA") - { -#if !defined(BOTAN_HAS_SRP6) - return false; -#endif - } - else if(kex_algo() == "ECDH" || kex_algo() == "ECDHE_PSK") - { -#if !defined(BOTAN_HAS_ECDH) - return false; -#endif - } - else if(kex_algo() == "DH" || kex_algo() == "DHE_PSK") - { -#if !defined(BOTAN_HAS_DIFFIE_HELLMAN) - return false; -#endif - } - - if(sig_algo() == "DSA") - { -#if !defined(BOTAN_HAS_DSA) - return false; -#endif - } - else if(sig_algo() == "ECDSA") - { -#if !defined(BOTAN_HAS_ECDSA) - return false; -#endif - } - else if(sig_algo() == "RSA") - { -#if !defined(BOTAN_HAS_RSA) - return false; -#endif - } - - return true; - } - -std::string Ciphersuite::to_string() const - { - if(m_cipher_keylen == 0) - throw std::runtime_error("Ciphersuite::to_string - no value set"); - - std::ostringstream out; - - out << "TLS_"; - - if(kex_algo() != "RSA") - { - if(kex_algo() == "DH") - out << "DHE"; - else if(kex_algo() == "ECDH") - out << "ECDHE"; - else - out << kex_algo(); - - out << '_'; - } - - if(sig_algo() == "DSA") - out << "DSS_"; - else if(sig_algo() != "") - out << sig_algo() << '_'; - - out << "WITH_"; - - if(cipher_algo() == "RC4") - { - out << "RC4_128_"; - } - else - { - if(cipher_algo() == "3DES") - out << "3DES_EDE"; - else if(cipher_algo().find("Camellia") == 0) - out << "CAMELLIA_" << std::to_string(8*cipher_keylen()); - else - out << replace_chars(cipher_algo(), {'-', '/'}, '_'); - - if(cipher_algo().find("/") != std::string::npos) - out << "_"; // some explicit mode already included - else - out << "_CBC_"; - } - - if(mac_algo() == "SHA-1") - out << "SHA"; - else if(mac_algo() == "AEAD") - out << erase_chars(prf_algo(), {'-'}); - else - out << erase_chars(mac_algo(), {'-'}); - - return out.str(); - } - -} - -} - diff --git a/src/tls/tls_ciphersuite.h b/src/tls/tls_ciphersuite.h deleted file mode 100644 index 865e66abb..000000000 --- a/src/tls/tls_ciphersuite.h +++ /dev/null @@ -1,137 +0,0 @@ -/* -* TLS Cipher Suites -* (C) 2004-2011,2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_CIPHER_SUITES_H__ -#define BOTAN_TLS_CIPHER_SUITES_H__ - -#include <botan/types.h> -#include <string> -#include <vector> - -namespace Botan { - -namespace TLS { - -/** -* Ciphersuite Information -*/ -class BOTAN_DLL Ciphersuite - { - public: - /** - * Convert an SSL/TLS ciphersuite to algorithm fields - * @param suite the ciphersuite code number - * @return ciphersuite object - */ - static Ciphersuite by_id(u16bit suite); - - /** - * Lookup a ciphersuite by name - * @param name the name (eg TLS_RSA_WITH_RC4_128_SHA) - * @return ciphersuite object - */ - static Ciphersuite by_name(const std::string& name); - - /** - * Generate a static list of all known ciphersuites and return it. - * - * @return list of all known ciphersuites - */ - static const std::vector<Ciphersuite>& all_known_ciphersuites(); - - /** - * Formats the ciphersuite back to an RFC-style ciphersuite string - * @return RFC ciphersuite string identifier - */ - std::string to_string() const; - - /** - * @return ciphersuite number - */ - u16bit ciphersuite_code() const { return m_ciphersuite_code; } - - /** - * @return true if this is a PSK ciphersuite - */ - bool psk_ciphersuite() const; - - /** - * @return true if this is an ECC ciphersuite - */ - bool ecc_ciphersuite() const; - - /** - * @return key exchange algorithm used by this ciphersuite - */ - std::string kex_algo() const { return m_kex_algo; } - - /** - * @return signature algorithm used by this ciphersuite - */ - std::string sig_algo() const { return m_sig_algo; } - - /** - * @return symmetric cipher algorithm used by this ciphersuite - */ - std::string cipher_algo() const { return m_cipher_algo; } - - /** - * @return message authentication algorithm used by this ciphersuite - */ - std::string mac_algo() const { return m_mac_algo; } - - std::string prf_algo() const - { - return (m_prf_algo != "") ? m_prf_algo : m_mac_algo; - } - - /** - * @return cipher key length used by this ciphersuite - */ - size_t cipher_keylen() const { return m_cipher_keylen; } - - size_t cipher_ivlen() const { return m_cipher_ivlen; } - - size_t mac_keylen() const { return m_mac_keylen; } - - /** - * @return true if this is a valid/known ciphersuite - */ - bool valid() const; - - Ciphersuite() {} - - private: - - Ciphersuite(u16bit ciphersuite_code, - const char* sig_algo, - const char* kex_algo, - const char* cipher_algo, - size_t cipher_keylen, - size_t cipher_ivlen, - const char* mac_algo, - size_t mac_keylen, - const char* prf_algo = ""); - - u16bit m_ciphersuite_code = 0; - - std::string m_sig_algo; - std::string m_kex_algo; - std::string m_cipher_algo; - std::string m_mac_algo; - std::string m_prf_algo; - - size_t m_cipher_keylen = 0; - size_t m_cipher_ivlen = 0; - size_t m_mac_keylen = 0; - }; - -} - -} - -#endif 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"); - } - -} - -} diff --git a/src/tls/tls_client.h b/src/tls/tls_client.h deleted file mode 100644 index c4440c7ac..000000000 --- a/src/tls/tls_client.h +++ /dev/null @@ -1,106 +0,0 @@ -/* -* TLS Client -* (C) 2004-2011 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_CLIENT_H__ -#define BOTAN_TLS_CLIENT_H__ - -#include <botan/tls_channel.h> -#include <botan/credentials_manager.h> -#include <vector> - -namespace Botan { - -namespace TLS { - -/** -* SSL/TLS Client -*/ -class BOTAN_DLL Client : public Channel - { - public: - /** - * Set up a new TLS client session - * - * @param socket_output_fn is called with data for the outbound socket - * - * @param proc_cb is called when new application data is received - * - * @param alert_cb is called when a TLS alert is received - * - * @param handshake_cb is called when a handshake is completed - * - * @param session_manager manages session state - * - * @param creds manages application/user credentials - * - * @param policy specifies other connection policy information - * - * @param rng a random number generator - * - * @param server_info is identifying information about the TLS server - * - * @param offer_version specifies which version we will offer - * to the TLS server. - * - * @param next_protocol allows the client to specify what the next - * protocol will be. For more information read - * http://technotes.googlecode.com/git/nextprotoneg.html. - * - * If the function is not empty, NPN will be negotiated - * and if the server supports NPN the function will be - * called with the list of protocols the server advertised; - * the client should return the protocol it would like to use. - * - * @param reserved_io_buffer_size This many bytes of memory will - * be preallocated for the read and write buffers. Smaller - * values just mean reallocations and copies are more likely. - */ - Client(std::function<void (const byte[], size_t)> socket_output_fn, - std::function<void (const byte[], size_t)> data_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& server_info = Server_Information(), - const Protocol_Version offer_version = Protocol_Version::latest_tls_version(), - std::function<std::string (std::vector<std::string>)> next_protocol = - std::function<std::string (std::vector<std::string>)>(), - size_t reserved_io_buffer_size = 16*1024 - ); - private: - std::vector<X509_Certificate> - get_peer_cert_chain(const Handshake_State& state) const override; - - void initiate_handshake(Handshake_State& state, - bool force_full_renegotiation) override; - - void send_client_hello(Handshake_State& state, - bool force_full_renegotiation, - Protocol_Version version, - const std::string& srp_identifier = "", - std::function<std::string (std::vector<std::string>)> next_protocol = - std::function<std::string (std::vector<std::string>)>()); - - void process_handshake_msg(const Handshake_State* active_state, - Handshake_State& pending_state, - Handshake_Type type, - const std::vector<byte>& contents) override; - - Handshake_State* new_handshake_state(Handshake_IO* io) override; - - const Policy& m_policy; - Credentials_Manager& m_creds; - const Server_Information m_info; - }; - -} - -} - -#endif diff --git a/src/tls/tls_exceptn.h b/src/tls/tls_exceptn.h deleted file mode 100644 index 529d1f315..000000000 --- a/src/tls/tls_exceptn.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -* Exceptions -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_EXCEPTION_H__ -#define BOTAN_TLS_EXCEPTION_H__ - -#include <botan/exceptn.h> -#include <botan/tls_alert.h> - -namespace Botan { - -namespace TLS { - -/** -* Exception Base Class -*/ -class BOTAN_DLL TLS_Exception : public Exception - { - public: - Alert::Type type() const noexcept { return alert_type; } - - TLS_Exception(Alert::Type type, - const std::string& err_msg = "Unknown error") : - Exception(err_msg), alert_type(type) {} - - private: - Alert::Type alert_type; - }; - -/** -* Unexpected_Message Exception -*/ -struct BOTAN_DLL Unexpected_Message : public TLS_Exception - { - Unexpected_Message(const std::string& err) : - TLS_Exception(Alert::UNEXPECTED_MESSAGE, err) {} - }; - -} - -} - -#endif diff --git a/src/tls/tls_extensions.cpp b/src/tls/tls_extensions.cpp deleted file mode 100644 index 1ae9f1749..000000000 --- a/src/tls/tls_extensions.cpp +++ /dev/null @@ -1,533 +0,0 @@ -/* -* TLS Extensions -* (C) 2011,2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/internal/tls_extensions.h> -#include <botan/internal/tls_reader.h> -#include <botan/tls_exceptn.h> - -namespace Botan { - -namespace TLS { - -namespace { - -Extension* make_extension(TLS_Data_Reader& reader, - u16bit code, - u16bit size) - { - switch(code) - { - case TLSEXT_SERVER_NAME_INDICATION: - return new Server_Name_Indicator(reader, size); - - case TLSEXT_MAX_FRAGMENT_LENGTH: - return new Maximum_Fragment_Length(reader, size); - - case TLSEXT_SRP_IDENTIFIER: - return new SRP_Identifier(reader, size); - - case TLSEXT_USABLE_ELLIPTIC_CURVES: - return new Supported_Elliptic_Curves(reader, size); - - case TLSEXT_SAFE_RENEGOTIATION: - return new Renegotiation_Extension(reader, size); - - case TLSEXT_SIGNATURE_ALGORITHMS: - return new Signature_Algorithms(reader, size); - - case TLSEXT_NEXT_PROTOCOL: - return new Next_Protocol_Notification(reader, size); - - case TLSEXT_HEARTBEAT_SUPPORT: - return new Heartbeat_Support_Indicator(reader, size); - - case TLSEXT_SESSION_TICKET: - return new Session_Ticket(reader, size); - - default: - return nullptr; // not known - } - } - -} - -void Extensions::deserialize(TLS_Data_Reader& reader) - { - if(reader.has_remaining()) - { - const u16bit all_extn_size = reader.get_u16bit(); - - if(reader.remaining_bytes() != all_extn_size) - throw Decoding_Error("Bad extension size"); - - while(reader.has_remaining()) - { - const u16bit extension_code = reader.get_u16bit(); - const u16bit extension_size = reader.get_u16bit(); - - Extension* extn = make_extension(reader, - extension_code, - extension_size); - - if(extn) - this->add(extn); - else // unknown/unhandled extension - reader.discard_next(extension_size); - } - } - } - -std::vector<byte> Extensions::serialize() const - { - std::vector<byte> buf(2); // 2 bytes for length field - - for(auto& extn : extensions) - { - if(extn.second->empty()) - continue; - - const u16bit extn_code = extn.second->type(); - - std::vector<byte> extn_val = extn.second->serialize(); - - buf.push_back(get_byte(0, extn_code)); - buf.push_back(get_byte(1, extn_code)); - - buf.push_back(get_byte<u16bit>(0, extn_val.size())); - buf.push_back(get_byte<u16bit>(1, extn_val.size())); - - buf += extn_val; - } - - const u16bit extn_size = buf.size() - 2; - - buf[0] = get_byte(0, extn_size); - buf[1] = get_byte(1, extn_size); - - // avoid sending a completely empty extensions block - if(buf.size() == 2) - return std::vector<byte>(); - - return buf; - } - -Server_Name_Indicator::Server_Name_Indicator(TLS_Data_Reader& reader, - u16bit extension_size) - { - /* - * This is used by the server to confirm that it knew the name - */ - if(extension_size == 0) - return; - - u16bit name_bytes = reader.get_u16bit(); - - if(name_bytes + 2 != extension_size) - throw Decoding_Error("Bad encoding of SNI extension"); - - while(name_bytes) - { - byte name_type = reader.get_byte(); - name_bytes--; - - if(name_type == 0) // DNS - { - sni_host_name = reader.get_string(2, 1, 65535); - name_bytes -= (2 + sni_host_name.size()); - } - else // some other unknown name type - { - reader.discard_next(name_bytes); - name_bytes = 0; - } - } - } - -std::vector<byte> Server_Name_Indicator::serialize() const - { - std::vector<byte> buf; - - size_t name_len = sni_host_name.size(); - - buf.push_back(get_byte<u16bit>(0, name_len+3)); - buf.push_back(get_byte<u16bit>(1, name_len+3)); - buf.push_back(0); // DNS - - buf.push_back(get_byte<u16bit>(0, name_len)); - buf.push_back(get_byte<u16bit>(1, name_len)); - - buf += std::make_pair( - reinterpret_cast<const byte*>(sni_host_name.data()), - sni_host_name.size()); - - return buf; - } - -SRP_Identifier::SRP_Identifier(TLS_Data_Reader& reader, - u16bit extension_size) - { - srp_identifier = reader.get_string(1, 1, 255); - - if(srp_identifier.size() + 1 != extension_size) - throw Decoding_Error("Bad encoding for SRP identifier extension"); - } - -std::vector<byte> SRP_Identifier::serialize() const - { - std::vector<byte> buf; - - const byte* srp_bytes = - reinterpret_cast<const byte*>(srp_identifier.data()); - - append_tls_length_value(buf, srp_bytes, srp_identifier.size(), 1); - - return buf; - } - -Renegotiation_Extension::Renegotiation_Extension(TLS_Data_Reader& reader, - u16bit extension_size) - { - reneg_data = reader.get_range<byte>(1, 0, 255); - - if(reneg_data.size() + 1 != extension_size) - throw Decoding_Error("Bad encoding for secure renegotiation extn"); - } - -std::vector<byte> Renegotiation_Extension::serialize() const - { - std::vector<byte> buf; - append_tls_length_value(buf, reneg_data, 1); - return buf; - } - -std::vector<byte> Maximum_Fragment_Length::serialize() const - { - const std::map<size_t, byte> fragment_to_code = { { 512, 1 }, - { 1024, 2 }, - { 2048, 3 }, - { 4096, 4 } }; - - auto i = fragment_to_code.find(m_max_fragment); - - if(i == fragment_to_code.end()) - throw std::invalid_argument("Bad setting " + - std::to_string(m_max_fragment) + - " for maximum fragment size"); - - return std::vector<byte>(1, i->second); - } - -Maximum_Fragment_Length::Maximum_Fragment_Length(TLS_Data_Reader& reader, - u16bit extension_size) - { - if(extension_size != 1) - throw Decoding_Error("Bad size for maximum fragment extension"); - byte val = reader.get_byte(); - - const std::map<byte, size_t> code_to_fragment = { { 1, 512 }, - { 2, 1024 }, - { 3, 2048 }, - { 4, 4096 } }; - - auto i = code_to_fragment.find(val); - - if(i == code_to_fragment.end()) - throw TLS_Exception(Alert::ILLEGAL_PARAMETER, - "Bad value in maximum fragment extension"); - - m_max_fragment = i->second; - } - -Next_Protocol_Notification::Next_Protocol_Notification(TLS_Data_Reader& reader, - u16bit extension_size) - { - if(extension_size == 0) - return; // empty extension - - size_t bytes_remaining = extension_size; - - while(bytes_remaining) - { - const std::string p = reader.get_string(1, 0, 255); - - if(bytes_remaining < p.size() + 1) - throw Decoding_Error("Bad encoding for next protocol extension"); - - bytes_remaining -= (p.size() + 1); - - m_protocols.push_back(p); - } - } - -std::vector<byte> Next_Protocol_Notification::serialize() const - { - std::vector<byte> buf; - - for(size_t i = 0; i != m_protocols.size(); ++i) - { - const std::string p = m_protocols[i]; - - if(p != "") - append_tls_length_value(buf, - reinterpret_cast<const byte*>(p.data()), - p.size(), - 1); - } - - return buf; - } - -std::string Supported_Elliptic_Curves::curve_id_to_name(u16bit id) - { - switch(id) - { - case 15: - return "secp160k1"; - case 16: - return "secp160r1"; - case 17: - return "secp160r2"; - case 18: - return "secp192k1"; - case 19: - return "secp192r1"; - case 20: - return "secp224k1"; - case 21: - return "secp224r1"; - case 22: - return "secp256k1"; - case 23: - return "secp256r1"; - case 24: - return "secp384r1"; - case 25: - return "secp521r1"; - case 26: - return "brainpool256r1"; - case 27: - return "brainpool384r1"; - case 28: - return "brainpool512r1"; - default: - return ""; // something we don't know or support - } - } - -u16bit Supported_Elliptic_Curves::name_to_curve_id(const std::string& name) - { - if(name == "secp160k1") - return 15; - if(name == "secp160r1") - return 16; - if(name == "secp160r2") - return 17; - if(name == "secp192k1") - return 18; - if(name == "secp192r1") - return 19; - if(name == "secp224k1") - return 20; - if(name == "secp224r1") - return 21; - if(name == "secp256k1") - return 22; - if(name == "secp256r1") - return 23; - if(name == "secp384r1") - return 24; - if(name == "secp521r1") - return 25; - if(name == "brainpool256r1") - return 26; - if(name == "brainpool384r1") - return 27; - if(name == "brainpool512r1") - return 28; - - throw Invalid_Argument("name_to_curve_id unknown name " + name); - } - -std::vector<byte> Supported_Elliptic_Curves::serialize() const - { - std::vector<byte> buf(2); - - for(size_t i = 0; i != m_curves.size(); ++i) - { - const u16bit id = name_to_curve_id(m_curves[i]); - buf.push_back(get_byte(0, id)); - buf.push_back(get_byte(1, id)); - } - - buf[0] = get_byte<u16bit>(0, buf.size()-2); - buf[1] = get_byte<u16bit>(1, buf.size()-2); - - return buf; - } - -Supported_Elliptic_Curves::Supported_Elliptic_Curves(TLS_Data_Reader& reader, - u16bit extension_size) - { - u16bit len = reader.get_u16bit(); - - if(len + 2 != extension_size) - throw Decoding_Error("Inconsistent length field in elliptic curve list"); - - if(len % 2 == 1) - throw Decoding_Error("Elliptic curve list of strange size"); - - len /= 2; - - for(size_t i = 0; i != len; ++i) - { - const u16bit id = reader.get_u16bit(); - const std::string name = curve_id_to_name(id); - - if(name != "") - m_curves.push_back(name); - } - } - -std::string Signature_Algorithms::hash_algo_name(byte code) - { - switch(code) - { - case 1: - return "MD5"; - // code 1 is MD5 - ignore it - - case 2: - return "SHA-1"; - case 3: - return "SHA-224"; - case 4: - return "SHA-256"; - case 5: - return "SHA-384"; - case 6: - return "SHA-512"; - default: - return ""; - } - } - -byte Signature_Algorithms::hash_algo_code(const std::string& name) - { - if(name == "MD5") - return 1; - - if(name == "SHA-1") - return 2; - - if(name == "SHA-224") - return 3; - - if(name == "SHA-256") - return 4; - - if(name == "SHA-384") - return 5; - - if(name == "SHA-512") - return 6; - - throw Internal_Error("Unknown hash ID " + name + " for signature_algorithms"); - } - -std::string Signature_Algorithms::sig_algo_name(byte code) - { - switch(code) - { - case 1: - return "RSA"; - case 2: - return "DSA"; - case 3: - return "ECDSA"; - default: - return ""; - } - } - -byte Signature_Algorithms::sig_algo_code(const std::string& name) - { - if(name == "RSA") - return 1; - - if(name == "DSA") - return 2; - - if(name == "ECDSA") - return 3; - - throw Internal_Error("Unknown sig ID " + name + " for signature_algorithms"); - } - -std::vector<byte> Signature_Algorithms::serialize() const - { - std::vector<byte> buf(2); - - for(size_t i = 0; i != m_supported_algos.size(); ++i) - { - try - { - const byte hash_code = hash_algo_code(m_supported_algos[i].first); - const byte sig_code = sig_algo_code(m_supported_algos[i].second); - - buf.push_back(hash_code); - buf.push_back(sig_code); - } - catch(...) - {} - } - - buf[0] = get_byte<u16bit>(0, buf.size()-2); - buf[1] = get_byte<u16bit>(1, buf.size()-2); - - return buf; - } - -Signature_Algorithms::Signature_Algorithms(const std::vector<std::string>& hashes, - const std::vector<std::string>& sigs) - { - for(size_t i = 0; i != hashes.size(); ++i) - for(size_t j = 0; j != sigs.size(); ++j) - m_supported_algos.push_back(std::make_pair(hashes[i], sigs[j])); - } - -Signature_Algorithms::Signature_Algorithms(TLS_Data_Reader& reader, - u16bit extension_size) - { - u16bit len = reader.get_u16bit(); - - if(len + 2 != extension_size) - throw Decoding_Error("Bad encoding on signature algorithms extension"); - - while(len) - { - const std::string hash_code = hash_algo_name(reader.get_byte()); - const std::string sig_code = sig_algo_name(reader.get_byte()); - - len -= 2; - - // If not something we know, ignore it completely - if(hash_code == "" || sig_code == "") - continue; - - m_supported_algos.push_back(std::make_pair(hash_code, sig_code)); - } - } - -Session_Ticket::Session_Ticket(TLS_Data_Reader& reader, - u16bit extension_size) - { - m_ticket = reader.get_elem<byte, std::vector<byte> >(extension_size); - } - -} - -} diff --git a/src/tls/tls_extensions.h b/src/tls/tls_extensions.h deleted file mode 100644 index de3654fd3..000000000 --- a/src/tls/tls_extensions.h +++ /dev/null @@ -1,397 +0,0 @@ -/* -* TLS Extensions -* (C) 2011-2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_EXTENSIONS_H__ -#define BOTAN_TLS_EXTENSIONS_H__ - -#include <botan/secmem.h> -#include <botan/tls_magic.h> -#include <vector> -#include <string> -#include <memory> -#include <map> - -namespace Botan { - -namespace TLS { - -class TLS_Data_Reader; - -enum Handshake_Extension_Type { - TLSEXT_SERVER_NAME_INDICATION = 0, - TLSEXT_MAX_FRAGMENT_LENGTH = 1, - TLSEXT_CLIENT_CERT_URL = 2, - TLSEXT_TRUSTED_CA_KEYS = 3, - TLSEXT_TRUNCATED_HMAC = 4, - - TLSEXT_CERTIFICATE_TYPES = 9, - TLSEXT_USABLE_ELLIPTIC_CURVES = 10, - TLSEXT_EC_POINT_FORMATS = 11, - TLSEXT_SRP_IDENTIFIER = 12, - TLSEXT_SIGNATURE_ALGORITHMS = 13, - TLSEXT_HEARTBEAT_SUPPORT = 15, - - TLSEXT_SESSION_TICKET = 35, - - TLSEXT_NEXT_PROTOCOL = 13172, - - TLSEXT_SAFE_RENEGOTIATION = 65281, -}; - -/** -* Base class representing a TLS extension of some kind -*/ -class Extension - { - public: - /** - * @return code number of the extension - */ - virtual Handshake_Extension_Type type() const = 0; - - /** - * @return serialized binary for the extension - */ - virtual std::vector<byte> serialize() const = 0; - - /** - * @return if we should encode this extension or not - */ - virtual bool empty() const = 0; - - virtual ~Extension() {} - }; - -/** -* Server Name Indicator extension (RFC 3546) -*/ -class Server_Name_Indicator : public Extension - { - public: - static Handshake_Extension_Type static_type() - { return TLSEXT_SERVER_NAME_INDICATION; } - - Handshake_Extension_Type type() const { return static_type(); } - - Server_Name_Indicator(const std::string& host_name) : - sni_host_name(host_name) {} - - Server_Name_Indicator(TLS_Data_Reader& reader, - u16bit extension_size); - - std::string host_name() const { return sni_host_name; } - - std::vector<byte> serialize() const; - - bool empty() const { return sni_host_name == ""; } - private: - std::string sni_host_name; - }; - -/** -* SRP identifier extension (RFC 5054) -*/ -class SRP_Identifier : public Extension - { - public: - static Handshake_Extension_Type static_type() - { return TLSEXT_SRP_IDENTIFIER; } - - Handshake_Extension_Type type() const { return static_type(); } - - SRP_Identifier(const std::string& identifier) : - srp_identifier(identifier) {} - - SRP_Identifier(TLS_Data_Reader& reader, - u16bit extension_size); - - std::string identifier() const { return srp_identifier; } - - std::vector<byte> serialize() const; - - bool empty() const { return srp_identifier == ""; } - private: - std::string srp_identifier; - }; - -/** -* Renegotiation Indication Extension (RFC 5746) -*/ -class Renegotiation_Extension : public Extension - { - public: - static Handshake_Extension_Type static_type() - { return TLSEXT_SAFE_RENEGOTIATION; } - - Handshake_Extension_Type type() const { return static_type(); } - - Renegotiation_Extension() {} - - Renegotiation_Extension(const std::vector<byte>& bits) : - reneg_data(bits) {} - - Renegotiation_Extension(TLS_Data_Reader& reader, - u16bit extension_size); - - const std::vector<byte>& renegotiation_info() const - { return reneg_data; } - - std::vector<byte> serialize() const; - - bool empty() const { return false; } // always send this - private: - std::vector<byte> reneg_data; - }; - -/** -* Maximum Fragment Length Negotiation Extension (RFC 4366 sec 3.2) -*/ -class Maximum_Fragment_Length : public Extension - { - public: - static Handshake_Extension_Type static_type() - { return TLSEXT_MAX_FRAGMENT_LENGTH; } - - Handshake_Extension_Type type() const { return static_type(); } - - bool empty() const { return false; } - - size_t fragment_size() const { return m_max_fragment; } - - std::vector<byte> serialize() const; - - /** - * @param max_fragment specifies what maximum fragment size to - * advertise. Currently must be one of 512, 1024, 2048, or - * 4096. - */ - Maximum_Fragment_Length(size_t max_fragment) : - m_max_fragment(max_fragment) {} - - Maximum_Fragment_Length(TLS_Data_Reader& reader, - u16bit extension_size); - - private: - size_t m_max_fragment; - }; - -/** -* Next Protocol Negotiation -* http://technotes.googlecode.com/git/nextprotoneg.html -* -* This implementation requires the semantics defined in the Google -* spec (implemented in Chromium); the internet draft leaves the format -* unspecified. -*/ -class Next_Protocol_Notification : public Extension - { - public: - static Handshake_Extension_Type static_type() - { return TLSEXT_NEXT_PROTOCOL; } - - Handshake_Extension_Type type() const { return static_type(); } - - const std::vector<std::string>& protocols() const - { return m_protocols; } - - /** - * Empty extension, used by client - */ - Next_Protocol_Notification() {} - - /** - * List of protocols, used by server - */ - Next_Protocol_Notification(const std::vector<std::string>& protocols) : - m_protocols(protocols) {} - - Next_Protocol_Notification(TLS_Data_Reader& reader, - u16bit extension_size); - - std::vector<byte> serialize() const; - - bool empty() const { return false; } - private: - std::vector<std::string> m_protocols; - }; - -/** -* Session Ticket Extension (RFC 5077) -*/ -class Session_Ticket : public Extension - { - public: - static Handshake_Extension_Type static_type() - { return TLSEXT_SESSION_TICKET; } - - Handshake_Extension_Type type() const { return static_type(); } - - /** - * @return contents of the session ticket - */ - const std::vector<byte>& contents() const { return m_ticket; } - - /** - * Create empty extension, used by both client and server - */ - Session_Ticket() {} - - /** - * Extension with ticket, used by client - */ - Session_Ticket(const std::vector<byte>& session_ticket) : - m_ticket(session_ticket) {} - - /** - * Deserialize a session ticket - */ - Session_Ticket(TLS_Data_Reader& reader, u16bit extension_size); - - std::vector<byte> serialize() const { return m_ticket; } - - bool empty() const { return false; } - private: - std::vector<byte> m_ticket; - }; - -/** -* Supported Elliptic Curves Extension (RFC 4492) -*/ -class Supported_Elliptic_Curves : public Extension - { - public: - static Handshake_Extension_Type static_type() - { return TLSEXT_USABLE_ELLIPTIC_CURVES; } - - Handshake_Extension_Type type() const { return static_type(); } - - static std::string curve_id_to_name(u16bit id); - static u16bit name_to_curve_id(const std::string& name); - - const std::vector<std::string>& curves() const { return m_curves; } - - std::vector<byte> serialize() const; - - Supported_Elliptic_Curves(const std::vector<std::string>& curves) : - m_curves(curves) {} - - Supported_Elliptic_Curves(TLS_Data_Reader& reader, - u16bit extension_size); - - bool empty() const { return m_curves.empty(); } - private: - std::vector<std::string> m_curves; - }; - -/** -* Signature Algorithms Extension for TLS 1.2 (RFC 5246) -*/ -class Signature_Algorithms : public Extension - { - public: - static Handshake_Extension_Type static_type() - { return TLSEXT_SIGNATURE_ALGORITHMS; } - - Handshake_Extension_Type type() const { return static_type(); } - - static std::string hash_algo_name(byte code); - static byte hash_algo_code(const std::string& name); - - static std::string sig_algo_name(byte code); - static byte sig_algo_code(const std::string& name); - - std::vector<std::pair<std::string, std::string> > - supported_signature_algorthms() const - { - return m_supported_algos; - } - - std::vector<byte> serialize() const; - - bool empty() const { return false; } - - Signature_Algorithms(const std::vector<std::string>& hashes, - const std::vector<std::string>& sig_algos); - - Signature_Algorithms(const std::vector<std::pair<std::string, std::string> >& algos) : - m_supported_algos(algos) {} - - Signature_Algorithms(TLS_Data_Reader& reader, - u16bit extension_size); - private: - std::vector<std::pair<std::string, std::string> > m_supported_algos; - }; - -/** -* Heartbeat Extension (RFC 6520) -*/ -class Heartbeat_Support_Indicator : public Extension - { - public: - static Handshake_Extension_Type static_type() - { return TLSEXT_HEARTBEAT_SUPPORT; } - - Handshake_Extension_Type type() const { return static_type(); } - - bool peer_allowed_to_send() const { return m_peer_allowed_to_send; } - - std::vector<byte> serialize() const; - - bool empty() const { return false; } - - Heartbeat_Support_Indicator(bool peer_allowed_to_send) : - m_peer_allowed_to_send(peer_allowed_to_send) {} - - Heartbeat_Support_Indicator(TLS_Data_Reader& reader, u16bit extension_size); - - private: - bool m_peer_allowed_to_send; - }; - -/** -* Represents a block of extensions in a hello message -*/ -class Extensions - { - public: - template<typename T> - T* get() const - { - Handshake_Extension_Type type = T::static_type(); - - auto i = extensions.find(type); - - if(i != extensions.end()) - return dynamic_cast<T*>(i->second.get()); - return nullptr; - } - - void add(Extension* extn) - { - extensions[extn->type()].reset(extn); - } - - std::vector<byte> serialize() const; - - void deserialize(TLS_Data_Reader& reader); - - Extensions() {} - - Extensions(TLS_Data_Reader& reader) { deserialize(reader); } - - private: - Extensions(const Extensions&) {} - Extensions& operator=(const Extensions&) { return (*this); } - - std::map<Handshake_Extension_Type, std::unique_ptr<Extension>> extensions; - }; - -} - -} - -#endif diff --git a/src/tls/tls_handshake_hash.cpp b/src/tls/tls_handshake_hash.cpp deleted file mode 100644 index 4e7a0b9b7..000000000 --- a/src/tls/tls_handshake_hash.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* -* TLS Handshake Hash -* (C) 2004-2006,2011,2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/internal/tls_handshake_hash.h> -#include <botan/tls_exceptn.h> -#include <botan/libstate.h> -#include <botan/hash.h> -#include <memory> - -namespace Botan { - -namespace TLS { - -/** -* Return a TLS Handshake Hash -*/ -secure_vector<byte> Handshake_Hash::final(Protocol_Version version, - const std::string& mac_algo) const - { - Algorithm_Factory& af = global_state().algorithm_factory(); - - std::unique_ptr<HashFunction> hash; - - if(version.supports_ciphersuite_specific_prf()) - { - if(mac_algo == "MD5" || mac_algo == "SHA-1") - hash.reset(af.make_hash_function("SHA-256")); - else - hash.reset(af.make_hash_function(mac_algo)); - } - else - hash.reset(af.make_hash_function("Parallel(MD5,SHA-160)")); - - hash->update(data); - return hash->final(); - } - -/** -* Return a SSLv3 Handshake Hash -*/ -secure_vector<byte> Handshake_Hash::final_ssl3(const secure_vector<byte>& secret) const - { - const byte PAD_INNER = 0x36, PAD_OUTER = 0x5C; - - Algorithm_Factory& af = global_state().algorithm_factory(); - - std::unique_ptr<HashFunction> md5(af.make_hash_function("MD5")); - std::unique_ptr<HashFunction> sha1(af.make_hash_function("SHA-1")); - - md5->update(data); - sha1->update(data); - - md5->update(secret); - sha1->update(secret); - - for(size_t i = 0; i != 48; ++i) - md5->update(PAD_INNER); - for(size_t i = 0; i != 40; ++i) - sha1->update(PAD_INNER); - - secure_vector<byte> inner_md5 = md5->final(), inner_sha1 = sha1->final(); - - md5->update(secret); - sha1->update(secret); - - for(size_t i = 0; i != 48; ++i) - md5->update(PAD_OUTER); - for(size_t i = 0; i != 40; ++i) - sha1->update(PAD_OUTER); - - md5->update(inner_md5); - sha1->update(inner_sha1); - - secure_vector<byte> output; - output += md5->final(); - output += sha1->final(); - return output; - } - -} - -} diff --git a/src/tls/tls_handshake_hash.h b/src/tls/tls_handshake_hash.h deleted file mode 100644 index 840895963..000000000 --- a/src/tls/tls_handshake_hash.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -* TLS Handshake Hash -* (C) 2004-2006,2011,2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_HANDSHAKE_HASH_H__ -#define BOTAN_TLS_HANDSHAKE_HASH_H__ - -#include <botan/secmem.h> -#include <botan/tls_version.h> -#include <botan/tls_magic.h> - -namespace Botan { - -namespace TLS { - -using namespace Botan; - -/** -* TLS Handshake Hash -*/ -class Handshake_Hash - { - public: - void update(const byte in[], size_t length) - { data += std::make_pair(in, length); } - - void update(const std::vector<byte>& in) - { data += in; } - - secure_vector<byte> final(Protocol_Version version, - const std::string& mac_algo) const; - - secure_vector<byte> final_ssl3(const secure_vector<byte>& master_secret) const; - - const std::vector<byte>& get_contents() const - { return data; } - - void reset() { data.clear(); } - private: - std::vector<byte> data; - }; - -} - -} - -#endif diff --git a/src/tls/tls_handshake_io.cpp b/src/tls/tls_handshake_io.cpp deleted file mode 100644 index 38def13a2..000000000 --- a/src/tls/tls_handshake_io.cpp +++ /dev/null @@ -1,381 +0,0 @@ -/* -* TLS Handshake IO -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/internal/tls_handshake_io.h> -#include <botan/internal/tls_messages.h> -#include <botan/internal/tls_record.h> -#include <botan/internal/tls_seq_numbers.h> -#include <botan/exceptn.h> - -namespace Botan { - -namespace TLS { - -namespace { - -inline size_t load_be24(const byte q[3]) - { - return make_u32bit(0, - q[0], - q[1], - q[2]); - } - -void store_be24(byte out[3], size_t val) - { - out[0] = get_byte<u32bit>(1, val); - out[1] = get_byte<u32bit>(2, val); - out[2] = get_byte<u32bit>(3, val); - } - -} - -Protocol_Version Stream_Handshake_IO::initial_record_version() const - { - return Protocol_Version::TLS_V10; - } - -void Stream_Handshake_IO::add_record(const std::vector<byte>& record, - Record_Type record_type, u64bit) - { - if(record_type == HANDSHAKE) - { - m_queue.insert(m_queue.end(), record.begin(), record.end()); - } - else if(record_type == CHANGE_CIPHER_SPEC) - { - if(record.size() != 1 || record[0] != 1) - throw Decoding_Error("Invalid ChangeCipherSpec"); - - // Pretend it's a regular handshake message of zero length - const byte ccs_hs[] = { HANDSHAKE_CCS, 0, 0, 0 }; - m_queue.insert(m_queue.end(), ccs_hs, ccs_hs + sizeof(ccs_hs)); - } - else - throw Decoding_Error("Unknown message type in handshake processing"); - } - -std::pair<Handshake_Type, std::vector<byte>> -Stream_Handshake_IO::get_next_record(bool) - { - if(m_queue.size() >= 4) - { - const size_t length = load_be24(&m_queue[1]); - - if(m_queue.size() >= length + 4) - { - Handshake_Type type = static_cast<Handshake_Type>(m_queue[0]); - - std::vector<byte> contents(m_queue.begin() + 4, - m_queue.begin() + 4 + length); - - m_queue.erase(m_queue.begin(), m_queue.begin() + 4 + length); - - return std::make_pair(type, contents); - } - } - - return std::make_pair(HANDSHAKE_NONE, std::vector<byte>()); - } - -std::vector<byte> -Stream_Handshake_IO::format(const std::vector<byte>& msg, - Handshake_Type type) const - { - std::vector<byte> send_buf(4 + msg.size()); - - const size_t buf_size = msg.size(); - - send_buf[0] = type; - - store_be24(&send_buf[1], buf_size); - - copy_mem(&send_buf[4], &msg[0], msg.size()); - - return send_buf; - } - -std::vector<byte> Stream_Handshake_IO::send(const Handshake_Message& msg) - { - const std::vector<byte> msg_bits = msg.serialize(); - - if(msg.type() == HANDSHAKE_CCS) - { - m_send_hs(CHANGE_CIPHER_SPEC, msg_bits); - return std::vector<byte>(); // not included in handshake hashes - } - - const std::vector<byte> buf = format(msg_bits, msg.type()); - m_send_hs(HANDSHAKE, buf); - return buf; - } - -Protocol_Version Datagram_Handshake_IO::initial_record_version() const - { - return Protocol_Version::DTLS_V10; - } - -void Datagram_Handshake_IO::add_record(const std::vector<byte>& record, - Record_Type record_type, - u64bit record_sequence) - { - const u16bit epoch = static_cast<u16bit>(record_sequence >> 48); - - if(record_type == CHANGE_CIPHER_SPEC) - { - m_ccs_epochs.insert(epoch); - return; - } - - const size_t DTLS_HANDSHAKE_HEADER_LEN = 12; - - const byte* record_bits = &record[0]; - size_t record_size = record.size(); - - while(record_size) - { - if(record_size < DTLS_HANDSHAKE_HEADER_LEN) - return; // completely bogus? at least degenerate/weird - - const byte msg_type = record_bits[0]; - const size_t msg_len = load_be24(&record_bits[1]); - const u16bit message_seq = load_be<u16bit>(&record_bits[4], 0); - const size_t fragment_offset = load_be24(&record_bits[6]); - const size_t fragment_length = load_be24(&record_bits[9]); - - const size_t total_size = DTLS_HANDSHAKE_HEADER_LEN + fragment_length; - - if(record_size < total_size) - throw Decoding_Error("Bad lengths in DTLS header"); - - if(message_seq >= m_in_message_seq) - { - m_messages[message_seq].add_fragment(&record_bits[DTLS_HANDSHAKE_HEADER_LEN], - fragment_length, - fragment_offset, - epoch, - msg_type, - msg_len); - } - - record_bits += total_size; - record_size -= total_size; - } - } - -std::pair<Handshake_Type, std::vector<byte>> -Datagram_Handshake_IO::get_next_record(bool expecting_ccs) - { - if(!m_flights.rbegin()->empty()) - m_flights.push_back(std::vector<u16bit>()); - - if(expecting_ccs) - { - if(!m_messages.empty()) - { - const u16bit current_epoch = m_messages.begin()->second.epoch(); - - if(m_ccs_epochs.count(current_epoch)) - return std::make_pair(HANDSHAKE_CCS, std::vector<byte>()); - } - - return std::make_pair(HANDSHAKE_NONE, std::vector<byte>()); - } - - auto i = m_messages.find(m_in_message_seq); - - if(i == m_messages.end() || !i->second.complete()) - return std::make_pair(HANDSHAKE_NONE, std::vector<byte>()); - - m_in_message_seq += 1; - - return i->second.message(); - } - -void Datagram_Handshake_IO::Handshake_Reassembly::add_fragment( - const byte fragment[], - size_t fragment_length, - size_t fragment_offset, - u16bit epoch, - byte msg_type, - size_t msg_length) - { - if(complete()) - return; // already have entire message, ignore this - - if(m_msg_type == HANDSHAKE_NONE) - { - m_epoch = epoch; - m_msg_type = msg_type; - m_msg_length = msg_length; - } - - if(msg_type != m_msg_type || msg_length != m_msg_length || epoch != m_epoch) - throw Decoding_Error("Inconsistent values in DTLS handshake header"); - - if(fragment_offset > m_msg_length) - throw Decoding_Error("Fragment offset past end of message"); - - if(fragment_offset + fragment_length > m_msg_length) - throw Decoding_Error("Fragment overlaps past end of message"); - - if(fragment_offset == 0 && fragment_length == m_msg_length) - { - m_fragments.clear(); - m_message.assign(fragment, fragment+fragment_length); - } - else - { - /* - * FIXME. This is a pretty lame way to do defragmentation, huge - * overhead with a tree node per byte. - * - * Also should confirm that all overlaps have no changes, - * otherwise we expose ourselves to the classic fingerprinting - * and IDS evasion attacks on IP fragmentation. - */ - for(size_t i = 0; i != fragment_length; ++i) - m_fragments[fragment_offset+i] = fragment[i]; - - if(m_fragments.size() == m_msg_length) - { - m_message.resize(m_msg_length); - for(size_t i = 0; i != m_msg_length; ++i) - m_message[i] = m_fragments[i]; - m_fragments.clear(); - } - } - } - -bool Datagram_Handshake_IO::Handshake_Reassembly::complete() const - { - return (m_msg_type != HANDSHAKE_NONE && m_message.size() == m_msg_length); - } - -std::pair<Handshake_Type, std::vector<byte>> -Datagram_Handshake_IO::Handshake_Reassembly::message() const - { - if(!complete()) - throw Internal_Error("Datagram_Handshake_IO - message not complete"); - - return std::make_pair(static_cast<Handshake_Type>(m_msg_type), m_message); - } - -std::vector<byte> -Datagram_Handshake_IO::format_fragment(const byte fragment[], - size_t frag_len, - u16bit frag_offset, - u16bit msg_len, - Handshake_Type type, - u16bit msg_sequence) const - { - std::vector<byte> send_buf(12 + frag_len); - - send_buf[0] = type; - - store_be24(&send_buf[1], msg_len); - - store_be(msg_sequence, &send_buf[4]); - - store_be24(&send_buf[6], frag_offset); - store_be24(&send_buf[9], frag_len); - - copy_mem(&send_buf[12], &fragment[0], frag_len); - - return send_buf; - } - -std::vector<byte> -Datagram_Handshake_IO::format_w_seq(const std::vector<byte>& msg, - Handshake_Type type, - u16bit msg_sequence) const - { - return format_fragment(&msg[0], msg.size(), 0, msg.size(), type, msg_sequence); - } - -std::vector<byte> -Datagram_Handshake_IO::format(const std::vector<byte>& msg, - Handshake_Type type) const - { - return format_w_seq(msg, type, m_in_message_seq - 1); - } - -namespace { - -size_t split_for_mtu(size_t mtu, size_t msg_size) - { - const size_t DTLS_HEADERS_SIZE = 25; // DTLS record+handshake headers - - const size_t parts = (msg_size + mtu) / mtu; - - if(parts + DTLS_HEADERS_SIZE > mtu) - return parts + 1; - - return parts; - } - -} - -std::vector<byte> -Datagram_Handshake_IO::send(const Handshake_Message& msg) - { - const std::vector<byte> msg_bits = msg.serialize(); - const u16bit epoch = m_seqs.current_write_epoch(); - const Handshake_Type msg_type = msg.type(); - - std::tuple<u16bit, byte, std::vector<byte>> msg_info(epoch, msg_type, msg_bits); - - if(msg_type == HANDSHAKE_CCS) - { - m_send_hs(epoch, CHANGE_CIPHER_SPEC, msg_bits); - return std::vector<byte>(); // not included in handshake hashes - } - - const std::vector<byte> no_fragment = - format_w_seq(msg_bits, msg_type, m_out_message_seq); - - if(no_fragment.size() + DTLS_HEADER_SIZE <= m_mtu) - m_send_hs(epoch, HANDSHAKE, no_fragment); - else - { - const size_t parts = split_for_mtu(m_mtu, msg_bits.size()); - - const size_t parts_size = (msg_bits.size() + parts) / parts; - - size_t frag_offset = 0; - - while(frag_offset != msg_bits.size()) - { - const size_t frag_len = - std::min<size_t>(msg_bits.size() - frag_offset, - parts_size); - - m_send_hs(epoch, - HANDSHAKE, - format_fragment(&msg_bits[frag_offset], - frag_len, - frag_offset, - msg_bits.size(), - msg_type, - m_out_message_seq)); - - frag_offset += frag_len; - } - } - - // Note: not saving CCS, instead we know it was there due to change in epoch - m_flights.rbegin()->push_back(m_out_message_seq); - m_flight_data[m_out_message_seq] = msg_info; - - m_out_message_seq += 1; - - return no_fragment; - } - -} - -} diff --git a/src/tls/tls_handshake_io.h b/src/tls/tls_handshake_io.h deleted file mode 100644 index 36c605c30..000000000 --- a/src/tls/tls_handshake_io.h +++ /dev/null @@ -1,168 +0,0 @@ -/* -* TLS Handshake Serialization -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_HANDSHAKE_IO_H__ -#define BOTAN_TLS_HANDSHAKE_IO_H__ - -#include <botan/tls_magic.h> -#include <botan/tls_version.h> -#include <botan/loadstor.h> -#include <functional> -#include <vector> -#include <deque> -#include <map> -#include <set> -#include <utility> -#include <tuple> - -namespace Botan { - -namespace TLS { - -class Handshake_Message; - -/** -* Handshake IO Interface -*/ -class Handshake_IO - { - public: - virtual Protocol_Version initial_record_version() const = 0; - - virtual std::vector<byte> send(const Handshake_Message& msg) = 0; - - virtual std::vector<byte> format( - const std::vector<byte>& handshake_msg, - Handshake_Type handshake_type) const = 0; - - virtual void add_record(const std::vector<byte>& record, - Record_Type type, - u64bit sequence_number) = 0; - - /** - * Returns (HANDSHAKE_NONE, std::vector<>()) if no message currently available - */ - virtual std::pair<Handshake_Type, std::vector<byte>> - get_next_record(bool expecting_ccs) = 0; - - Handshake_IO() {} - - Handshake_IO(const Handshake_IO&) = delete; - - Handshake_IO& operator=(const Handshake_IO&) = delete; - - virtual ~Handshake_IO() {} - }; - -/** -* Handshake IO for stream-based handshakes -*/ -class Stream_Handshake_IO : public Handshake_IO - { - public: - Stream_Handshake_IO(std::function<void (byte, const std::vector<byte>&)> writer) : - m_send_hs(writer) {} - - Protocol_Version initial_record_version() const override; - - std::vector<byte> send(const Handshake_Message& msg) override; - - std::vector<byte> format( - const std::vector<byte>& handshake_msg, - Handshake_Type handshake_type) const override; - - void add_record(const std::vector<byte>& record, - Record_Type type, - u64bit sequence_number) override; - - std::pair<Handshake_Type, std::vector<byte>> - get_next_record(bool expecting_ccs) override; - private: - std::deque<byte> m_queue; - std::function<void (byte, const std::vector<byte>&)> m_send_hs; - }; - -/** -* Handshake IO for datagram-based handshakes -*/ -class Datagram_Handshake_IO : public Handshake_IO - { - public: - Datagram_Handshake_IO(class Connection_Sequence_Numbers& seq, - std::function<void (u16bit, byte, const std::vector<byte>&)> writer) : - m_seqs(seq), m_flights(1), m_send_hs(writer) {} - - Protocol_Version initial_record_version() const override; - - std::vector<byte> send(const Handshake_Message& msg) override; - - std::vector<byte> format( - const std::vector<byte>& handshake_msg, - Handshake_Type handshake_type) const override; - - void add_record(const std::vector<byte>& record, - Record_Type type, - u64bit sequence_number) override; - - std::pair<Handshake_Type, std::vector<byte>> - get_next_record(bool expecting_ccs) override; - private: - std::vector<byte> format_fragment( - const byte fragment[], - size_t fragment_len, - u16bit frag_offset, - u16bit msg_len, - Handshake_Type type, - u16bit msg_sequence) const; - - std::vector<byte> format_w_seq( - const std::vector<byte>& handshake_msg, - Handshake_Type handshake_type, - u16bit msg_sequence) const; - - class Handshake_Reassembly - { - public: - void add_fragment(const byte fragment[], - size_t fragment_length, - size_t fragment_offset, - u16bit epoch, - byte msg_type, - size_t msg_length); - - bool complete() const; - - u16bit epoch() const { return m_epoch; } - - std::pair<Handshake_Type, std::vector<byte>> message() const; - private: - byte m_msg_type = HANDSHAKE_NONE; - size_t m_msg_length = 0; - u16bit m_epoch = 0; - - std::map<size_t, byte> m_fragments; - std::vector<byte> m_message; - }; - - class Connection_Sequence_Numbers& m_seqs; - std::map<u16bit, Handshake_Reassembly> m_messages; - std::set<u16bit> m_ccs_epochs; - std::vector<std::vector<u16bit>> m_flights; - std::map<u16bit, std::tuple<u16bit, byte, std::vector<byte>>> m_flight_data; - - // default MTU is IPv6 min MTU minus UDP/IP headers - u16bit m_mtu = 1280 - 40 - 8; - u16bit m_in_message_seq = 0; - u16bit m_out_message_seq = 0; - std::function<void (u16bit, byte, const std::vector<byte>&)> m_send_hs; - }; - -} - -} - -#endif diff --git a/src/tls/tls_handshake_msg.h b/src/tls/tls_handshake_msg.h deleted file mode 100644 index 1c44554d3..000000000 --- a/src/tls/tls_handshake_msg.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -* TLS Handshake Message -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_HANDSHAKE_MSG_H__ -#define BOTAN_TLS_HANDSHAKE_MSG_H__ - -#include <botan/tls_magic.h> -#include <vector> -#include <string> - -namespace Botan { - -namespace TLS { - -/** -* TLS Handshake Message Base Class -*/ -class BOTAN_DLL Handshake_Message - { - public: - virtual Handshake_Type type() const = 0; - - virtual std::vector<byte> serialize() const = 0; - - virtual ~Handshake_Message() {} - }; - -} - -} - -#endif diff --git a/src/tls/tls_handshake_state.cpp b/src/tls/tls_handshake_state.cpp deleted file mode 100644 index 84b22cc09..000000000 --- a/src/tls/tls_handshake_state.cpp +++ /dev/null @@ -1,442 +0,0 @@ -/* -* TLS Handshaking -* (C) 2004-2006,2011,2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/internal/tls_handshake_state.h> -#include <botan/internal/tls_messages.h> -#include <botan/internal/tls_record.h> -#include <botan/lookup.h> - -namespace Botan { - -namespace TLS { - -namespace { - -u32bit bitmask_for_handshake_type(Handshake_Type type) - { - switch(type) - { - case HELLO_VERIFY_REQUEST: - return (1 << 0); - - case HELLO_REQUEST: - return (1 << 1); - - /* - * Same code point for both client hello styles - */ - case CLIENT_HELLO: - case CLIENT_HELLO_SSLV2: - return (1 << 2); - - case SERVER_HELLO: - return (1 << 3); - - case CERTIFICATE: - return (1 << 4); - - case CERTIFICATE_URL: - return (1 << 5); - - case CERTIFICATE_STATUS: - return (1 << 6); - - case SERVER_KEX: - return (1 << 7); - - case CERTIFICATE_REQUEST: - return (1 << 8); - - case SERVER_HELLO_DONE: - return (1 << 9); - - case CERTIFICATE_VERIFY: - return (1 << 10); - - case CLIENT_KEX: - return (1 << 11); - - case NEXT_PROTOCOL: - return (1 << 12); - - case NEW_SESSION_TICKET: - return (1 << 13); - - case HANDSHAKE_CCS: - return (1 << 14); - - case FINISHED: - return (1 << 15); - - // allow explicitly disabling new handshakes - case HANDSHAKE_NONE: - return 0; - } - - throw Internal_Error("Unknown handshake type " + std::to_string(type)); - } - -} - -/* -* Initialize the SSL/TLS Handshake State -*/ -Handshake_State::Handshake_State(Handshake_IO* io, - std::function<void (const Handshake_Message&)> msg_callback) : - m_msg_callback(msg_callback), - m_handshake_io(io), - m_version(m_handshake_io->initial_record_version()) - { - } - -Handshake_State::~Handshake_State() {} - -void Handshake_State::hello_verify_request(const Hello_Verify_Request& hello_verify) - { - note_message(hello_verify); - - m_client_hello->update_hello_cookie(hello_verify); - hash().reset(); - hash().update(handshake_io().send(*m_client_hello)); - note_message(*m_client_hello); - } - -void Handshake_State::client_hello(Client_Hello* client_hello) - { - m_client_hello.reset(client_hello); - note_message(*m_client_hello); - } - -void Handshake_State::server_hello(Server_Hello* server_hello) - { - m_server_hello.reset(server_hello); - m_ciphersuite = Ciphersuite::by_id(m_server_hello->ciphersuite()); - note_message(*m_server_hello); - } - -void Handshake_State::server_certs(Certificate* server_certs) - { - m_server_certs.reset(server_certs); - note_message(*m_server_certs); - } - -void Handshake_State::server_kex(Server_Key_Exchange* server_kex) - { - m_server_kex.reset(server_kex); - note_message(*m_server_kex); - } - -void Handshake_State::cert_req(Certificate_Req* cert_req) - { - m_cert_req.reset(cert_req); - note_message(*m_cert_req); - } - -void Handshake_State::server_hello_done(Server_Hello_Done* server_hello_done) - { - m_server_hello_done.reset(server_hello_done); - note_message(*m_server_hello_done); - } - -void Handshake_State::client_certs(Certificate* client_certs) - { - m_client_certs.reset(client_certs); - note_message(*m_client_certs); - } - -void Handshake_State::client_kex(Client_Key_Exchange* client_kex) - { - m_client_kex.reset(client_kex); - note_message(*m_client_kex); - } - -void Handshake_State::client_verify(Certificate_Verify* client_verify) - { - m_client_verify.reset(client_verify); - note_message(*m_client_verify); - } - -void Handshake_State::next_protocol(Next_Protocol* next_protocol) - { - m_next_protocol.reset(next_protocol); - note_message(*m_next_protocol); - } - -void Handshake_State::new_session_ticket(New_Session_Ticket* new_session_ticket) - { - m_new_session_ticket.reset(new_session_ticket); - note_message(*m_new_session_ticket); - } - -void Handshake_State::server_finished(Finished* server_finished) - { - m_server_finished.reset(server_finished); - note_message(*m_server_finished); - } - -void Handshake_State::client_finished(Finished* client_finished) - { - m_client_finished.reset(client_finished); - note_message(*m_client_finished); - } - -void Handshake_State::set_version(const Protocol_Version& version) - { - m_version = version; - } - -void Handshake_State::compute_session_keys() - { - m_session_keys = Session_Keys(this, client_kex()->pre_master_secret(), false); - } - -void Handshake_State::compute_session_keys(const secure_vector<byte>& resume_master_secret) - { - m_session_keys = Session_Keys(this, resume_master_secret, true); - } - -void Handshake_State::confirm_transition_to(Handshake_Type handshake_msg) - { - const u32bit mask = bitmask_for_handshake_type(handshake_msg); - - m_hand_received_mask |= mask; - - const bool ok = (m_hand_expecting_mask & mask); // overlap? - - if(!ok) - throw Unexpected_Message("Unexpected state transition in handshake, got " + - std::to_string(handshake_msg) + - " expected " + std::to_string(m_hand_expecting_mask) + - " received " + std::to_string(m_hand_received_mask)); - - /* We don't know what to expect next, so force a call to - set_expected_next; if it doesn't happen, the next transition - check will always fail which is what we want. - */ - m_hand_expecting_mask = 0; - } - -void Handshake_State::set_expected_next(Handshake_Type handshake_msg) - { - m_hand_expecting_mask |= bitmask_for_handshake_type(handshake_msg); - } - -bool Handshake_State::received_handshake_msg(Handshake_Type handshake_msg) const - { - const u32bit mask = bitmask_for_handshake_type(handshake_msg); - - return (m_hand_received_mask & mask); - } - -std::pair<Handshake_Type, std::vector<byte>> -Handshake_State::get_next_handshake_msg() - { - const bool expecting_ccs = - (bitmask_for_handshake_type(HANDSHAKE_CCS) & m_hand_expecting_mask); - - return m_handshake_io->get_next_record(expecting_ccs); - } - -std::string Handshake_State::srp_identifier() const - { - if(ciphersuite().valid() && ciphersuite().kex_algo() == "SRP_SHA") - return client_hello()->srp_identifier(); - - return ""; - } - -std::vector<byte> Handshake_State::session_ticket() const - { - if(new_session_ticket() && !new_session_ticket()->ticket().empty()) - return new_session_ticket()->ticket(); - - return client_hello()->session_ticket(); - } - -KDF* Handshake_State::protocol_specific_prf() const - { - if(version() == Protocol_Version::SSL_V3) - { - return get_kdf("SSL3-PRF"); - } - else if(version().supports_ciphersuite_specific_prf()) - { - const std::string prf_algo = ciphersuite().prf_algo(); - - if(prf_algo == "MD5" || prf_algo == "SHA-1") - return get_kdf("TLS-12-PRF(SHA-256)"); - - return get_kdf("TLS-12-PRF(" + prf_algo + ")"); - } - else - { - // TLS v1.0, v1.1 and DTLS v1.0 - return get_kdf("TLS-PRF"); - } - - throw Internal_Error("Unknown version code " + version().to_string()); - } - -namespace { - -std::string choose_hash(const std::string& sig_algo, - Protocol_Version negotiated_version, - const Policy& policy, - bool for_client_auth, - const Client_Hello* client_hello, - const Certificate_Req* cert_req) - { - if(!negotiated_version.supports_negotiable_signature_algorithms()) - { - if(for_client_auth && negotiated_version == Protocol_Version::SSL_V3) - return "Raw"; - - if(sig_algo == "RSA") - return "Parallel(MD5,SHA-160)"; - - if(sig_algo == "DSA") - return "SHA-1"; - - if(sig_algo == "ECDSA") - return "SHA-1"; - - throw Internal_Error("Unknown TLS signature algo " + sig_algo); - } - - const auto supported_algos = for_client_auth ? - cert_req->supported_algos() : - client_hello->supported_algos(); - - if(!supported_algos.empty()) - { - const auto hashes = policy.allowed_signature_hashes(); - - /* - * Choose our most preferred hash that the counterparty supports - * in pairing with the signature algorithm we want to use. - */ - for(auto hash : hashes) - { - for(auto algo : supported_algos) - { - if(algo.first == hash && algo.second == sig_algo) - return hash; - } - } - } - - // TLS v1.2 default hash if the counterparty sent nothing - return "SHA-1"; - } - -} - -std::pair<std::string, Signature_Format> -Handshake_State::choose_sig_format(const Private_Key& key, - std::string& hash_algo_out, - std::string& sig_algo_out, - bool for_client_auth, - const Policy& policy) const - { - const std::string sig_algo = key.algo_name(); - - const std::string hash_algo = - choose_hash(sig_algo, - this->version(), - policy, - for_client_auth, - client_hello(), - cert_req()); - - if(this->version().supports_negotiable_signature_algorithms()) - { - hash_algo_out = hash_algo; - sig_algo_out = sig_algo; - } - - if(sig_algo == "RSA") - { - const std::string padding = "EMSA3(" + hash_algo + ")"; - - return std::make_pair(padding, IEEE_1363); - } - else if(sig_algo == "DSA" || sig_algo == "ECDSA") - { - const std::string padding = "EMSA1(" + hash_algo + ")"; - - return std::make_pair(padding, DER_SEQUENCE); - } - - throw Invalid_Argument(sig_algo + " is invalid/unknown for TLS signatures"); - } - -std::pair<std::string, Signature_Format> -Handshake_State::understand_sig_format(const Public_Key& key, - std::string hash_algo, - std::string sig_algo, - bool for_client_auth) const - { - const std::string algo_name = key.algo_name(); - - /* - FIXME: This should check what was sent against the client hello - preferences, or the certificate request, to ensure it was allowed - by those restrictions. - - Or not? - */ - - if(this->version().supports_negotiable_signature_algorithms()) - { - if(hash_algo == "") - throw Decoding_Error("Counterparty did not send hash/sig IDS"); - - if(sig_algo != algo_name) - throw Decoding_Error("Counterparty sent inconsistent key and sig types"); - } - else - { - if(hash_algo != "" || sig_algo != "") - throw Decoding_Error("Counterparty sent hash/sig IDs with old version"); - } - - if(algo_name == "RSA") - { - if(for_client_auth && this->version() == Protocol_Version::SSL_V3) - { - hash_algo = "Raw"; - } - else if(!this->version().supports_negotiable_signature_algorithms()) - { - hash_algo = "Parallel(MD5,SHA-160)"; - } - - const std::string padding = "EMSA3(" + hash_algo + ")"; - return std::make_pair(padding, IEEE_1363); - } - else if(algo_name == "DSA" || algo_name == "ECDSA") - { - if(algo_name == "DSA" && for_client_auth && this->version() == Protocol_Version::SSL_V3) - { - hash_algo = "Raw"; - } - else if(!this->version().supports_negotiable_signature_algorithms()) - { - hash_algo = "SHA-1"; - } - - const std::string padding = "EMSA1(" + hash_algo + ")"; - - return std::make_pair(padding, DER_SEQUENCE); - } - - throw Invalid_Argument(algo_name + " is invalid/unknown for TLS signatures"); - } - -} - -} diff --git a/src/tls/tls_handshake_state.h b/src/tls/tls_handshake_state.h deleted file mode 100644 index 9afcd0374..000000000 --- a/src/tls/tls_handshake_state.h +++ /dev/null @@ -1,210 +0,0 @@ -/* -* TLS Handshake State -* (C) 2004-2006,2011,2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_HANDSHAKE_STATE_H__ -#define BOTAN_TLS_HANDSHAKE_STATE_H__ - -#include <botan/internal/tls_handshake_hash.h> -#include <botan/internal/tls_handshake_io.h> -#include <botan/internal/tls_session_key.h> -#include <botan/tls_ciphersuite.h> -#include <botan/tls_exceptn.h> -#include <botan/tls_handshake_msg.h> -#include <botan/pk_keys.h> -#include <botan/pubkey.h> -#include <functional> -#include <memory> - -namespace Botan { - -class KDF; - -namespace TLS { - -class Policy; - -class Hello_Verify_Request; -class Client_Hello; -class Server_Hello; -class Certificate; -class Server_Key_Exchange; -class Certificate_Req; -class Server_Hello_Done; -class Certificate; -class Client_Key_Exchange; -class Certificate_Verify; -class Next_Protocol; -class New_Session_Ticket; -class Finished; - -/** -* SSL/TLS Handshake State -*/ -class Handshake_State - { - public: - Handshake_State(Handshake_IO* io, - std::function<void (const Handshake_Message&)> msg_callback = - std::function<void (const Handshake_Message&)>()); - - virtual ~Handshake_State(); - - Handshake_State(const Handshake_State&) = delete; - Handshake_State& operator=(const Handshake_State&) = delete; - - Handshake_IO& handshake_io() { return *m_handshake_io; } - - /** - * Return true iff we have received a particular message already - * @param msg_type the message type - */ - bool received_handshake_msg(Handshake_Type msg_type) const; - - /** - * Confirm that we were expecting this message type - * @param msg_type the message type - */ - void confirm_transition_to(Handshake_Type msg_type); - - /** - * Record that we are expecting a particular message type next - * @param msg_type the message type - */ - void set_expected_next(Handshake_Type msg_type); - - std::pair<Handshake_Type, std::vector<byte>> - get_next_handshake_msg(); - - std::vector<byte> session_ticket() const; - - std::pair<std::string, Signature_Format> - understand_sig_format(const Public_Key& key, - std::string hash_algo, - std::string sig_algo, - bool for_client_auth) const; - - std::pair<std::string, Signature_Format> - choose_sig_format(const Private_Key& key, - std::string& hash_algo, - std::string& sig_algo, - bool for_client_auth, - const Policy& policy) const; - - std::string srp_identifier() const; - - KDF* protocol_specific_prf() const; - - Protocol_Version version() const { return m_version; } - - void set_version(const Protocol_Version& version); - - void hello_verify_request(const Hello_Verify_Request& hello_verify); - - void client_hello(Client_Hello* client_hello); - void server_hello(Server_Hello* server_hello); - void server_certs(Certificate* server_certs); - void server_kex(Server_Key_Exchange* server_kex); - void cert_req(Certificate_Req* cert_req); - void server_hello_done(Server_Hello_Done* server_hello_done); - void client_certs(Certificate* client_certs); - void client_kex(Client_Key_Exchange* client_kex); - void client_verify(Certificate_Verify* client_verify); - void next_protocol(Next_Protocol* next_protocol); - void new_session_ticket(New_Session_Ticket* new_session_ticket); - void server_finished(Finished* server_finished); - void client_finished(Finished* client_finished); - - const Client_Hello* client_hello() const - { return m_client_hello.get(); } - - const Server_Hello* server_hello() const - { return m_server_hello.get(); } - - const Certificate* server_certs() const - { return m_server_certs.get(); } - - const Server_Key_Exchange* server_kex() const - { return m_server_kex.get(); } - - const Certificate_Req* cert_req() const - { return m_cert_req.get(); } - - const Server_Hello_Done* server_hello_done() const - { return m_server_hello_done.get(); } - - const Certificate* client_certs() const - { return m_client_certs.get(); } - - const Client_Key_Exchange* client_kex() const - { return m_client_kex.get(); } - - const Certificate_Verify* client_verify() const - { return m_client_verify.get(); } - - const Next_Protocol* next_protocol() const - { return m_next_protocol.get(); } - - const New_Session_Ticket* new_session_ticket() const - { return m_new_session_ticket.get(); } - - const Finished* server_finished() const - { return m_server_finished.get(); } - - const Finished* client_finished() const - { return m_client_finished.get(); } - - const Ciphersuite& ciphersuite() const { return m_ciphersuite; } - - const Session_Keys& session_keys() const { return m_session_keys; } - - void compute_session_keys(); - - void compute_session_keys(const secure_vector<byte>& resume_master_secret); - - Handshake_Hash& hash() { return m_handshake_hash; } - - const Handshake_Hash& hash() const { return m_handshake_hash; } - - void note_message(const Handshake_Message& msg) - { - if(m_msg_callback) - m_msg_callback(msg); - } - - private: - - std::function<void (const Handshake_Message&)> m_msg_callback; - - std::unique_ptr<Handshake_IO> m_handshake_io; - - u32bit m_hand_expecting_mask = 0; - u32bit m_hand_received_mask = 0; - Protocol_Version m_version; - Ciphersuite m_ciphersuite; - Session_Keys m_session_keys; - Handshake_Hash m_handshake_hash; - - std::unique_ptr<Client_Hello> m_client_hello; - std::unique_ptr<Server_Hello> m_server_hello; - std::unique_ptr<Certificate> m_server_certs; - std::unique_ptr<Server_Key_Exchange> m_server_kex; - std::unique_ptr<Certificate_Req> m_cert_req; - std::unique_ptr<Server_Hello_Done> m_server_hello_done; - std::unique_ptr<Certificate> m_client_certs; - std::unique_ptr<Client_Key_Exchange> m_client_kex; - std::unique_ptr<Certificate_Verify> m_client_verify; - std::unique_ptr<Next_Protocol> m_next_protocol; - std::unique_ptr<New_Session_Ticket> m_new_session_ticket; - std::unique_ptr<Finished> m_server_finished; - std::unique_ptr<Finished> m_client_finished; - }; - -} - -} - -#endif diff --git a/src/tls/tls_heartbeats.cpp b/src/tls/tls_heartbeats.cpp deleted file mode 100644 index 8c129858e..000000000 --- a/src/tls/tls_heartbeats.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* -* TLS Heartbeats -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/internal/tls_heartbeats.h> -#include <botan/internal/tls_extensions.h> -#include <botan/internal/tls_reader.h> -#include <botan/tls_exceptn.h> - -namespace Botan { - -namespace TLS { - -Heartbeat_Message::Heartbeat_Message(const std::vector<byte>& buf) - { - TLS_Data_Reader reader(buf); - - const byte type = reader.get_byte(); - - if(type != 1 && type != 2) - throw TLS_Exception(Alert::ILLEGAL_PARAMETER, - "Unknown heartbeat message type"); - - m_type = static_cast<Type>(type); - - m_payload = reader.get_range<byte>(2, 0, 16*1024); - - // padding follows and is ignored - } - -Heartbeat_Message::Heartbeat_Message(Type type, - const byte payload[], - size_t payload_len) : - m_type(type), - m_payload(payload, payload + payload_len) - { - } - -std::vector<byte> Heartbeat_Message::contents() const - { - std::vector<byte> send_buf(3 + m_payload.size() + 16); - send_buf[0] = m_type; - send_buf[1] = get_byte<u16bit>(0, m_payload.size()); - send_buf[2] = get_byte<u16bit>(1, m_payload.size()); - copy_mem(&send_buf[3], &m_payload[0], m_payload.size()); - // leave padding as all zeros - - return send_buf; - } - -std::vector<byte> Heartbeat_Support_Indicator::serialize() const - { - std::vector<byte> heartbeat(1); - heartbeat[0] = (m_peer_allowed_to_send ? 1 : 2); - return heartbeat; - } - -Heartbeat_Support_Indicator::Heartbeat_Support_Indicator(TLS_Data_Reader& reader, - u16bit extension_size) - { - if(extension_size != 1) - throw Decoding_Error("Strange size for heartbeat extension"); - - const byte code = reader.get_byte(); - - if(code != 1 && code != 2) - throw TLS_Exception(Alert::ILLEGAL_PARAMETER, - "Unknown heartbeat code " + std::to_string(code)); - - m_peer_allowed_to_send = (code == 1); - } - -} - -} diff --git a/src/tls/tls_heartbeats.h b/src/tls/tls_heartbeats.h deleted file mode 100644 index 00b197089..000000000 --- a/src/tls/tls_heartbeats.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -* TLS Heartbeats -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_HEARTBEATS_H__ -#define BOTAN_TLS_HEARTBEATS_H__ - -#include <botan/secmem.h> - -namespace Botan { - -namespace TLS { - -/** -* TLS Heartbeat message -*/ -class Heartbeat_Message - { - public: - enum Type { REQUEST = 1, RESPONSE = 2 }; - - std::vector<byte> contents() const; - - const std::vector<byte>& payload() const { return m_payload; } - - bool is_request() const { return m_type == REQUEST; } - - Heartbeat_Message(const std::vector<byte>& buf); - - Heartbeat_Message(Type type, const byte payload[], size_t payload_len); - private: - Type m_type; - std::vector<byte> m_payload; - }; - -} - -} - -#endif diff --git a/src/tls/tls_magic.h b/src/tls/tls_magic.h deleted file mode 100644 index 51f1fce47..000000000 --- a/src/tls/tls_magic.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -* SSL/TLS Protocol Constants -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_PROTOCOL_MAGIC_H__ -#define BOTAN_TLS_PROTOCOL_MAGIC_H__ - -namespace Botan { - -namespace TLS { - -/** -* Protocol Constants for SSL/TLS -*/ -enum Size_Limits { - TLS_HEADER_SIZE = 5, - DTLS_HEADER_SIZE = TLS_HEADER_SIZE + 8, - - MAX_PLAINTEXT_SIZE = 16*1024, - MAX_COMPRESSED_SIZE = MAX_PLAINTEXT_SIZE + 1024, - MAX_CIPHERTEXT_SIZE = MAX_COMPRESSED_SIZE + 1024, -}; - -enum Connection_Side { CLIENT = 1, SERVER = 2 }; - -enum Record_Type { - NO_RECORD = 0, - - CHANGE_CIPHER_SPEC = 20, - ALERT = 21, - HANDSHAKE = 22, - APPLICATION_DATA = 23, - HEARTBEAT = 24, -}; - -enum Handshake_Type { - HELLO_REQUEST = 0, - CLIENT_HELLO = 1, - CLIENT_HELLO_SSLV2 = 253, // Not a wire value - SERVER_HELLO = 2, - HELLO_VERIFY_REQUEST = 3, - NEW_SESSION_TICKET = 4, // RFC 5077 - CERTIFICATE = 11, - SERVER_KEX = 12, - CERTIFICATE_REQUEST = 13, - SERVER_HELLO_DONE = 14, - CERTIFICATE_VERIFY = 15, - CLIENT_KEX = 16, - FINISHED = 20, - - CERTIFICATE_URL = 21, - CERTIFICATE_STATUS = 22, - - NEXT_PROTOCOL = 67, - - HANDSHAKE_CCS = 254, // Not a wire value - HANDSHAKE_NONE = 255 // Null value -}; - -enum Compression_Method { - NO_COMPRESSION = 0x00, - DEFLATE_COMPRESSION = 0x01 -}; - -} - -} - -#endif diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h deleted file mode 100644 index 155d2427b..000000000 --- a/src/tls/tls_messages.h +++ /dev/null @@ -1,567 +0,0 @@ -/* -* TLS Messages -* (C) 2004-2011 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_MESSAGES_H__ -#define BOTAN_TLS_MESSAGES_H__ - -#include <botan/internal/tls_handshake_state.h> -#include <botan/internal/tls_extensions.h> -#include <botan/tls_handshake_msg.h> -#include <botan/tls_session.h> -#include <botan/tls_policy.h> -#include <botan/tls_ciphersuite.h> -#include <botan/bigint.h> -#include <botan/pkcs8.h> -#include <botan/x509cert.h> -#include <vector> -#include <memory> -#include <string> - -namespace Botan { - -class Credentials_Manager; -class SRP6_Server_Session; - -namespace TLS { - -class Handshake_IO; - -std::vector<byte> make_hello_random(RandomNumberGenerator& rng); - -/** -* DTLS Hello Verify Request -*/ -class Hello_Verify_Request : public Handshake_Message - { - public: - std::vector<byte> serialize() const override; - Handshake_Type type() const override { return HELLO_VERIFY_REQUEST; } - - std::vector<byte> cookie() const { return m_cookie; } - - Hello_Verify_Request(const std::vector<byte>& buf); - - Hello_Verify_Request(const std::vector<byte>& client_hello_bits, - const std::string& client_identity, - const SymmetricKey& secret_key); - private: - std::vector<byte> m_cookie; - }; - -/** -* Client Hello Message -*/ -class Client_Hello : public Handshake_Message - { - public: - Handshake_Type type() const override { return CLIENT_HELLO; } - - Protocol_Version version() const { return m_version; } - - const std::vector<byte>& random() const { return m_random; } - - const std::vector<byte>& session_id() const { return m_session_id; } - - std::vector<u16bit> ciphersuites() const { return m_suites; } - - std::vector<byte> compression_methods() const { return m_comp_methods; } - - bool offered_suite(u16bit ciphersuite) const; - - std::vector<std::pair<std::string, std::string>> supported_algos() const - { - if(Signature_Algorithms* sigs = m_extensions.get<Signature_Algorithms>()) - return sigs->supported_signature_algorthms(); - return std::vector<std::pair<std::string, std::string>>(); - } - - std::vector<std::string> supported_ecc_curves() const - { - if(Supported_Elliptic_Curves* ecc = m_extensions.get<Supported_Elliptic_Curves>()) - return ecc->curves(); - return std::vector<std::string>(); - } - - std::string sni_hostname() const - { - if(Server_Name_Indicator* sni = m_extensions.get<Server_Name_Indicator>()) - return sni->host_name(); - return ""; - } - - std::string srp_identifier() const - { - if(SRP_Identifier* srp = m_extensions.get<SRP_Identifier>()) - return srp->identifier(); - return ""; - } - - bool secure_renegotiation() const - { - return m_extensions.get<Renegotiation_Extension>(); - } - - std::vector<byte> renegotiation_info() const - { - if(Renegotiation_Extension* reneg = m_extensions.get<Renegotiation_Extension>()) - return reneg->renegotiation_info(); - return std::vector<byte>(); - } - - bool next_protocol_notification() const - { - return m_extensions.get<Next_Protocol_Notification>(); - } - - size_t fragment_size() const - { - if(Maximum_Fragment_Length* frag = m_extensions.get<Maximum_Fragment_Length>()) - return frag->fragment_size(); - return 0; - } - - bool supports_session_ticket() const - { - return m_extensions.get<Session_Ticket>(); - } - - std::vector<byte> session_ticket() const - { - if(Session_Ticket* ticket = m_extensions.get<Session_Ticket>()) - return ticket->contents(); - return std::vector<byte>(); - } - - bool supports_heartbeats() const - { - return m_extensions.get<Heartbeat_Support_Indicator>(); - } - - bool peer_can_send_heartbeats() const - { - if(Heartbeat_Support_Indicator* hb = m_extensions.get<Heartbeat_Support_Indicator>()) - return hb->peer_allowed_to_send(); - return false; - } - - void update_hello_cookie(const Hello_Verify_Request& hello_verify); - - Client_Hello(Handshake_IO& io, - Handshake_Hash& hash, - Protocol_Version version, - const Policy& policy, - RandomNumberGenerator& rng, - const std::vector<byte>& reneg_info, - bool next_protocol = false, - const std::string& hostname = "", - const std::string& srp_identifier = ""); - - Client_Hello(Handshake_IO& io, - Handshake_Hash& hash, - const Policy& policy, - RandomNumberGenerator& rng, - const std::vector<byte>& reneg_info, - const Session& resumed_session, - bool next_protocol = false); - - Client_Hello(const std::vector<byte>& buf, - Handshake_Type type); - - private: - std::vector<byte> serialize() const override; - void deserialize(const std::vector<byte>& buf); - void deserialize_sslv2(const std::vector<byte>& buf); - - Protocol_Version m_version; - std::vector<byte> m_session_id; - std::vector<byte> m_random; - std::vector<u16bit> m_suites; - std::vector<byte> m_comp_methods; - std::vector<byte> m_hello_cookie; // DTLS only - - Extensions m_extensions; - }; - -/** -* Server Hello Message -*/ -class Server_Hello : public Handshake_Message - { - public: - Handshake_Type type() const override { return SERVER_HELLO; } - - Protocol_Version version() const { return m_version; } - - const std::vector<byte>& random() const { return m_random; } - - const std::vector<byte>& session_id() const { return m_session_id; } - - u16bit ciphersuite() const { return m_ciphersuite; } - - byte compression_method() const { return m_comp_method; } - - bool secure_renegotiation() const - { - return m_extensions.get<Renegotiation_Extension>(); - } - - std::vector<byte> renegotiation_info() const - { - if(Renegotiation_Extension* reneg = m_extensions.get<Renegotiation_Extension>()) - return reneg->renegotiation_info(); - return std::vector<byte>(); - } - - bool next_protocol_notification() const - { - return m_extensions.get<Next_Protocol_Notification>(); - } - - std::vector<std::string> next_protocols() const - { - if(Next_Protocol_Notification* npn = m_extensions.get<Next_Protocol_Notification>()) - return npn->protocols(); - return std::vector<std::string>(); - } - - size_t fragment_size() const - { - if(Maximum_Fragment_Length* frag = m_extensions.get<Maximum_Fragment_Length>()) - return frag->fragment_size(); - return 0; - } - - bool supports_session_ticket() const - { - return m_extensions.get<Session_Ticket>(); - } - - bool supports_heartbeats() const - { - return m_extensions.get<Heartbeat_Support_Indicator>(); - } - - bool peer_can_send_heartbeats() const - { - if(Heartbeat_Support_Indicator* hb = m_extensions.get<Heartbeat_Support_Indicator>()) - return hb->peer_allowed_to_send(); - return false; - } - - Server_Hello(Handshake_IO& io, - Handshake_Hash& hash, - const Policy& policy, - const std::vector<byte>& session_id, - Protocol_Version ver, - u16bit ciphersuite, - byte compression, - size_t max_fragment_size, - bool client_has_secure_renegotiation, - const std::vector<byte>& reneg_info, - bool offer_session_ticket, - bool client_has_npn, - const std::vector<std::string>& next_protocols, - bool client_has_heartbeat, - RandomNumberGenerator& rng); - - Server_Hello(const std::vector<byte>& buf); - private: - std::vector<byte> serialize() const override; - - Protocol_Version m_version; - std::vector<byte> m_session_id, m_random; - u16bit m_ciphersuite; - byte m_comp_method; - - Extensions m_extensions; - }; - -/** -* Client Key Exchange Message -*/ -class Client_Key_Exchange : public Handshake_Message - { - public: - Handshake_Type type() const override { return CLIENT_KEX; } - - const secure_vector<byte>& pre_master_secret() const - { return m_pre_master; } - - Client_Key_Exchange(Handshake_IO& io, - Handshake_State& state, - const Policy& policy, - Credentials_Manager& creds, - const Public_Key* server_public_key, - const std::string& hostname, - RandomNumberGenerator& rng); - - Client_Key_Exchange(const std::vector<byte>& buf, - const Handshake_State& state, - const Private_Key* server_rsa_kex_key, - Credentials_Manager& creds, - const Policy& policy, - RandomNumberGenerator& rng); - - private: - std::vector<byte> serialize() const override - { return m_key_material; } - - std::vector<byte> m_key_material; - secure_vector<byte> m_pre_master; - }; - -/** -* Certificate Message -*/ -class Certificate : public Handshake_Message - { - public: - Handshake_Type type() const override { return CERTIFICATE; } - const std::vector<X509_Certificate>& cert_chain() const { return m_certs; } - - size_t count() const { return m_certs.size(); } - bool empty() const { return m_certs.empty(); } - - Certificate(Handshake_IO& io, - Handshake_Hash& hash, - const std::vector<X509_Certificate>& certs); - - Certificate(const std::vector<byte>& buf); - private: - std::vector<byte> serialize() const override; - - std::vector<X509_Certificate> m_certs; - }; - -/** -* Certificate Request Message -*/ -class Certificate_Req : public Handshake_Message - { - public: - Handshake_Type type() const override { return CERTIFICATE_REQUEST; } - - const std::vector<std::string>& acceptable_cert_types() const - { return m_cert_key_types; } - - std::vector<X509_DN> acceptable_CAs() const { return m_names; } - - std::vector<std::pair<std::string, std::string> > supported_algos() const - { return m_supported_algos; } - - Certificate_Req(Handshake_IO& io, - Handshake_Hash& hash, - const Policy& policy, - const std::vector<X509_DN>& allowed_cas, - Protocol_Version version); - - Certificate_Req(const std::vector<byte>& buf, - Protocol_Version version); - private: - std::vector<byte> serialize() const override; - - std::vector<X509_DN> m_names; - std::vector<std::string> m_cert_key_types; - - std::vector<std::pair<std::string, std::string> > m_supported_algos; - }; - -/** -* Certificate Verify Message -*/ -class Certificate_Verify : public Handshake_Message - { - public: - Handshake_Type type() const override { return CERTIFICATE_VERIFY; } - - /** - * Check the signature on a certificate verify message - * @param cert the purported certificate - * @param state the handshake state - */ - bool verify(const X509_Certificate& cert, - const Handshake_State& state) const; - - Certificate_Verify(Handshake_IO& io, - Handshake_State& state, - const Policy& policy, - RandomNumberGenerator& rng, - const Private_Key* key); - - Certificate_Verify(const std::vector<byte>& buf, - Protocol_Version version); - private: - std::vector<byte> serialize() const override; - - std::string m_sig_algo; // sig algo used to create signature - std::string m_hash_algo; // hash used to create signature - std::vector<byte> m_signature; - }; - -/** -* Finished Message -*/ -class Finished : public Handshake_Message - { - public: - Handshake_Type type() const override { return FINISHED; } - - std::vector<byte> verify_data() const - { return m_verification_data; } - - bool verify(const Handshake_State& state, - Connection_Side side) const; - - Finished(Handshake_IO& io, - Handshake_State& state, - Connection_Side side); - - Finished(const std::vector<byte>& buf); - private: - std::vector<byte> serialize() const override; - - std::vector<byte> m_verification_data; - }; - -/** -* Hello Request Message -*/ -class Hello_Request : public Handshake_Message - { - public: - Handshake_Type type() const override { return HELLO_REQUEST; } - - Hello_Request(Handshake_IO& io); - Hello_Request(const std::vector<byte>& buf); - private: - std::vector<byte> serialize() const override; - }; - -/** -* Server Key Exchange Message -*/ -class Server_Key_Exchange : public Handshake_Message - { - public: - Handshake_Type type() const override { return SERVER_KEX; } - - const std::vector<byte>& params() const { return m_params; } - - bool verify(const Public_Key& server_key, - const Handshake_State& state) const; - - // Only valid for certain kex types - const Private_Key& server_kex_key() const; - - // Only valid for SRP negotiation - SRP6_Server_Session& server_srp_params() const; - - Server_Key_Exchange(Handshake_IO& io, - Handshake_State& state, - const Policy& policy, - Credentials_Manager& creds, - RandomNumberGenerator& rng, - const Private_Key* signing_key = nullptr); - - Server_Key_Exchange(const std::vector<byte>& buf, - const std::string& kex_alg, - const std::string& sig_alg, - Protocol_Version version); - - ~Server_Key_Exchange(); - private: - std::vector<byte> serialize() const override; - - std::unique_ptr<Private_Key> m_kex_key; - std::unique_ptr<SRP6_Server_Session> m_srp_params; - - std::vector<byte> m_params; - - std::string m_sig_algo; // sig algo used to create signature - std::string m_hash_algo; // hash used to create signature - std::vector<byte> m_signature; - }; - -/** -* Server Hello Done Message -*/ -class Server_Hello_Done : public Handshake_Message - { - public: - Handshake_Type type() const override { return SERVER_HELLO_DONE; } - - Server_Hello_Done(Handshake_IO& io, Handshake_Hash& hash); - Server_Hello_Done(const std::vector<byte>& buf); - private: - std::vector<byte> serialize() const override; - }; - -/** -* Next Protocol Message -*/ -class Next_Protocol : public Handshake_Message - { - public: - Handshake_Type type() const override { return NEXT_PROTOCOL; } - - std::string protocol() const { return m_protocol; } - - Next_Protocol(Handshake_IO& io, - Handshake_Hash& hash, - const std::string& protocol); - - Next_Protocol(const std::vector<byte>& buf); - private: - std::vector<byte> serialize() const override; - - std::string m_protocol; - }; - -/** -* New Session Ticket Message -*/ -class New_Session_Ticket : public Handshake_Message - { - public: - Handshake_Type type() const override { return NEW_SESSION_TICKET; } - - u32bit ticket_lifetime_hint() const { return m_ticket_lifetime_hint; } - const std::vector<byte>& ticket() const { return m_ticket; } - - New_Session_Ticket(Handshake_IO& io, - Handshake_Hash& hash, - const std::vector<byte>& ticket, - u32bit lifetime); - - New_Session_Ticket(Handshake_IO& io, - Handshake_Hash& hash); - - New_Session_Ticket(const std::vector<byte>& buf); - private: - std::vector<byte> serialize() const override; - - u32bit m_ticket_lifetime_hint; - std::vector<byte> m_ticket; - }; - -/** -* Change Cipher Spec -*/ -class Change_Cipher_Spec : public Handshake_Message - { - public: - Handshake_Type type() const override { return HANDSHAKE_CCS; } - - std::vector<byte> serialize() const override - { return std::vector<byte>(1, 1); } - }; - -} - -} - -#endif diff --git a/src/tls/tls_policy.cpp b/src/tls/tls_policy.cpp deleted file mode 100644 index 05251e186..000000000 --- a/src/tls/tls_policy.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/* -* Policies for TLS -* (C) 2004-2010,2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/tls_policy.h> -#include <botan/tls_ciphersuite.h> -#include <botan/tls_magic.h> -#include <botan/tls_exceptn.h> -#include <botan/internal/stl_util.h> - -namespace Botan { - -namespace TLS { - -std::vector<std::string> Policy::allowed_ciphers() const - { - return std::vector<std::string>({ - "AES-256/GCM", - "AES-128/GCM", - "AES-256/CCM", - "AES-128/CCM", - "AES-256/CCM-8", - "AES-128/CCM-8", - //"Camellia-256/GCM", - //"Camellia-128/GCM", - "AES-256", - "AES-128", - //"Camellia-256", - //"Camellia-128", - //"SEED" - //"3DES", - //"RC4", - }); - } - -std::vector<std::string> Policy::allowed_signature_hashes() const - { - return std::vector<std::string>({ - "SHA-512", - "SHA-384", - "SHA-256", - "SHA-224", - //"SHA-1", - //"MD5", - }); - } - -std::vector<std::string> Policy::allowed_macs() const - { - return std::vector<std::string>({ - "AEAD", - "SHA-384", - "SHA-256", - "SHA-1", - //"MD5", - }); - } - -std::vector<std::string> Policy::allowed_key_exchange_methods() const - { - return std::vector<std::string>({ - "SRP_SHA", - //"ECDHE_PSK", - //"DHE_PSK", - //"PSK", - "ECDH", - "DH", - "RSA", - }); - } - -std::vector<std::string> Policy::allowed_signature_methods() const - { - return std::vector<std::string>({ - "ECDSA", - "RSA", - "DSA", - //"" - }); - } - -std::vector<std::string> Policy::allowed_ecc_curves() const - { - return std::vector<std::string>({ - "brainpool512r1", - "brainpool384r1", - "brainpool256r1", - "secp521r1", - "secp384r1", - "secp256r1", - "secp256k1", - "secp224r1", - "secp224k1", - //"secp192r1", - //"secp192k1", - //"secp160r2", - //"secp160r1", - //"secp160k1", - }); - } - -/* -* Choose an ECC curve to use -*/ -std::string Policy::choose_curve(const std::vector<std::string>& curve_names) const - { - const std::vector<std::string> our_curves = allowed_ecc_curves(); - - for(size_t i = 0; i != our_curves.size(); ++i) - if(value_exists(curve_names, our_curves[i])) - return our_curves[i]; - - return ""; // no shared curve - } - -DL_Group Policy::dh_group() const - { - return DL_Group("modp/ietf/2048"); - } - -size_t Policy::minimum_dh_group_size() const - { - return 1024; - } - -/* -* Return allowed compression algorithms -*/ -std::vector<byte> Policy::compression() const - { - return std::vector<byte>{ NO_COMPRESSION }; - } - -u32bit Policy::session_ticket_lifetime() const - { - return 86400; // 1 day - } - -bool Policy::acceptable_protocol_version(Protocol_Version version) const - { - // By default require TLS to minimize surprise - if(version.is_datagram_protocol()) - return false; - - return (version > Protocol_Version::SSL_V3); - } - -bool Policy::acceptable_ciphersuite(const Ciphersuite&) const - { - return true; - } - -namespace { - -class Ciphersuite_Preference_Ordering - { - public: - Ciphersuite_Preference_Ordering(const std::vector<std::string>& ciphers, - const std::vector<std::string>& macs, - const std::vector<std::string>& kex, - const std::vector<std::string>& sigs) : - m_ciphers(ciphers), m_macs(macs), m_kex(kex), m_sigs(sigs) {} - - bool operator()(const Ciphersuite& a, const Ciphersuite& b) const - { - if(a.kex_algo() != b.kex_algo()) - { - for(size_t i = 0; i != m_kex.size(); ++i) - { - if(a.kex_algo() == m_kex[i]) - return true; - if(b.kex_algo() == m_kex[i]) - return false; - } - } - - if(a.cipher_algo() != b.cipher_algo()) - { - for(size_t i = 0; i != m_ciphers.size(); ++i) - { - if(a.cipher_algo() == m_ciphers[i]) - return true; - if(b.cipher_algo() == m_ciphers[i]) - return false; - } - } - - if(a.cipher_keylen() != b.cipher_keylen()) - { - if(a.cipher_keylen() < b.cipher_keylen()) - return false; - if(a.cipher_keylen() > b.cipher_keylen()) - return true; - } - - if(a.sig_algo() != b.sig_algo()) - { - for(size_t i = 0; i != m_sigs.size(); ++i) - { - if(a.sig_algo() == m_sigs[i]) - return true; - if(b.sig_algo() == m_sigs[i]) - return false; - } - } - - if(a.mac_algo() != b.mac_algo()) - { - for(size_t i = 0; i != m_macs.size(); ++i) - { - if(a.mac_algo() == m_macs[i]) - return true; - if(b.mac_algo() == m_macs[i]) - return false; - } - } - - return false; // equal (?!?) - } - private: - std::vector<std::string> m_ciphers, m_macs, m_kex, m_sigs; - }; - -} - -std::vector<u16bit> Policy::ciphersuite_list(Protocol_Version version, - bool have_srp) const - { - const std::vector<std::string> ciphers = allowed_ciphers(); - const std::vector<std::string> macs = allowed_macs(); - const std::vector<std::string> kex = allowed_key_exchange_methods(); - const std::vector<std::string> sigs = allowed_signature_methods(); - - Ciphersuite_Preference_Ordering order(ciphers, macs, kex, sigs); - - std::set<Ciphersuite, Ciphersuite_Preference_Ordering> ciphersuites(order); - - for(auto suite : Ciphersuite::all_known_ciphersuites()) - { - if(!acceptable_ciphersuite(suite)) - continue; - - if(!have_srp && suite.kex_algo() == "SRP_SHA") - continue; - - if(version.is_datagram_protocol() && suite.cipher_algo() == "RC4") - continue; - - if(!version.supports_aead_modes() && suite.mac_algo() == "AEAD") - continue; - - if(!value_exists(kex, suite.kex_algo())) - continue; // unsupported key exchange - - if(!value_exists(ciphers, suite.cipher_algo())) - continue; // unsupported cipher - - if(!value_exists(macs, suite.mac_algo())) - continue; // unsupported MAC algo - - if(!value_exists(sigs, suite.sig_algo())) - { - // allow if it's an empty sig algo and we want to use PSK - if(suite.sig_algo() != "" || !suite.psk_ciphersuite()) - continue; - } - - // OK, allow it: - ciphersuites.insert(suite); - } - - if(ciphersuites.empty()) - throw std::logic_error("Policy does not allow any available cipher suite"); - - std::vector<u16bit> ciphersuite_codes; - for(auto i : ciphersuites) - ciphersuite_codes.push_back(i.ciphersuite_code()); - return ciphersuite_codes; - } - -} - -} diff --git a/src/tls/tls_policy.h b/src/tls/tls_policy.h deleted file mode 100644 index 5b205dfeb..000000000 --- a/src/tls/tls_policy.h +++ /dev/null @@ -1,194 +0,0 @@ -/* -* Hooks for application level policies on TLS connections -* (C) 2004-2006,2013 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_POLICY_H__ -#define BOTAN_TLS_POLICY_H__ - -#include <botan/tls_version.h> -#include <botan/tls_ciphersuite.h> -#include <botan/x509cert.h> -#include <botan/dl_group.h> -#include <vector> - -namespace Botan { - -namespace TLS { - -/** -* TLS Policy Base Class -* Inherit and overload as desired to suit local policy concerns -*/ -class BOTAN_DLL Policy - { - public: - - /** - * Returns a list of ciphers we are willing to negotiate, in - * order of preference. - */ - virtual std::vector<std::string> allowed_ciphers() const; - - /** - * Returns a list of hash algorithms we are willing to use for - * signatures, in order of preference. - */ - virtual std::vector<std::string> allowed_signature_hashes() const; - - /** - * Returns a list of MAC algorithms we are willing to use. - */ - virtual std::vector<std::string> allowed_macs() const; - - /** - * Returns a list of key exchange algorithms we are willing to - * use, in order of preference. Allowed values: DH, empty string - * (representing RSA using server certificate key) - */ - virtual std::vector<std::string> allowed_key_exchange_methods() const; - - /** - * Returns a list of signature algorithms we are willing to - * use, in order of preference. Allowed values RSA and DSA. - */ - virtual std::vector<std::string> allowed_signature_methods() const; - - /** - * Return list of ECC curves we are willing to use in order of preference - */ - virtual std::vector<std::string> allowed_ecc_curves() const; - - /** - * Returns a list of compression algorithms we are willing to use, - * in order of preference. Allowed values any value of - * Compression_Method. - * - * @note Compression is not currently supported - */ - virtual std::vector<byte> compression() const; - - /** - * Choose an elliptic curve to use - */ - virtual std::string choose_curve(const std::vector<std::string>& curve_names) const; - - /** - * Attempt to negotiate the use of the heartbeat extension - */ - virtual bool negotiate_heartbeat_support() const { return false; } - - /** - * Allow renegotiation even if the counterparty doesn't - * support the secure renegotiation extension. - * - * @warning Changing this to true exposes you to injected - * plaintext attacks. Read RFC 5746 for background. - */ - virtual bool allow_insecure_renegotiation() const { return false; } - - /** - * Allow servers to initiate a new handshake - */ - virtual bool allow_server_initiated_renegotiation() const { return true; } - - /** - * Return the group to use for ephemeral Diffie-Hellman key agreement - */ - virtual DL_Group dh_group() const; - - /** - * Return the minimum DH group size we're willing to use - */ - virtual size_t minimum_dh_group_size() const; - - /** - * If this function returns false, unknown SRP/PSK identifiers - * will be rejected with an unknown_psk_identifier alert as soon - * as the non-existence is identified. Otherwise, a false - * identifier value will be used and the protocol allowed to - * proceed, causing the handshake to eventually fail without - * revealing that the username does not exist on this system. - */ - virtual bool hide_unknown_users() const { return false; } - - /** - * Return the allowed lifetime of a session ticket. If 0, session - * tickets do not expire until the session ticket key rolls over. - * Expired session tickets cannot be used to resume a session. - */ - virtual u32bit session_ticket_lifetime() const; - - /** - * @return true if and only if we are willing to accept this version - * Default accepts only TLS, so override if you want to enable DTLS - * in your application. - */ - virtual bool acceptable_protocol_version(Protocol_Version version) const; - - virtual bool acceptable_ciphersuite(const Ciphersuite& suite) const; - - /** - * @return true if servers should choose the ciphersuite matching - * their highest preference, rather than the clients. - * Has no effect on client side. - */ - virtual bool server_uses_own_ciphersuite_preferences() const { return true; } - - /** - * Return allowed ciphersuites, in order of preference - */ - virtual std::vector<u16bit> ciphersuite_list(Protocol_Version version, - bool have_srp) const; - - virtual ~Policy() {} - }; - -/** -* NSA Suite B 128-bit security level (see @rfc 6460) -*/ -class BOTAN_DLL NSA_Suite_B_128 : public Policy - { - public: - std::vector<std::string> allowed_ciphers() const override - { return std::vector<std::string>({"AES-128/GCM"}); } - - std::vector<std::string> allowed_signature_hashes() const override - { return std::vector<std::string>({"SHA-256"}); } - - std::vector<std::string> allowed_macs() const override - { return std::vector<std::string>({"AEAD"}); } - - std::vector<std::string> allowed_key_exchange_methods() const override - { return std::vector<std::string>({"ECDH"}); } - - std::vector<std::string> allowed_signature_methods() const override - { return std::vector<std::string>({"ECDSA"}); } - - std::vector<std::string> allowed_ecc_curves() const override - { return std::vector<std::string>({"secp256r1"}); } - - bool acceptable_protocol_version(Protocol_Version version) const override - { return version == Protocol_Version::TLS_V12; } - }; - -/** -* Policy for DTLS. We require DTLS v1.2 and an AEAD mode -*/ -class BOTAN_DLL Datagram_Policy : public Policy - { - public: - std::vector<std::string> allowed_macs() const override - { return std::vector<std::string>({"AEAD"}); } - - bool acceptable_protocol_version(Protocol_Version version) const override - { return version == Protocol_Version::DTLS_V12; } - }; - -} - -} - -#endif diff --git a/src/tls/tls_reader.h b/src/tls/tls_reader.h deleted file mode 100644 index 7440e16b7..000000000 --- a/src/tls/tls_reader.h +++ /dev/null @@ -1,226 +0,0 @@ -/* -* TLS Data Reader -* (C) 2010-2011 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_READER_H__ -#define BOTAN_TLS_READER_H__ - -#include <botan/exceptn.h> -#include <botan/secmem.h> -#include <botan/loadstor.h> -#include <string> -#include <vector> -#include <stdexcept> - -namespace Botan { - -namespace TLS { - -/** -* Helper class for decoding TLS protocol messages -*/ -class TLS_Data_Reader - { - public: - TLS_Data_Reader(const std::vector<byte>& buf_in) : - buf(buf_in), offset(0) {} - - void assert_done() const - { - if(has_remaining()) - throw Decoding_Error("Extra bytes at end of message"); - } - - size_t remaining_bytes() const - { - return buf.size() - offset; - } - - bool has_remaining() const - { - return (remaining_bytes() > 0); - } - - void discard_next(size_t bytes) - { - assert_at_least(bytes); - offset += bytes; - } - - u16bit get_u32bit() - { - assert_at_least(4); - u16bit result = make_u32bit(buf[offset ], buf[offset+1], - buf[offset+2], buf[offset+3]); - offset += 4; - return result; - } - - u16bit get_u16bit() - { - assert_at_least(2); - u16bit result = make_u16bit(buf[offset], buf[offset+1]); - offset += 2; - return result; - } - - byte get_byte() - { - assert_at_least(1); - byte result = buf[offset]; - offset += 1; - return result; - } - - template<typename T, typename Container> - Container get_elem(size_t num_elems) - { - assert_at_least(num_elems * sizeof(T)); - - Container result(num_elems); - - for(size_t i = 0; i != num_elems; ++i) - result[i] = load_be<T>(&buf[offset], i); - - offset += num_elems * sizeof(T); - - return result; - } - - template<typename T> - std::vector<T> get_range(size_t len_bytes, - size_t min_elems, - size_t max_elems) - { - const size_t num_elems = - get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); - - return get_elem<T, std::vector<T> >(num_elems); - } - - template<typename T> - std::vector<T> get_range_vector(size_t len_bytes, - size_t min_elems, - size_t max_elems) - { - const size_t num_elems = - get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); - - return get_elem<T, std::vector<T> >(num_elems); - } - - std::string get_string(size_t len_bytes, - size_t min_bytes, - size_t max_bytes) - { - std::vector<byte> v = - get_range_vector<byte>(len_bytes, min_bytes, max_bytes); - - return std::string(reinterpret_cast<char*>(&v[0]), v.size()); - } - - template<typename T> - std::vector<T> get_fixed(size_t size) - { - return get_elem<T, std::vector<T> >(size); - } - - private: - size_t get_length_field(size_t len_bytes) - { - assert_at_least(len_bytes); - - if(len_bytes == 1) - return get_byte(); - else if(len_bytes == 2) - return get_u16bit(); - - throw Decoding_Error("TLS_Data_Reader: Bad length size"); - } - - size_t get_num_elems(size_t len_bytes, - size_t T_size, - size_t min_elems, - size_t max_elems) - { - const size_t byte_length = get_length_field(len_bytes); - - if(byte_length % T_size != 0) - throw Decoding_Error("TLS_Data_Reader: Size isn't multiple of T"); - - const size_t num_elems = byte_length / T_size; - - if(num_elems < min_elems || num_elems > max_elems) - throw Decoding_Error("TLS_Data_Reader: Range outside paramaters"); - - return num_elems; - } - - void assert_at_least(size_t n) const - { - if(buf.size() - offset < n) - { - throw Decoding_Error("TLS_Data_Reader: Expected " + std::to_string(n) + - " bytes remaining, only " + std::to_string(buf.size()-offset) + - " left"); - } - } - - const std::vector<byte>& buf; - size_t offset; - }; - -/** -* Helper function for encoding length-tagged vectors -*/ -template<typename T, typename Alloc> -void append_tls_length_value(std::vector<byte, Alloc>& buf, - const T* vals, - size_t vals_size, - size_t tag_size) - { - const size_t T_size = sizeof(T); - const size_t val_bytes = T_size * vals_size; - - if(tag_size != 1 && tag_size != 2) - throw std::invalid_argument("append_tls_length_value: invalid tag size"); - - if((tag_size == 1 && val_bytes > 255) || - (tag_size == 2 && val_bytes > 65535)) - throw std::invalid_argument("append_tls_length_value: value too large"); - - for(size_t i = 0; i != tag_size; ++i) - buf.push_back(get_byte(sizeof(val_bytes)-tag_size+i, val_bytes)); - - for(size_t i = 0; i != vals_size; ++i) - for(size_t j = 0; j != T_size; ++j) - buf.push_back(get_byte(j, vals[i])); - } - -template<typename T, typename Alloc, typename Alloc2> -void append_tls_length_value(std::vector<byte, Alloc>& buf, - const std::vector<T, Alloc2>& vals, - size_t tag_size) - { - append_tls_length_value(buf, &vals[0], vals.size(), tag_size); - } - -template<typename Alloc> -void append_tls_length_value(std::vector<byte, Alloc>& buf, - const std::string& str, - size_t tag_size) - { - append_tls_length_value(buf, - reinterpret_cast<const byte*>(&str[0]), - str.size(), - tag_size); - } - -} - -} - -#endif diff --git a/src/tls/tls_record.cpp b/src/tls/tls_record.cpp deleted file mode 100644 index fc4908dc5..000000000 --- a/src/tls/tls_record.cpp +++ /dev/null @@ -1,622 +0,0 @@ -/* -* TLS Record Handling -* (C) 2012,2013 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/internal/tls_record.h> -#include <botan/tls_ciphersuite.h> -#include <botan/tls_exceptn.h> -#include <botan/libstate.h> -#include <botan/loadstor.h> -#include <botan/internal/tls_seq_numbers.h> -#include <botan/internal/tls_session_key.h> -#include <botan/internal/rounding.h> -#include <botan/internal/xor_buf.h> - -namespace Botan { - -namespace TLS { - -Connection_Cipher_State::Connection_Cipher_State(Protocol_Version version, - Connection_Side side, - bool our_side, - const Ciphersuite& suite, - const Session_Keys& keys) : - m_start_time(std::chrono::system_clock::now()), - m_is_ssl3(version == Protocol_Version::SSL_V3) - { - SymmetricKey mac_key, cipher_key; - InitializationVector iv; - - if(side == CLIENT) - { - cipher_key = keys.client_cipher_key(); - iv = keys.client_iv(); - mac_key = keys.client_mac_key(); - } - else - { - cipher_key = keys.server_cipher_key(); - iv = keys.server_iv(); - mac_key = keys.server_mac_key(); - } - - const std::string cipher_algo = suite.cipher_algo(); - const std::string mac_algo = suite.mac_algo(); - - if(AEAD_Mode* aead = get_aead(cipher_algo, our_side ? ENCRYPTION : DECRYPTION)) - { - m_aead.reset(aead); - m_aead->set_key(cipher_key + mac_key); - - BOTAN_ASSERT(iv.length() == 4, "Using 4/8 partial implicit nonce"); - m_nonce = iv.bits_of(); - m_nonce.resize(12); - return; - } - - Algorithm_Factory& af = global_state().algorithm_factory(); - - if(const BlockCipher* bc = af.prototype_block_cipher(cipher_algo)) - { - m_block_cipher.reset(bc->clone()); - m_block_cipher->set_key(cipher_key); - m_block_cipher_cbc_state = iv.bits_of(); - m_block_size = bc->block_size(); - - if(version.supports_explicit_cbc_ivs()) - m_iv_size = m_block_size; - } - else if(const StreamCipher* sc = af.prototype_stream_cipher(cipher_algo)) - { - m_stream_cipher.reset(sc->clone()); - m_stream_cipher->set_key(cipher_key); - } - else - throw Invalid_Argument("Unknown TLS cipher " + cipher_algo); - - if(version == Protocol_Version::SSL_V3) - m_mac.reset(af.make_mac("SSL3-MAC(" + mac_algo + ")")); - else - m_mac.reset(af.make_mac("HMAC(" + mac_algo + ")")); - - m_mac->set_key(mac_key); - } - -const secure_vector<byte>& Connection_Cipher_State::aead_nonce(u64bit seq) - { - BOTAN_ASSERT(m_aead, "Using AEAD mode"); - BOTAN_ASSERT(m_nonce.size() == 12, "Expected nonce size"); - store_be(seq, &m_nonce[4]); - return m_nonce; - } - -const secure_vector<byte>& -Connection_Cipher_State::aead_nonce(const byte record[], size_t record_len) - { - BOTAN_ASSERT(m_aead, "Using AEAD mode"); - BOTAN_ASSERT(m_nonce.size() == 12, "Expected nonce size"); - BOTAN_ASSERT(record_len >= 8, "Record includes nonce"); - copy_mem(&m_nonce[4], record, 8); - return m_nonce; - } - -const secure_vector<byte>& -Connection_Cipher_State::format_ad(u64bit msg_sequence, - byte msg_type, - Protocol_Version version, - u16bit msg_length) - { - m_ad.clear(); - for(size_t i = 0; i != 8; ++i) - m_ad.push_back(get_byte(i, msg_sequence)); - m_ad.push_back(msg_type); - - if(version != Protocol_Version::SSL_V3) - { - m_ad.push_back(version.major_version()); - m_ad.push_back(version.minor_version()); - } - - m_ad.push_back(get_byte(0, msg_length)); - m_ad.push_back(get_byte(1, msg_length)); - - return m_ad; - } - -void write_record(secure_vector<byte>& output, - byte msg_type, const byte msg[], size_t msg_length, - Protocol_Version version, - u64bit msg_sequence, - Connection_Cipher_State* cipherstate, - RandomNumberGenerator& rng) - { - output.clear(); - - output.push_back(msg_type); - output.push_back(version.major_version()); - output.push_back(version.minor_version()); - - if(version.is_datagram_protocol()) - { - for(size_t i = 0; i != 8; ++i) - output.push_back(get_byte(i, msg_sequence)); - } - - if(!cipherstate) // initial unencrypted handshake records - { - output.push_back(get_byte<u16bit>(0, msg_length)); - output.push_back(get_byte<u16bit>(1, msg_length)); - - output.insert(output.end(), &msg[0], &msg[msg_length]); - - return; - } - - if(AEAD_Mode* aead = cipherstate->aead()) - { - const size_t ctext_size = aead->output_length(msg_length); - - auto nonce = cipherstate->aead_nonce(msg_sequence); - const size_t implicit_nonce_bytes = 4; // FIXME, take from ciphersuite - const size_t explicit_nonce_bytes = 8; - - BOTAN_ASSERT(nonce.size() == implicit_nonce_bytes + explicit_nonce_bytes, - "Expected nonce size"); - - // wrong if start_vec returns something - const size_t rec_size = ctext_size + explicit_nonce_bytes; - - BOTAN_ASSERT(rec_size <= 0xFFFF, "Ciphertext length fits in field"); - - output.push_back(get_byte<u16bit>(0, rec_size)); - output.push_back(get_byte<u16bit>(1, rec_size)); - - aead->set_associated_data_vec( - cipherstate->format_ad(msg_sequence, msg_type, version, msg_length) - ); - - output += std::make_pair(&nonce[implicit_nonce_bytes], explicit_nonce_bytes); - output += aead->start_vec(nonce); - - const size_t offset = output.size(); - output += std::make_pair(&msg[0], msg_length); - aead->finish(output, offset); - - BOTAN_ASSERT(output.size() == offset + ctext_size, "Expected size"); - - BOTAN_ASSERT(output.size() < MAX_CIPHERTEXT_SIZE, - "Produced ciphertext larger than protocol allows"); - return; - } - - cipherstate->mac()->update( - cipherstate->format_ad(msg_sequence, msg_type, version, msg_length) - ); - - cipherstate->mac()->update(msg, msg_length); - - const size_t block_size = cipherstate->block_size(); - const size_t iv_size = cipherstate->iv_size(); - const size_t mac_size = cipherstate->mac_size(); - - const size_t buf_size = round_up( - iv_size + msg_length + mac_size + (block_size ? 1 : 0), - block_size); - - if(buf_size > MAX_CIPHERTEXT_SIZE) - throw Internal_Error("Output record is larger than allowed by protocol"); - - output.push_back(get_byte<u16bit>(0, buf_size)); - output.push_back(get_byte<u16bit>(1, buf_size)); - - const size_t header_size = output.size(); - - if(iv_size) - { - output.resize(output.size() + iv_size); - rng.randomize(&output[output.size() - iv_size], iv_size); - } - - output.insert(output.end(), &msg[0], &msg[msg_length]); - - output.resize(output.size() + mac_size); - cipherstate->mac()->final(&output[output.size() - mac_size]); - - if(block_size) - { - const size_t pad_val = - buf_size - (iv_size + msg_length + mac_size + 1); - - for(size_t i = 0; i != pad_val + 1; ++i) - output.push_back(pad_val); - } - - if(buf_size > MAX_CIPHERTEXT_SIZE) - throw Internal_Error("Produced ciphertext larger than protocol allows"); - - BOTAN_ASSERT(buf_size + header_size == output.size(), - "Output buffer is sized properly"); - - if(StreamCipher* sc = cipherstate->stream_cipher()) - { - sc->cipher1(&output[header_size], buf_size); - } - else if(BlockCipher* bc = cipherstate->block_cipher()) - { - secure_vector<byte>& cbc_state = cipherstate->cbc_state(); - - BOTAN_ASSERT(buf_size % block_size == 0, - "Buffer is an even multiple of block size"); - - byte* buf = &output[header_size]; - - const size_t blocks = buf_size / block_size; - - xor_buf(&buf[0], &cbc_state[0], block_size); - bc->encrypt(&buf[0]); - - for(size_t i = 1; i < blocks; ++i) - { - xor_buf(&buf[block_size*i], &buf[block_size*(i-1)], block_size); - bc->encrypt(&buf[block_size*i]); - } - - cbc_state.assign(&buf[block_size*(blocks-1)], - &buf[block_size*blocks]); - } - else - throw Internal_Error("NULL cipher not supported"); - } - -namespace { - -size_t fill_buffer_to(secure_vector<byte>& readbuf, - const byte*& input, - size_t& input_size, - size_t& input_consumed, - size_t desired) - { - if(readbuf.size() >= desired) - return 0; // already have it - - const size_t taken = std::min(input_size, desired - readbuf.size()); - - readbuf.insert(readbuf.end(), &input[0], &input[taken]); - input_consumed += taken; - input_size -= taken; - input += taken; - - return (desired - readbuf.size()); // how many bytes do we still need? - } - -/* -* Checks the TLS padding. Returns 0 if the padding is invalid (we -* count the padding_length field as part of the padding size so a -* valid padding will always be at least one byte long), or the length -* of the padding otherwise. This is actually padding_length + 1 -* because both the padding and padding_length fields are padding from -* our perspective. -* -* Returning 0 in the error case should ensure the MAC check will fail. -* This approach is suggested in section 6.2.3.2 of RFC 5246. -* -* Also returns 0 if block_size == 0, so can be safely called with a -* stream cipher in use. -* -* @fixme This should run in constant time -*/ -size_t tls_padding_check(bool sslv3_padding, - size_t block_size, - const byte record[], - size_t record_len) - { - const size_t padding_length = record[(record_len-1)]; - - if(padding_length >= record_len) - return 0; - - /* - * SSL v3 requires that the padding be less than the block size - * but not does specify the value of the padding bytes. - */ - if(sslv3_padding) - { - if(padding_length > 0 && padding_length < block_size) - return (padding_length + 1); - else - return 0; - } - - /* - * TLS v1.0 and up require all the padding bytes be the same value - * and allows up to 255 bytes. - */ - const size_t pad_start = record_len - padding_length - 1; - - volatile size_t cmp = 0; - - for(size_t i = 0; i != padding_length; ++i) - cmp += record[pad_start + i] ^ padding_length; - - return cmp ? 0 : padding_length + 1; - } - -void cbc_decrypt_record(byte record_contents[], size_t record_len, - Connection_Cipher_State& cipherstate, - const BlockCipher& bc) - { - const size_t block_size = cipherstate.block_size(); - - BOTAN_ASSERT(record_len % block_size == 0, - "Buffer is an even multiple of block size"); - - const size_t blocks = record_len / block_size; - - BOTAN_ASSERT(blocks >= 1, "At least one ciphertext block"); - - byte* buf = record_contents; - - secure_vector<byte> last_ciphertext(block_size); - copy_mem(&last_ciphertext[0], &buf[0], block_size); - - bc.decrypt(&buf[0]); - xor_buf(&buf[0], &cipherstate.cbc_state()[0], block_size); - - secure_vector<byte> last_ciphertext2; - - for(size_t i = 1; i < blocks; ++i) - { - last_ciphertext2.assign(&buf[block_size*i], &buf[block_size*(i+1)]); - bc.decrypt(&buf[block_size*i]); - xor_buf(&buf[block_size*i], &last_ciphertext[0], block_size); - std::swap(last_ciphertext, last_ciphertext2); - } - - cipherstate.cbc_state() = last_ciphertext; - } - -void decrypt_record(secure_vector<byte>& output, - byte record_contents[], size_t record_len, - u64bit record_sequence, - Protocol_Version record_version, - Record_Type record_type, - Connection_Cipher_State& cipherstate) - { - if(AEAD_Mode* aead = cipherstate.aead()) - { - auto nonce = cipherstate.aead_nonce(record_contents, record_len); - const size_t nonce_length = 8; // fixme, take from ciphersuite - - BOTAN_ASSERT(record_len > nonce_length, "Have data past the nonce"); - const byte* msg = &record_contents[nonce_length]; - const size_t msg_length = record_len - nonce_length; - - const size_t ptext_size = aead->output_length(msg_length); - - aead->set_associated_data_vec( - cipherstate.format_ad(record_sequence, record_type, record_version, ptext_size) - ); - - output += aead->start_vec(nonce); - - const size_t offset = output.size(); - output += std::make_pair(&msg[0], msg_length); - aead->finish(output, offset); - - BOTAN_ASSERT(output.size() == ptext_size + offset, "Produced expected size"); - } - else - { - // GenericBlockCipher / GenericStreamCipher case - - volatile bool padding_bad = false; - size_t pad_size = 0; - - if(StreamCipher* sc = cipherstate.stream_cipher()) - { - sc->cipher1(record_contents, record_len); - // no padding to check or remove - } - else if(BlockCipher* bc = cipherstate.block_cipher()) - { - cbc_decrypt_record(record_contents, record_len, cipherstate, *bc); - - pad_size = tls_padding_check(cipherstate.cipher_padding_single_byte(), - cipherstate.block_size(), - record_contents, record_len); - - padding_bad = (pad_size == 0); - } - else - { - throw Internal_Error("No cipher state set but needed to decrypt"); - } - - const size_t mac_size = cipherstate.mac_size(); - const size_t iv_size = cipherstate.iv_size(); - - const size_t mac_pad_iv_size = mac_size + pad_size + iv_size; - - if(record_len < mac_pad_iv_size) - throw Decoding_Error("Record sent with invalid length"); - - const byte* plaintext_block = &record_contents[iv_size]; - const u16bit plaintext_length = record_len - mac_pad_iv_size; - - cipherstate.mac()->update( - cipherstate.format_ad(record_sequence, record_type, record_version, plaintext_length) - ); - - cipherstate.mac()->update(plaintext_block, plaintext_length); - - std::vector<byte> mac_buf(mac_size); - cipherstate.mac()->final(&mac_buf[0]); - - const size_t mac_offset = record_len - (mac_size + pad_size); - - const bool mac_bad = !same_mem(&record_contents[mac_offset], &mac_buf[0], mac_size); - - if(mac_bad || padding_bad) - throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure"); - - output.assign(plaintext_block, plaintext_block + plaintext_length); - } - } - -} - -size_t read_record(secure_vector<byte>& readbuf, - const byte input[], - size_t input_sz, - size_t& consumed, - secure_vector<byte>& record, - u64bit* record_sequence, - Protocol_Version* record_version, - Record_Type* record_type, - Connection_Sequence_Numbers* sequence_numbers, - std::function<Connection_Cipher_State* (u16bit)> get_cipherstate) - { - consumed = 0; - - if(readbuf.size() < TLS_HEADER_SIZE) // header incomplete? - { - if(size_t needed = fill_buffer_to(readbuf, - input, input_sz, consumed, - TLS_HEADER_SIZE)) - return needed; - - BOTAN_ASSERT_EQUAL(readbuf.size(), TLS_HEADER_SIZE, - "Have an entire header"); - } - - // Possible SSLv2 format client hello - if(!sequence_numbers && (readbuf[0] & 0x80) && (readbuf[2] == 1)) - { - if(readbuf[3] == 0 && readbuf[4] == 2) - throw TLS_Exception(Alert::PROTOCOL_VERSION, - "Client claims to only support SSLv2, rejecting"); - - if(readbuf[3] >= 3) // SSLv2 mapped TLS hello, then? - { - const size_t record_len = make_u16bit(readbuf[0], readbuf[1]) & 0x7FFF; - - if(size_t needed = fill_buffer_to(readbuf, - input, input_sz, consumed, - record_len + 2)) - return needed; - - BOTAN_ASSERT_EQUAL(readbuf.size(), (record_len + 2), - "Have the entire SSLv2 hello"); - - // Fake v3-style handshake message wrapper - *record_version = Protocol_Version::TLS_V10; - *record_sequence = 0; - *record_type = HANDSHAKE; - - record.resize(4 + readbuf.size() - 2); - - record[0] = CLIENT_HELLO_SSLV2; - record[1] = 0; - record[2] = readbuf[0] & 0x7F; - record[3] = readbuf[1]; - copy_mem(&record[4], &readbuf[2], readbuf.size() - 2); - - readbuf.clear(); - return 0; - } - } - - *record_version = Protocol_Version(readbuf[1], readbuf[2]); - - const bool is_dtls = record_version->is_datagram_protocol(); - - if(is_dtls && readbuf.size() < DTLS_HEADER_SIZE) - { - if(size_t needed = fill_buffer_to(readbuf, - input, input_sz, consumed, - DTLS_HEADER_SIZE)) - return needed; - - BOTAN_ASSERT_EQUAL(readbuf.size(), DTLS_HEADER_SIZE, - "Have an entire header"); - } - - const size_t header_size = (is_dtls) ? DTLS_HEADER_SIZE : TLS_HEADER_SIZE; - - const size_t record_len = make_u16bit(readbuf[header_size-2], - readbuf[header_size-1]); - - if(record_len > MAX_CIPHERTEXT_SIZE) - throw TLS_Exception(Alert::RECORD_OVERFLOW, - "Got message that exceeds maximum size"); - - if(size_t needed = fill_buffer_to(readbuf, - input, input_sz, consumed, - header_size + record_len)) - return needed; // wrong for DTLS? - - BOTAN_ASSERT_EQUAL(static_cast<size_t>(header_size) + record_len, - readbuf.size(), - "Have the full record"); - - *record_type = static_cast<Record_Type>(readbuf[0]); - - u16bit epoch = 0; - - if(is_dtls) - { - *record_sequence = load_be<u64bit>(&readbuf[3], 0); - epoch = (*record_sequence >> 48); - } - else if(sequence_numbers) - { - *record_sequence = sequence_numbers->next_read_sequence(); - epoch = sequence_numbers->current_read_epoch(); - } - else - { - // server initial handshake case - *record_sequence = 0; - epoch = 0; - } - - if(sequence_numbers && sequence_numbers->already_seen(*record_sequence)) - return 0; - - byte* record_contents = &readbuf[header_size]; - - if(epoch == 0) // Unencrypted initial handshake - { - record.assign(&readbuf[header_size], &readbuf[header_size + record_len]); - readbuf.clear(); - return 0; // got a full record - } - - // Otherwise, decrypt, check MAC, return plaintext - Connection_Cipher_State* cipherstate = get_cipherstate(epoch); - - // FIXME: DTLS reordering might cause us not to have the cipher state - - BOTAN_ASSERT(cipherstate, "Have cipherstate for this epoch"); - - decrypt_record(record, - record_contents, - record_len, - *record_sequence, - *record_version, - *record_type, - *cipherstate); - - if(sequence_numbers) - sequence_numbers->read_accept(*record_sequence); - - readbuf.clear(); - return 0; - } - -} - -} diff --git a/src/tls/tls_record.h b/src/tls/tls_record.h deleted file mode 100644 index ef27a0a02..000000000 --- a/src/tls/tls_record.h +++ /dev/null @@ -1,135 +0,0 @@ -/* -* TLS Record Handling -* (C) 2004-2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_RECORDS_H__ -#define BOTAN_TLS_RECORDS_H__ - -#include <botan/tls_magic.h> -#include <botan/tls_version.h> -#include <botan/aead.h> -#include <botan/block_cipher.h> -#include <botan/stream_cipher.h> -#include <botan/mac.h> -#include <vector> -#include <memory> -#include <chrono> - -namespace Botan { - -namespace TLS { - -class Ciphersuite; -class Session_Keys; - -class Connection_Sequence_Numbers; - -/** -* TLS Cipher State -*/ -class Connection_Cipher_State - { - public: - /** - * Initialize a new cipher state - */ - Connection_Cipher_State(Protocol_Version version, - Connection_Side which_side, - bool is_our_side, - const Ciphersuite& suite, - const Session_Keys& keys); - - AEAD_Mode* aead() { return m_aead.get(); } - - const secure_vector<byte>& aead_nonce(u64bit seq); - - const secure_vector<byte>& aead_nonce(const byte record[], size_t record_len); - - const secure_vector<byte>& format_ad(u64bit seq, byte type, - Protocol_Version version, - u16bit ptext_length); - - BlockCipher* block_cipher() { return m_block_cipher.get(); } - - StreamCipher* stream_cipher() { return m_stream_cipher.get(); } - - MessageAuthenticationCode* mac() { return m_mac.get(); } - - secure_vector<byte>& cbc_state() { return m_block_cipher_cbc_state; } - - size_t block_size() const { return m_block_size; } - - size_t mac_size() const { return m_mac->output_length(); } - - size_t iv_size() const { return m_iv_size; } - - bool mac_includes_record_version() const { return !m_is_ssl3; } - - bool cipher_padding_single_byte() const { return m_is_ssl3; } - - bool cbc_without_explicit_iv() const - { return (m_block_size > 0) && (m_iv_size == 0); } - - std::chrono::seconds age() const - { - return std::chrono::duration_cast<std::chrono::seconds>( - std::chrono::system_clock::now() - m_start_time); - } - - private: - std::chrono::system_clock::time_point m_start_time; - std::unique_ptr<BlockCipher> m_block_cipher; - secure_vector<byte> m_block_cipher_cbc_state; - std::unique_ptr<StreamCipher> m_stream_cipher; - std::unique_ptr<MessageAuthenticationCode> m_mac; - - std::unique_ptr<AEAD_Mode> m_aead; - secure_vector<byte> m_nonce, m_ad; - - size_t m_block_size = 0; - size_t m_iv_size = 0; - bool m_is_ssl3 = false; - }; - -/** -* Create a TLS record -* @param write_buffer the output record is placed here -* @param msg_type is the type of the message (handshake, alert, ...) -* @param msg is the plaintext message -* @param msg_length is the length of msg -* @param msg_sequence is the sequence number -* @param version is the protocol version -* @param cipherstate is the writing cipher state -* @param rng is a random number generator -* @return number of bytes written to write_buffer -*/ -void write_record(secure_vector<byte>& write_buffer, - byte msg_type, const byte msg[], size_t msg_length, - Protocol_Version version, - u64bit msg_sequence, - Connection_Cipher_State* cipherstate, - RandomNumberGenerator& rng); - -/** -* Decode a TLS record -* @return zero if full message, else number of bytes still needed -*/ -size_t read_record(secure_vector<byte>& read_buffer, - const byte input[], - size_t input_length, - size_t& input_consumed, - secure_vector<byte>& record, - u64bit* record_sequence, - Protocol_Version* record_version, - Record_Type* record_type, - Connection_Sequence_Numbers* sequence_numbers, - std::function<Connection_Cipher_State* (u16bit)> get_cipherstate); - -} - -} - -#endif diff --git a/src/tls/tls_seq_numbers.h b/src/tls/tls_seq_numbers.h deleted file mode 100644 index 87edf3130..000000000 --- a/src/tls/tls_seq_numbers.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -* TLS Sequence Number Handling -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_SEQ_NUMBERS_H__ -#define BOTAN_TLS_SEQ_NUMBERS_H__ - -#include <botan/types.h> -#include <stdexcept> - -namespace Botan { - -namespace TLS { - -class Connection_Sequence_Numbers - { - public: - virtual void new_read_cipher_state() = 0; - virtual void new_write_cipher_state() = 0; - - virtual u16bit current_read_epoch() const = 0; - virtual u16bit current_write_epoch() const = 0; - - virtual u64bit next_write_sequence() = 0; - virtual u64bit next_read_sequence() = 0; - - virtual bool already_seen(u64bit seq) const = 0; - virtual void read_accept(u64bit seq) = 0; - }; - -class Stream_Sequence_Numbers : public Connection_Sequence_Numbers - { - public: - void new_read_cipher_state() override { m_read_seq_no = 0; m_read_epoch += 1; } - void new_write_cipher_state() override { m_write_seq_no = 0; m_write_epoch += 1; } - - u16bit current_read_epoch() const override { return m_read_epoch; } - u16bit current_write_epoch() const override { return m_write_epoch; } - - u64bit next_write_sequence() override { return m_write_seq_no++; } - u64bit next_read_sequence() override { return m_read_seq_no; } - - bool already_seen(u64bit) const override { return false; } - void read_accept(u64bit) override { m_read_seq_no++; } - private: - u64bit m_write_seq_no = 0; - u64bit m_read_seq_no = 0; - u16bit m_read_epoch = 0; - u16bit m_write_epoch = 0; - }; - -class Datagram_Sequence_Numbers : public Connection_Sequence_Numbers - { - public: - void new_read_cipher_state() override { m_read_epoch += 1; } - - void new_write_cipher_state() override - { - // increment epoch - m_write_seq_no = ((m_write_seq_no >> 48) + 1) << 48; - } - - u16bit current_read_epoch() const override { return m_read_epoch; } - u16bit current_write_epoch() const override { return (m_write_seq_no >> 48); } - - u64bit next_write_sequence() override { return m_write_seq_no++; } - - u64bit next_read_sequence() override - { - throw std::runtime_error("DTLS uses explicit sequence numbers"); - } - - bool already_seen(u64bit sequence) const override - { - const size_t window_size = sizeof(m_window_bits) * 8; - - if(sequence > m_window_highest) - return false; - - const u64bit offset = m_window_highest - sequence; - - if(offset >= window_size) - return true; // really old? - - return (((m_window_bits >> offset) & 1) == 1); - } - - void read_accept(u64bit sequence) override - { - const size_t window_size = sizeof(m_window_bits) * 8; - - if(sequence > m_window_highest) - { - const size_t offset = sequence - m_window_highest; - m_window_highest += offset; - - if(offset >= window_size) - m_window_bits = 0; - else - m_window_bits <<= offset; - - m_window_bits |= 0x01; - } - else - { - const u64bit offset = m_window_highest - sequence; - m_window_bits |= (static_cast<u64bit>(1) << offset); - } - } - - private: - u64bit m_write_seq_no = 0; - u16bit m_read_epoch = 0; - u64bit m_window_highest = 0; - u64bit m_window_bits = 0; - }; - -} - -} - -#endif diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp deleted file mode 100644 index bc518571b..000000000 --- a/src/tls/tls_server.cpp +++ /dev/null @@ -1,725 +0,0 @@ -/* -* TLS Server -* (C) 2004-2011,2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/tls_server.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 Server_Handshake_State : public Handshake_State - { - public: - // using Handshake_State::Handshake_State; - - Server_Handshake_State(Handshake_IO* io) : Handshake_State(io) {} - - // Used by the server only, in case of RSA key exchange. Not owned - Private_Key* server_rsa_kex_key = nullptr; - - /* - * Used by the server to know if resumption should be allowed on - * a server-initiated renegotiation - */ - bool allow_session_resumption = true; - }; - -bool check_for_resume(Session& session_info, - Session_Manager& session_manager, - Credentials_Manager& credentials, - const Client_Hello* client_hello, - std::chrono::seconds session_ticket_lifetime) - { - const std::vector<byte>& client_session_id = client_hello->session_id(); - const std::vector<byte>& session_ticket = client_hello->session_ticket(); - - if(session_ticket.empty()) - { - if(client_session_id.empty()) // not resuming - return false; - - // not found - if(!session_manager.load_from_session_id(client_session_id, session_info)) - return false; - } - else - { - // If a session ticket was sent, ignore client session ID - try - { - session_info = Session::decrypt( - session_ticket, - credentials.psk("tls-server", "session-ticket", "")); - - if(session_ticket_lifetime != std::chrono::seconds(0) && - session_info.session_age() > session_ticket_lifetime) - return false; // ticket has expired - } - catch(...) - { - return false; - } - } - - // wrong version - if(client_hello->version() != session_info.version()) - return false; - - // client didn't send original ciphersuite - if(!value_exists(client_hello->ciphersuites(), - session_info.ciphersuite_code())) - return false; - - // client didn't send original compression method - if(!value_exists(client_hello->compression_methods(), - session_info.compression_method())) - return false; - - // client sent a different SRP identity - if(client_hello->srp_identifier() != "") - { - if(client_hello->srp_identifier() != session_info.srp_identifier()) - return false; - } - - // client sent a different SNI hostname - if(client_hello->sni_hostname() != "") - { - if(client_hello->sni_hostname() != session_info.server_info().hostname()) - return false; - } - - return true; - } - -/* -* Choose which ciphersuite to use -*/ -u16bit choose_ciphersuite( - const Policy& policy, - Protocol_Version version, - Credentials_Manager& creds, - const std::map<std::string, std::vector<X509_Certificate> >& cert_chains, - const Client_Hello* client_hello) - { - const bool our_choice = policy.server_uses_own_ciphersuite_preferences(); - - const bool have_srp = creds.attempt_srp("tls-server", - client_hello->sni_hostname()); - - const std::vector<u16bit> client_suites = client_hello->ciphersuites(); - - const std::vector<u16bit> server_suites = policy.ciphersuite_list(version, have_srp); - - if(server_suites.empty()) - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Policy forbids us from negotiating any ciphersuite"); - - const bool have_shared_ecc_curve = - (policy.choose_curve(client_hello->supported_ecc_curves()) != ""); - - std::vector<u16bit> pref_list = server_suites; - std::vector<u16bit> other_list = client_suites; - - if(!our_choice) - std::swap(pref_list, other_list); - - for(auto suite_id : pref_list) - { - if(!value_exists(other_list, suite_id)) - continue; - - Ciphersuite suite = Ciphersuite::by_id(suite_id); - - if(!have_shared_ecc_curve && suite.ecc_ciphersuite()) - continue; - - if(suite.sig_algo() != "" && cert_chains.count(suite.sig_algo()) == 0) - continue; - - /* - The client may offer SRP cipher suites in the hello message but - omit the SRP extension. If the server would like to select an - SRP cipher suite in this case, the server SHOULD return a fatal - "unknown_psk_identity" alert immediately after processing the - client hello message. - - RFC 5054 section 2.5.1.2 - */ - if(suite.kex_algo() == "SRP_SHA" && client_hello->srp_identifier() == "") - throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, - "Client wanted SRP but did not send username"); - - return suite_id; - } - - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Can't agree on a ciphersuite with client"); - } - - -/* -* Choose which compression algorithm to use -*/ -byte choose_compression(const Policy& policy, - const std::vector<byte>& c_comp) - { - std::vector<byte> s_comp = policy.compression(); - - for(size_t i = 0; i != s_comp.size(); ++i) - for(size_t j = 0; j != c_comp.size(); ++j) - if(s_comp[i] == c_comp[j]) - return s_comp[i]; - - return NO_COMPRESSION; - } - -std::map<std::string, std::vector<X509_Certificate> > -get_server_certs(const std::string& hostname, - Credentials_Manager& creds) - { - const char* cert_types[] = { "RSA", "DSA", "ECDSA", nullptr }; - - std::map<std::string, std::vector<X509_Certificate> > cert_chains; - - for(size_t i = 0; cert_types[i]; ++i) - { - std::vector<X509_Certificate> certs = - creds.cert_chain_single_type(cert_types[i], "tls-server", hostname); - - if(!certs.empty()) - cert_chains[cert_types[i]] = certs; - } - - return cert_chains; - } - -} - -/* -* TLS Server Constructor -*/ -Server::Server(std::function<void (const byte[], size_t)> output_fn, - std::function<void (const byte[], size_t)> data_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 std::vector<std::string>& next_protocols, - size_t io_buf_sz) : - Channel(output_fn, data_cb, alert_cb, handshake_cb, session_manager, rng, io_buf_sz), - m_policy(policy), - m_creds(creds), - m_possible_protocols(next_protocols) - { - } - -Handshake_State* Server::new_handshake_state(Handshake_IO* io) - { - std::unique_ptr<Handshake_State> state(new Server_Handshake_State(io)); - state->set_expected_next(CLIENT_HELLO); - return state.release(); - } - -std::vector<X509_Certificate> -Server::get_peer_cert_chain(const Handshake_State& state) const - { - if(state.client_certs()) - return state.client_certs()->cert_chain(); - return std::vector<X509_Certificate>(); - } - -/* -* Send a hello request to the client -*/ -void Server::initiate_handshake(Handshake_State& state, - bool force_full_renegotiation) - { - dynamic_cast<Server_Handshake_State&>(state).allow_session_resumption = - !force_full_renegotiation; - - Hello_Request hello_req(state.handshake_io()); - } - -/* -* Process a handshake message -*/ -void Server::process_handshake_msg(const Handshake_State* active_state, - Handshake_State& state_base, - Handshake_Type type, - const std::vector<byte>& contents) - { - Server_Handshake_State& state = dynamic_cast<Server_Handshake_State&>(state_base); - - state.confirm_transition_to(type); - - /* - * The change cipher spec message isn't technically a handshake - * message so it's not included in the hash. The finished and - * certificate verify messages are verified based on the current - * state of the hash *before* this message so we delay adding them - * to the hash computation until we've processed them below. - */ - if(type != HANDSHAKE_CCS && type != FINISHED && type != CERTIFICATE_VERIFY) - { - if(type == CLIENT_HELLO_SSLV2) - state.hash().update(contents); - else - state.hash().update(state.handshake_io().format(contents, type)); - } - - if(type == CLIENT_HELLO || type == CLIENT_HELLO_SSLV2) - { - const bool initial_handshake = !active_state; - - if(!m_policy.allow_insecure_renegotiation() && - !(initial_handshake || secure_renegotiation_supported())) - { - send_warning_alert(Alert::NO_RENEGOTIATION); - return; - } - - state.client_hello(new Client_Hello(contents, type)); - - Protocol_Version client_version = state.client_hello()->version(); - - Protocol_Version negotiated_version; - - if((initial_handshake && client_version.known_version()) || - (!initial_handshake && client_version == active_state->version())) - { - /* - Common cases: new client hello with some known version, or a - renegotiation using the same version as previously - negotiated. - */ - - negotiated_version = client_version; - } - else if(!initial_handshake && (client_version != active_state->version())) - { - /* - * If this is a renegotiation, and the client has offered a - * later version than what it initially negotiated, negotiate - * the old version. This matches OpenSSL's behavior. If the - * client is offering a version earlier than what it initially - * negotiated, reject as a probable attack. - */ - if(active_state->version() > client_version) - { - throw TLS_Exception(Alert::PROTOCOL_VERSION, - "Client negotiated " + - active_state->version().to_string() + - " then renegotiated with " + - client_version.to_string()); - } - else - negotiated_version = active_state->version(); - } - else - { - /* - New negotiation using a version we don't know. Offer - them the best we currently know. - */ - negotiated_version = client_version.best_known_match(); - } - - if(!m_policy.acceptable_protocol_version(negotiated_version)) - { - throw TLS_Exception(Alert::PROTOCOL_VERSION, - "Client version is unacceptable by policy"); - } - - if(!initial_handshake && state.client_hello()->next_protocol_notification()) - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Client included NPN extension for renegotiation"); - - secure_renegotiation_check(state.client_hello()); - - state.set_version(negotiated_version); - - Session session_info; - const bool resuming = - state.allow_session_resumption && - check_for_resume(session_info, - session_manager(), - m_creds, - state.client_hello(), - std::chrono::seconds(m_policy.session_ticket_lifetime())); - - bool have_session_ticket_key = false; - - try - { - have_session_ticket_key = - m_creds.psk("tls-server", "session-ticket", "").length() > 0; - } - catch(...) {} - - if(resuming) - { - // resume session - - const bool offer_new_session_ticket = - (state.client_hello()->supports_session_ticket() && - state.client_hello()->session_ticket().empty() && - have_session_ticket_key); - - state.server_hello( - new Server_Hello( - state.handshake_io(), - state.hash(), - m_policy, - state.client_hello()->session_id(), - Protocol_Version(session_info.version()), - session_info.ciphersuite_code(), - session_info.compression_method(), - session_info.fragment_size(), - state.client_hello()->secure_renegotiation(), - secure_renegotiation_data_for_server_hello(), - offer_new_session_ticket, - state.client_hello()->next_protocol_notification(), - m_possible_protocols, - state.client_hello()->supports_heartbeats(), - rng()) - ); - - secure_renegotiation_check(state.server_hello()); - - state.compute_session_keys(session_info.master_secret()); - - if(!save_session(session_info)) - { - session_manager().remove_entry(session_info.session_id()); - - if(state.server_hello()->supports_session_ticket()) // send an empty ticket - { - state.new_session_ticket( - new New_Session_Ticket(state.handshake_io(), - state.hash()) - ); - } - } - - if(state.server_hello()->supports_session_ticket() && !state.new_session_ticket()) - { - try - { - const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); - - state.new_session_ticket( - new New_Session_Ticket(state.handshake_io(), - state.hash(), - session_info.encrypt(ticket_key, rng()), - m_policy.session_ticket_lifetime()) - ); - } - catch(...) {} - - if(!state.new_session_ticket()) - { - state.new_session_ticket( - new New_Session_Ticket(state.handshake_io(), state.hash()) - ); - } - } - - state.handshake_io().send(Change_Cipher_Spec()); - - change_cipher_spec_writer(SERVER); - - state.server_finished( - new Finished(state.handshake_io(), state, SERVER) - ); - - state.set_expected_next(HANDSHAKE_CCS); - } - else // new session - { - std::map<std::string, std::vector<X509_Certificate> > cert_chains; - - const std::string sni_hostname = state.client_hello()->sni_hostname(); - - cert_chains = get_server_certs(sni_hostname, m_creds); - - if(sni_hostname != "" && cert_chains.empty()) - { - cert_chains = get_server_certs("", m_creds); - - /* - * Only send the unrecognized_name alert if we couldn't - * find any certs for the requested name but did find at - * least one cert to use in general. That avoids sending an - * unrecognized_name when a server is configured for purely - * anonymous operation. - */ - if(!cert_chains.empty()) - send_alert(Alert(Alert::UNRECOGNIZED_NAME)); - } - - state.server_hello( - new Server_Hello( - state.handshake_io(), - state.hash(), - m_policy, - make_hello_random(rng()), // new session ID - state.version(), - choose_ciphersuite(m_policy, - state.version(), - m_creds, - cert_chains, - state.client_hello()), - choose_compression(m_policy, state.client_hello()->compression_methods()), - state.client_hello()->fragment_size(), - state.client_hello()->secure_renegotiation(), - secure_renegotiation_data_for_server_hello(), - state.client_hello()->supports_session_ticket() && have_session_ticket_key, - state.client_hello()->next_protocol_notification(), - m_possible_protocols, - state.client_hello()->supports_heartbeats(), - rng()) - ); - - secure_renegotiation_check(state.server_hello()); - - const std::string sig_algo = state.ciphersuite().sig_algo(); - const std::string kex_algo = state.ciphersuite().kex_algo(); - - if(sig_algo != "") - { - BOTAN_ASSERT(!cert_chains[sig_algo].empty(), - "Attempting to send empty certificate chain"); - - state.server_certs( - new Certificate(state.handshake_io(), - state.hash(), - cert_chains[sig_algo]) - ); - } - - Private_Key* private_key = nullptr; - - if(kex_algo == "RSA" || sig_algo != "") - { - private_key = m_creds.private_key_for( - state.server_certs()->cert_chain()[0], - "tls-server", - sni_hostname); - - if(!private_key) - throw Internal_Error("No private key located for associated server cert"); - } - - if(kex_algo == "RSA") - { - state.server_rsa_kex_key = private_key; - } - else - { - state.server_kex( - new Server_Key_Exchange(state.handshake_io(), - state, - m_policy, - m_creds, - rng(), - private_key) - ); - } - - auto trusted_CAs = - m_creds.trusted_certificate_authorities("tls-server", sni_hostname); - - std::vector<X509_DN> client_auth_CAs; - - for(auto store : trusted_CAs) - { - auto subjects = store->all_subjects(); - client_auth_CAs.insert(client_auth_CAs.end(), - subjects.begin(), - subjects.end()); - } - - if(!client_auth_CAs.empty() && state.ciphersuite().sig_algo() != "") - { - state.cert_req( - new Certificate_Req(state.handshake_io(), - state.hash(), - m_policy, - client_auth_CAs, - state.version()) - ); - - state.set_expected_next(CERTIFICATE); - } - - /* - * If the client doesn't have a cert they want to use they are - * allowed to send either an empty cert message or proceed - * directly to the client key exchange, so allow either case. - */ - state.set_expected_next(CLIENT_KEX); - - state.server_hello_done( - new Server_Hello_Done(state.handshake_io(), state.hash()) - ); - } - } - else if(type == CERTIFICATE) - { - state.client_certs(new Certificate(contents)); - - state.set_expected_next(CLIENT_KEX); - } - else if(type == CLIENT_KEX) - { - if(state.received_handshake_msg(CERTIFICATE) && !state.client_certs()->empty()) - state.set_expected_next(CERTIFICATE_VERIFY); - else - state.set_expected_next(HANDSHAKE_CCS); - - state.client_kex( - new Client_Key_Exchange(contents, state, - state.server_rsa_kex_key, - m_creds, m_policy, rng()) - ); - - state.compute_session_keys(); - } - else if(type == CERTIFICATE_VERIFY) - { - state.client_verify(new Certificate_Verify(contents, state.version())); - - const std::vector<X509_Certificate>& client_certs = - state.client_certs()->cert_chain(); - - const bool sig_valid = - state.client_verify()->verify(client_certs[0], state); - - state.hash().update(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 - { - m_creds.verify_certificate_chain("tls-server", "", client_certs); - } - catch(std::exception& e) - { - throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what()); - } - - state.set_expected_next(HANDSHAKE_CCS); - } - else if(type == HANDSHAKE_CCS) - { - if(state.server_hello()->next_protocol_notification()) - state.set_expected_next(NEXT_PROTOCOL); - else - state.set_expected_next(FINISHED); - - change_cipher_spec_reader(SERVER); - } - else if(type == NEXT_PROTOCOL) - { - state.set_expected_next(FINISHED); - - state.next_protocol(new Next_Protocol(contents)); - - // should this be a callback? - m_next_protocol = state.next_protocol()->protocol(); - } - else if(type == FINISHED) - { - state.set_expected_next(HANDSHAKE_NONE); - - state.client_finished(new Finished(contents)); - - if(!state.client_finished()->verify(state, CLIENT)) - throw TLS_Exception(Alert::DECRYPT_ERROR, - "Finished message didn't verify"); - - if(!state.server_finished()) - { - // already sent finished if resuming, so this is a new session - - state.hash().update(state.handshake_io().format(contents, type)); - - Session session_info( - state.server_hello()->session_id(), - state.session_keys().master_secret(), - state.server_hello()->version(), - state.server_hello()->ciphersuite(), - state.server_hello()->compression_method(), - SERVER, - state.server_hello()->fragment_size(), - get_peer_cert_chain(state), - std::vector<byte>(), - Server_Information(state.client_hello()->sni_hostname()), - state.srp_identifier() - ); - - if(save_session(session_info)) - { - if(state.server_hello()->supports_session_ticket()) - { - try - { - const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); - - state.new_session_ticket( - new New_Session_Ticket(state.handshake_io(), - state.hash(), - session_info.encrypt(ticket_key, rng()), - m_policy.session_ticket_lifetime()) - ); - } - catch(...) {} - } - else - session_manager().save(session_info); - } - - if(!state.new_session_ticket() && - state.server_hello()->supports_session_ticket()) - { - state.new_session_ticket( - new New_Session_Ticket(state.handshake_io(), state.hash()) - ); - } - - state.handshake_io().send(Change_Cipher_Spec()); - - change_cipher_spec_writer(SERVER); - - state.server_finished( - new Finished(state.handshake_io(), state, SERVER) - ); - } - - activate_session(); - } - else - throw Unexpected_Message("Unknown handshake message received"); - } - -} - -} diff --git a/src/tls/tls_server.h b/src/tls/tls_server.h deleted file mode 100644 index a514607ba..000000000 --- a/src/tls/tls_server.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -* TLS Server -* (C) 2004-2011 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_SERVER_H__ -#define BOTAN_TLS_SERVER_H__ - -#include <botan/tls_channel.h> -#include <botan/credentials_manager.h> -#include <vector> - -namespace Botan { - -namespace TLS { - -/** -* TLS Server -*/ -class BOTAN_DLL Server : public Channel - { - public: - /** - * Server initialization - */ - Server(std::function<void (const byte[], size_t)> socket_output_fn, - std::function<void (const byte[], size_t)> data_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 std::vector<std::string>& protocols = std::vector<std::string>(), - size_t reserved_io_buffer_size = 16*1024 - ); - - /** - * Return the protocol notification set by the client (using the - * NPN extension) for this connection, if any - */ - std::string next_protocol() const { return m_next_protocol; } - - private: - std::vector<X509_Certificate> - get_peer_cert_chain(const Handshake_State& state) const override; - - void initiate_handshake(Handshake_State& state, - bool force_full_renegotiation) override; - - void process_handshake_msg(const Handshake_State* active_state, - Handshake_State& pending_state, - Handshake_Type type, - const std::vector<byte>& contents) override; - - Handshake_State* new_handshake_state(Handshake_IO* io) override; - - const Policy& m_policy; - Credentials_Manager& m_creds; - - std::vector<std::string> m_possible_protocols; - std::string m_next_protocol; - }; - -} - -} - -#endif diff --git a/src/tls/tls_server_info.h b/src/tls/tls_server_info.h deleted file mode 100644 index 773296eaf..000000000 --- a/src/tls/tls_server_info.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -* TLS Server Information -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_SERVER_INFO_H__ -#define BOTAN_TLS_SERVER_INFO_H__ - -#include <botan/types.h> -#include <string> - -namespace Botan { - -namespace TLS { - -/** -* Represents information known about a TLS server. -*/ -class BOTAN_DLL Server_Information - { - public: - /** - * An empty server info - nothing known - */ - Server_Information() : m_hostname(""), m_service(""), m_port(0) {} - - /** - * @param hostname the host's DNS name, if known - * @param port specifies the protocol port of the server (eg for - * TCP/UDP). Zero represents unknown. - */ - Server_Information(const std::string& hostname, - u16bit port = 0) : - m_hostname(hostname), m_service(""), m_port(port) {} - - /** - * @param hostname the host's DNS name, if known - * @param service is a text string of the service type - * (eg "https", "tor", or "git") - * @param port specifies the protocol port of the server (eg for - * TCP/UDP). Zero represents unknown. - */ - Server_Information(const std::string& hostname, - const std::string& service, - u16bit port = 0) : - m_hostname(hostname), m_service(service), m_port(port) {} - - std::string hostname() const { return m_hostname; } - - std::string service() const { return m_service; } - - u16bit port() const { return m_port; } - - bool empty() const { return m_hostname.empty(); } - - private: - std::string m_hostname, m_service; - u16bit m_port; - }; - -inline bool operator==(const Server_Information& a, const Server_Information& b) - { - return (a.hostname() == b.hostname()) && - (a.service() == b.service()) && - (a.port() == b.port()); - - } - -inline bool operator!=(const Server_Information& a, const Server_Information& b) - { - return !(a == b); - } - -inline bool operator<(const Server_Information& a, const Server_Information& b) - { - if(a.hostname() != b.hostname()) - return (a.hostname() < b.hostname()); - if(a.service() != b.service()) - return (a.service() < b.service()); - if(a.port() != b.port()) - return (a.port() < b.port()); - return false; // equal - } - -} - -} - -#endif diff --git a/src/tls/tls_session.cpp b/src/tls/tls_session.cpp deleted file mode 100644 index 6596804b5..000000000 --- a/src/tls/tls_session.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* -* TLS Session State -* (C) 2011-2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/tls_session.h> -#include <botan/der_enc.h> -#include <botan/ber_dec.h> -#include <botan/asn1_str.h> -#include <botan/pem.h> -#include <botan/cryptobox_psk.h> -#include <memory> - -namespace Botan { - -namespace TLS { - -Session::Session(const std::vector<byte>& session_identifier, - const secure_vector<byte>& master_secret, - Protocol_Version version, - u16bit ciphersuite, - byte compression_method, - Connection_Side side, - size_t fragment_size, - const std::vector<X509_Certificate>& certs, - const std::vector<byte>& ticket, - const Server_Information& server_info, - const std::string& srp_identifier) : - m_start_time(std::chrono::system_clock::now()), - m_identifier(session_identifier), - m_session_ticket(ticket), - m_master_secret(master_secret), - m_version(version), - m_ciphersuite(ciphersuite), - m_compression_method(compression_method), - m_connection_side(side), - m_fragment_size(fragment_size), - m_peer_certs(certs), - m_server_info(server_info), - m_srp_identifier(srp_identifier) - { - } - -Session::Session(const std::string& pem) - { - secure_vector<byte> der = PEM_Code::decode_check_label(pem, "SSL SESSION"); - - *this = Session(&der[0], der.size()); - } - -Session::Session(const byte ber[], size_t ber_len) - { - byte side_code = 0; - - ASN1_String server_hostname; - ASN1_String server_service; - size_t server_port; - - ASN1_String srp_identifier_str; - - byte major_version = 0, minor_version = 0; - - std::vector<byte> peer_cert_bits; - - size_t start_time = 0; - - BER_Decoder(ber, ber_len) - .start_cons(SEQUENCE) - .decode_and_check(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION), - "Unknown version in session structure") - .decode_integer_type(start_time) - .decode_integer_type(major_version) - .decode_integer_type(minor_version) - .decode(m_identifier, OCTET_STRING) - .decode(m_session_ticket, OCTET_STRING) - .decode_integer_type(m_ciphersuite) - .decode_integer_type(m_compression_method) - .decode_integer_type(side_code) - .decode_integer_type(m_fragment_size) - .decode(m_master_secret, OCTET_STRING) - .decode(peer_cert_bits, OCTET_STRING) - .decode(server_hostname) - .decode(server_service) - .decode(server_port) - .decode(srp_identifier_str) - .end_cons() - .verify_end(); - - m_version = Protocol_Version(major_version, minor_version); - m_start_time = std::chrono::system_clock::from_time_t(start_time); - m_connection_side = static_cast<Connection_Side>(side_code); - - m_server_info = Server_Information(server_hostname.value(), - server_service.value(), - server_port); - - m_srp_identifier = srp_identifier_str.value(); - - if(!peer_cert_bits.empty()) - { - DataSource_Memory certs(&peer_cert_bits[0], peer_cert_bits.size()); - - while(!certs.end_of_data()) - m_peer_certs.push_back(X509_Certificate(certs)); - } - } - -secure_vector<byte> Session::DER_encode() const - { - std::vector<byte> peer_cert_bits; - for(size_t i = 0; i != m_peer_certs.size(); ++i) - peer_cert_bits += m_peer_certs[i].BER_encode(); - - return DER_Encoder() - .start_cons(SEQUENCE) - .encode(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION)) - .encode(static_cast<size_t>(std::chrono::system_clock::to_time_t(m_start_time))) - .encode(static_cast<size_t>(m_version.major_version())) - .encode(static_cast<size_t>(m_version.minor_version())) - .encode(m_identifier, OCTET_STRING) - .encode(m_session_ticket, OCTET_STRING) - .encode(static_cast<size_t>(m_ciphersuite)) - .encode(static_cast<size_t>(m_compression_method)) - .encode(static_cast<size_t>(m_connection_side)) - .encode(static_cast<size_t>(m_fragment_size)) - .encode(m_master_secret, OCTET_STRING) - .encode(peer_cert_bits, OCTET_STRING) - .encode(ASN1_String(m_server_info.hostname(), UTF8_STRING)) - .encode(ASN1_String(m_server_info.service(), UTF8_STRING)) - .encode(static_cast<size_t>(m_server_info.port())) - .encode(ASN1_String(m_srp_identifier, UTF8_STRING)) - .end_cons() - .get_contents(); - } - -std::string Session::PEM_encode() const - { - return PEM_Code::encode(this->DER_encode(), "SSL SESSION"); - } - -std::chrono::seconds Session::session_age() const - { - return std::chrono::duration_cast<std::chrono::seconds>( - std::chrono::system_clock::now() - m_start_time); - } - -std::vector<byte> -Session::encrypt(const SymmetricKey& master_key, - RandomNumberGenerator& rng) const - { - const auto der = this->DER_encode(); - - return CryptoBox::encrypt(&der[0], der.size(), master_key, rng); - } - -Session Session::decrypt(const byte buf[], size_t buf_len, - const SymmetricKey& master_key) - { - try - { - const auto ber = CryptoBox::decrypt(buf, buf_len, master_key); - - return Session(&ber[0], ber.size()); - } - catch(std::exception& e) - { - throw Decoding_Error("Failed to decrypt encrypted session -" + - std::string(e.what())); - } - } - -} - -} - diff --git a/src/tls/tls_session.h b/src/tls/tls_session.h deleted file mode 100644 index 65154dfce..000000000 --- a/src/tls/tls_session.h +++ /dev/null @@ -1,206 +0,0 @@ -/* -* TLS Session -* (C) 2011-2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_SESSION_STATE_H__ -#define BOTAN_TLS_SESSION_STATE_H__ - -#include <botan/x509cert.h> -#include <botan/tls_version.h> -#include <botan/tls_ciphersuite.h> -#include <botan/tls_magic.h> -#include <botan/tls_server_info.h> -#include <botan/secmem.h> -#include <botan/symkey.h> -#include <chrono> - -namespace Botan { - -namespace TLS { - -/** -* Class representing a TLS session state -*/ -class BOTAN_DLL Session - { - public: - - /** - * Uninitialized session - */ - Session() : - m_start_time(std::chrono::system_clock::time_point::min()), - m_version(), - m_ciphersuite(0), - m_compression_method(0), - m_connection_side(static_cast<Connection_Side>(0)), - m_fragment_size(0) - {} - - /** - * New session (sets session start time) - */ - Session(const std::vector<byte>& session_id, - const secure_vector<byte>& master_secret, - Protocol_Version version, - u16bit ciphersuite, - byte compression_method, - Connection_Side side, - size_t fragment_size, - const std::vector<X509_Certificate>& peer_certs, - const std::vector<byte>& session_ticket, - const Server_Information& server_info, - const std::string& srp_identifier); - - /** - * Load a session from DER representation (created by DER_encode) - */ - Session(const byte ber[], size_t ber_len); - - /** - * Load a session from PEM representation (created by PEM_encode) - */ - Session(const std::string& pem); - - /** - * Encode this session data for storage - * @warning if the master secret is compromised so is the - * session traffic - */ - secure_vector<byte> DER_encode() const; - - /** - * Encrypt a session (useful for serialization or session tickets) - */ - std::vector<byte> encrypt(const SymmetricKey& key, - RandomNumberGenerator& rng) const; - - - /** - * Decrypt a session created by encrypt - * @param ctext the ciphertext returned by encrypt - * @param ctext_size the size of ctext in bytes - * @param key the same key used by the encrypting side - */ - static Session decrypt(const byte ctext[], - size_t ctext_size, - const SymmetricKey& key); - - /** - * Decrypt a session created by encrypt - * @param ctext the ciphertext returned by encrypt - * @param key the same key used by the encrypting side - */ - static inline Session decrypt(const std::vector<byte>& ctext, - const SymmetricKey& key) - { - return Session::decrypt(&ctext[0], ctext.size(), key); - } - - /** - * Encode this session data for storage - * @warning if the master secret is compromised so is the - * session traffic - */ - std::string PEM_encode() const; - - /** - * Get the version of the saved session - */ - Protocol_Version version() const { return m_version; } - - /** - * Get the ciphersuite code of the saved session - */ - u16bit ciphersuite_code() const { return m_ciphersuite; } - - /** - * Get the ciphersuite info of the saved session - */ - Ciphersuite ciphersuite() const { return Ciphersuite::by_id(m_ciphersuite); } - - /** - * Get the compression method used in the saved session - */ - byte compression_method() const { return m_compression_method; } - - /** - * Get which side of the connection the resumed session we are/were - * acting as. - */ - Connection_Side side() const { return m_connection_side; } - - /** - * Get the SRP identity (if sent by the client in the initial handshake) - */ - std::string srp_identifier() const { return m_srp_identifier; } - - /** - * Get the saved master secret - */ - const secure_vector<byte>& master_secret() const - { return m_master_secret; } - - /** - * Get the session identifier - */ - const std::vector<byte>& session_id() const - { return m_identifier; } - - /** - * Get the negotiated maximum fragment size (or 0 if default) - */ - size_t fragment_size() const { return m_fragment_size; } - - /** - * Return the certificate chain of the peer (possibly empty) - */ - std::vector<X509_Certificate> peer_certs() const { return m_peer_certs; } - - /** - * Get the wall clock time this session began - */ - std::chrono::system_clock::time_point start_time() const - { return m_start_time; } - - /** - * Return how long this session has existed (in seconds) - */ - std::chrono::seconds session_age() const; - - /** - * Return the session ticket the server gave us - */ - const std::vector<byte>& session_ticket() const { return m_session_ticket; } - - Server_Information server_info() const { return m_server_info; } - - private: - enum { TLS_SESSION_PARAM_STRUCT_VERSION = 0x2994e301 }; - - std::chrono::system_clock::time_point m_start_time; - - std::vector<byte> m_identifier; - std::vector<byte> m_session_ticket; // only used by client side - secure_vector<byte> m_master_secret; - - Protocol_Version m_version; - u16bit m_ciphersuite; - byte m_compression_method; - Connection_Side m_connection_side; - - size_t m_fragment_size; - - std::vector<X509_Certificate> m_peer_certs; - Server_Information m_server_info; // optional - std::string m_srp_identifier; // optional - }; - -} - -} - -#endif diff --git a/src/tls/tls_session_key.cpp b/src/tls/tls_session_key.cpp deleted file mode 100644 index 06cd1d0a1..000000000 --- a/src/tls/tls_session_key.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* -* TLS Session Key -* (C) 2004-2006,2011 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/internal/tls_session_key.h> -#include <botan/internal/tls_handshake_state.h> -#include <botan/internal/tls_messages.h> -#include <botan/lookup.h> -#include <memory> - -namespace Botan { - -namespace TLS { - -/** -* Session_Keys Constructor -*/ -Session_Keys::Session_Keys(const Handshake_State* state, - const secure_vector<byte>& pre_master_secret, - bool resuming) - { - const size_t cipher_keylen = state->ciphersuite().cipher_keylen(); - const size_t mac_keylen = state->ciphersuite().mac_keylen(); - const size_t cipher_ivlen = state->ciphersuite().cipher_ivlen(); - - const size_t prf_gen = 2 * (mac_keylen + cipher_keylen + cipher_ivlen); - - const byte MASTER_SECRET_MAGIC[] = { - 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74 }; - - const byte KEY_GEN_MAGIC[] = { - 0x6B, 0x65, 0x79, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6E, 0x73, 0x69, 0x6F, 0x6E }; - - std::unique_ptr<KDF> prf(state->protocol_specific_prf()); - - if(resuming) - { - master_sec = pre_master_secret; - } - else - { - secure_vector<byte> salt; - - if(state->version() != Protocol_Version::SSL_V3) - salt += std::make_pair(MASTER_SECRET_MAGIC, sizeof(MASTER_SECRET_MAGIC)); - - salt += state->client_hello()->random(); - salt += state->server_hello()->random(); - - master_sec = prf->derive_key(48, pre_master_secret, salt); - } - - secure_vector<byte> salt; - if(state->version() != Protocol_Version::SSL_V3) - salt += std::make_pair(KEY_GEN_MAGIC, sizeof(KEY_GEN_MAGIC)); - salt += state->server_hello()->random(); - salt += state->client_hello()->random(); - - SymmetricKey keyblock = prf->derive_key(prf_gen, master_sec, salt); - - const byte* key_data = keyblock.begin(); - - c_mac = SymmetricKey(key_data, mac_keylen); - key_data += mac_keylen; - - s_mac = SymmetricKey(key_data, mac_keylen); - key_data += mac_keylen; - - c_cipher = SymmetricKey(key_data, cipher_keylen); - key_data += cipher_keylen; - - s_cipher = SymmetricKey(key_data, cipher_keylen); - key_data += cipher_keylen; - - c_iv = InitializationVector(key_data, cipher_ivlen); - key_data += cipher_ivlen; - - s_iv = InitializationVector(key_data, cipher_ivlen); - } - -} - -} diff --git a/src/tls/tls_session_key.h b/src/tls/tls_session_key.h deleted file mode 100644 index d62e3400d..000000000 --- a/src/tls/tls_session_key.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -* TLS Session Key -* (C) 2004-2006,2011 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_SESSION_KEYS_H__ -#define BOTAN_TLS_SESSION_KEYS_H__ - -#include <botan/symkey.h> - -namespace Botan { - -namespace TLS { - -/** -* TLS Session Keys -*/ -class Session_Keys - { - public: - SymmetricKey client_cipher_key() const { return c_cipher; } - SymmetricKey server_cipher_key() const { return s_cipher; } - - SymmetricKey client_mac_key() const { return c_mac; } - SymmetricKey server_mac_key() const { return s_mac; } - - InitializationVector client_iv() const { return c_iv; } - InitializationVector server_iv() const { return s_iv; } - - const secure_vector<byte>& master_secret() const { return master_sec; } - - Session_Keys() {} - - Session_Keys(const class Handshake_State* state, - const secure_vector<byte>& pre_master, - bool resuming); - - private: - secure_vector<byte> master_sec; - SymmetricKey c_cipher, s_cipher, c_mac, s_mac; - InitializationVector c_iv, s_iv; - }; - -} - -} - -#endif diff --git a/src/tls/tls_session_manager.h b/src/tls/tls_session_manager.h deleted file mode 100644 index e6eacc88c..000000000 --- a/src/tls/tls_session_manager.h +++ /dev/null @@ -1,149 +0,0 @@ -/* -* TLS Session Manager -* (C) 2011 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_SESSION_MANAGER_H__ -#define BOTAN_TLS_SESSION_MANAGER_H__ - -#include <botan/tls_session.h> -#include <mutex> -#include <chrono> -#include <map> - -namespace Botan { - -namespace TLS { - -/** -* Session_Manager is an interface to systems which can save -* session parameters for supporting session resumption. -* -* Saving sessions is done on a best-effort basis; an implementation is -* allowed to drop sessions due to space constraints. -* -* Implementations should strive to be thread safe -*/ -class BOTAN_DLL Session_Manager - { - public: - /** - * Try to load a saved session (using session ID) - * @param session_id the session identifier we are trying to resume - * @param session will be set to the saved session data (if found), - or not modified if not found - * @return true if session was modified - */ - virtual bool load_from_session_id(const std::vector<byte>& session_id, - Session& session) = 0; - - /** - * Try to load a saved session (using info about server) - * @param info the information about the server - * @param session will be set to the saved session data (if found), - or not modified if not found - * @return true if session was modified - */ - virtual bool load_from_server_info(const Server_Information& info, - Session& session) = 0; - - /** - * Remove this session id from the cache, if it exists - */ - virtual void remove_entry(const std::vector<byte>& session_id) = 0; - - /** - * Save a session on a best effort basis; the manager may not in - * fact be able to save the session for whatever reason; this is - * not an error. Caller cannot assume that calling save followed - * immediately by load_from_* will result in a successful lookup. - * - * @param session to save - */ - virtual void save(const Session& session) = 0; - - /** - * Return the allowed lifetime of a session; beyond this time, - * sessions are not resumed. Returns 0 if unknown/no explicit - * expiration policy. - */ - virtual std::chrono::seconds session_lifetime() const = 0; - - virtual ~Session_Manager() {} - }; - -/** -* An implementation of Session_Manager that does not save sessions at -* all, preventing session resumption. -*/ -class BOTAN_DLL Session_Manager_Noop : public Session_Manager - { - public: - bool load_from_session_id(const std::vector<byte>&, Session&) override - { return false; } - - bool load_from_server_info(const Server_Information&, Session&) override - { return false; } - - void remove_entry(const std::vector<byte>&) override {} - - void save(const Session&) override {} - - std::chrono::seconds session_lifetime() const override - { return std::chrono::seconds(0); } - }; - -/** -* An implementation of Session_Manager that saves values in memory. -*/ -class BOTAN_DLL Session_Manager_In_Memory : public Session_Manager - { - public: - /** - * @param max_sessions a hint on the maximum number of sessions - * to keep in memory at any one time. (If zero, don't cap) - * @param session_lifetime sessions are expired after this many - * seconds have elapsed from initial handshake. - */ - Session_Manager_In_Memory(RandomNumberGenerator& rng, - size_t max_sessions = 1000, - std::chrono::seconds session_lifetime = - std::chrono::seconds(7200)); - - bool load_from_session_id(const std::vector<byte>& session_id, - Session& session) override; - - bool load_from_server_info(const Server_Information& info, - Session& session) override; - - void remove_entry(const std::vector<byte>& session_id) override; - - void save(const Session& session_data) override; - - std::chrono::seconds session_lifetime() const override - { return m_session_lifetime; } - - private: - bool load_from_session_str(const std::string& session_str, - Session& session); - - std::mutex m_mutex; - - size_t m_max_sessions; - - std::chrono::seconds m_session_lifetime; - - RandomNumberGenerator& m_rng; - SymmetricKey m_session_key; - - std::map<std::string, std::vector<byte>> m_sessions; // hex(session_id) -> session - std::map<Server_Information, std::string> m_info_sessions; - }; - -} - -} - -#endif diff --git a/src/tls/tls_session_manager_memory.cpp b/src/tls/tls_session_manager_memory.cpp deleted file mode 100644 index 24ede276c..000000000 --- a/src/tls/tls_session_manager_memory.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* -* TLS Session Management -* (C) 2011,2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/tls_session_manager.h> -#include <botan/hex.h> -#include <chrono> - -namespace Botan { - -namespace TLS { - -Session_Manager_In_Memory::Session_Manager_In_Memory( - RandomNumberGenerator& rng, - size_t max_sessions, - std::chrono::seconds session_lifetime) : - m_max_sessions(max_sessions), - m_session_lifetime(session_lifetime), - m_rng(rng), - m_session_key(m_rng, 32) - {} - -bool Session_Manager_In_Memory::load_from_session_str( - const std::string& session_str, Session& session) - { - // assert(lock is held) - - auto i = m_sessions.find(session_str); - - if(i == m_sessions.end()) - return false; - - try - { - session = Session::decrypt(i->second, m_session_key); - } - catch(...) - { - return false; - } - - // if session has expired, remove it - const auto now = std::chrono::system_clock::now(); - - if(session.start_time() + session_lifetime() < now) - { - m_sessions.erase(i); - return false; - } - - return true; - } - -bool Session_Manager_In_Memory::load_from_session_id( - const std::vector<byte>& session_id, Session& session) - { - std::lock_guard<std::mutex> lock(m_mutex); - - return load_from_session_str(hex_encode(session_id), session); - } - -bool Session_Manager_In_Memory::load_from_server_info( - const Server_Information& info, Session& session) - { - std::lock_guard<std::mutex> lock(m_mutex); - - auto i = m_info_sessions.find(info); - - if(i == m_info_sessions.end()) - return false; - - if(load_from_session_str(i->second, session)) - return true; - - /* - * It existed at one point but was removed from the sessions map, - * remove m_info_sessions entry as well - */ - m_info_sessions.erase(i); - - return false; - } - -void Session_Manager_In_Memory::remove_entry( - const std::vector<byte>& session_id) - { - std::lock_guard<std::mutex> lock(m_mutex); - - auto i = m_sessions.find(hex_encode(session_id)); - - if(i != m_sessions.end()) - m_sessions.erase(i); - } - -void Session_Manager_In_Memory::save(const Session& session) - { - std::lock_guard<std::mutex> lock(m_mutex); - - if(m_max_sessions != 0) - { - /* - We generate new session IDs with the first 4 bytes being a - timestamp, so this actually removes the oldest sessions first. - */ - while(m_sessions.size() >= m_max_sessions) - m_sessions.erase(m_sessions.begin()); - } - - const std::string session_id_str = hex_encode(session.session_id()); - - m_sessions[session_id_str] = session.encrypt(m_session_key, m_rng); - - if(session.side() == CLIENT && !session.server_info().empty()) - m_info_sessions[session.server_info()] = session_id_str; - } - -} - -} diff --git a/src/tls/tls_suite_info.cpp b/src/tls/tls_suite_info.cpp deleted file mode 100644 index 2984fd535..000000000 --- a/src/tls/tls_suite_info.cpp +++ /dev/null @@ -1,463 +0,0 @@ -/* -* TLS cipher suite information -* -* This file was automatically generated from the IANA assignments -* (tls-parameters.txt hash a794db70c6546a47e3bc3181dc0fd908a322e50c) -* by ./src/build-data/scripts/tls_suite_info.py on 2013-12-04 -* -* Released under the terms of the Botan license -*/ - -#include <botan/tls_ciphersuite.h> - -namespace Botan { - -namespace TLS { - -Ciphersuite Ciphersuite::by_id(u16bit suite) - { - switch(suite) - { - case 0x0013: // DHE_DSS_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0x0013, "DSA", "DH", "3DES", 24, 8, "SHA-1", 20); - - case 0x0032: // DHE_DSS_WITH_AES_128_CBC_SHA - return Ciphersuite(0x0032, "DSA", "DH", "AES-128", 16, 16, "SHA-1", 20); - - case 0x0040: // DHE_DSS_WITH_AES_128_CBC_SHA256 - return Ciphersuite(0x0040, "DSA", "DH", "AES-128", 16, 16, "SHA-256", 32); - - case 0x00A2: // DHE_DSS_WITH_AES_128_GCM_SHA256 - return Ciphersuite(0x00A2, "DSA", "DH", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x0038: // DHE_DSS_WITH_AES_256_CBC_SHA - return Ciphersuite(0x0038, "DSA", "DH", "AES-256", 32, 16, "SHA-1", 20); - - case 0x006A: // DHE_DSS_WITH_AES_256_CBC_SHA256 - return Ciphersuite(0x006A, "DSA", "DH", "AES-256", 32, 16, "SHA-256", 32); - - case 0x00A3: // DHE_DSS_WITH_AES_256_GCM_SHA384 - return Ciphersuite(0x00A3, "DSA", "DH", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0x0044: // DHE_DSS_WITH_CAMELLIA_128_CBC_SHA - return Ciphersuite(0x0044, "DSA", "DH", "Camellia-128", 16, 16, "SHA-1", 20); - - case 0x00BD: // DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 - return Ciphersuite(0x00BD, "DSA", "DH", "Camellia-128", 16, 16, "SHA-256", 32); - - case 0xC080: // DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 - return Ciphersuite(0xC080, "DSA", "DH", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x0087: // DHE_DSS_WITH_CAMELLIA_256_CBC_SHA - return Ciphersuite(0x0087, "DSA", "DH", "Camellia-256", 32, 16, "SHA-1", 20); - - case 0x00C3: // DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 - return Ciphersuite(0x00C3, "DSA", "DH", "Camellia-256", 32, 16, "SHA-256", 32); - - case 0xC081: // DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 - return Ciphersuite(0xC081, "DSA", "DH", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0x0066: // DHE_DSS_WITH_RC4_128_SHA - return Ciphersuite(0x0066, "DSA", "DH", "RC4", 16, 0, "SHA-1", 20); - - case 0x0099: // DHE_DSS_WITH_SEED_CBC_SHA - return Ciphersuite(0x0099, "DSA", "DH", "SEED", 16, 16, "SHA-1", 20); - - case 0x008F: // DHE_PSK_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0x008F, "", "DHE_PSK", "3DES", 24, 8, "SHA-1", 20); - - case 0x0090: // DHE_PSK_WITH_AES_128_CBC_SHA - return Ciphersuite(0x0090, "", "DHE_PSK", "AES-128", 16, 16, "SHA-1", 20); - - case 0x00B2: // DHE_PSK_WITH_AES_128_CBC_SHA256 - return Ciphersuite(0x00B2, "", "DHE_PSK", "AES-128", 16, 16, "SHA-256", 32); - - case 0xC0A6: // DHE_PSK_WITH_AES_128_CCM - return Ciphersuite(0xC0A6, "", "DHE_PSK", "AES-128/CCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x00AA: // DHE_PSK_WITH_AES_128_GCM_SHA256 - return Ciphersuite(0x00AA, "", "DHE_PSK", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x0091: // DHE_PSK_WITH_AES_256_CBC_SHA - return Ciphersuite(0x0091, "", "DHE_PSK", "AES-256", 32, 16, "SHA-1", 20); - - case 0x00B3: // DHE_PSK_WITH_AES_256_CBC_SHA384 - return Ciphersuite(0x00B3, "", "DHE_PSK", "AES-256", 32, 16, "SHA-384", 48); - - case 0xC0A7: // DHE_PSK_WITH_AES_256_CCM - return Ciphersuite(0xC0A7, "", "DHE_PSK", "AES-256/CCM", 32, 4, "AEAD", 0, "SHA-256"); - - case 0x00AB: // DHE_PSK_WITH_AES_256_GCM_SHA384 - return Ciphersuite(0x00AB, "", "DHE_PSK", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0xC096: // DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 - return Ciphersuite(0xC096, "", "DHE_PSK", "Camellia-128", 16, 16, "SHA-256", 32); - - case 0xC090: // DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 - return Ciphersuite(0xC090, "", "DHE_PSK", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0xC097: // DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 - return Ciphersuite(0xC097, "", "DHE_PSK", "Camellia-256", 32, 16, "SHA-384", 48); - - case 0xC091: // DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 - return Ciphersuite(0xC091, "", "DHE_PSK", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0x008E: // DHE_PSK_WITH_RC4_128_SHA - return Ciphersuite(0x008E, "", "DHE_PSK", "RC4", 16, 0, "SHA-1", 20); - - case 0x0016: // DHE_RSA_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0x0016, "RSA", "DH", "3DES", 24, 8, "SHA-1", 20); - - case 0x0033: // DHE_RSA_WITH_AES_128_CBC_SHA - return Ciphersuite(0x0033, "RSA", "DH", "AES-128", 16, 16, "SHA-1", 20); - - case 0x0067: // DHE_RSA_WITH_AES_128_CBC_SHA256 - return Ciphersuite(0x0067, "RSA", "DH", "AES-128", 16, 16, "SHA-256", 32); - - case 0xC09E: // DHE_RSA_WITH_AES_128_CCM - return Ciphersuite(0xC09E, "RSA", "DH", "AES-128/CCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0xC0A2: // DHE_RSA_WITH_AES_128_CCM_8 - return Ciphersuite(0xC0A2, "RSA", "DH", "AES-128/CCM-8", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x009E: // DHE_RSA_WITH_AES_128_GCM_SHA256 - return Ciphersuite(0x009E, "RSA", "DH", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x0039: // DHE_RSA_WITH_AES_256_CBC_SHA - return Ciphersuite(0x0039, "RSA", "DH", "AES-256", 32, 16, "SHA-1", 20); - - case 0x006B: // DHE_RSA_WITH_AES_256_CBC_SHA256 - return Ciphersuite(0x006B, "RSA", "DH", "AES-256", 32, 16, "SHA-256", 32); - - case 0xC09F: // DHE_RSA_WITH_AES_256_CCM - return Ciphersuite(0xC09F, "RSA", "DH", "AES-256/CCM", 32, 4, "AEAD", 0, "SHA-256"); - - case 0xC0A3: // DHE_RSA_WITH_AES_256_CCM_8 - return Ciphersuite(0xC0A3, "RSA", "DH", "AES-256/CCM-8", 32, 4, "AEAD", 0, "SHA-256"); - - case 0x009F: // DHE_RSA_WITH_AES_256_GCM_SHA384 - return Ciphersuite(0x009F, "RSA", "DH", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0x0045: // DHE_RSA_WITH_CAMELLIA_128_CBC_SHA - return Ciphersuite(0x0045, "RSA", "DH", "Camellia-128", 16, 16, "SHA-1", 20); - - case 0x00BE: // DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - return Ciphersuite(0x00BE, "RSA", "DH", "Camellia-128", 16, 16, "SHA-256", 32); - - case 0xC07C: // DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 - return Ciphersuite(0xC07C, "RSA", "DH", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x0088: // DHE_RSA_WITH_CAMELLIA_256_CBC_SHA - return Ciphersuite(0x0088, "RSA", "DH", "Camellia-256", 32, 16, "SHA-1", 20); - - case 0x00C4: // DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 - return Ciphersuite(0x00C4, "RSA", "DH", "Camellia-256", 32, 16, "SHA-256", 32); - - case 0xC07D: // DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 - return Ciphersuite(0xC07D, "RSA", "DH", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0x009A: // DHE_RSA_WITH_SEED_CBC_SHA - return Ciphersuite(0x009A, "RSA", "DH", "SEED", 16, 16, "SHA-1", 20); - - case 0x001B: // DH_anon_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0x001B, "", "DH", "3DES", 24, 8, "SHA-1", 20); - - case 0x0034: // DH_anon_WITH_AES_128_CBC_SHA - return Ciphersuite(0x0034, "", "DH", "AES-128", 16, 16, "SHA-1", 20); - - case 0x006C: // DH_anon_WITH_AES_128_CBC_SHA256 - return Ciphersuite(0x006C, "", "DH", "AES-128", 16, 16, "SHA-256", 32); - - case 0x00A6: // DH_anon_WITH_AES_128_GCM_SHA256 - return Ciphersuite(0x00A6, "", "DH", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x003A: // DH_anon_WITH_AES_256_CBC_SHA - return Ciphersuite(0x003A, "", "DH", "AES-256", 32, 16, "SHA-1", 20); - - case 0x006D: // DH_anon_WITH_AES_256_CBC_SHA256 - return Ciphersuite(0x006D, "", "DH", "AES-256", 32, 16, "SHA-256", 32); - - case 0x00A7: // DH_anon_WITH_AES_256_GCM_SHA384 - return Ciphersuite(0x00A7, "", "DH", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0x0046: // DH_anon_WITH_CAMELLIA_128_CBC_SHA - return Ciphersuite(0x0046, "", "DH", "Camellia-128", 16, 16, "SHA-1", 20); - - case 0x00BF: // DH_anon_WITH_CAMELLIA_128_CBC_SHA256 - return Ciphersuite(0x00BF, "", "DH", "Camellia-128", 16, 16, "SHA-256", 32); - - case 0xC084: // DH_anon_WITH_CAMELLIA_128_GCM_SHA256 - return Ciphersuite(0xC084, "", "DH", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x0089: // DH_anon_WITH_CAMELLIA_256_CBC_SHA - return Ciphersuite(0x0089, "", "DH", "Camellia-256", 32, 16, "SHA-1", 20); - - case 0x00C5: // DH_anon_WITH_CAMELLIA_256_CBC_SHA256 - return Ciphersuite(0x00C5, "", "DH", "Camellia-256", 32, 16, "SHA-256", 32); - - case 0xC085: // DH_anon_WITH_CAMELLIA_256_GCM_SHA384 - return Ciphersuite(0xC085, "", "DH", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0x0018: // DH_anon_WITH_RC4_128_MD5 - return Ciphersuite(0x0018, "", "DH", "RC4", 16, 0, "MD5", 16); - - case 0x009B: // DH_anon_WITH_SEED_CBC_SHA - return Ciphersuite(0x009B, "", "DH", "SEED", 16, 16, "SHA-1", 20); - - case 0xC008: // ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0xC008, "ECDSA", "ECDH", "3DES", 24, 8, "SHA-1", 20); - - case 0xC009: // ECDHE_ECDSA_WITH_AES_128_CBC_SHA - return Ciphersuite(0xC009, "ECDSA", "ECDH", "AES-128", 16, 16, "SHA-1", 20); - - case 0xC023: // ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - return Ciphersuite(0xC023, "ECDSA", "ECDH", "AES-128", 16, 16, "SHA-256", 32); - - case 0xC02B: // ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - return Ciphersuite(0xC02B, "ECDSA", "ECDH", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0xC00A: // ECDHE_ECDSA_WITH_AES_256_CBC_SHA - return Ciphersuite(0xC00A, "ECDSA", "ECDH", "AES-256", 32, 16, "SHA-1", 20); - - case 0xC024: // ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - return Ciphersuite(0xC024, "ECDSA", "ECDH", "AES-256", 32, 16, "SHA-384", 48); - - case 0xC02C: // ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - return Ciphersuite(0xC02C, "ECDSA", "ECDH", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0xC072: // ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 - return Ciphersuite(0xC072, "ECDSA", "ECDH", "Camellia-128", 16, 16, "SHA-256", 32); - - case 0xC086: // ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 - return Ciphersuite(0xC086, "ECDSA", "ECDH", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0xC073: // ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 - return Ciphersuite(0xC073, "ECDSA", "ECDH", "Camellia-256", 32, 16, "SHA-384", 48); - - case 0xC087: // ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 - return Ciphersuite(0xC087, "ECDSA", "ECDH", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0xC007: // ECDHE_ECDSA_WITH_RC4_128_SHA - return Ciphersuite(0xC007, "ECDSA", "ECDH", "RC4", 16, 0, "SHA-1", 20); - - case 0xC034: // ECDHE_PSK_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0xC034, "", "ECDHE_PSK", "3DES", 24, 8, "SHA-1", 20); - - case 0xC035: // ECDHE_PSK_WITH_AES_128_CBC_SHA - return Ciphersuite(0xC035, "", "ECDHE_PSK", "AES-128", 16, 16, "SHA-1", 20); - - case 0xC037: // ECDHE_PSK_WITH_AES_128_CBC_SHA256 - return Ciphersuite(0xC037, "", "ECDHE_PSK", "AES-128", 16, 16, "SHA-256", 32); - - case 0xC036: // ECDHE_PSK_WITH_AES_256_CBC_SHA - return Ciphersuite(0xC036, "", "ECDHE_PSK", "AES-256", 32, 16, "SHA-1", 20); - - case 0xC038: // ECDHE_PSK_WITH_AES_256_CBC_SHA384 - return Ciphersuite(0xC038, "", "ECDHE_PSK", "AES-256", 32, 16, "SHA-384", 48); - - case 0xC09A: // ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 - return Ciphersuite(0xC09A, "", "ECDHE_PSK", "Camellia-128", 16, 16, "SHA-256", 32); - - case 0xC09B: // ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 - return Ciphersuite(0xC09B, "", "ECDHE_PSK", "Camellia-256", 32, 16, "SHA-384", 48); - - case 0xC033: // ECDHE_PSK_WITH_RC4_128_SHA - return Ciphersuite(0xC033, "", "ECDHE_PSK", "RC4", 16, 0, "SHA-1", 20); - - case 0xC012: // ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0xC012, "RSA", "ECDH", "3DES", 24, 8, "SHA-1", 20); - - case 0xC013: // ECDHE_RSA_WITH_AES_128_CBC_SHA - return Ciphersuite(0xC013, "RSA", "ECDH", "AES-128", 16, 16, "SHA-1", 20); - - case 0xC027: // ECDHE_RSA_WITH_AES_128_CBC_SHA256 - return Ciphersuite(0xC027, "RSA", "ECDH", "AES-128", 16, 16, "SHA-256", 32); - - case 0xC02F: // ECDHE_RSA_WITH_AES_128_GCM_SHA256 - return Ciphersuite(0xC02F, "RSA", "ECDH", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0xC014: // ECDHE_RSA_WITH_AES_256_CBC_SHA - return Ciphersuite(0xC014, "RSA", "ECDH", "AES-256", 32, 16, "SHA-1", 20); - - case 0xC028: // ECDHE_RSA_WITH_AES_256_CBC_SHA384 - return Ciphersuite(0xC028, "RSA", "ECDH", "AES-256", 32, 16, "SHA-384", 48); - - case 0xC030: // ECDHE_RSA_WITH_AES_256_GCM_SHA384 - return Ciphersuite(0xC030, "RSA", "ECDH", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0xC076: // ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - return Ciphersuite(0xC076, "RSA", "ECDH", "Camellia-128", 16, 16, "SHA-256", 32); - - case 0xC08A: // ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 - return Ciphersuite(0xC08A, "RSA", "ECDH", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0xC077: // ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 - return Ciphersuite(0xC077, "RSA", "ECDH", "Camellia-256", 32, 16, "SHA-384", 48); - - case 0xC08B: // ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 - return Ciphersuite(0xC08B, "RSA", "ECDH", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0xC011: // ECDHE_RSA_WITH_RC4_128_SHA - return Ciphersuite(0xC011, "RSA", "ECDH", "RC4", 16, 0, "SHA-1", 20); - - case 0xC017: // ECDH_anon_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0xC017, "", "ECDH", "3DES", 24, 8, "SHA-1", 20); - - case 0xC018: // ECDH_anon_WITH_AES_128_CBC_SHA - return Ciphersuite(0xC018, "", "ECDH", "AES-128", 16, 16, "SHA-1", 20); - - case 0xC019: // ECDH_anon_WITH_AES_256_CBC_SHA - return Ciphersuite(0xC019, "", "ECDH", "AES-256", 32, 16, "SHA-1", 20); - - case 0xC016: // ECDH_anon_WITH_RC4_128_SHA - return Ciphersuite(0xC016, "", "ECDH", "RC4", 16, 0, "SHA-1", 20); - - case 0xC0AA: // PSK_DHE_WITH_AES_128_CCM_8 - return Ciphersuite(0xC0AA, "", "DHE_PSK", "AES-128/CCM-8", 16, 4, "AEAD", 0, "SHA-256"); - - case 0xC0AB: // PSK_DHE_WITH_AES_256_CCM_8 - return Ciphersuite(0xC0AB, "", "DHE_PSK", "AES-256/CCM-8", 32, 4, "AEAD", 0, "SHA-256"); - - case 0x008B: // PSK_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0x008B, "", "PSK", "3DES", 24, 8, "SHA-1", 20); - - case 0x008C: // PSK_WITH_AES_128_CBC_SHA - return Ciphersuite(0x008C, "", "PSK", "AES-128", 16, 16, "SHA-1", 20); - - case 0x00AE: // PSK_WITH_AES_128_CBC_SHA256 - return Ciphersuite(0x00AE, "", "PSK", "AES-128", 16, 16, "SHA-256", 32); - - case 0xC0A4: // PSK_WITH_AES_128_CCM - return Ciphersuite(0xC0A4, "", "PSK", "AES-128/CCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0xC0A8: // PSK_WITH_AES_128_CCM_8 - return Ciphersuite(0xC0A8, "", "PSK", "AES-128/CCM-8", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x00A8: // PSK_WITH_AES_128_GCM_SHA256 - return Ciphersuite(0x00A8, "", "PSK", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x008D: // PSK_WITH_AES_256_CBC_SHA - return Ciphersuite(0x008D, "", "PSK", "AES-256", 32, 16, "SHA-1", 20); - - case 0x00AF: // PSK_WITH_AES_256_CBC_SHA384 - return Ciphersuite(0x00AF, "", "PSK", "AES-256", 32, 16, "SHA-384", 48); - - case 0xC0A5: // PSK_WITH_AES_256_CCM - return Ciphersuite(0xC0A5, "", "PSK", "AES-256/CCM", 32, 4, "AEAD", 0, "SHA-256"); - - case 0xC0A9: // PSK_WITH_AES_256_CCM_8 - return Ciphersuite(0xC0A9, "", "PSK", "AES-256/CCM-8", 32, 4, "AEAD", 0, "SHA-256"); - - case 0x00A9: // PSK_WITH_AES_256_GCM_SHA384 - return Ciphersuite(0x00A9, "", "PSK", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0xC094: // PSK_WITH_CAMELLIA_128_CBC_SHA256 - return Ciphersuite(0xC094, "", "PSK", "Camellia-128", 16, 16, "SHA-256", 32); - - case 0xC08E: // PSK_WITH_CAMELLIA_128_GCM_SHA256 - return Ciphersuite(0xC08E, "", "PSK", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0xC095: // PSK_WITH_CAMELLIA_256_CBC_SHA384 - return Ciphersuite(0xC095, "", "PSK", "Camellia-256", 32, 16, "SHA-384", 48); - - case 0xC08F: // PSK_WITH_CAMELLIA_256_GCM_SHA384 - return Ciphersuite(0xC08F, "", "PSK", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0x008A: // PSK_WITH_RC4_128_SHA - return Ciphersuite(0x008A, "", "PSK", "RC4", 16, 0, "SHA-1", 20); - - case 0x000A: // RSA_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0x000A, "RSA", "RSA", "3DES", 24, 8, "SHA-1", 20); - - case 0x002F: // RSA_WITH_AES_128_CBC_SHA - return Ciphersuite(0x002F, "RSA", "RSA", "AES-128", 16, 16, "SHA-1", 20); - - case 0x003C: // RSA_WITH_AES_128_CBC_SHA256 - return Ciphersuite(0x003C, "RSA", "RSA", "AES-128", 16, 16, "SHA-256", 32); - - case 0xC09C: // RSA_WITH_AES_128_CCM - return Ciphersuite(0xC09C, "RSA", "RSA", "AES-128/CCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0xC0A0: // RSA_WITH_AES_128_CCM_8 - return Ciphersuite(0xC0A0, "RSA", "RSA", "AES-128/CCM-8", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x009C: // RSA_WITH_AES_128_GCM_SHA256 - return Ciphersuite(0x009C, "RSA", "RSA", "AES-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x0035: // RSA_WITH_AES_256_CBC_SHA - return Ciphersuite(0x0035, "RSA", "RSA", "AES-256", 32, 16, "SHA-1", 20); - - case 0x003D: // RSA_WITH_AES_256_CBC_SHA256 - return Ciphersuite(0x003D, "RSA", "RSA", "AES-256", 32, 16, "SHA-256", 32); - - case 0xC09D: // RSA_WITH_AES_256_CCM - return Ciphersuite(0xC09D, "RSA", "RSA", "AES-256/CCM", 32, 4, "AEAD", 0, "SHA-256"); - - case 0xC0A1: // RSA_WITH_AES_256_CCM_8 - return Ciphersuite(0xC0A1, "RSA", "RSA", "AES-256/CCM-8", 32, 4, "AEAD", 0, "SHA-256"); - - case 0x009D: // RSA_WITH_AES_256_GCM_SHA384 - return Ciphersuite(0x009D, "RSA", "RSA", "AES-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0x0041: // RSA_WITH_CAMELLIA_128_CBC_SHA - return Ciphersuite(0x0041, "RSA", "RSA", "Camellia-128", 16, 16, "SHA-1", 20); - - case 0x00BA: // RSA_WITH_CAMELLIA_128_CBC_SHA256 - return Ciphersuite(0x00BA, "RSA", "RSA", "Camellia-128", 16, 16, "SHA-256", 32); - - case 0xC07A: // RSA_WITH_CAMELLIA_128_GCM_SHA256 - return Ciphersuite(0xC07A, "RSA", "RSA", "Camellia-128/GCM", 16, 4, "AEAD", 0, "SHA-256"); - - case 0x0084: // RSA_WITH_CAMELLIA_256_CBC_SHA - return Ciphersuite(0x0084, "RSA", "RSA", "Camellia-256", 32, 16, "SHA-1", 20); - - case 0x00C0: // RSA_WITH_CAMELLIA_256_CBC_SHA256 - return Ciphersuite(0x00C0, "RSA", "RSA", "Camellia-256", 32, 16, "SHA-256", 32); - - case 0xC07B: // RSA_WITH_CAMELLIA_256_GCM_SHA384 - return Ciphersuite(0xC07B, "RSA", "RSA", "Camellia-256/GCM", 32, 4, "AEAD", 0, "SHA-384"); - - case 0x0004: // RSA_WITH_RC4_128_MD5 - return Ciphersuite(0x0004, "RSA", "RSA", "RC4", 16, 0, "MD5", 16); - - case 0x0005: // RSA_WITH_RC4_128_SHA - return Ciphersuite(0x0005, "RSA", "RSA", "RC4", 16, 0, "SHA-1", 20); - - case 0x0096: // RSA_WITH_SEED_CBC_SHA - return Ciphersuite(0x0096, "RSA", "RSA", "SEED", 16, 16, "SHA-1", 20); - - case 0xC01C: // SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0xC01C, "DSA", "SRP_SHA", "3DES", 24, 8, "SHA-1", 20); - - case 0xC01F: // SRP_SHA_DSS_WITH_AES_128_CBC_SHA - return Ciphersuite(0xC01F, "DSA", "SRP_SHA", "AES-128", 16, 16, "SHA-1", 20); - - case 0xC022: // SRP_SHA_DSS_WITH_AES_256_CBC_SHA - return Ciphersuite(0xC022, "DSA", "SRP_SHA", "AES-256", 32, 16, "SHA-1", 20); - - case 0xC01B: // SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0xC01B, "RSA", "SRP_SHA", "3DES", 24, 8, "SHA-1", 20); - - case 0xC01E: // SRP_SHA_RSA_WITH_AES_128_CBC_SHA - return Ciphersuite(0xC01E, "RSA", "SRP_SHA", "AES-128", 16, 16, "SHA-1", 20); - - case 0xC021: // SRP_SHA_RSA_WITH_AES_256_CBC_SHA - return Ciphersuite(0xC021, "RSA", "SRP_SHA", "AES-256", 32, 16, "SHA-1", 20); - - case 0xC01A: // SRP_SHA_WITH_3DES_EDE_CBC_SHA - return Ciphersuite(0xC01A, "", "SRP_SHA", "3DES", 24, 8, "SHA-1", 20); - - case 0xC01D: // SRP_SHA_WITH_AES_128_CBC_SHA - return Ciphersuite(0xC01D, "", "SRP_SHA", "AES-128", 16, 16, "SHA-1", 20); - - case 0xC020: // SRP_SHA_WITH_AES_256_CBC_SHA - return Ciphersuite(0xC020, "", "SRP_SHA", "AES-256", 32, 16, "SHA-1", 20); - - } - - return Ciphersuite(); // some unknown ciphersuite - } - -} - -} diff --git a/src/tls/tls_version.cpp b/src/tls/tls_version.cpp deleted file mode 100644 index 7b880d98c..000000000 --- a/src/tls/tls_version.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* -* TLS Protocol Version Management -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/tls_version.h> -#include <botan/tls_exceptn.h> -#include <botan/parsing.h> - -namespace Botan { - -namespace TLS { - -std::string Protocol_Version::to_string() const - { - const byte maj = major_version(); - const byte min = minor_version(); - - if(maj == 3 && min == 0) - return "SSL v3"; - - if(maj == 3 && min >= 1) // TLS v1.x - return "TLS v1." + std::to_string(min-1); - - if(maj == 254) // DTLS 1.x - return "DTLS v1." + std::to_string(255 - min); - - // Some very new or very old protocol (or bogus data) - return "Unknown " + std::to_string(maj) + "." + std::to_string(min); - } - -bool Protocol_Version::is_datagram_protocol() const - { - return major_version() == 254; - } - -bool Protocol_Version::operator>(const Protocol_Version& other) const - { - if(this->is_datagram_protocol() != other.is_datagram_protocol()) - throw TLS_Exception(Alert::PROTOCOL_VERSION, - "Version comparing " + to_string() + - " with " + other.to_string()); - - if(this->is_datagram_protocol()) - return m_version < other.m_version; // goes backwards - - return m_version > other.m_version; - } - -Protocol_Version Protocol_Version::best_known_match() const - { - if(known_version()) - return *this; // known version is its own best match - - if(is_datagram_protocol()) - return Protocol_Version::DTLS_V12; - else - return Protocol_Version::TLS_V12; - } - -bool Protocol_Version::known_version() const - { - return (m_version == Protocol_Version::SSL_V3 || - m_version == Protocol_Version::TLS_V10 || - m_version == Protocol_Version::TLS_V11 || - m_version == Protocol_Version::TLS_V12 || - m_version == Protocol_Version::DTLS_V10 || - m_version == Protocol_Version::DTLS_V12); - } - -bool Protocol_Version::supports_negotiable_signature_algorithms() const - { - return (m_version == Protocol_Version::TLS_V12 || - m_version == Protocol_Version::DTLS_V12); - } - -bool Protocol_Version::supports_explicit_cbc_ivs() const - { - return (m_version == Protocol_Version::TLS_V11 || - m_version == Protocol_Version::TLS_V12 || - m_version == Protocol_Version::DTLS_V10 || - m_version == Protocol_Version::DTLS_V12); - } - -bool Protocol_Version::supports_ciphersuite_specific_prf() const - { - return (m_version == Protocol_Version::TLS_V12 || - m_version == Protocol_Version::DTLS_V12); - } - -bool Protocol_Version::supports_aead_modes() const - { - return (m_version == Protocol_Version::TLS_V12 || - m_version == Protocol_Version::DTLS_V12); - } - -} - -} diff --git a/src/tls/tls_version.h b/src/tls/tls_version.h deleted file mode 100644 index 9fd71b629..000000000 --- a/src/tls/tls_version.h +++ /dev/null @@ -1,151 +0,0 @@ -/* -* TLS Protocol Version Management -* (C) 2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_PROTOCOL_VERSION_H__ -#define BOTAN_TLS_PROTOCOL_VERSION_H__ - -#include <botan/get_byte.h> -#include <string> - -namespace Botan { - -namespace TLS { - -/** -* TLS Protocol Version -*/ -class BOTAN_DLL Protocol_Version - { - public: - enum Version_Code { - SSL_V3 = 0x0300, - TLS_V10 = 0x0301, - TLS_V11 = 0x0302, - TLS_V12 = 0x0303, - - DTLS_V10 = 0xFEFF, - DTLS_V12 = 0xFEFD - }; - - static Protocol_Version latest_tls_version() - { - return Protocol_Version(TLS_V12); - } - - static Protocol_Version latest_dtls_version() - { - return Protocol_Version(DTLS_V12); - } - - Protocol_Version() : m_version(0) {} - - /** - * @param named_version a specific named version of the protocol - */ - Protocol_Version(Version_Code named_version) : - m_version(static_cast<u16bit>(named_version)) {} - - /** - * @param major the major version - * @param minor the minor version - */ - Protocol_Version(byte major, byte minor) : - m_version((static_cast<u16bit>(major) << 8) | minor) {} - - /** - * @return true if this is a valid protocol version - */ - bool valid() const { return (m_version != 0); } - - /** - * @return true if this is a protocol version we know about - */ - bool known_version() const; - - /** - * @return major version of the protocol version - */ - byte major_version() const { return get_byte(0, m_version); } - - /** - * @return minor version of the protocol version - */ - byte minor_version() const { return get_byte(1, m_version); } - - /** - * @return human-readable description of this version - */ - std::string to_string() const; - - /** - * If this version is known, return that. Otherwise return the - * best (most recent) version we know of. - * @return best matching protocol version - */ - Protocol_Version best_known_match() const; - - /** - * @return true iff this is a DTLS version - */ - bool is_datagram_protocol() const; - - /** - * @return true if this version supports negotiable signature algorithms - */ - bool supports_negotiable_signature_algorithms() const; - - /** - * @return true if this version uses explicit IVs for block ciphers - */ - bool supports_explicit_cbc_ivs() const; - - /** - * @return true if this version uses a ciphersuite specific PRF - */ - bool supports_ciphersuite_specific_prf() const; - - bool supports_aead_modes() const; - - /** - * @return if this version is equal to other - */ - bool operator==(const Protocol_Version& other) const - { - return (m_version == other.m_version); - } - - /** - * @return if this version is not equal to other - */ - bool operator!=(const Protocol_Version& other) const - { - return (m_version != other.m_version); - } - - /** - * @return if this version is later than other - */ - bool operator>(const Protocol_Version& other) const; - - /** - * @return if this version is later than or equal to other - */ - bool operator>=(const Protocol_Version& other) const - { - return (*this == other || *this > other); - } - - private: - u16bit m_version; - }; - -} - -} - -#endif - |