aboutsummaryrefslogtreecommitdiffstats
path: root/src/tls
diff options
context:
space:
mode:
authorlloyd <[email protected]>2012-04-25 13:48:08 +0000
committerlloyd <[email protected]>2012-04-25 13:48:08 +0000
commitb72a44475d06263e1492f8913310b5f29515cba6 (patch)
tree680752dbd43999cea16851b9c196046d9e5fbd7f /src/tls
parentedca5f211722ea6b9d99b8b5fce4603a1b9b422d (diff)
parentf14a9fdee7902ba1a4c962cfbabe29d5146e7c55 (diff)
propagate from branch 'net.randombit.botan.tls-state-machine' (head a4741cd07f50a9e1b29b0dd97c6fb8697c038ade)
to branch 'net.randombit.botan.cxx11' (head 116e5ff139c07000be431e07d3472cc8f3919b91)
Diffstat (limited to 'src/tls')
-rw-r--r--src/tls/c_hello.cpp64
-rw-r--r--src/tls/c_kex.cpp40
-rw-r--r--src/tls/cert_req.cpp10
-rw-r--r--src/tls/info.txt14
-rw-r--r--src/tls/rec_read.cpp5
-rw-r--r--src/tls/s_hello.cpp93
-rw-r--r--src/tls/s_kex.cpp75
-rw-r--r--src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp41
-rw-r--r--src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h10
-rw-r--r--src/tls/tls_alert.cpp14
-rw-r--r--src/tls/tls_alert.h65
-rw-r--r--src/tls/tls_channel.cpp58
-rw-r--r--src/tls/tls_channel.h28
-rw-r--r--src/tls/tls_ciphersuite.cpp272
-rw-r--r--src/tls/tls_ciphersuite.h16
-rw-r--r--src/tls/tls_client.cpp73
-rw-r--r--src/tls/tls_client.h13
-rw-r--r--src/tls/tls_extensions.cpp18
-rw-r--r--src/tls/tls_extensions.h27
-rw-r--r--src/tls/tls_handshake_hash.cpp8
-rw-r--r--src/tls/tls_handshake_state.cpp22
-rw-r--r--src/tls/tls_handshake_state.h24
-rw-r--r--src/tls/tls_heartbeats.cpp78
-rw-r--r--src/tls/tls_heartbeats.h40
-rw-r--r--src/tls/tls_magic.h87
-rw-r--r--src/tls/tls_messages.h73
-rw-r--r--src/tls/tls_policy.cpp166
-rw-r--r--src/tls/tls_policy.h29
-rw-r--r--src/tls/tls_record.h17
-rw-r--r--src/tls/tls_server.cpp167
-rw-r--r--src/tls/tls_server.h8
-rw-r--r--src/tls/tls_session.cpp23
-rw-r--r--src/tls/tls_session.h17
-rw-r--r--src/tls/tls_session_manager.cpp12
-rw-r--r--src/tls/tls_session_manager.h28
-rw-r--r--src/tls/tls_suite_info.cpp317
36 files changed, 1264 insertions, 788 deletions
diff --git a/src/tls/c_hello.cpp b/src/tls/c_hello.cpp
index b08e1abe2..056a7550f 100644
--- a/src/tls/c_hello.cpp
+++ b/src/tls/c_hello.cpp
@@ -11,19 +11,20 @@
#include <botan/internal/tls_extensions.h>
#include <botan/tls_record.h>
#include <botan/internal/stl_util.h>
-#include <chrono>
+#include <botan/time.h>
namespace Botan {
namespace TLS {
+enum {
+ TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF
+};
+
MemoryVector<byte> make_hello_random(RandomNumberGenerator& rng)
{
MemoryVector<byte> buf(32);
-
- const u32bit time32 = static_cast<u32bit>(
- std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()));
-
+ const u32bit time32 = system_time();
store_be(time32, buf);
rng.randomize(&buf[4], buf.size() - 4);
return buf;
@@ -67,7 +68,7 @@ Client_Hello::Client_Hello(Record_Writer& writer,
const std::string& srp_identifier) :
m_version(policy.pref_version()),
m_random(make_hello_random(rng)),
- m_suites(policy.ciphersuite_list((srp_identifier != ""))),
+ m_suites(ciphersuite_list(policy, (srp_identifier != ""))),
m_comp_methods(policy.compression()),
m_hostname(hostname),
m_srp_identifier(srp_identifier),
@@ -76,7 +77,9 @@ Client_Hello::Client_Hello(Record_Writer& writer,
m_secure_renegotiation(true),
m_renegotiation_info(reneg_info),
m_supported_curves(policy.allowed_ecc_curves()),
- m_supports_session_ticket(true)
+ m_supports_session_ticket(true),
+ m_supports_heartbeats(true),
+ m_peer_can_send_heartbeats(true)
{
std::vector<std::string> hashes = policy.allowed_hashes();
std::vector<std::string> sigs = policy.allowed_signature_methods();
@@ -95,21 +98,25 @@ Client_Hello::Client_Hello(Record_Writer& writer,
Handshake_Hash& hash,
const Policy& policy,
RandomNumberGenerator& rng,
+ const MemoryRegion<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(session.srp_identifier() != "")),
+ m_suites(ciphersuite_list(policy, (session.srp_identifier() != ""))),
m_comp_methods(policy.compression()),
m_hostname(session.sni_hostname()),
m_srp_identifier(session.srp_identifier()),
m_next_protocol(next_protocol),
m_fragment_size(session.fragment_size()),
m_secure_renegotiation(session.secure_renegotiation()),
+ m_renegotiation_info(reneg_info),
m_supported_curves(policy.allowed_ecc_curves()),
m_supports_session_ticket(true),
- m_session_ticket(session.session_ticket())
+ m_session_ticket(session.session_ticket()),
+ m_supports_heartbeats(true),
+ m_peer_can_send_heartbeats(true)
{
if(!value_exists(m_suites, session.ciphersuite_code()))
m_suites.push_back(session.ciphersuite_code());
@@ -135,6 +142,8 @@ Client_Hello::Client_Hello(const MemoryRegion<byte>& buf, Handshake_Type type)
m_next_protocol = false;
m_secure_renegotiation = false;
m_supports_session_ticket = false;
+ m_supports_heartbeats = false;
+ m_peer_can_send_heartbeats = false;
m_fragment_size = 0;
if(type == CLIENT_HELLO)
@@ -167,28 +176,23 @@ MemoryVector<byte> Client_Hello::serialize() const
Extensions extensions;
- // Initial handshake
- if(m_renegotiation_info.empty())
- {
+ if(m_secure_renegotiation)
extensions.add(new Renegotation_Extension(m_renegotiation_info));
- extensions.add(new Server_Name_Indicator(m_hostname));
- extensions.add(new SRP_Identifier(m_srp_identifier));
- extensions.add(new Supported_Elliptic_Curves(m_supported_curves));
- if(m_version >= Protocol_Version::TLS_V12)
- extensions.add(new Signature_Algorithms(m_supported_algos));
+ extensions.add(new Session_Ticket(m_session_ticket));
- if(m_next_protocol)
- extensions.add(new Next_Protocol_Notification());
+ extensions.add(new Server_Name_Indicator(m_hostname));
+ extensions.add(new SRP_Identifier(m_srp_identifier));
- extensions.add(new Session_Ticket(m_session_ticket));
- }
- else
- {
- // renegotiation
- extensions.add(new Renegotation_Extension(m_renegotiation_info));
- extensions.add(new Session_Ticket(m_session_ticket));
- }
+ extensions.add(new Supported_Elliptic_Curves(m_supported_curves));
+
+ if(m_version >= Protocol_Version::TLS_V12)
+ extensions.add(new Signature_Algorithms(m_supported_algos));
+
+ extensions.add(new Heartbeat_Support_Indicator(true));
+
+ if(m_renegotiation_info.empty() && m_next_protocol)
+ extensions.add(new Next_Protocol_Notification());
buf += extensions.serialize();
@@ -337,6 +341,12 @@ void Client_Hello::deserialize(const MemoryRegion<byte>& buf)
m_session_ticket = ticket->contents();
}
+ if(Heartbeat_Support_Indicator* hb = extensions.get<Heartbeat_Support_Indicator>())
+ {
+ m_supports_heartbeats = true;
+ m_peer_can_send_heartbeats = hb->peer_allowed_to_send();
+ }
+
if(Renegotation_Extension* reneg = extensions.get<Renegotation_Extension>())
{
// checked by TLS_Client / TLS_Server as they know the handshake state
diff --git a/src/tls/c_kex.cpp b/src/tls/c_kex.cpp
index 0e7eba23a..13925a482 100644
--- a/src/tls/c_kex.cpp
+++ b/src/tls/c_kex.cpp
@@ -15,6 +15,7 @@
#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>
@@ -50,6 +51,7 @@ Client_Key_Exchange::Client_Key_Exchange(Record_Writer& writer,
Handshake_State* state,
Credentials_Manager& creds,
const std::vector<X509_Certificate>& peer_certs,
+ const std::string& hostname,
RandomNumberGenerator& rng)
{
const std::string kex_algo = state->suite.kex_algo();
@@ -147,8 +149,7 @@ Client_Key_Exchange::Client_Key_Exchange(Record_Writer& writer,
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));
+ throw Decoding_Error("Server sent unknown named curve " + to_string(curve_id));
EC_Group group(name);
@@ -172,6 +173,33 @@ Client_Key_Exchange::Client_Key_Exchange(Record_Writer& writer,
append_tls_length_value(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));
+ MemoryVector<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(key_material, BigInt::encode(srp_vals.first), 2);
+ pre_master = srp_vals.second.bits_of();
+ }
else
{
throw Internal_Error("Client_Key_Exchange: Unknown kex " +
@@ -188,7 +216,7 @@ Client_Key_Exchange::Client_Key_Exchange(Record_Writer& writer,
if(peer_certs.empty())
throw Internal_Error("No certificate and no server key exchange");
- std::unique_ptr<Public_Key> pub_key(peer_certs[0].subject_public_key());
+ std::auto_ptr<Public_Key> pub_key(peer_certs[0].subject_public_key());
if(const RSA_PublicKey* rsa_pub = dynamic_cast<const RSA_PublicKey*>(pub_key.get()))
{
@@ -302,6 +330,12 @@ Client_Key_Exchange::Client_Key_Exchange(const MemoryRegion<byte>& contents,
append_tls_length_value(pre_master, zeros, 2);
append_tls_length_value(pre_master, psk.bits_of(), 2);
}
+ else if(kex_algo == "SRP_SHA")
+ {
+ SRP6_Server_Session& srp = state->server_kex->server_srp_params();
+
+ 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")
{
diff --git a/src/tls/cert_req.cpp b/src/tls/cert_req.cpp
index df70cc43d..1b686c1c4 100644
--- a/src/tls/cert_req.cpp
+++ b/src/tls/cert_req.cpp
@@ -122,7 +122,7 @@ Certificate_Req::Certificate_Req(const MemoryRegion<byte>& buf,
m_supported_algos.push_back(std::make_pair("SHA-1", "ECDSA"));
}
- u16bit purported_size = reader.get_u16bit();
+ const u16bit purported_size = reader.get_u16bit();
if(reader.remaining_bytes() != purported_size)
throw Decoding_Error("Inconsistent length in certificate request");
@@ -153,18 +153,20 @@ MemoryVector<byte> Certificate_Req::serialize() const
append_tls_length_value(buf, cert_types, 1);
if(!m_supported_algos.empty())
- {
buf += Signature_Algorithms(m_supported_algos).serialize();
- }
+
+ MemoryVector<byte> encoded_names;
for(size_t i = 0; i != names.size(); ++i)
{
DER_Encoder encoder;
encoder.encode(names[i]);
- append_tls_length_value(buf, encoder.get_contents(), 2);
+ 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/info.txt b/src/tls/info.txt
index b19eedb20..3407aba32 100644
--- a/src/tls/info.txt
+++ b/src/tls/info.txt
@@ -1,5 +1,7 @@
define TLS
+load_on auto
+
<comment>
The TLS code is complex, new, and not yet reviewed, there may be
serious bugs or security issues.
@@ -8,6 +10,7 @@ serious bugs or security issues.
<header:public>
tls_alert.h
tls_channel.h
+tls_ciphersuite.h
tls_client.h
tls_exceptn.h
tls_magic.h
@@ -16,7 +19,6 @@ tls_record.h
tls_server.h
tls_session.h
tls_session_manager.h
-tls_ciphersuite.h
tls_version.h
</header:public>
@@ -25,13 +27,13 @@ tls_extensions.h
tls_handshake_hash.h
tls_handshake_reader.h
tls_handshake_state.h
+tls_heartbeats.h
tls_messages.h
tls_reader.h
tls_session_key.h
</header:internal>
<source>
-tls_alert.cpp
c_hello.cpp
c_kex.cpp
cert_req.cpp
@@ -44,18 +46,21 @@ rec_wri.cpp
s_hello.cpp
s_kex.cpp
session_ticket.cpp
+tls_alert.cpp
tls_channel.cpp
+tls_ciphersuite.cpp
tls_client.cpp
tls_extensions.cpp
tls_handshake_hash.cpp
tls_handshake_reader.cpp
tls_handshake_state.cpp
+tls_heartbeats.cpp
tls_policy.cpp
tls_server.cpp
tls_session.cpp
tls_session_key.cpp
tls_session_manager.cpp
-tls_ciphersuite.cpp
+tls_suite_info.cpp
tls_version.cpp
</source>
@@ -63,6 +68,8 @@ tls_version.cpp
aes
arc4
asn1
+camellia
+cbc
credentials
des
dh
@@ -80,6 +87,7 @@ prf_tls
rng
rsa
seed
+srp6
sha1
sha2_32
ssl3mac
diff --git a/src/tls/rec_read.cpp b/src/tls/rec_read.cpp
index bd6ae5af9..5d46ec1fa 100644
--- a/src/tls/rec_read.cpp
+++ b/src/tls/rec_read.cpp
@@ -216,10 +216,11 @@ size_t Record_Reader::add_input(const byte input_array[], size_t input_sz,
if(m_readbuf[0] != CHANGE_CIPHER_SPEC &&
m_readbuf[0] != ALERT &&
m_readbuf[0] != HANDSHAKE &&
- m_readbuf[0] != APPLICATION_DATA)
+ m_readbuf[0] != APPLICATION_DATA &&
+ m_readbuf[0] != HEARTBEAT)
{
throw Unexpected_Message(
- "Unknown record type " + std::to_string(m_readbuf[0]) + " from counterparty");
+ "Unknown record type " + to_string(m_readbuf[0]) + " from counterparty");
}
const size_t record_len = make_u16bit(m_readbuf[3], m_readbuf[4]);
diff --git a/src/tls/s_hello.cpp b/src/tls/s_hello.cpp
index 7da9fdc57..1244dd2d8 100644
--- a/src/tls/s_hello.cpp
+++ b/src/tls/s_hello.cpp
@@ -21,47 +21,6 @@ namespace TLS {
*/
Server_Hello::Server_Hello(Record_Writer& writer,
Handshake_Hash& hash,
- Protocol_Version version,
- const Client_Hello& c_hello,
- const std::vector<std::string>& available_cert_types,
- const Policy& policy,
- bool have_session_ticket_key,
- bool client_has_secure_renegotiation,
- const MemoryRegion<byte>& reneg_info,
- bool client_has_npn,
- const std::vector<std::string>& next_protocols,
- RandomNumberGenerator& rng) :
- s_version(version),
- m_session_id(rng.random_vec(32)),
- s_random(make_hello_random(rng)),
- m_fragment_size(c_hello.fragment_size()),
- m_secure_renegotiation(client_has_secure_renegotiation),
- m_renegotiation_info(reneg_info),
- m_next_protocol(client_has_npn),
- m_next_protocols(next_protocols),
- m_supports_session_ticket(have_session_ticket_key &&
- c_hello.supports_session_ticket())
- {
- suite = policy.choose_suite(
- c_hello.ciphersuites(),
- available_cert_types,
- policy.choose_curve(c_hello.supported_ecc_curves()) != "",
- false);
-
- if(suite == 0)
- throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
- "Can't agree on a ciphersuite with client");
-
- comp_method = policy.choose_compression(c_hello.compression_methods());
-
- hash.update(writer.send(*this));
- }
-
-/*
-* Create a new Server Hello message
-*/
-Server_Hello::Server_Hello(Record_Writer& writer,
- Handshake_Hash& hash,
const MemoryRegion<byte>& session_id,
Protocol_Version ver,
u16bit ciphersuite,
@@ -69,21 +28,24 @@ Server_Hello::Server_Hello(Record_Writer& writer,
size_t max_fragment_size,
bool client_has_secure_renegotiation,
const MemoryRegion<byte>& reneg_info,
- bool client_supports_session_tickets,
+ bool offer_session_ticket,
bool client_has_npn,
const std::vector<std::string>& next_protocols,
+ bool client_has_heartbeat,
RandomNumberGenerator& rng) :
- s_version(ver),
+ m_version(ver),
m_session_id(session_id),
- s_random(make_hello_random(rng)),
- suite(ciphersuite),
- comp_method(compression),
+ m_random(make_hello_random(rng)),
+ m_ciphersuite(ciphersuite),
+ m_comp_method(compression),
m_fragment_size(max_fragment_size),
m_secure_renegotiation(client_has_secure_renegotiation),
m_renegotiation_info(reneg_info),
m_next_protocol(client_has_npn),
m_next_protocols(next_protocols),
- m_supports_session_ticket(client_supports_session_tickets)
+ m_supports_session_ticket(offer_session_ticket),
+ m_supports_heartbeats(client_has_heartbeat),
+ m_peer_can_send_heartbeats(true)
{
hash.update(writer.send(*this));
}
@@ -105,24 +67,24 @@ Server_Hello::Server_Hello(const MemoryRegion<byte>& buf)
const byte major_version = reader.get_byte();
const byte minor_version = reader.get_byte();
- s_version = Protocol_Version(major_version, minor_version);
+ m_version = Protocol_Version(major_version, minor_version);
- if(s_version != Protocol_Version::SSL_V3 &&
- s_version != Protocol_Version::TLS_V10 &&
- s_version != Protocol_Version::TLS_V11 &&
- s_version != Protocol_Version::TLS_V12)
+ if(m_version != Protocol_Version::SSL_V3 &&
+ m_version != Protocol_Version::TLS_V10 &&
+ m_version != Protocol_Version::TLS_V11 &&
+ m_version != Protocol_Version::TLS_V12)
{
throw TLS_Exception(Alert::PROTOCOL_VERSION,
"Server_Hello: Unsupported server version");
}
- s_random = reader.get_fixed<byte>(32);
+ m_random = reader.get_fixed<byte>(32);
m_session_id = reader.get_range<byte>(1, 0, 32);
- suite = reader.get_u16bit();
+ m_ciphersuite = reader.get_u16bit();
- comp_method = reader.get_byte();
+ m_comp_method = reader.get_byte();
Extensions extensions(reader);
@@ -145,6 +107,12 @@ Server_Hello::Server_Hello(const MemoryRegion<byte>& buf)
throw Decoding_Error("TLS server sent non-empty session ticket extension");
m_supports_session_ticket = true;
}
+
+ if(Heartbeat_Support_Indicator* hb = extensions.get<Heartbeat_Support_Indicator>())
+ {
+ m_supports_heartbeats = true;
+ m_peer_can_send_heartbeats = hb->peer_allowed_to_send();
+ }
}
/*
@@ -154,19 +122,22 @@ MemoryVector<byte> Server_Hello::serialize() const
{
MemoryVector<byte> buf;
- buf.push_back(s_version.major_version());
- buf.push_back(s_version.minor_version());
- buf += s_random;
+ 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, suite));
- buf.push_back(get_byte(1, suite));
+ buf.push_back(get_byte(0, m_ciphersuite));
+ buf.push_back(get_byte(1, m_ciphersuite));
- buf.push_back(comp_method);
+ buf.push_back(m_comp_method);
Extensions extensions;
+ if(m_supports_heartbeats)
+ extensions.add(new Heartbeat_Support_Indicator(m_peer_can_send_heartbeats));
+
if(m_secure_renegotiation)
extensions.add(new Renegotation_Extension(m_renegotiation_info));
diff --git a/src/tls/s_kex.cpp b/src/tls/s_kex.cpp
index 0890cac49..95518aa32 100644
--- a/src/tls/s_kex.cpp
+++ b/src/tls/s_kex.cpp
@@ -16,6 +16,7 @@
#include <botan/dh.h>
#include <botan/ecdh.h>
#include <botan/rsa.h>
+#include <botan/srp6.h>
#include <botan/oids.h>
#include <memory>
@@ -32,22 +33,22 @@ Server_Key_Exchange::Server_Key_Exchange(Record_Writer& writer,
Credentials_Manager& creds,
RandomNumberGenerator& rng,
const Private_Key* signing_key) :
- m_kex_key(0)
+ m_kex_key(0), m_srp_params(0)
{
+ const std::string hostname = state->client_hello->sni_hostname();
const std::string kex_algo = state->suite.kex_algo();
if(kex_algo == "PSK" || kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK")
{
std::string identity_hint =
- creds.psk_identity_hint("tls-server",
- state->client_hello->sni_hostname());
+ 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()));
+ std::auto_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);
@@ -70,7 +71,7 @@ Server_Key_Exchange::Server_Key_Exchange(Record_Writer& writer,
EC_Group ec_group(curve_name);
- std::unique_ptr<ECDH_PrivateKey> ecdh(new ECDH_PrivateKey(rng, ec_group));
+ std::auto_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));
@@ -88,6 +89,35 @@ Server_Key_Exchange::Server_Key_Exchange(Record_Writer& writer,
m_kex_key = ecdh.release();
}
+ else if(kex_algo == "SRP_SHA")
+ {
+ const std::string srp_identifier = state->client_hello->srp_identifier();
+
+ std::string group_id;
+ BigInt v;
+ MemoryVector<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 = 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);
@@ -116,7 +146,7 @@ Server_Key_Exchange::Server_Key_Exchange(const MemoryRegion<byte>& buf,
const std::string& kex_algo,
const std::string& sig_algo,
Protocol_Version version) :
- m_kex_key(0)
+ m_kex_key(0), m_srp_params(0)
{
if(buf.size() < 6)
throw Decoding_Error("Server_Key_Exchange: Packet corrupted");
@@ -160,13 +190,27 @@ Server_Key_Exchange::Server_Key_Exchange(const MemoryRegion<byte>& buf,
if(name == "")
throw Decoding_Error("Server_Key_Exchange: Server sent unknown named curve " +
- std::to_string(curve_id));
+ 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));
+ MemoryVector<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);
@@ -182,6 +226,12 @@ Server_Key_Exchange::Server_Key_Exchange(const MemoryRegion<byte>& buf,
}
}
+Server_Key_Exchange::~Server_Key_Exchange()
+ {
+ delete m_kex_key;
+ delete m_srp_params;
+ }
+
/**
* Serialize a Server Key Exchange message
@@ -211,7 +261,7 @@ MemoryVector<byte> Server_Key_Exchange::serialize() const
bool Server_Key_Exchange::verify(const X509_Certificate& cert,
Handshake_State* state) const
{
- std::unique_ptr<Public_Key> key(cert.subject_public_key());
+ std::auto_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, false);
@@ -230,6 +280,15 @@ const Private_Key& Server_Key_Exchange::server_kex_key() const
BOTAN_ASSERT(m_kex_key, "Key is non-NULL");
return *m_kex_key;
}
+
+// Only valid for SRP negotiation
+SRP6_Server_Session& Server_Key_Exchange::server_srp_params()
+ {
+ BOTAN_ASSERT(m_srp_params, "SRP params are non-NULL");
+ return *m_srp_params;
+ }
+}
+
}
}
diff --git a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp
index 175adad6c..aa9385d70 100644
--- a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp
+++ b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp
@@ -9,9 +9,9 @@
#include <botan/internal/assert.h>
#include <botan/lookup.h>
#include <botan/hex.h>
+#include <botan/time.h>
#include <botan/loadstor.h>
#include <memory>
-#include <chrono>
#include <sqlite3.h>
@@ -86,6 +86,38 @@ class sqlite3_statement
{}
}
+ std::pair<const byte*, size_t> get_blob(int column)
+ {
+ BOTAN_ASSERT(sqlite3_column_type(m_stmt, 0) == SQLITE_BLOB,
+ "Return value is a blob");
+
+ const void* session_blob = sqlite3_column_blob(m_stmt, column);
+ const int session_blob_size = sqlite3_column_bytes(m_stmt, column);
+
+ BOTAN_ASSERT(session_blob_size >= 0, "Blob size is non-negative");
+
+ return std::make_pair(static_cast<const byte*>(session_blob),
+ static_cast<size_t>(session_blob_size));
+ }
+
+ size_t get_size_t(int column)
+ {
+ BOTAN_ASSERT(sqlite3_column_type(m_stmt, column) == SQLITE_INTEGER,
+ "Return count is an integer");
+
+ const int sessions_int = sqlite3_column_int(m_stmt, column);
+
+ BOTAN_ASSERT(sessions_int >= 0, "Expected size_t is non-negative");
+
+ return static_cast<size_t>(sessions_int);
+ }
+
+ void spin()
+ {
+ while(sqlite3_step(m_stmt) == SQLITE_ROW)
+ {}
+ }
+
int step()
{
return sqlite3_step(m_stmt);
@@ -146,7 +178,7 @@ 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) :
+ u32bit session_lifetime) :
m_rng(rng),
m_max_sessions(max_sessions),
m_session_lifetime(session_lifetime)
@@ -309,7 +341,7 @@ void Session_Manager_SQLite::save(const Session& session)
" values(?1, ?2, ?3, ?4, ?5)");
stmt.bind(1, hex_encode(session.session_id()));
- stmt.bind(2, std::chrono::system_clock::to_time_t(session.start_time()));
+ stmt.bind(2, session.start_time());
stmt.bind(3, session.sni_hostname());
stmt.bind(4, 0);
stmt.bind(5, session.encrypt(m_session_key, m_rng));
@@ -323,8 +355,7 @@ 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::to_time_t(
- std::chrono::system_clock::now() - m_session_lifetime));
+ remove_expired.bind(1, system_time() - m_session_lifetime);
remove_expired.spin();
diff --git a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h
index 1d12b71cd..57e5a58f6 100644
--- a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h
+++ b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h
@@ -5,8 +5,8 @@
* Released under the terms of the Botan license
*/
-#ifndef TLS_SQLITE_SESSION_MANAGER_H__
-#define TLS_SQLITE_SESSION_MANAGER_H__
+#ifndef BOTAN_TLS_SQLITE_SESSION_MANAGER_H__
+#define BOTAN_TLS_SQLITE_SESSION_MANAGER_H__
#include <botan/tls_session_manager.h>
#include <botan/rng.h>
@@ -36,7 +36,7 @@ class BOTAN_DLL Session_Manager_SQLite : public Session_Manager
RandomNumberGenerator& rng,
const std::string& db_filename,
size_t max_sessions = 1000,
- std::chrono::seconds session_lifetime = std::chrono::seconds(7200));
+ u32bit session_lifetime = 7200);
~Session_Manager_SQLite();
@@ -49,6 +49,8 @@ class BOTAN_DLL Session_Manager_SQLite : public Session_Manager
void remove_entry(const MemoryRegion<byte>& session_id);
void save(const Session& session_data);
+
+ u32bit session_lifetime() const { return m_session_lifetime; }
private:
Session_Manager_SQLite(const Session_Manager_SQLite&);
Session_Manager_SQLite& operator=(const Session_Manager_SQLite&);
@@ -58,7 +60,7 @@ class BOTAN_DLL Session_Manager_SQLite : public Session_Manager
SymmetricKey m_session_key;
RandomNumberGenerator& m_rng;
size_t m_max_sessions;
- std::chrono::seconds m_session_lifetime;
+ u32bit m_session_lifetime;
class sqlite3* m_db;
};
diff --git a/src/tls/tls_alert.cpp b/src/tls/tls_alert.cpp
index 30c51d4c8..9b37a282f 100644
--- a/src/tls/tls_alert.cpp
+++ b/src/tls/tls_alert.cpp
@@ -90,14 +90,22 @@ std::string Alert::type_string() const
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 "";
+ return "none";
+
+ case HEARTBEAT_PAYLOAD:
+ return "heartbeat_payload";
}
/*
@@ -106,7 +114,7 @@ std::string Alert::type_string() const
* compiler can warn us that it is not included in the switch
* statement.
*/
- return "unrecognized_alert_" + std::to_string(type());
+ return "unrecognized_alert_" + to_string(type());
}
diff --git a/src/tls/tls_alert.h b/src/tls/tls_alert.h
index 0446a8c30..3dfff3d29 100644
--- a/src/tls/tls_alert.h
+++ b/src/tls/tls_alert.h
@@ -22,37 +22,40 @@ class BOTAN_DLL Alert
{
public:
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,
- UNRECOGNIZED_NAME = 112,
-
- UNKNOWN_PSK_IDENTITY = 115,
-
- NULL_ALERT = 255
+ 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,
+
+ NULL_ALERT = 255,
+
+ HEARTBEAT_PAYLOAD = 256
};
/**
diff --git a/src/tls/tls_channel.cpp b/src/tls/tls_channel.cpp
index 736b37654..86d9db8bd 100644
--- a/src/tls/tls_channel.cpp
+++ b/src/tls/tls_channel.cpp
@@ -8,6 +8,7 @@
#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/assert.h>
#include <botan/loadstor.h>
@@ -15,15 +16,17 @@ namespace Botan {
namespace TLS {
-Channel::Channel(std::function<void (const byte[], size_t)> socket_output_fn,
- std::function<void (const byte[], size_t, Alert)> proc_fn,
- std::function<bool (const Session&)> handshake_complete) :
+Channel::Channel(std::tr1::function<void (const byte[], size_t)> socket_output_fn,
+ std::tr1::function<void (const byte[], size_t, Alert)> proc_fn,
+ std::tr1::function<bool (const Session&)> handshake_complete) :
proc_fn(proc_fn),
handshake_fn(handshake_complete),
writer(socket_output_fn),
state(0),
handshake_completed(false),
- connection_closed(false)
+ connection_closed(false),
+ m_peer_supports_heartbeats(false),
+ m_heartbeat_sending_allowed(false)
{
}
@@ -56,7 +59,30 @@ size_t Channel::received_data(const byte buf[], size_t buf_size)
if(buf_size == 0 && needed != 0)
return needed; // need more data to complete record
- if(rec_type == APPLICATION_DATA)
+ if(rec_type == HANDSHAKE || rec_type == CHANGE_CIPHER_SPEC)
+ {
+ read_handshake(rec_type, record);
+ }
+ else if(rec_type == HEARTBEAT && m_peer_supports_heartbeats)
+ {
+ Heartbeat_Message heartbeat(record);
+
+ const MemoryRegion<byte>& payload = heartbeat.payload();
+
+ if(heartbeat.is_request() && !state)
+ {
+ Heartbeat_Message response(Heartbeat_Message::RESPONSE,
+ payload, payload.size());
+
+ writer.send(HEARTBEAT, response.contents());
+ }
+ else
+ {
+ // pass up to the application
+ proc_fn(&payload[0], payload.size(), Alert(Alert::HEARTBEAT_PAYLOAD));
+ }
+ }
+ else if(rec_type == APPLICATION_DATA)
{
if(handshake_completed)
{
@@ -73,10 +99,6 @@ size_t Channel::received_data(const byte buf[], size_t buf_size)
throw Unexpected_Message("Application data before handshake done");
}
}
- else if(rec_type == HANDSHAKE || rec_type == CHANGE_CIPHER_SPEC)
- {
- read_handshake(rec_type, record);
- }
else if(rec_type == ALERT)
{
Alert alert_msg(record);
@@ -106,7 +128,7 @@ size_t Channel::received_data(const byte buf[], size_t buf_size)
}
else
throw Unexpected_Message("Unknown TLS message type " +
- std::to_string(rec_type) + " received");
+ to_string(rec_type) + " received");
}
return 0; // on a record boundary
@@ -178,6 +200,20 @@ void Channel::read_handshake(byte rec_type,
}
}
+void Channel::heartbeat(const byte payload[], size_t payload_size)
+ {
+ if(!is_active())
+ throw std::runtime_error("Heartbeat cannot be sent on inactive TLS connection");
+
+ if(m_heartbeat_sending_allowed)
+ {
+ Heartbeat_Message heartbeat(Heartbeat_Message::REQUEST,
+ payload, payload_size);
+
+ writer.send(HEARTBEAT, heartbeat.contents());
+ }
+ }
+
void Channel::send(const byte buf[], size_t buf_size)
{
if(!is_active())
@@ -287,3 +323,5 @@ void Channel::Secure_Renegotiation_State::update(Finished* client_finished,
}
}
+
+}
diff --git a/src/tls/tls_channel.h b/src/tls/tls_channel.h
index 9ab89e5f7..257745d80 100644
--- a/src/tls/tls_channel.h
+++ b/src/tls/tls_channel.h
@@ -54,17 +54,31 @@ class BOTAN_DLL Channel
/**
* Attempt to renegotiate the session
+ * @param force_full_renegotiation if true, require a full renegotiation,
+ * otherwise allow session resumption
*/
- virtual void renegotiate() = 0;
+ virtual void renegotiate(bool force_full_renegotiation) = 0;
+
+ /**
+ * Attempt to send a heartbeat message (if negotiated with counterparty)
+ * @param payload will be echoed back
+ * @param countents_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(0, 0); }
/**
* @return certificate chain of the peer (may be empty)
*/
std::vector<X509_Certificate> peer_cert_chain() const { return peer_certs; }
- Channel(std::function<void (const byte[], size_t)> socket_output_fn,
- std::function<void (const byte[], size_t, Alert)> proc_fn,
- std::function<bool (const Session&)> handshake_complete);
+ Channel(std::tr1::function<void (const byte[], size_t)> socket_output_fn,
+ std::tr1::function<void (const byte[], size_t, Alert)> proc_fn,
+ std::tr1::function<bool (const Session&)> handshake_complete);
virtual ~Channel();
protected:
@@ -85,8 +99,8 @@ class BOTAN_DLL Channel
virtual void alert_notify(const Alert& alert) = 0;
- std::function<void (const byte[], size_t, Alert)> proc_fn;
- std::function<bool (const Session&)> handshake_fn;
+ std::tr1::function<void (const byte[], size_t, Alert)> proc_fn;
+ std::tr1::function<bool (const Session&)> handshake_fn;
Record_Writer writer;
Record_Reader reader;
@@ -130,6 +144,8 @@ class BOTAN_DLL Channel
bool handshake_completed;
bool connection_closed;
+ bool m_peer_supports_heartbeats;
+ bool m_heartbeat_sending_allowed;
};
}
diff --git a/src/tls/tls_ciphersuite.cpp b/src/tls/tls_ciphersuite.cpp
index 89daaf679..798df0186 100644
--- a/src/tls/tls_ciphersuite.cpp
+++ b/src/tls/tls_ciphersuite.cpp
@@ -1,12 +1,11 @@
/*
-* TLS Cipher Suites
+* TLS Cipher Suite
* (C) 2004-2010,2012 Jack Lloyd
*
* Released under the terms of the Botan license
*/
#include <botan/tls_ciphersuite.h>
-#include <botan/tls_magic.h>
#include <botan/parsing.h>
#include <sstream>
#include <stdexcept>
@@ -15,246 +14,6 @@ namespace Botan {
namespace TLS {
-/**
-* Convert an SSL/TLS ciphersuite to algorithm fields
-*/
-Ciphersuite Ciphersuite::by_id(u16bit suite)
- {
- switch(static_cast<Ciphersuite_Code>(suite))
- {
- // RSA ciphersuites
-
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- return Ciphersuite("RSA", "RSA", "SHA-1", "AES-128", 16);
-
- case TLS_RSA_WITH_AES_256_CBC_SHA:
- return Ciphersuite("RSA", "RSA", "SHA-1", "AES-256", 32);
-
- case TLS_RSA_WITH_AES_128_CBC_SHA256:
- return Ciphersuite("RSA", "RSA", "SHA-256", "AES-128", 16);
-
- case TLS_RSA_WITH_AES_256_CBC_SHA256:
- return Ciphersuite("RSA", "RSA", "SHA-256", "AES-256", 32);
-
- case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
- return Ciphersuite("RSA", "RSA", "SHA-1", "3DES", 24);
-
- case TLS_RSA_WITH_RC4_128_SHA:
- return Ciphersuite("RSA", "RSA", "SHA-1", "ARC4", 16);
-
- case TLS_RSA_WITH_RC4_128_MD5:
- return Ciphersuite("RSA", "RSA", "MD5", "ARC4", 16);
-
- case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
- return Ciphersuite("RSA", "RSA", "SHA-1", "Camellia", 16);
-
- case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
- return Ciphersuite("RSA", "RSA", "SHA-1", "Camellia", 32);
-
- case TLS_RSA_WITH_SEED_CBC_SHA:
- return Ciphersuite("RSA", "RSA", "SHA-1", "SEED", 16);
-
-#if defined(BOTAN_HAS_IDEA)
- case TLS_RSA_WITH_IDEA_CBC_SHA:
- return Ciphersuite("RSA", "RSA", "SHA-1", "IDEA", 16);
-#endif
-
- // DH/DSS ciphersuites
-
- case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
- return Ciphersuite("DSA", "DH", "SHA-1", "AES-128", 16);
-
- case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
- return Ciphersuite("DSA", "DH", "SHA-1", "AES-256", 32);
-
- case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
- return Ciphersuite("DSA", "DH", "SHA-256", "AES-128", 16);
-
- case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
- return Ciphersuite("DSA", "DH", "SHA-256", "AES-256", 32);
-
- case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
- return Ciphersuite("DSA", "DH", "SHA-1", "3DES", 24);
-
- case TLS_DHE_DSS_WITH_RC4_128_SHA:
- return Ciphersuite("DSA", "DH", "SHA-1", "ARC4", 16);
-
- case TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
- return Ciphersuite("DSA", "DH", "SHA-1", "Camellia", 16);
-
- case TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
- return Ciphersuite("DSA", "DH", "SHA-1", "Camellia", 32);
-
- case TLS_DHE_DSS_WITH_SEED_CBC_SHA:
- return Ciphersuite("DSA", "DH", "SHA-1", "SEED", 16);
-
- // DH/RSA ciphersuites
-
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
- return Ciphersuite("RSA", "DH", "SHA-1", "AES-128", 16);
-
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
- return Ciphersuite("RSA", "DH", "SHA-1", "AES-256", 32);
-
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
- return Ciphersuite("RSA", "DH", "SHA-256", "AES-128", 16);
-
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
- return Ciphersuite("RSA", "DH", "SHA-256", "AES-256", 32);
-
- case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
- return Ciphersuite("RSA", "DH", "SHA-1", "3DES", 24);
-
- case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
- return Ciphersuite("RSA", "DH", "SHA-1", "Camellia", 16);
-
- case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
- return Ciphersuite("RSA", "DH", "SHA-1", "Camellia", 32);
-
- case TLS_DHE_RSA_WITH_SEED_CBC_SHA:
- return Ciphersuite("RSA", "DH", "SHA-1", "SEED", 16);
-
- // ECDH/RSA ciphersuites
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
- return Ciphersuite("RSA", "ECDH", "SHA-1", "AES-128", 16);
-
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- return Ciphersuite("RSA", "ECDH", "SHA-1", "AES-256", 32);
-
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
- return Ciphersuite("RSA", "ECDH", "SHA-256", "AES-128", 16);
-
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
- return Ciphersuite("RSA", "ECDH", "SHA-384", "AES-256", 32);
-
- case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- return Ciphersuite("RSA", "ECDH", "SHA-1", "3DES", 24);
-
- case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- return Ciphersuite("RSA", "ECDH", "SHA-1", "ARC4", 16);
-
- // ECDH/ECDSA ciphersuites
-
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
- return Ciphersuite("ECDSA", "ECDH", "SHA-1", "AES-128", 16);
-
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- return Ciphersuite("ECDSA", "ECDH", "SHA-1", "AES-256", 32);
-
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
- return Ciphersuite("ECDSA", "ECDH", "SHA-256", "AES-128", 16);
-
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
- return Ciphersuite("ECDSA", "ECDH", "SHA-384", "AES-256", 32);
-
- case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- return Ciphersuite("ECDSA", "ECDH", "SHA-1", "ARC4", 16);
-
- case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- return Ciphersuite("ECDSA", "ECDH", "SHA-1", "3DES", 24);
-
- // PSK ciphersuites
-
- case TLS_PSK_WITH_RC4_128_SHA:
- return Ciphersuite("", "PSK", "SHA-1", "ARC4", 16);
-
- case TLS_PSK_WITH_3DES_EDE_CBC_SHA:
- return Ciphersuite("", "PSK", "SHA-1", "3DES", 24);
-
- case TLS_PSK_WITH_AES_128_CBC_SHA:
- return Ciphersuite("", "PSK", "SHA-1", "AES-128", 16);
-
- case TLS_PSK_WITH_AES_128_CBC_SHA256:
- return Ciphersuite("", "PSK", "SHA-256", "AES-128", 16);
-
- case TLS_PSK_WITH_AES_256_CBC_SHA:
- return Ciphersuite("", "PSK", "SHA-1", "AES-256", 32);
-
- case TLS_PSK_WITH_AES_256_CBC_SHA384:
- return Ciphersuite("", "PSK", "SHA-384", "AES-256", 32);
-
- // PSK+DH ciphersuites
-
- case TLS_DHE_PSK_WITH_RC4_128_SHA:
- return Ciphersuite("", "DHE_PSK", "SHA-1", "ARC4", 16);
-
- case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
- return Ciphersuite("", "DHE_PSK", "SHA-1", "3DES", 24);
-
- case TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
- return Ciphersuite("", "DHE_PSK", "SHA-1", "AES-128", 16);
-
- case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
- return Ciphersuite("", "DHE_PSK", "SHA-256", "AES-128", 16);
-
- case TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
- return Ciphersuite("", "DHE_PSK", "SHA-1", "AES-256", 32);
-
- case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
- return Ciphersuite("", "DHE_PSK", "SHA-384", "AES-256", 32);
-
- // PSK+ECDH ciphersuites
-
- case TLS_ECDHE_PSK_WITH_RC4_128_SHA:
- return Ciphersuite("", "ECDHE_PSK", "SHA-1", "ARC4", 16);
-
- case TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
- return Ciphersuite("", "ECDHE_PSK", "SHA-1", "3DES", 24);
-
- case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
- return Ciphersuite("", "ECDHE_PSK", "SHA-1", "AES-128", 16);
-
- case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
- return Ciphersuite("", "ECDHE_PSK", "SHA-256", "AES-128", 16);
-
- case TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
- return Ciphersuite("", "ECDHE_PSK", "SHA-1", "AES-256", 32);
-
- case TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
- return Ciphersuite("", "ECDHE_PSK", "SHA-384", "AES-256", 32);
-
- // SRP ciphersuites
-
- case TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
- return Ciphersuite("", "SRP", "SHA-1", "AES-128", 16);
-
- case TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
- return Ciphersuite("", "SRP", "SHA-1", "AES-256", 32);
-
- case TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
- return Ciphersuite("", "SRP", "SHA-1", "3DES", 24);
-
- // SRP/RSA ciphersuites
-
- case TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
- return Ciphersuite("RSA", "SRP", "SHA-1", "AES-128", 16);
-
- case TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
- return Ciphersuite("RSA", "SRP", "SHA-1", "AES-256", 32);
-
- case TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
- return Ciphersuite("RSA", "SRP", "SHA-1", "3DES", 24);
-
- // SRP/DSA ciphersuites
-
- case TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
- return Ciphersuite("DSA", "SRP", "SHA-1", "AES-128", 16);
-
- case TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
- return Ciphersuite("DSA", "SRP", "SHA-1", "AES-256", 32);
-
- case TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
- return Ciphersuite("DSA", "SRP", "SHA-1", "3DES", 24);
-
- // Signaling ciphersuite values
-
- case TLS_EMPTY_RENEGOTIATION_INFO_SCSV:
- return Ciphersuite();
- }
-
- return Ciphersuite(); // some unknown ciphersuite
- }
-
Ciphersuite Ciphersuite::by_name(const std::string& name)
{
for(size_t i = 0; i != 65536; ++i)
@@ -271,6 +30,18 @@ Ciphersuite Ciphersuite::by_name(const std::string& name)
return Ciphersuite(); // some unknown ciphersuite
}
+bool Ciphersuite::psk_ciphersuite() const
+ {
+ return (kex_algo() == "PSK" ||
+ kex_algo() == "DHE_PSK" ||
+ kex_algo() == "ECDHE_PSK");
+ }
+
+bool Ciphersuite::ecc_ciphersuite() const
+ {
+ return (kex_algo() == "ECDH" || sig_algo() == "ECDSA");
+ }
+
std::string Ciphersuite::to_string() const
{
if(m_cipher_keylen == 0)
@@ -286,8 +57,6 @@ std::string Ciphersuite::to_string() const
out << "DHE";
else if(kex_algo() == "ECDH")
out << "ECDHE";
- else if(kex_algo() == "SRP")
- out << "SRP_SHA";
else
out << kex_algo();
@@ -310,7 +79,7 @@ std::string Ciphersuite::to_string() const
if(cipher_algo() == "3DES")
out << "3DES_EDE";
else if(cipher_algo() == "Camellia")
- out << "CAMELLIA_" << std::to_string(8*cipher_keylen());
+ out << "CAMELLIA_" << Botan::to_string(8*cipher_keylen());
else
out << replace_char(cipher_algo(), '-', '_');
@@ -329,18 +98,7 @@ std::string Ciphersuite::to_string() const
return out.str();
}
-Ciphersuite::Ciphersuite(const std::string& sig_algo,
- const std::string& kex_algo,
- const std::string& mac_algo,
- const std::string& cipher_algo,
- size_t cipher_algo_keylen) :
- m_sig_algo(sig_algo),
- m_kex_algo(kex_algo),
- m_mac_algo(mac_algo),
- m_cipher_algo(cipher_algo),
- m_cipher_keylen(cipher_algo_keylen)
- {
- }
+}
}
diff --git a/src/tls/tls_ciphersuite.h b/src/tls/tls_ciphersuite.h
index e5d8c967b..dcb4b6a6f 100644
--- a/src/tls/tls_ciphersuite.h
+++ b/src/tls/tls_ciphersuite.h
@@ -21,6 +21,9 @@ namespace TLS {
class BOTAN_DLL Ciphersuite
{
public:
+ /**
+ * Convert an SSL/TLS ciphersuite to algorithm fields
+ */
static Ciphersuite by_id(u16bit suite);
static Ciphersuite by_name(const std::string& name);
@@ -30,6 +33,9 @@ class BOTAN_DLL Ciphersuite
*/
std::string to_string() const;
+ bool psk_ciphersuite() const;
+ bool ecc_ciphersuite() const;
+
std::string kex_algo() const { return m_kex_algo; }
std::string sig_algo() const { return m_sig_algo; }
@@ -46,7 +52,15 @@ class BOTAN_DLL Ciphersuite
const std::string& kex_algo,
const std::string& mac_algo,
const std::string& cipher_algo,
- size_t cipher_algo_keylen);
+ size_t cipher_algo_keylen) :
+ m_sig_algo(sig_algo),
+ m_kex_algo(kex_algo),
+ m_mac_algo(mac_algo),
+ m_cipher_algo(cipher_algo),
+ m_cipher_keylen(cipher_algo_keylen)
+ {
+ }
+
private:
std::string m_sig_algo, m_kex_algo, m_mac_algo, m_cipher_algo;
size_t m_cipher_keylen;
diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp
index 77e87e9bc..63d0ee148 100644
--- a/src/tls/tls_client.cpp
+++ b/src/tls/tls_client.cpp
@@ -18,20 +18,21 @@ namespace TLS {
/*
* TLS Client Constructor
*/
-Client::Client(std::function<void (const byte[], size_t)> output_fn,
- std::function<void (const byte[], size_t, Alert)> proc_fn,
- std::function<bool (const Session&)> handshake_fn,
+Client::Client(std::tr1::function<void (const byte[], size_t)> output_fn,
+ std::tr1::function<void (const byte[], size_t, Alert)> proc_fn,
+ std::tr1::function<bool (const Session&)> handshake_fn,
Session_Manager& session_manager,
Credentials_Manager& creds,
const Policy& policy,
RandomNumberGenerator& rng,
const std::string& hostname,
- std::function<std::string (std::vector<std::string>)> next_protocol) :
+ std::tr1::function<std::string (std::vector<std::string>)> next_protocol) :
Channel(output_fn, proc_fn, handshake_fn),
policy(policy),
rng(rng),
session_manager(session_manager),
- creds(creds)
+ creds(creds),
+ m_hostname(hostname)
{
writer.set_version(Protocol_Version::SSL_V3);
@@ -56,6 +57,7 @@ Client::Client(std::function<void (const byte[], size_t)> output_fn,
state->hash,
policy,
rng,
+ secure_renegotiation.for_client_hello(),
session_info,
send_npn_request);
@@ -83,16 +85,42 @@ Client::Client(std::function<void (const byte[], size_t)> output_fn,
/*
* Send a new client hello to renegotiate
*/
-void Client::renegotiate()
+void Client::renegotiate(bool force_full_renegotiation)
{
- if(state)
- return; // currently in handshake
+ if(state && state->client_hello)
+ return; // currently in active handshake
+ delete state;
state = new Handshake_State(new Stream_Handshake_Reader);
+
state->set_expected_next(SERVER_HELLO);
- state->client_hello = new Client_Hello(writer, state->hash, policy, rng,
- secure_renegotiation.for_client_hello());
+ if(!force_full_renegotiation)
+ {
+ Session session_info;
+ if(session_manager.load_from_host_info(m_hostname, 0, session_info))
+ {
+ state->client_hello = new Client_Hello(
+ writer,
+ state->hash,
+ policy,
+ rng,
+ secure_renegotiation.for_client_hello(),
+ session_info);
+
+ state->resume_master_secret = session_info.master_secret();
+ }
+ }
+
+ if(!state->client_hello)
+ {
+ state->client_hello = new Client_Hello(
+ writer,
+ state->hash,
+ policy,
+ rng,
+ secure_renegotiation.for_client_hello());
+ }
secure_renegotiation.update(state->client_hello);
}
@@ -136,11 +164,7 @@ void Client::process_handshake_msg(Handshake_Type type,
return;
}
- state->client_hello = new Client_Hello(writer, state->hash, policy, rng,
- secure_renegotiation.for_client_hello());
- secure_renegotiation.update(state->client_hello);
-
- state->set_expected_next(SERVER_HELLO);
+ renegotiate(false);
return;
}
@@ -188,6 +212,9 @@ void Client::process_handshake_msg(Handshake_Type type,
secure_renegotiation.update(state->server_hello);
+ m_peer_supports_heartbeats = state->server_hello->supports_heartbeats();
+ m_heartbeat_sending_allowed = state->server_hello->peer_can_send_heartbeats();
+
state->suite = Ciphersuite::by_id(state->server_hello->ciphersuite());
const bool server_returned_same_session_id =
@@ -241,8 +268,8 @@ void Client::process_handshake_msg(Handshake_Type type,
ever sent. The server may or may not send a server kex,
depending on if it has an identity hint for us.
- DHE_PSK always sends a server key exchange for the DH
- exchange portion.
+ (EC)DHE_PSK always sends a server key exchange for the
+ DH exchange portion.
*/
state->set_expected_next(SERVER_KEX);
@@ -280,15 +307,14 @@ void Client::process_handshake_msg(Handshake_Type type,
try
{
- const std::string hostname = state->client_hello->sni_hostname();
- creds.verify_certificate_chain("tls-client", hostname, peer_certs);
+ creds.verify_certificate_chain("tls-client", m_hostname, peer_certs);
}
catch(std::exception& e)
{
throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what());
}
- std::unique_ptr<Public_Key> peer_key(peer_certs[0].subject_public_key());
+ std::auto_ptr<Public_Key> peer_key(peer_certs[0].subject_public_key());
if(peer_key->algo_name() != state->suite.sig_algo())
throw TLS_Exception(Alert::ILLEGAL_PARAMETER,
@@ -330,7 +356,7 @@ void Client::process_handshake_msg(Handshake_Type type,
std::vector<X509_Certificate> client_certs =
creds.cert_chain(types,
"tls-client",
- state->client_hello->sni_hostname());
+ m_hostname);
state->client_certs = new Certificate(writer,
state->hash,
@@ -342,6 +368,7 @@ void Client::process_handshake_msg(Handshake_Type type,
state,
creds,
peer_certs,
+ m_hostname,
rng);
state->keys = Session_Keys(state,
@@ -354,7 +381,7 @@ void Client::process_handshake_msg(Handshake_Type type,
Private_Key* private_key =
creds.private_key_for(state->client_certs->cert_chain()[0],
"tls-client",
- state->client_hello->sni_hostname());
+ m_hostname);
state->client_verify = new Certificate_Verify(writer,
state,
@@ -437,7 +464,7 @@ void Client::process_handshake_msg(Handshake_Type type,
state->server_hello->fragment_size(),
peer_certs,
session_ticket,
- state->client_hello->sni_hostname(),
+ m_hostname,
""
);
diff --git a/src/tls/tls_client.h b/src/tls/tls_client.h
index cd972fa28..4efe2a2df 100644
--- a/src/tls/tls_client.h
+++ b/src/tls/tls_client.h
@@ -42,18 +42,18 @@ class BOTAN_DLL Client : public Channel
* called with the list of protocols the server advertised;
* the client should return the protocol it would like to use.
*/
- Client(std::function<void (const byte[], size_t)> socket_output_fn,
- std::function<void (const byte[], size_t, Alert)> proc_fn,
- std::function<bool (const Session&)> handshake_complete,
+ Client(std::tr1::function<void (const byte[], size_t)> socket_output_fn,
+ std::tr1::function<void (const byte[], size_t, Alert)> proc_fn,
+ std::tr1::function<bool (const Session&)> handshake_complete,
Session_Manager& session_manager,
Credentials_Manager& creds,
const Policy& policy,
RandomNumberGenerator& rng,
const std::string& servername = "",
- std::function<std::string (std::vector<std::string>)> next_protocol =
- std::function<std::string (std::vector<std::string>)>());
+ std::tr1::function<std::string (std::vector<std::string>)> next_protocol =
+ std::tr1::function<std::string (std::vector<std::string>)>());
- void renegotiate();
+ void renegotiate(bool force_full_renegotiation);
private:
void process_handshake_msg(Handshake_Type type,
const MemoryRegion<byte>& contents);
@@ -64,6 +64,7 @@ class BOTAN_DLL Client : public Channel
RandomNumberGenerator& rng;
Session_Manager& session_manager;
Credentials_Manager& creds;
+ const std::string m_hostname;
};
}
diff --git a/src/tls/tls_extensions.cpp b/src/tls/tls_extensions.cpp
index c0de24bfe..f1361bbb9 100644
--- a/src/tls/tls_extensions.cpp
+++ b/src/tls/tls_extensions.cpp
@@ -42,6 +42,9 @@ Extension* make_extension(TLS_Data_Reader& reader,
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);
@@ -242,7 +245,7 @@ Maximum_Fragment_Length::Maximum_Fragment_Length(size_t max_fragment)
else if(max_fragment == 4096)
val = 4;
else
- throw std::invalid_argument("Bad setting " + std::to_string(max_fragment) +
+ throw std::invalid_argument("Bad setting " + to_string(max_fragment) +
" for maximum fragment size");
}
@@ -468,11 +471,16 @@ MemoryVector<byte> Signature_Algorithms::serialize() const
for(size_t i = 0; i != m_supported_algos.size(); ++i)
{
- if(m_supported_algos[i].second == "")
- continue;
+ 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_algo_code(m_supported_algos[i].first));
- buf.push_back(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);
diff --git a/src/tls/tls_extensions.h b/src/tls/tls_extensions.h
index 6a97d2560..3fe3f7399 100644
--- a/src/tls/tls_extensions.h
+++ b/src/tls/tls_extensions.h
@@ -32,6 +32,7 @@ enum Handshake_Extension_Type {
TLSEXT_EC_POINT_FORMATS = 11,
TLSEXT_SRP_IDENTIFIER = 12,
TLSEXT_SIGNATURE_ALGORITHMS = 13,
+ TLSEXT_HEARTBEAT_SUPPORT = 15,
TLSEXT_SESSION_TICKET = 35,
@@ -309,6 +310,32 @@ class Signature_Algorithms : public Extension
};
/**
+* 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; }
+
+ MemoryVector<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
diff --git a/src/tls/tls_handshake_hash.cpp b/src/tls/tls_handshake_hash.cpp
index a9bd8dccf..d0c74136b 100644
--- a/src/tls/tls_handshake_hash.cpp
+++ b/src/tls/tls_handshake_hash.cpp
@@ -35,7 +35,7 @@ SecureVector<byte> Handshake_Hash::final(Protocol_Version version,
{
Algorithm_Factory& af = global_state().algorithm_factory();
- std::unique_ptr<HashFunction> hash;
+ std::auto_ptr<HashFunction> hash;
if(version == Protocol_Version::TLS_V10 || version == Protocol_Version::TLS_V11)
{
@@ -43,7 +43,7 @@ SecureVector<byte> Handshake_Hash::final(Protocol_Version version,
}
else if(version == Protocol_Version::TLS_V12)
{
- if(mac_algo == "SHA-1" || mac_algo == "SHA-256")
+ if(mac_algo == "MD5" || mac_algo == "SHA-1" || mac_algo == "SHA-256")
hash.reset(af.make_hash_function("SHA-256"));
else
hash.reset(af.make_hash_function(mac_algo));
@@ -65,8 +65,8 @@ SecureVector<byte> Handshake_Hash::final_ssl3(const MemoryRegion<byte>& secret)
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"));
+ std::auto_ptr<HashFunction> md5(af.make_hash_function("MD5"));
+ std::auto_ptr<HashFunction> sha1(af.make_hash_function("SHA-1"));
md5->update(data);
sha1->update(data);
diff --git a/src/tls/tls_handshake_state.cpp b/src/tls/tls_handshake_state.cpp
index b34d8616d..1a55305e3 100644
--- a/src/tls/tls_handshake_state.cpp
+++ b/src/tls/tls_handshake_state.cpp
@@ -68,7 +68,7 @@ u32bit bitmask_for_handshake_type(Handshake_Type type)
return 0;
default:
- throw Internal_Error("Unknown handshake type " + std::to_string(type));
+ throw Internal_Error("Unknown handshake type " + to_string(type));
}
return 0;
@@ -104,6 +104,8 @@ Handshake_State::Handshake_State(Handshake_Reader* reader)
hand_expecting_mask = 0;
hand_received_mask = 0;
+
+ allow_session_resumption = true;
}
void Handshake_State::set_version(const Protocol_Version& version)
@@ -121,8 +123,8 @@ void Handshake_State::confirm_transition_to(Handshake_Type handshake_msg)
if(!ok)
throw Unexpected_Message("Unexpected state transition in handshake, got " +
- std::to_string(handshake_msg) + " mask is " +
- std::to_string(hand_expecting_mask));
+ to_string(handshake_msg) + " mask is " +
+ to_string(hand_expecting_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
@@ -143,6 +145,14 @@ bool Handshake_State::received_handshake_msg(Handshake_Type handshake_msg) const
return (hand_received_mask & mask);
}
+std::string Handshake_State::srp_identifier() const
+ {
+ if(suite.valid() && suite.kex_algo() == "SRP_SHA")
+ return client_hello->srp_identifier();
+
+ return "";
+ }
+
const MemoryRegion<byte>& Handshake_State::session_ticket() const
{
if(new_session_ticket && !new_session_ticket->ticket().empty())
@@ -163,8 +173,12 @@ KDF* Handshake_State::protocol_specific_prf()
}
else if(version() == Protocol_Version::TLS_V12)
{
- if(suite.mac_algo() == "SHA-1" || suite.mac_algo() == "SHA-256")
+ if(suite.mac_algo() == "MD5" ||
+ suite.mac_algo() == "SHA-1" ||
+ suite.mac_algo() == "SHA-256")
+ {
return get_kdf("TLS-12-PRF(SHA-256)");
+ }
return get_kdf("TLS-12-PRF(" + suite.mac_algo() + ")");
}
diff --git a/src/tls/tls_handshake_state.h b/src/tls/tls_handshake_state.h
index d2f64c43b..ec4c2fea8 100644
--- a/src/tls/tls_handshake_state.h
+++ b/src/tls/tls_handshake_state.h
@@ -15,7 +15,20 @@
#include <botan/pubkey.h>
#include <utility>
-#include <functional>
+
+#if defined(BOTAN_USE_STD_TR1)
+
+#if defined(BOTAN_BUILD_COMPILER_IS_MSVC)
+ #include <functional>
+#else
+ #include <tr1/functional>
+#endif
+
+#elif defined(BOTAN_USE_BOOST_TR1)
+ #include <boost/tr1/functional.hpp>
+#else
+ #error "No TR1 library defined for use"
+#endif
namespace Botan {
@@ -51,6 +64,8 @@ class Handshake_State
std::string& sig_algo,
bool for_client_auth);
+ std::string srp_identifier() const;
+
KDF* protocol_specific_prf();
Protocol_Version version() const { return m_version; }
@@ -86,10 +101,15 @@ class Handshake_State
*/
SecureVector<byte> resume_master_secret;
+ /*
+ *
+ */
+ bool allow_session_resumption;
+
/**
* Used by client using NPN
*/
- std::function<std::string (std::vector<std::string>)> client_npn_cb;
+ std::tr1::function<std::string (std::vector<std::string>)> client_npn_cb;
Handshake_Reader* handshake_reader() { return m_handshake_reader; }
private:
diff --git a/src/tls/tls_heartbeats.cpp b/src/tls/tls_heartbeats.cpp
new file mode 100644
index 000000000..a77d23534
--- /dev/null
+++ b/src/tls/tls_heartbeats.cpp
@@ -0,0 +1,78 @@
+/*
+* 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 MemoryRegion<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_len)
+ {
+ }
+
+MemoryVector<byte> Heartbeat_Message::contents() const
+ {
+ MemoryVector<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;
+ }
+
+MemoryVector<byte> Heartbeat_Support_Indicator::serialize() const
+ {
+ MemoryVector<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 " + to_string(code));
+
+ m_peer_allowed_to_send = (code == 1);
+ }
+
+}
+
+}
diff --git a/src/tls/tls_heartbeats.h b/src/tls/tls_heartbeats.h
new file mode 100644
index 000000000..4fa49501b
--- /dev/null
+++ b/src/tls/tls_heartbeats.h
@@ -0,0 +1,40 @@
+/*
+* 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 {
+
+class Heartbeat_Message
+ {
+ public:
+ enum Type { REQUEST = 1, RESPONSE = 2 };
+
+ MemoryVector<byte> contents() const;
+
+ const MemoryRegion<byte>& payload() const { return m_payload; }
+
+ bool is_request() const { return m_type == REQUEST; }
+
+ Heartbeat_Message(const MemoryRegion<byte>& buf);
+
+ Heartbeat_Message(Type type, const byte payload[], size_t payload_len);
+ private:
+ Type m_type;
+ MemoryVector<byte> m_payload;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_magic.h b/src/tls/tls_magic.h
index 0e45407d3..2972321c9 100644
--- a/src/tls/tls_magic.h
+++ b/src/tls/tls_magic.h
@@ -32,7 +32,8 @@ enum Record_Type {
CHANGE_CIPHER_SPEC = 20,
ALERT = 21,
HANDSHAKE = 22,
- APPLICATION_DATA = 23
+ APPLICATION_DATA = 23,
+ HEARTBEAT = 24,
};
enum Handshake_Type {
@@ -56,90 +57,6 @@ enum Handshake_Type {
HANDSHAKE_NONE = 255 // Null value
};
-enum Ciphersuite_Code {
- TLS_RSA_WITH_RC4_128_MD5 = 0x0004,
- TLS_RSA_WITH_RC4_128_SHA = 0x0005,
-
- TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A,
- TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F,
- TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035,
- TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C,
- TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D,
- TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0041,
- TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0084,
- TLS_RSA_WITH_SEED_CBC_SHA = 0x0096,
- TLS_RSA_WITH_IDEA_CBC_SHA = 0x0007,
-
- TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013,
- TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032,
- TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038,
- TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040,
- TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A,
- TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044,
- TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0087,
- TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099,
- TLS_DHE_DSS_WITH_RC4_128_SHA = 0x0066,
-
- TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016,
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033,
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039,
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067,
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B,
- TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0045,
- TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088,
- TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A,
-
- TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007,
- TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008,
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009,
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A,
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023,
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024,
-
- TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011,
- TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012,
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013,
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014,
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027,
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028,
-
- TLS_PSK_WITH_RC4_128_SHA = 0x008A,
- TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B,
- TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C,
- TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D,
- TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AE,
- TLS_PSK_WITH_AES_256_CBC_SHA384 = 0x00AF,
-
- TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008E,
- TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008F,
- TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090,
- TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091,
- TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = 0x00B2,
- TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = 0x00B3,
-
- TLS_ECDHE_PSK_WITH_RC4_128_SHA = 0xC033,
- TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = 0xC034,
- TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = 0xC035,
- TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = 0xC036,
- TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = 0xC037,
- TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = 0xC038,
-
- TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01A,
- TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01D,
- TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0xC020,
-
- TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = 0xC01C,
- TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = 0xC01F,
- TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = 0xC022,
-
- TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0xC01B,
- TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0xC01E,
- TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0xC021,
-
- /* signalling values that cannot be negotiated */
- TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF
-};
-
enum Compression_Method {
NO_COMPRESSION = 0x00,
DEFLATE_COMPRESSION = 0x01
diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h
index 2f8af5fd2..d9146dda1 100644
--- a/src/tls/tls_messages.h
+++ b/src/tls/tls_messages.h
@@ -21,6 +21,7 @@
namespace Botan {
class Credentials_Manager;
+class SRP6_Server_Session;
namespace TLS {
@@ -72,15 +73,10 @@ class Client_Hello : public Handshake_Message
{
public:
Handshake_Type type() const { return CLIENT_HELLO; }
+
Protocol_Version version() const { return m_version; }
- const MemoryVector<byte>& session_id() const { return m_session_id; }
- std::vector<byte> session_id_vector() const
- {
- std::vector<byte> v;
- v.insert(v.begin(), &m_session_id[0], &m_session_id[m_session_id.size()]);
- return v;
- }
+ const MemoryVector<byte>& session_id() const { return m_session_id; }
const std::vector<std::pair<std::string, std::string> >& supported_algos() const
{ return m_supported_algos; }
@@ -113,6 +109,10 @@ class Client_Hello : public Handshake_Message
const MemoryRegion<byte>& session_ticket() const
{ return m_session_ticket; }
+ bool supports_heartbeats() const { return m_supports_heartbeats; }
+
+ bool peer_can_send_heartbeats() const { return m_peer_can_send_heartbeats; }
+
Client_Hello(Record_Writer& writer,
Handshake_Hash& hash,
const Policy& policy,
@@ -126,6 +126,7 @@ class Client_Hello : public Handshake_Message
Handshake_Hash& hash,
const Policy& policy,
RandomNumberGenerator& rng,
+ const MemoryRegion<byte>& reneg_info,
const Session& resumed_session,
bool next_protocol = false);
@@ -154,6 +155,9 @@ class Client_Hello : public Handshake_Message
bool m_supports_session_ticket;
MemoryVector<byte> m_session_ticket;
+
+ bool m_supports_heartbeats;
+ bool m_peer_can_send_heartbeats;
};
/**
@@ -163,17 +167,16 @@ class Server_Hello : public Handshake_Message
{
public:
Handshake_Type type() const { return SERVER_HELLO; }
- Protocol_Version version() { return s_version; }
+
+ Protocol_Version version() { return m_version; }
+
+ const MemoryVector<byte>& random() const { return m_random; }
+
const MemoryVector<byte>& session_id() const { return m_session_id; }
- u16bit ciphersuite() const { return suite; }
- byte compression_method() const { return comp_method; }
- std::vector<byte> session_id_vector() const
- {
- std::vector<byte> v;
- v.insert(v.begin(), &m_session_id[0], &m_session_id[m_session_id.size()]);
- return v;
- }
+ u16bit ciphersuite() const { return m_ciphersuite; }
+
+ byte compression_method() const { return m_comp_method; }
bool secure_renegotiation() const { return m_secure_renegotiation; }
@@ -189,20 +192,9 @@ class Server_Hello : public Handshake_Message
const MemoryVector<byte>& renegotiation_info()
{ return m_renegotiation_info; }
- const MemoryVector<byte>& random() const { return s_random; }
+ bool supports_heartbeats() const { return m_supports_heartbeats; }
- Server_Hello(Record_Writer& writer,
- Handshake_Hash& hash,
- Protocol_Version version,
- const Client_Hello& other,
- const std::vector<std::string>& available_cert_types,
- const Policy& policies,
- bool have_session_ticket_key,
- bool client_has_secure_renegotiation,
- const MemoryRegion<byte>& reneg_info,
- bool client_has_npn,
- const std::vector<std::string>& next_protocols,
- RandomNumberGenerator& rng);
+ bool peer_can_send_heartbeats() const { return m_peer_can_send_heartbeats; }
Server_Hello(Record_Writer& writer,
Handshake_Hash& hash,
@@ -213,19 +205,20 @@ class Server_Hello : public Handshake_Message
size_t max_fragment_size,
bool client_has_secure_renegotiation,
const MemoryRegion<byte>& reneg_info,
- bool client_supports_session_tickets,
+ bool offer_session_ticket,
bool client_has_npn,
const std::vector<std::string>& next_protocols,
+ bool client_has_heartbeat,
RandomNumberGenerator& rng);
Server_Hello(const MemoryRegion<byte>& buf);
private:
MemoryVector<byte> serialize() const;
- Protocol_Version s_version;
- MemoryVector<byte> m_session_id, s_random;
- u16bit suite;
- byte comp_method;
+ Protocol_Version m_version;
+ MemoryVector<byte> m_session_id, m_random;
+ u16bit m_ciphersuite;
+ byte m_comp_method;
size_t m_fragment_size;
bool m_secure_renegotiation;
@@ -234,6 +227,9 @@ class Server_Hello : public Handshake_Message
bool m_next_protocol;
std::vector<std::string> m_next_protocols;
bool m_supports_session_ticket;
+
+ bool m_supports_heartbeats;
+ bool m_peer_can_send_heartbeats;
};
/**
@@ -251,6 +247,7 @@ class Client_Key_Exchange : public Handshake_Message
Handshake_State* state,
Credentials_Manager& creds,
const std::vector<X509_Certificate>& peer_certs,
+ const std::string& hostname,
RandomNumberGenerator& rng);
Client_Key_Exchange(const MemoryRegion<byte>& buf,
@@ -408,6 +405,9 @@ class Server_Key_Exchange : public Handshake_Message
// Only valid for certain kex types
const Private_Key& server_kex_key() const;
+ // Only valid for SRP negotiation
+ SRP6_Server_Session& server_srp_params();
+
Server_Key_Exchange(Record_Writer& writer,
Handshake_State* state,
const Policy& policy,
@@ -420,11 +420,12 @@ class Server_Key_Exchange : public Handshake_Message
const std::string& sig_alg,
Protocol_Version version);
- ~Server_Key_Exchange() { delete m_kex_key; }
+ ~Server_Key_Exchange();
private:
MemoryVector<byte> serialize() const;
Private_Key* m_kex_key;
+ SRP6_Server_Session* m_srp_params;
MemoryVector<byte> m_params;
@@ -479,7 +480,7 @@ class New_Session_Ticket : public Handshake_Message
New_Session_Ticket(Record_Writer& writer,
Handshake_Hash& hash,
const MemoryRegion<byte>& ticket,
- u32bit lifetime = 0);
+ u32bit lifetime);
New_Session_Ticket(Record_Writer& writer,
Handshake_Hash& hash);
diff --git a/src/tls/tls_policy.cpp b/src/tls/tls_policy.cpp
index 1ab55f7c6..f240bebac 100644
--- a/src/tls/tls_policy.cpp
+++ b/src/tls/tls_policy.cpp
@@ -11,8 +11,6 @@
#include <botan/tls_exceptn.h>
#include <botan/internal/stl_util.h>
-#include <assert.h>
-
namespace Botan {
namespace TLS {
@@ -25,8 +23,8 @@ std::vector<std::string> Policy::allowed_ciphers() const
allowed.push_back("AES-128");
allowed.push_back("3DES");
allowed.push_back("ARC4");
-
- // Note that Camellia, SEED and IDEA are not included by default
+ //allowed.push_back("Camellia");
+ //allowed.push_back("SEED");
return allowed;
}
@@ -40,7 +38,7 @@ std::vector<std::string> Policy::allowed_hashes() const
allowed.push_back("SHA-256");
allowed.push_back("SHA-224");
allowed.push_back("SHA-1");
- // Note that MD5 is not included by default
+ //allowed.push_back("MD5");
return allowed;
}
@@ -49,13 +47,14 @@ std::vector<std::string> Policy::allowed_key_exchange_methods() const
{
std::vector<std::string> allowed;
- //allowed.push_back("SRP");
+ allowed.push_back("SRP_SHA");
//allowed.push_back("ECDHE_PSK");
//allowed.push_back("DHE_PSK");
//allowed.push_back("PSK");
+
allowed.push_back("ECDH");
allowed.push_back("DH");
- allowed.push_back("RSA"); // RSA via server cert
+ allowed.push_back("RSA");
return allowed;
}
@@ -67,7 +66,7 @@ std::vector<std::string> Policy::allowed_signature_methods() const
allowed.push_back("ECDSA");
allowed.push_back("RSA");
allowed.push_back("DSA");
- allowed.push_back("");
+ //allowed.push_back("");
return allowed;
}
@@ -89,6 +88,40 @@ std::vector<std::string> Policy::allowed_ecc_curves() const
return curves;
}
+/*
+* 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");
+ }
+
+/*
+* Return allowed compression algorithms
+*/
+std::vector<byte> Policy::compression() const
+ {
+ std::vector<byte> algs;
+ algs.push_back(NO_COMPRESSION);
+ return algs;
+ }
+
+u32bit Policy::session_ticket_lifetime() const
+ {
+ return 86400; // 1 day
+ }
+
Protocol_Version Policy::min_version() const
{
return Protocol_Version::SSL_V3;
@@ -173,21 +206,13 @@ class Ciphersuite_Preference_Ordering
}
-std::vector<u16bit> Policy::ciphersuite_list(bool have_srp) const
+std::vector<u16bit> ciphersuite_list(const Policy& policy,
+ bool have_srp)
{
- std::vector<std::string> ciphers = allowed_ciphers();
- std::vector<std::string> hashes = allowed_hashes();
- std::vector<std::string> kex = allowed_key_exchange_methods();
- std::vector<std::string> sigs = allowed_signature_methods();
-
- if(!have_srp)
- {
- std::vector<std::string>::iterator i =
- std::find(kex.begin(), kex.end(), "SRP");
-
- if(i != kex.end())
- kex.erase(i);
- }
+ const std::vector<std::string> ciphers = policy.allowed_ciphers();
+ const std::vector<std::string> hashes = policy.allowed_hashes();
+ const std::vector<std::string> kex = policy.allowed_key_exchange_methods();
+ const std::vector<std::string> sigs = policy.allowed_signature_methods();
Ciphersuite_Preference_Ordering order(ciphers, hashes, kex, sigs);
@@ -201,13 +226,27 @@ std::vector<u16bit> Policy::ciphersuite_list(bool have_srp) const
if(!suite.valid())
continue; // not a ciphersuite we know, skip
- if(value_exists(ciphers, suite.cipher_algo()) &&
- value_exists(hashes, suite.mac_algo()) &&
- value_exists(kex, suite.kex_algo()) &&
- value_exists(sigs, suite.sig_algo()))
+ if(!have_srp && suite.kex_algo() == "SRP_SHA")
+ 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(hashes, suite.mac_algo()))
+ continue; // unsupported MAC algo
+
+ if(!value_exists(sigs, suite.sig_algo()))
{
- ciphersuites[suite] = i;
+ // 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[suite] = i;
}
std::vector<u16bit> ciphersuite_codes;
@@ -221,79 +260,6 @@ std::vector<u16bit> Policy::ciphersuite_list(bool have_srp) const
return ciphersuite_codes;
}
-/*
-* Return allowed compression algorithms
-*/
-std::vector<byte> Policy::compression() const
- {
- std::vector<byte> algs;
- algs.push_back(NO_COMPRESSION);
- return algs;
- }
-
-/*
-* Choose an ECC curve to use
-*/
-std::string Policy::choose_curve(const std::vector<std::string>& curve_names) 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
- }
-
-/*
-* Choose which ciphersuite to use
-*/
-u16bit Policy::choose_suite(const std::vector<u16bit>& client_suites,
- const std::vector<std::string>& available_cert_types,
- bool have_shared_ecc_curve,
- bool have_srp) const
- {
- std::vector<u16bit> ciphersuites = ciphersuite_list(have_srp);
-
- for(size_t i = 0; i != ciphersuites.size(); ++i)
- {
- const u16bit suite_id = ciphersuites[i];
- Ciphersuite suite = Ciphersuite::by_id(suite_id);
-
- if(!have_shared_ecc_curve)
- {
- if(suite.kex_algo() == "ECDH" || suite.sig_algo() == "ECDSA")
- continue;
- }
-
- if(suite.sig_algo() != "" &&
- !value_exists(available_cert_types, suite.sig_algo()))
- {
- continue;
- }
-
- if(value_exists(client_suites, suite_id))
- return suite_id;
- }
-
- return 0; // no shared cipersuite
- }
-
-/*
-* Choose which compression algorithm to use
-*/
-byte Policy::choose_compression(const std::vector<byte>& c_comp) const
- {
- std::vector<byte> s_comp = 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;
- }
-
}
}
diff --git a/src/tls/tls_policy.h b/src/tls/tls_policy.h
index f53b9bab6..c3a0fc29e 100644
--- a/src/tls/tls_policy.h
+++ b/src/tls/tls_policy.h
@@ -82,19 +82,26 @@ class BOTAN_DLL Policy
/**
* Return the group to use for ephemeral Diffie-Hellman key agreement
*/
- virtual DL_Group dh_group() const { return DL_Group("modp/ietf/1536"); }
+ virtual DL_Group dh_group() 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 login to eventually fail without
+ * 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 the minimum version that we are willing to negotiate
*/
virtual Protocol_Version min_version() const;
@@ -104,21 +111,15 @@ class BOTAN_DLL Policy
*/
virtual Protocol_Version pref_version() const;
- /**
- * Return allowed ciphersuites, in order of preference
- */
- std::vector<u16bit> ciphersuite_list(bool have_srp) const;
-
- u16bit choose_suite(const std::vector<u16bit>& client_suites,
- const std::vector<std::string>& available_cert_types,
- bool have_shared_ecc_curve,
- bool have_srp) const;
-
- byte choose_compression(const std::vector<byte>& client_algos) const;
-
virtual ~Policy() {}
};
+/**
+* Return allowed ciphersuites, in order of preference
+*/
+std::vector<u16bit> ciphersuite_list(const Policy& policy,
+ bool have_srp);
+
}
}
diff --git a/src/tls/tls_record.h b/src/tls/tls_record.h
index b966e3c72..680ec8f7b 100644
--- a/src/tls/tls_record.h
+++ b/src/tls/tls_record.h
@@ -22,6 +22,16 @@ namespace Botan {
namespace TLS {
+#elif defined(BOTAN_USE_BOOST_TR1)
+ #include <boost/tr1/functional.hpp>
+#else
+ #error "No TR1 library defined for use"
+#endif
+
+namespace Botan {
+
+namespace TLS {
+
class Session_Keys;
/**
@@ -33,6 +43,9 @@ class BOTAN_DLL Record_Writer
void send(byte type, const byte input[], size_t length);
void send(byte type, byte val) { send(type, &val, 1); }
+ void send(byte type, const MemoryRegion<byte>& input)
+ { send(type, &input[0], input.size()); }
+
MemoryVector<byte> send(class Handshake_Message& msg);
void send_alert(const Alert& alert);
@@ -48,7 +61,7 @@ class BOTAN_DLL Record_Writer
void set_maximum_fragment_size(size_t max_fragment);
- Record_Writer(std::function<void (const byte[], size_t)> output_fn);
+ Record_Writer(std::tr1::function<void (const byte[], size_t)> output_fn);
~Record_Writer() { delete m_mac; }
private:
@@ -57,7 +70,7 @@ class BOTAN_DLL Record_Writer
void send_record(byte type, const byte input[], size_t length);
- std::function<void (const byte[], size_t)> m_output_fn;
+ std::tr1::function<void (const byte[], size_t)> m_output_fn;
MemoryVector<byte> m_writebuf;
diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp
index 3b4a526cc..9da4ca3b8 100644
--- a/src/tls/tls_server.cpp
+++ b/src/tls/tls_server.cpp
@@ -21,7 +21,8 @@ namespace {
bool check_for_resume(Session& session_info,
Session_Manager& session_manager,
Credentials_Manager& credentials,
- Client_Hello* client_hello)
+ Client_Hello* client_hello,
+ u32bit session_ticket_lifetime)
{
const MemoryVector<byte>& client_session_id = client_hello->session_id();
const MemoryVector<byte>& session_ticket = client_hello->session_ticket();
@@ -43,6 +44,10 @@ bool check_for_resume(Session& session_info,
session_info = Session::decrypt(
session_ticket,
credentials.psk("tls-server", "session-ticket", ""));
+
+ if(session_ticket_lifetime &&
+ session_info.session_age() > session_ticket_lifetime)
+ return false; // ticket has expired
}
catch(...)
{
@@ -81,6 +86,79 @@ bool check_for_resume(Session& session_info,
return true;
}
+/*
+* Choose which ciphersuite to use
+*/
+u16bit choose_ciphersuite(
+ const Policy& policy,
+ Credentials_Manager& creds,
+ const std::map<std::string, std::vector<X509_Certificate> >& cert_chains,
+ const Client_Hello* client_hello)
+ {
+ 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 = ciphersuite_list(policy, have_srp);
+
+ if(server_suites.empty())
+ throw Internal_Error("Policy forbids us from negotiating any ciphersuite");
+
+ const bool have_shared_ecc_curve =
+ (policy.choose_curve(client_hello->supported_ecc_curves()) != "");
+
+ // Ordering by our preferences rather than by clients
+ for(size_t i = 0; i != server_suites.size(); ++i)
+ {
+ const u16bit suite_id = server_suites[i];
+
+ if(!value_exists(client_suites, suite_id))
+ continue;
+
+ Ciphersuite suite = Ciphersuite::by_id(suite_id);
+
+ if(!have_shared_ecc_curve && suite.ecc_ciphersuite())
+ continue;
+
+ if(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)
@@ -106,9 +184,9 @@ get_server_certs(const std::string& hostname,
/*
* TLS Server Constructor
*/
-Server::Server(std::function<void (const byte[], size_t)> output_fn,
- std::function<void (const byte[], size_t, Alert)> proc_fn,
- std::function<bool (const Session&)> handshake_fn,
+Server::Server(std::tr1::function<void (const byte[], size_t)> output_fn,
+ std::tr1::function<void (const byte[], size_t, Alert)> proc_fn,
+ std::tr1::function<bool (const Session&)> handshake_fn,
Session_Manager& session_manager,
Credentials_Manager& creds,
const Policy& policy,
@@ -126,12 +204,14 @@ Server::Server(std::function<void (const byte[], size_t)> output_fn,
/*
* Send a hello request to the client
*/
-void Server::renegotiate()
+void Server::renegotiate(bool force_full_renegotiation)
{
if(state)
return; // currently in handshake
state = new Handshake_State(new Stream_Handshake_Reader);
+
+ state->allow_session_resumption = !force_full_renegotiation;
state->set_expected_next(CLIENT_HELLO);
Hello_Request hello_req(writer);
}
@@ -193,7 +273,8 @@ void Server::process_handshake_msg(Handshake_Type type,
{
state->client_hello = new Client_Hello(contents, type);
- m_hostname = state->client_hello->sni_hostname();
+ if(state->client_hello->sni_hostname() != "")
+ m_hostname = state->client_hello->sni_hostname();
Protocol_Version client_version = state->client_hello->version();
@@ -208,14 +289,20 @@ void Server::process_handshake_msg(Handshake_Type type,
secure_renegotiation.update(state->client_hello);
+ m_peer_supports_heartbeats = state->client_hello->supports_heartbeats();
+ m_heartbeat_sending_allowed = state->client_hello->peer_can_send_heartbeats();
+
writer.set_version(state->version());
reader.set_version(state->version());
Session session_info;
- const bool resuming = check_for_resume(session_info,
- session_manager,
- creds,
- state->client_hello);
+ const bool resuming =
+ state->allow_session_resumption &&
+ check_for_resume(session_info,
+ session_manager,
+ creds,
+ state->client_hello,
+ policy.session_ticket_lifetime());
bool have_session_ticket_key = false;
@@ -240,11 +327,16 @@ void Server::process_handshake_msg(Handshake_Type type,
session_info.fragment_size(),
secure_renegotiation.supported(),
secure_renegotiation.for_server_hello(),
- state->client_hello->supports_session_ticket() && have_session_ticket_key,
+ (state->client_hello->supports_session_ticket() &&
+ state->client_hello->session_ticket().empty() &&
+ have_session_ticket_key),
state->client_hello->next_protocol_notification(),
m_possible_protocols,
+ state->client_hello->supports_heartbeats(),
rng);
+ secure_renegotiation.update(state->server_hello);
+
if(session_info.fragment_size())
{
reader.set_maximum_fragment_size(session_info.fragment_size());
@@ -257,13 +349,12 @@ void Server::process_handshake_msg(Handshake_Type type,
if(!handshake_fn(session_info))
{
- if(state->server_hello->supports_session_ticket())
+ 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(writer, state->hash);
- else
- session_manager.remove_entry(session_info.session_id());
}
- // FIXME: should only send a new ticket if we need too (eg old session)
if(state->server_hello->supports_session_ticket() && !state->new_session_ticket)
{
try
@@ -272,7 +363,8 @@ void Server::process_handshake_msg(Handshake_Type type,
state->new_session_ticket =
new New_Session_Ticket(writer, state->hash,
- session_info.encrypt(ticket_key, rng));
+ session_info.encrypt(ticket_key, rng),
+ policy.session_ticket_lifetime());
}
catch(...) {}
@@ -301,29 +393,24 @@ void Server::process_handshake_msg(Handshake_Type type,
cert_chains = get_server_certs("", creds);
}
- std::vector<std::string> available_cert_types;
-
- for(std::map<std::string, std::vector<X509_Certificate> >::const_iterator i = cert_chains.begin();
- i != cert_chains.end(); ++i)
- {
- if(!i->second.empty())
- available_cert_types.push_back(i->first);
- }
-
state->server_hello = new Server_Hello(
writer,
state->hash,
+ rng.random_vec(32), // new session ID
state->version(),
- *(state->client_hello),
- available_cert_types,
- policy,
- have_session_ticket_key,
+ choose_ciphersuite(policy, creds, cert_chains, state->client_hello),
+ choose_compression(policy, state->client_hello->compression_methods()),
+ state->client_hello->fragment_size(),
secure_renegotiation.supported(),
secure_renegotiation.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.update(state->server_hello);
+
if(state->client_hello->fragment_size())
{
reader.set_maximum_fragment_size(state->client_hello->fragment_size());
@@ -381,8 +468,6 @@ void Server::process_handshake_msg(Handshake_Type type,
state->set_expected_next(CERTIFICATE);
}
- secure_renegotiation.update(state->server_hello);
-
/*
* If the client doesn't have a cert they want to use they are
* allowed to send either an empty cert message or proceed
@@ -397,11 +482,6 @@ void Server::process_handshake_msg(Handshake_Type type,
{
state->client_certs = new Certificate(contents);
- // Is this allowed by the protocol?
- if(state->client_certs->count() > 1)
- throw TLS_Exception(Alert::CERTIFICATE_UNKNOWN,
- "Client sent more than one certificate");
-
state->set_expected_next(CLIENT_KEX);
}
else if(type == CLIENT_KEX)
@@ -419,11 +499,10 @@ void Server::process_handshake_msg(Handshake_Type type,
{
state->client_verify = new Certificate_Verify(contents, state->version());
- const std::vector<X509_Certificate>& client_certs =
- state->client_certs->cert_chain();
+ peer_certs = state->client_certs->cert_chain();
const bool sig_valid =
- state->client_verify->verify(client_certs[0], state);
+ state->client_verify->verify(peer_certs[0], state);
state->hash.update(type, contents);
@@ -437,7 +516,7 @@ void Server::process_handshake_msg(Handshake_Type type,
try
{
- creds.verify_certificate_chain("tls-server", "", client_certs);
+ creds.verify_certificate_chain("tls-server", "", peer_certs);
}
catch(std::exception& e)
{
@@ -492,7 +571,7 @@ void Server::process_handshake_msg(Handshake_Type type,
peer_certs,
MemoryVector<byte>(),
m_hostname,
- ""
+ state->srp_identifier()
);
if(handshake_fn(session_info))
@@ -505,7 +584,8 @@ void Server::process_handshake_msg(Handshake_Type type,
state->new_session_ticket =
new New_Session_Ticket(writer, state->hash,
- session_info.encrypt(ticket_key, rng));
+ session_info.encrypt(ticket_key, rng),
+ policy.session_ticket_lifetime());
}
catch(...) {}
}
@@ -522,9 +602,6 @@ void Server::process_handshake_msg(Handshake_Type type,
state->server_hello->compression_method());
state->server_finished = new Finished(writer, state, SERVER);
-
- if(state->client_certs && state->client_verify)
- peer_certs = state->client_certs->cert_chain();
}
secure_renegotiation.update(state->client_finished,
diff --git a/src/tls/tls_server.h b/src/tls/tls_server.h
index a90982066..6ade91afc 100644
--- a/src/tls/tls_server.h
+++ b/src/tls/tls_server.h
@@ -26,9 +26,9 @@ class BOTAN_DLL Server : public Channel
/**
* Server initialization
*/
- Server(std::function<void (const byte[], size_t)> socket_output_fn,
- std::function<void (const byte[], size_t, Alert)> proc_fn,
- std::function<bool (const Session&)> handshake_complete,
+ Server(std::tr1::function<void (const byte[], size_t)> socket_output_fn,
+ std::tr1::function<void (const byte[], size_t, Alert)> proc_fn,
+ std::tr1::function<bool (const Session&)> handshake_complete,
Session_Manager& session_manager,
Credentials_Manager& creds,
const Policy& policy,
@@ -36,7 +36,7 @@ class BOTAN_DLL Server : public Channel
const std::vector<std::string>& protocols =
std::vector<std::string>());
- void renegotiate();
+ void renegotiate(bool force_full_renegotiation);
/**
* Return the server name indicator, if sent by the client
diff --git a/src/tls/tls_session.cpp b/src/tls/tls_session.cpp
index cec1c87ae..0e8bf3051 100644
--- a/src/tls/tls_session.cpp
+++ b/src/tls/tls_session.cpp
@@ -10,6 +10,7 @@
#include <botan/ber_dec.h>
#include <botan/asn1_str.h>
#include <botan/pem.h>
+#include <botan/time.h>
#include <botan/lookup.h>
#include <botan/loadstor.h>
#include <memory>
@@ -30,7 +31,7 @@ Session::Session(const MemoryRegion<byte>& session_identifier,
const MemoryRegion<byte>& ticket,
const std::string& sni_hostname,
const std::string& srp_identifier) :
- m_start_time(std::chrono::system_clock::now()),
+ m_start_time(system_time()),
m_identifier(session_identifier),
m_session_ticket(ticket),
m_master_secret(master_secret),
@@ -63,13 +64,11 @@ Session::Session(const byte ber[], size_t ber_len)
MemoryVector<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(m_start_time)
.decode_integer_type(major_version)
.decode_integer_type(minor_version)
.decode(m_identifier, OCTET_STRING)
@@ -87,7 +86,6 @@ Session::Session(const byte ber[], size_t ber_len)
.verify_end();
m_version = Protocol_Version(major_version, minor_version);
- m_start_time = std::chrono::system_clock::from_time_t(start_time);
m_sni_hostname = sni_hostname_str.value();
m_srp_identifier = srp_identifier_str.value();
m_connection_side = static_cast<Connection_Side>(side_code);
@@ -110,7 +108,7 @@ SecureVector<byte> Session::DER_encode() const
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_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)
@@ -133,6 +131,11 @@ std::string Session::PEM_encode() const
return PEM_Code::encode(this->DER_encode(), "SSL SESSION");
}
+u32bit Session::session_age() const
+ {
+ return (system_time() - m_start_time);
+ }
+
namespace {
const u32bit SESSION_CRYPTO_MAGIC = 0x571B0E4E;
@@ -152,7 +155,7 @@ MemoryVector<byte>
Session::encrypt(const SymmetricKey& master_key,
RandomNumberGenerator& rng) const
{
- std::unique_ptr<KDF> kdf(get_kdf(SESSION_CRYPTO_KDF));
+ std::auto_ptr<KDF> kdf(get_kdf(SESSION_CRYPTO_KDF));
SymmetricKey cipher_key =
kdf->derive_key(CIPHER_KEY_LENGTH,
@@ -166,7 +169,7 @@ Session::encrypt(const SymmetricKey& master_key,
InitializationVector cipher_iv(rng, 16);
- std::unique_ptr<MessageAuthenticationCode> mac(get_mac(SESSION_CRYPTO_MAC));
+ std::auto_ptr<MessageAuthenticationCode> mac(get_mac(SESSION_CRYPTO_MAC));
mac->set_key(mac_key);
Pipe pipe(get_cipher(SESSION_CRYPTO_CIPHER, cipher_key, cipher_iv, ENCRYPTION));
@@ -200,14 +203,14 @@ Session Session::decrypt(const byte buf[], size_t buf_len,
if(load_be<u32bit>(buf, 0) != SESSION_CRYPTO_MAGIC)
throw Decoding_Error("Unknown header value in encrypted session");
- std::unique_ptr<KDF> kdf(get_kdf(SESSION_CRYPTO_KDF));
+ std::auto_ptr<KDF> kdf(get_kdf(SESSION_CRYPTO_KDF));
SymmetricKey mac_key =
kdf->derive_key(MAC_KEY_LENGTH,
master_key.bits_of(),
"tls.session.mac-key");
- std::unique_ptr<MessageAuthenticationCode> mac(get_mac(SESSION_CRYPTO_MAC));
+ std::auto_ptr<MessageAuthenticationCode> mac(get_mac(SESSION_CRYPTO_MAC));
mac->set_key(mac_key);
mac->update(&buf[0], buf_len - MAC_OUTPUT_LENGTH);
diff --git a/src/tls/tls_session.h b/src/tls/tls_session.h
index 8fc048c75..290ee6dcc 100644
--- a/src/tls/tls_session.h
+++ b/src/tls/tls_session.h
@@ -5,8 +5,8 @@
* Released under the terms of the Botan license
*/
-#ifndef TLS_SESSION_STATE_H__
-#define TLS_SESSION_STATE_H__
+#ifndef BOTAN_TLS_SESSION_STATE_H__
+#define BOTAN_TLS_SESSION_STATE_H__
#include <botan/x509cert.h>
#include <botan/tls_version.h>
@@ -14,7 +14,6 @@
#include <botan/tls_magic.h>
#include <botan/secmem.h>
#include <botan/symkey.h>
-#include <chrono>
namespace Botan {
@@ -31,7 +30,7 @@ class BOTAN_DLL Session
* Uninitialized session
*/
Session() :
- m_start_time(std::chrono::system_clock::time_point::min()),
+ m_start_time(0),
m_version(),
m_ciphersuite(0),
m_compression_method(0),
@@ -175,8 +174,12 @@ class BOTAN_DLL Session
/**
* Get the time this session began (seconds since Epoch)
*/
- std::chrono::system_clock::time_point start_time() const
- { return m_start_time; }
+ u64bit start_time() const { return m_start_time; }
+
+ /**
+ * Return how long this session has existed (in seconds)
+ */
+ u32bit session_age() const;
/**
* Return the session ticket the server gave us
@@ -186,7 +189,7 @@ class BOTAN_DLL Session
private:
enum { TLS_SESSION_PARAM_STRUCT_VERSION = 0x2994e300 };
- std::chrono::system_clock::time_point m_start_time;
+ u64bit m_start_time;
MemoryVector<byte> m_identifier;
MemoryVector<byte> m_session_ticket; // only used by client side
diff --git a/src/tls/tls_session_manager.cpp b/src/tls/tls_session_manager.cpp
index 4c6bc1a47..69823e8bd 100644
--- a/src/tls/tls_session_manager.cpp
+++ b/src/tls/tls_session_manager.cpp
@@ -20,7 +20,7 @@ bool Session_Manager_In_Memory::load_from_session_str(
auto i = sessions.find(session_str);
- if(i == sessions.end())
+ if(i == m_sessions.end())
return false;
// if session has expired, remove it
@@ -28,7 +28,7 @@ bool Session_Manager_In_Memory::load_from_session_str(
if(i->second.start_time() + session_lifetime < now)
{
- sessions.erase(i);
+ m_sessions.erase(i);
return false;
}
@@ -75,8 +75,8 @@ void Session_Manager_In_Memory::remove_entry(
auto i = sessions.find(hex_encode(session_id));
- if(i != sessions.end())
- sessions.erase(i);
+ if(i != m_sessions.end())
+ m_sessions.erase(i);
}
void Session_Manager_In_Memory::save(const Session& session)
@@ -89,8 +89,8 @@ void Session_Manager_In_Memory::save(const Session& session)
This removes randomly based on ordering of session ids.
Instead, remove oldest first?
*/
- while(sessions.size() >= max_sessions)
- sessions.erase(sessions.begin());
+ while(m_sessions.size() >= m_max_sessions)
+ m_sessions.erase(m_sessions.begin());
}
const std::string session_id_str = hex_encode(session.session_id());
diff --git a/src/tls/tls_session_manager.h b/src/tls/tls_session_manager.h
index 4152f2392..8a4f31b78 100644
--- a/src/tls/tls_session_manager.h
+++ b/src/tls/tls_session_manager.h
@@ -5,8 +5,8 @@
* Released under the terms of the Botan license
*/
-#ifndef TLS_SESSION_MANAGER_H__
-#define TLS_SESSION_MANAGER_H__
+#ifndef BOTAN_TLS_SESSION_MANAGER_H__
+#define BOTAN_TLS_SESSION_MANAGER_H__
#include <botan/tls_session.h>
#include <mutex>
@@ -65,6 +65,13 @@ class BOTAN_DLL Session_Manager
*/
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 u32bit session_lifetime() const = 0;
+
virtual ~Session_Manager() {}
};
@@ -82,9 +89,9 @@ class BOTAN_DLL Session_Manager_In_Memory : public Session_Manager
* seconds have elapsed from initial handshake.
*/
Session_Manager_In_Memory(size_t max_sessions = 1000,
- std::chrono::seconds session_lifetime = std::chrono::seconds(7200)) :
- max_sessions(max_sessions),
- session_lifetime(session_lifetime)
+ u32bit session_lifetime = 7200) :
+ m_max_sessions(max_sessions),
+ m_session_lifetime(session_lifetime)
{}
bool load_from_session_id(const MemoryRegion<byte>& session_id,
@@ -97,17 +104,18 @@ class BOTAN_DLL Session_Manager_In_Memory : public Session_Manager
void save(const Session& session_data);
+ u32bit session_lifetime() const { return m_session_lifetime; }
+
private:
bool load_from_session_str(const std::string& session_str,
Session& session);
- std::mutex mutex;
+ size_t m_max_sessions;
- size_t max_sessions;
- std::chrono::seconds session_lifetime;
+ u32bit m_session_lifetime;
- std::map<std::string, Session> sessions; // hex(session_id) -> session
- std::map<std::string, std::string> host_sessions;
+ std::map<std::string, Session> m_sessions; // hex(session_id) -> session
+ std::map<std::string, std::string> m_host_sessions;
};
}
diff --git a/src/tls/tls_suite_info.cpp b/src/tls/tls_suite_info.cpp
new file mode 100644
index 000000000..997bda428
--- /dev/null
+++ b/src/tls/tls_suite_info.cpp
@@ -0,0 +1,317 @@
+/*
+* TLS Cipher Suite
+* (C) 2004-2010,2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_ciphersuite.h>
+
+namespace Botan {
+
+namespace TLS {
+
+Ciphersuite Ciphersuite::by_id(u16bit suite)
+ {
+ // Automatically generated by a Python script from the IANA values
+
+ switch(suite)
+ {
+ case 0x0013: // DHE_DSS_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("DSA", "DH", "SHA-1", "3DES", 24);
+
+ case 0x0032: // DHE_DSS_WITH_AES_128_CBC_SHA
+ return Ciphersuite("DSA", "DH", "SHA-1", "AES-128", 16);
+
+ case 0x0040: // DHE_DSS_WITH_AES_128_CBC_SHA256
+ return Ciphersuite("DSA", "DH", "SHA-256", "AES-128", 16);
+
+ case 0x0038: // DHE_DSS_WITH_AES_256_CBC_SHA
+ return Ciphersuite("DSA", "DH", "SHA-1", "AES-256", 32);
+
+ case 0x006A: // DHE_DSS_WITH_AES_256_CBC_SHA256
+ return Ciphersuite("DSA", "DH", "SHA-256", "AES-256", 32);
+
+ case 0x0044: // DHE_DSS_WITH_CAMELLIA_128_CBC_SHA
+ return Ciphersuite("DSA", "DH", "SHA-1", "Camellia-128", 16);
+
+ case 0x00BD: // DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256
+ return Ciphersuite("DSA", "DH", "SHA-256", "Camellia-128", 16);
+
+ case 0x0087: // DHE_DSS_WITH_CAMELLIA_256_CBC_SHA
+ return Ciphersuite("DSA", "DH", "SHA-1", "Camellia-256", 32);
+
+ case 0x00C3: // DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256
+ return Ciphersuite("DSA", "DH", "SHA-256", "Camellia-256", 32);
+
+ case 0x0066: // DHE_DSS_WITH_RC4_128_SHA
+ return Ciphersuite("DSA", "DH", "SHA-1", "ARC4", 16);
+
+ case 0x0099: // DHE_DSS_WITH_SEED_CBC_SHA
+ return Ciphersuite("DSA", "DH", "SHA-1", "SEED", 16);
+
+ case 0x008F: // DHE_PSK_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("", "DHE_PSK", "SHA-1", "3DES", 24);
+
+ case 0x0090: // DHE_PSK_WITH_AES_128_CBC_SHA
+ return Ciphersuite("", "DHE_PSK", "SHA-1", "AES-128", 16);
+
+ case 0x00B2: // DHE_PSK_WITH_AES_128_CBC_SHA256
+ return Ciphersuite("", "DHE_PSK", "SHA-256", "AES-128", 16);
+
+ case 0x0091: // DHE_PSK_WITH_AES_256_CBC_SHA
+ return Ciphersuite("", "DHE_PSK", "SHA-1", "AES-256", 32);
+
+ case 0x00B3: // DHE_PSK_WITH_AES_256_CBC_SHA384
+ return Ciphersuite("", "DHE_PSK", "SHA-384", "AES-256", 32);
+
+ case 0xC096: // DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ return Ciphersuite("", "DHE_PSK", "SHA-256", "Camellia-128", 16);
+
+ case 0xC097: // DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ return Ciphersuite("", "DHE_PSK", "SHA-384", "Camellia-256", 32);
+
+ case 0x008E: // DHE_PSK_WITH_RC4_128_SHA
+ return Ciphersuite("", "DHE_PSK", "SHA-1", "ARC4", 16);
+
+ case 0x0016: // DHE_RSA_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("RSA", "DH", "SHA-1", "3DES", 24);
+
+ case 0x0033: // DHE_RSA_WITH_AES_128_CBC_SHA
+ return Ciphersuite("RSA", "DH", "SHA-1", "AES-128", 16);
+
+ case 0x0067: // DHE_RSA_WITH_AES_128_CBC_SHA256
+ return Ciphersuite("RSA", "DH", "SHA-256", "AES-128", 16);
+
+ case 0x0039: // DHE_RSA_WITH_AES_256_CBC_SHA
+ return Ciphersuite("RSA", "DH", "SHA-1", "AES-256", 32);
+
+ case 0x006B: // DHE_RSA_WITH_AES_256_CBC_SHA256
+ return Ciphersuite("RSA", "DH", "SHA-256", "AES-256", 32);
+
+ case 0x0045: // DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+ return Ciphersuite("RSA", "DH", "SHA-1", "Camellia-128", 16);
+
+ case 0x00BE: // DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ return Ciphersuite("RSA", "DH", "SHA-256", "Camellia-128", 16);
+
+ case 0x0088: // DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+ return Ciphersuite("RSA", "DH", "SHA-1", "Camellia-256", 32);
+
+ case 0x00C4: // DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ return Ciphersuite("RSA", "DH", "SHA-256", "Camellia-256", 32);
+
+ case 0x009A: // DHE_RSA_WITH_SEED_CBC_SHA
+ return Ciphersuite("RSA", "DH", "SHA-1", "SEED", 16);
+
+ case 0x001B: // DH_anon_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("", "DH", "SHA-1", "3DES", 24);
+
+ case 0x0034: // DH_anon_WITH_AES_128_CBC_SHA
+ return Ciphersuite("", "DH", "SHA-1", "AES-128", 16);
+
+ case 0x006C: // DH_anon_WITH_AES_128_CBC_SHA256
+ return Ciphersuite("", "DH", "SHA-256", "AES-128", 16);
+
+ case 0x003A: // DH_anon_WITH_AES_256_CBC_SHA
+ return Ciphersuite("", "DH", "SHA-1", "AES-256", 32);
+
+ case 0x006D: // DH_anon_WITH_AES_256_CBC_SHA256
+ return Ciphersuite("", "DH", "SHA-256", "AES-256", 32);
+
+ case 0x0046: // DH_anon_WITH_CAMELLIA_128_CBC_SHA
+ return Ciphersuite("", "DH", "SHA-1", "Camellia-128", 16);
+
+ case 0x00BF: // DH_anon_WITH_CAMELLIA_128_CBC_SHA256
+ return Ciphersuite("", "DH", "SHA-256", "Camellia-128", 16);
+
+ case 0x0089: // DH_anon_WITH_CAMELLIA_256_CBC_SHA
+ return Ciphersuite("", "DH", "SHA-1", "Camellia-256", 32);
+
+ case 0x00C5: // DH_anon_WITH_CAMELLIA_256_CBC_SHA256
+ return Ciphersuite("", "DH", "SHA-256", "Camellia-256", 32);
+
+ case 0x0018: // DH_anon_WITH_RC4_128_MD5
+ return Ciphersuite("", "DH", "MD5", "ARC4", 16);
+
+ case 0x009B: // DH_anon_WITH_SEED_CBC_SHA
+ return Ciphersuite("", "DH", "SHA-1", "SEED", 16);
+
+ case 0xC008: // ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("ECDSA", "ECDH", "SHA-1", "3DES", 24);
+
+ case 0xC009: // ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+ return Ciphersuite("ECDSA", "ECDH", "SHA-1", "AES-128", 16);
+
+ case 0xC023: // ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+ return Ciphersuite("ECDSA", "ECDH", "SHA-256", "AES-128", 16);
+
+ case 0xC00A: // ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+ return Ciphersuite("ECDSA", "ECDH", "SHA-1", "AES-256", 32);
+
+ case 0xC024: // ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+ return Ciphersuite("ECDSA", "ECDH", "SHA-384", "AES-256", 32);
+
+ case 0xC072: // ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+ return Ciphersuite("ECDSA", "ECDH", "SHA-256", "Camellia-128", 16);
+
+ case 0xC073: // ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+ return Ciphersuite("ECDSA", "ECDH", "SHA-384", "Camellia-256", 32);
+
+ case 0xC007: // ECDHE_ECDSA_WITH_RC4_128_SHA
+ return Ciphersuite("ECDSA", "ECDH", "SHA-1", "ARC4", 16);
+
+ case 0xC034: // ECDHE_PSK_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("", "ECDHE_PSK", "SHA-1", "3DES", 24);
+
+ case 0xC035: // ECDHE_PSK_WITH_AES_128_CBC_SHA
+ return Ciphersuite("", "ECDHE_PSK", "SHA-1", "AES-128", 16);
+
+ case 0xC037: // ECDHE_PSK_WITH_AES_128_CBC_SHA256
+ return Ciphersuite("", "ECDHE_PSK", "SHA-256", "AES-128", 16);
+
+ case 0xC036: // ECDHE_PSK_WITH_AES_256_CBC_SHA
+ return Ciphersuite("", "ECDHE_PSK", "SHA-1", "AES-256", 32);
+
+ case 0xC038: // ECDHE_PSK_WITH_AES_256_CBC_SHA384
+ return Ciphersuite("", "ECDHE_PSK", "SHA-384", "AES-256", 32);
+
+ case 0xC09A: // ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+ return Ciphersuite("", "ECDHE_PSK", "SHA-256", "Camellia-128", 16);
+
+ case 0xC09B: // ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
+ return Ciphersuite("", "ECDHE_PSK", "SHA-384", "Camellia-256", 32);
+
+ case 0xC033: // ECDHE_PSK_WITH_RC4_128_SHA
+ return Ciphersuite("", "ECDHE_PSK", "SHA-1", "ARC4", 16);
+
+ case 0xC012: // ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("RSA", "ECDH", "SHA-1", "3DES", 24);
+
+ case 0xC013: // ECDHE_RSA_WITH_AES_128_CBC_SHA
+ return Ciphersuite("RSA", "ECDH", "SHA-1", "AES-128", 16);
+
+ case 0xC027: // ECDHE_RSA_WITH_AES_128_CBC_SHA256
+ return Ciphersuite("RSA", "ECDH", "SHA-256", "AES-128", 16);
+
+ case 0xC014: // ECDHE_RSA_WITH_AES_256_CBC_SHA
+ return Ciphersuite("RSA", "ECDH", "SHA-1", "AES-256", 32);
+
+ case 0xC028: // ECDHE_RSA_WITH_AES_256_CBC_SHA384
+ return Ciphersuite("RSA", "ECDH", "SHA-384", "AES-256", 32);
+
+ case 0xC076: // ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ return Ciphersuite("RSA", "ECDH", "SHA-256", "Camellia-128", 16);
+
+ case 0xC077: // ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384
+ return Ciphersuite("RSA", "ECDH", "SHA-384", "Camellia-256", 32);
+
+ case 0xC011: // ECDHE_RSA_WITH_RC4_128_SHA
+ return Ciphersuite("RSA", "ECDH", "SHA-1", "ARC4", 16);
+
+ case 0xC017: // ECDH_anon_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("", "ECDH", "SHA-1", "3DES", 24);
+
+ case 0xC018: // ECDH_anon_WITH_AES_128_CBC_SHA
+ return Ciphersuite("", "ECDH", "SHA-1", "AES-128", 16);
+
+ case 0xC019: // ECDH_anon_WITH_AES_256_CBC_SHA
+ return Ciphersuite("", "ECDH", "SHA-1", "AES-256", 32);
+
+ case 0xC016: // ECDH_anon_WITH_RC4_128_SHA
+ return Ciphersuite("", "ECDH", "SHA-1", "ARC4", 16);
+
+ case 0x008B: // PSK_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("", "PSK", "SHA-1", "3DES", 24);
+
+ case 0x008C: // PSK_WITH_AES_128_CBC_SHA
+ return Ciphersuite("", "PSK", "SHA-1", "AES-128", 16);
+
+ case 0x00AE: // PSK_WITH_AES_128_CBC_SHA256
+ return Ciphersuite("", "PSK", "SHA-256", "AES-128", 16);
+
+ case 0x008D: // PSK_WITH_AES_256_CBC_SHA
+ return Ciphersuite("", "PSK", "SHA-1", "AES-256", 32);
+
+ case 0x00AF: // PSK_WITH_AES_256_CBC_SHA384
+ return Ciphersuite("", "PSK", "SHA-384", "AES-256", 32);
+
+ case 0xC094: // PSK_WITH_CAMELLIA_128_CBC_SHA256
+ return Ciphersuite("", "PSK", "SHA-256", "Camellia-128", 16);
+
+ case 0xC095: // PSK_WITH_CAMELLIA_256_CBC_SHA384
+ return Ciphersuite("", "PSK", "SHA-384", "Camellia-256", 32);
+
+ case 0x008A: // PSK_WITH_RC4_128_SHA
+ return Ciphersuite("", "PSK", "SHA-1", "ARC4", 16);
+
+ case 0x000A: // RSA_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("RSA", "RSA", "SHA-1", "3DES", 24);
+
+ case 0x002F: // RSA_WITH_AES_128_CBC_SHA
+ return Ciphersuite("RSA", "RSA", "SHA-1", "AES-128", 16);
+
+ case 0x003C: // RSA_WITH_AES_128_CBC_SHA256
+ return Ciphersuite("RSA", "RSA", "SHA-256", "AES-128", 16);
+
+ case 0x0035: // RSA_WITH_AES_256_CBC_SHA
+ return Ciphersuite("RSA", "RSA", "SHA-1", "AES-256", 32);
+
+ case 0x003D: // RSA_WITH_AES_256_CBC_SHA256
+ return Ciphersuite("RSA", "RSA", "SHA-256", "AES-256", 32);
+
+ case 0x0041: // RSA_WITH_CAMELLIA_128_CBC_SHA
+ return Ciphersuite("RSA", "RSA", "SHA-1", "Camellia-128", 16);
+
+ case 0x00BA: // RSA_WITH_CAMELLIA_128_CBC_SHA256
+ return Ciphersuite("RSA", "RSA", "SHA-256", "Camellia-128", 16);
+
+ case 0x0084: // RSA_WITH_CAMELLIA_256_CBC_SHA
+ return Ciphersuite("RSA", "RSA", "SHA-1", "Camellia-256", 32);
+
+ case 0x00C0: // RSA_WITH_CAMELLIA_256_CBC_SHA256
+ return Ciphersuite("RSA", "RSA", "SHA-256", "Camellia-256", 32);
+
+ case 0x0004: // RSA_WITH_RC4_128_MD5
+ return Ciphersuite("RSA", "RSA", "MD5", "ARC4", 16);
+
+ case 0x0005: // RSA_WITH_RC4_128_SHA
+ return Ciphersuite("RSA", "RSA", "SHA-1", "ARC4", 16);
+
+ case 0x0096: // RSA_WITH_SEED_CBC_SHA
+ return Ciphersuite("RSA", "RSA", "SHA-1", "SEED", 16);
+
+ case 0xC01C: // SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("DSA", "SRP_SHA", "SHA-1", "3DES", 24);
+
+ case 0xC01F: // SRP_SHA_DSS_WITH_AES_128_CBC_SHA
+ return Ciphersuite("DSA", "SRP_SHA", "SHA-1", "AES-128", 16);
+
+ case 0xC022: // SRP_SHA_DSS_WITH_AES_256_CBC_SHA
+ return Ciphersuite("DSA", "SRP_SHA", "SHA-1", "AES-256", 32);
+
+ case 0xC01B: // SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("RSA", "SRP_SHA", "SHA-1", "3DES", 24);
+
+ case 0xC01E: // SRP_SHA_RSA_WITH_AES_128_CBC_SHA
+ return Ciphersuite("RSA", "SRP_SHA", "SHA-1", "AES-128", 16);
+
+ case 0xC021: // SRP_SHA_RSA_WITH_AES_256_CBC_SHA
+ return Ciphersuite("RSA", "SRP_SHA", "SHA-1", "AES-256", 32);
+
+ case 0xC01A: // SRP_SHA_WITH_3DES_EDE_CBC_SHA
+ return Ciphersuite("", "SRP_SHA", "SHA-1", "3DES", 24);
+
+ case 0xC01D: // SRP_SHA_WITH_AES_128_CBC_SHA
+ return Ciphersuite("", "SRP_SHA", "SHA-1", "AES-128", 16);
+
+ case 0xC020: // SRP_SHA_WITH_AES_256_CBC_SHA
+ return Ciphersuite("", "SRP_SHA", "SHA-1", "AES-256", 32);
+ }
+
+ return Ciphersuite(); // some unknown ciphersuite
+ }
+
+}
+
+}