aboutsummaryrefslogtreecommitdiffstats
path: root/src/tls
diff options
context:
space:
mode:
authorlloyd <[email protected]>2012-03-20 21:32:48 +0000
committerlloyd <[email protected]>2012-03-20 21:32:48 +0000
commitff2154e7998b44aa242e55daeeb79c6d5ab9e5df (patch)
treeba1af7aaec56315a27c47b49d7c412754c4fde6b /src/tls
parent9ecf7c11be659502e28407b7e5001d88cba763c2 (diff)
Basic protocol message flow for session tickets
Diffstat (limited to 'src/tls')
-rw-r--r--src/tls/c_hello.cpp4
-rw-r--r--src/tls/info.txt1
-rw-r--r--src/tls/s_hello.cpp8
-rw-r--r--src/tls/tls_client.cpp30
-rw-r--r--src/tls/tls_extensions.cpp2
-rw-r--r--src/tls/tls_handshake_state.cpp9
-rw-r--r--src/tls/tls_handshake_state.h1
-rw-r--r--src/tls/tls_messages.h22
-rw-r--r--src/tls/tls_server.cpp1
-rw-r--r--src/tls/tls_session.cpp88
-rw-r--r--src/tls/tls_session.h18
11 files changed, 120 insertions, 64 deletions
diff --git a/src/tls/c_hello.cpp b/src/tls/c_hello.cpp
index 712fde30c..df76c748f 100644
--- a/src/tls/c_hello.cpp
+++ b/src/tls/c_hello.cpp
@@ -71,8 +71,8 @@ Client_Hello::Client_Hello(Record_Writer& writer,
m_next_protocol(next_protocol),
m_fragment_size(0),
m_secure_renegotiation(true),
- m_supports_session_ticket(true),
- m_renegotiation_info(reneg_info)
+ m_renegotiation_info(reneg_info),
+ m_supports_session_ticket(true)
{
std::vector<std::string> hashes = policy.allowed_hashes();
std::vector<std::string> sigs = policy.allowed_signature_methods();
diff --git a/src/tls/info.txt b/src/tls/info.txt
index 822914a3d..9cc936471 100644
--- a/src/tls/info.txt
+++ b/src/tls/info.txt
@@ -45,6 +45,7 @@ rec_read.cpp
rec_wri.cpp
s_hello.cpp
s_kex.cpp
+session_ticket.cpp
tls_channel.cpp
tls_client.cpp
tls_extensions.cpp
diff --git a/src/tls/s_hello.cpp b/src/tls/s_hello.cpp
index 9bcbdb5e9..3e30382f6 100644
--- a/src/tls/s_hello.cpp
+++ b/src/tls/s_hello.cpp
@@ -89,6 +89,7 @@ Server_Hello::Server_Hello(Record_Writer& writer,
Server_Hello::Server_Hello(const MemoryRegion<byte>& buf)
{
m_secure_renegotiation = false;
+ m_supports_session_ticket = false;
m_next_protocol = false;
if(buf.size() < 38)
@@ -132,6 +133,13 @@ Server_Hello::Server_Hello(const MemoryRegion<byte>& buf)
m_next_protocols = npn->protocols();
m_next_protocol = true;
}
+
+ if(Session_Ticket* ticket = extensions.get<Session_Ticket>())
+ {
+ if(!ticket->contents().empty())
+ throw Decoding_Error("TLS server sent non-empty session ticket extension");
+ m_supports_session_ticket = true;
+ }
}
/*
diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp
index 02e24a1c9..f6e016725 100644
--- a/src/tls/tls_client.cpp
+++ b/src/tls/tls_client.cpp
@@ -11,6 +11,9 @@
#include <botan/internal/stl_util.h>
#include <memory>
+#include <stdio.h>
+#include <botan/hex.h>
+
namespace Botan {
namespace TLS {
@@ -173,6 +176,13 @@ void Client::process_handshake_msg(Handshake_Type type,
"Server sent next protocol but we didn't request it");
}
+ if(state->server_hello->supports_session_ticket())
+ {
+ if(!state->client_hello->supports_session_ticket())
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Server sent session ticket extension but we did not");
+ }
+
state->set_version(state->server_hello->version());
writer.set_version(state->version());
@@ -199,7 +209,10 @@ void Client::process_handshake_msg(Handshake_Type type,
state->resume_master_secret,
true);
- state->set_expected_next(HANDSHAKE_CCS);
+ if(state->server_hello->supports_session_ticket())
+ state->set_expected_next(NEW_SESSION_TICKET);
+ else
+ state->set_expected_next(HANDSHAKE_CCS);
}
else
{
@@ -306,8 +319,6 @@ void Client::process_handshake_msg(Handshake_Type type,
}
else if(type == SERVER_HELLO_DONE)
{
- state->set_expected_next(HANDSHAKE_CCS);
-
state->server_hello_done = new Server_Hello_Done(contents);
if(state->received_handshake_msg(CERTIFICATE_REQUEST))
@@ -364,6 +375,17 @@ void Client::process_handshake_msg(Handshake_Type type,
}
state->client_finished = new Finished(writer, state, CLIENT);
+
+ if(state->server_hello->supports_session_ticket())
+ state->set_expected_next(NEW_SESSION_TICKET);
+ else
+ state->set_expected_next(HANDSHAKE_CCS);
+ }
+ else if(type == NEW_SESSION_TICKET)
+ {
+ state->new_session_ticket = new New_Session_Ticket(contents);
+
+ state->set_expected_next(HANDSHAKE_CCS);
}
else if(type == HANDSHAKE_CCS)
{
@@ -404,6 +426,8 @@ void Client::process_handshake_msg(Handshake_Type type,
secure_renegotiation.supported(),
state->server_hello->fragment_size(),
peer_certs,
+ state->new_session_ticket ? state->new_session_ticket->ticket() :
+ MemoryVector<byte>(),
state->client_hello->sni_hostname(),
""
);
diff --git a/src/tls/tls_extensions.cpp b/src/tls/tls_extensions.cpp
index c1b62ef16..ae236d0c5 100644
--- a/src/tls/tls_extensions.cpp
+++ b/src/tls/tls_extensions.cpp
@@ -507,7 +507,7 @@ Signature_Algorithms::Signature_Algorithms(TLS_Data_Reader& reader,
Session_Ticket::Session_Ticket(const TLS_Data_Reader& reader,
u16bit extension_size)
{
-
+#warning "can't read session tickets"
}
}
diff --git a/src/tls/tls_handshake_state.cpp b/src/tls/tls_handshake_state.cpp
index 2db97db0a..4a82a1641 100644
--- a/src/tls/tls_handshake_state.cpp
+++ b/src/tls/tls_handshake_state.cpp
@@ -54,12 +54,15 @@ u32bit bitmask_for_handshake_type(Handshake_Type type)
case NEXT_PROTOCOL:
return (1 << 9);
- case HANDSHAKE_CCS:
+ case NEW_SESSION_TICKET:
return (1 << 10);
- case FINISHED:
+ case HANDSHAKE_CCS:
return (1 << 11);
+ case FINISHED:
+ return (1 << 12);
+
// allow explicitly disabling new handshakes
case HANDSHAKE_NONE:
return 0;
@@ -85,6 +88,7 @@ Handshake_State::Handshake_State(Handshake_Reader* reader)
cert_req = 0;
server_hello_done = 0;
next_protocol = 0;
+ new_session_ticket = 0;
client_certs = 0;
client_kex = 0;
@@ -287,6 +291,7 @@ Handshake_State::~Handshake_State()
delete cert_req;
delete server_hello_done;
delete next_protocol;
+ delete new_session_ticket;
delete client_certs;
delete client_kex;
diff --git a/src/tls/tls_handshake_state.h b/src/tls/tls_handshake_state.h
index 206e19096..52bfd24b2 100644
--- a/src/tls/tls_handshake_state.h
+++ b/src/tls/tls_handshake_state.h
@@ -80,6 +80,7 @@ class Handshake_State
class Certificate_Verify* client_verify;
class Next_Protocol* next_protocol;
+ class New_Session_Ticket* new_session_ticket;
class Finished* client_finished;
class Finished* server_finished;
diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h
index baee610d9..019dafa69 100644
--- a/src/tls/tls_messages.h
+++ b/src/tls/tls_messages.h
@@ -178,6 +178,8 @@ class Server_Hello : public Handshake_Message
bool next_protocol_notification() const { return m_next_protocol; }
+ bool supports_session_ticket() const { return m_supports_session_ticket; }
+
const std::vector<std::string>& next_protocols() const
{ return m_next_protocols; }
@@ -227,6 +229,7 @@ class Server_Hello : public Handshake_Message
MemoryVector<byte> m_renegotiation_info;
bool m_next_protocol;
+ bool m_supports_session_ticket;
std::vector<std::string> m_next_protocols;
};
@@ -467,23 +470,18 @@ class New_Session_Ticket : public Handshake_Message
public:
Handshake_Type type() const { return NEW_SESSION_TICKET; }
- static Session decrypt(const MemoryRegion<byte>& ctext,
- const SymmetricKey& key,
- const MemoryRegion<byte>& key_name);
-
- const MemoryVector<byte>& contents() const { return m_contents; }
+ u32bit ticket_lifetime_hint() const { return m_ticket_lifetime_hint; }
+ const MemoryVector<byte>& ticket() const { return m_ticket; }
- New_Session_Ticket(const Session& session_info,
- const SymmetricKey& key,
- const MemoryRegion<byte>& key_name,
- RandomNumberGenerator& rng);
+ New_Session_Ticket(const MemoryVector<byte>& ticket, u32bit lifetime = 0) :
+ m_ticket_lifetime_hint(lifetime), m_ticket(ticket) {}
- New_Session_Ticket(const MemoryRegion<byte>& buf) { deserialize(buf); }
+ New_Session_Ticket(const MemoryRegion<byte>& buf);
private:
MemoryVector<byte> serialize() const;
- void deserialize(const MemoryRegion<byte>&);
- MemoryVector<byte> m_contents;
+ u32bit m_ticket_lifetime_hint;
+ MemoryVector<byte> m_ticket;
};
}
diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp
index eacbc02e0..874aa064c 100644
--- a/src/tls/tls_server.cpp
+++ b/src/tls/tls_server.cpp
@@ -447,6 +447,7 @@ void Server::process_handshake_msg(Handshake_Type type,
secure_renegotiation.supported(),
state->server_hello->fragment_size(),
peer_certs,
+ MemoryVector<byte>(),
m_hostname,
""
);
diff --git a/src/tls/tls_session.cpp b/src/tls/tls_session.cpp
index ddf0661c6..3d890210f 100644
--- a/src/tls/tls_session.cpp
+++ b/src/tls/tls_session.cpp
@@ -12,6 +12,7 @@
#include <botan/pem.h>
#include <botan/time.h>
#include <botan/lookup.h>
+#include <botan/loadstor.h>
#include <memory>
namespace Botan {
@@ -27,10 +28,12 @@ Session::Session(const MemoryRegion<byte>& session_identifier,
bool secure_renegotiation_supported,
size_t fragment_size,
const std::vector<X509_Certificate>& certs,
+ const MemoryRegion<byte>& ticket,
const std::string& sni_hostname,
const std::string& srp_identifier) :
m_start_time(system_time()),
m_identifier(session_identifier),
+ m_session_ticket(ticket),
m_master_secret(master_secret),
m_version(version),
m_ciphersuite(ciphersuite),
@@ -44,6 +47,13 @@ Session::Session(const MemoryRegion<byte>& session_identifier,
{
}
+Session::Session(const std::string& pem)
+ {
+ SecureVector<byte> der = PEM_Code::decode_check_label(pem, "SSL SESSION");
+
+ *this = Session(&der[0], der.size());
+ }
+
Session::Session(const byte ber[], size_t ber_len)
{
BER_Decoder decoder(ber, ber_len);
@@ -60,10 +70,11 @@ Session::Session(const byte ber[], size_t ber_len)
.start_cons(SEQUENCE)
.decode_and_check(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION),
"Unknown version in session structure")
- .decode(m_identifier, OCTET_STRING)
.decode_integer_type(m_start_time)
.decode_integer_type(major_version)
.decode_integer_type(minor_version)
+ .decode(m_identifier, OCTET_STRING)
+ .decode(m_session_ticket, OCTET_STRING)
.decode_integer_type(m_ciphersuite)
.decode_integer_type(m_compression_method)
.decode_integer_type(side_code)
@@ -90,13 +101,6 @@ Session::Session(const byte ber[], size_t ber_len)
}
}
-Session::Session(const std::string& pem)
- {
- SecureVector<byte> der = PEM_Code::decode_check_label(pem, "SSL SESSION");
-
- *this = Session(&der[0], der.size());
- }
-
SecureVector<byte> Session::DER_encode() const
{
MemoryVector<byte> peer_cert_bits;
@@ -106,10 +110,11 @@ SecureVector<byte> Session::DER_encode() const
return DER_Encoder()
.start_cons(SEQUENCE)
.encode(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION))
- .encode(m_identifier, OCTET_STRING)
.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)
+ .encode(m_session_ticket, OCTET_STRING)
.encode(static_cast<size_t>(m_ciphersuite))
.encode(static_cast<size_t>(m_compression_method))
.encode(static_cast<size_t>(m_connection_side))
@@ -128,25 +133,23 @@ std::string Session::PEM_encode() const
return PEM_Code::encode(this->DER_encode(), "SSL SESSION");
}
+namespace {
+
+const u64bit ENCRYPTED_SESSION_MAGIC = 0xACE4480800000000;
+
+}
+
MemoryVector<byte>
Session::encrypt(const SymmetricKey& master_key,
- const MemoryRegion<byte>& key_name,
RandomNumberGenerator& rng)
{
- if(key_name.size() != 16)
- throw Encoding_Error("Bad length " + to_string(key_name.size()) +
- " for key_name in TLS_Session::encrypt");
-
- if(master_key.length() == 0)
- throw Decoding_Error("Session encryption key not set");
-
std::auto_ptr<KDF> kdf(get_kdf("KDF2(SHA-256)"));
SymmetricKey aes_key = kdf->derive_key(32, master_key.bits_of(),
- "session-ticket.cipher-key");
+ "tls.session.cipher-key");
SymmetricKey hmac_key = kdf->derive_key(32, master_key.bits_of(),
- "session-ticket.hmac-key");
+ "tls.session.hmac-key");
InitializationVector aes_iv(rng, 16);
@@ -157,8 +160,8 @@ Session::encrypt(const SymmetricKey& master_key,
pipe.process_msg(this->DER_encode());
MemoryVector<byte> ctext = pipe.read_all(0);
- MemoryVector<byte> out;
- out += key_name;
+ MemoryVector<byte> out(8);
+ store_be(ENCRYPTED_SESSION_MAGIC, &out[0]);
out += aes_iv.bits_of();
out += ctext;
@@ -169,25 +172,24 @@ Session::encrypt(const SymmetricKey& master_key,
}
Session Session::decrypt(const MemoryRegion<byte>& buf,
- const SymmetricKey& master_key,
- const MemoryRegion<byte>& key_name)
+ const SymmetricKey& master_key)
{
try
{
- if(buf.size() < (16 + 16 + 32 + 1))
- throw Decoding_Error("Encrypted TLS_Session too short to be real");
-
- if(master_key.length() == 0)
- throw Decoding_Error("Session master_key not set");
-
- if(key_name.size() != 16)
- throw Decoding_Error("Bad length " + to_string(key_name.size()) +
- " for key_name");
+ /*
+ 8 bytes header
+ 16 bytes IV
+ 32 bytes MAC
+ 16 bytes per AES block * 4 blocks (absolute min amount due to
+ 48 bytes master secret)
+ */
+ if(buf.size() < (8 + 16 + 32 + 4*16))
+ throw Decoding_Error("Encrypted TLS session too short to be valid");
std::auto_ptr<KDF> kdf(get_kdf("KDF2(SHA-256)"));
SymmetricKey hmac_key = kdf->derive_key(32, master_key.bits_of(),
- "session-ticket.hmac-key");
+ "tls.session.mac-key");
std::auto_ptr<MessageAuthenticationCode> mac(get_mac("HMAC(SHA-256)"));
mac->set_key(hmac_key);
@@ -196,22 +198,28 @@ Session Session::decrypt(const MemoryRegion<byte>& buf,
MemoryVector<byte> computed_mac = mac->final();
if(!same_mem(&buf[buf.size() - 32], &computed_mac[0], computed_mac.size()))
- throw Decoding_Error("MAC verification failed");
+ throw Decoding_Error("MAC verification failed for encrypted session");
+
+ const u64bit header = load_be<u64bit>(buf, 0);
+
+ if(header != ENCRYPTED_SESSION_MAGIC)
+ throw Decoding_Error("Unknown header value in encrypted session");
SymmetricKey aes_key = kdf->derive_key(32, master_key.bits_of(),
- "session-ticket.cipher-key");
+ "tls.session.cipher-key");
- InitializationVector aes_iv(&buf[16], 16);
+ InitializationVector aes_iv(&buf[8], 16);
Pipe pipe(get_cipher("AES-256/CBC", aes_key, aes_iv, DECRYPTION));
- pipe.process_msg(&buf[16], buf.size() - (16 + 32));
- MemoryVector<byte> ber = pipe.read_all();
+ pipe.process_msg(&buf[8+16], buf.size() - (32 + 8 + 16));
+ SecureVector<byte> ber = pipe.read_all();
return Session(&ber[0], ber.size());
}
- catch(...)
+ catch(std::exception& e)
{
- throw Decoding_Error("Failed to decrypt encrypted session");
+ throw Decoding_Error("Failed to decrypt encrypted session -" +
+ std::string(e.what()));
}
}
diff --git a/src/tls/tls_session.h b/src/tls/tls_session.h
index 64a83367e..ab11154c9 100644
--- a/src/tls/tls_session.h
+++ b/src/tls/tls_session.h
@@ -51,6 +51,7 @@ class BOTAN_DLL Session
bool secure_renegotiation_supported,
size_t fragment_size,
const std::vector<X509_Certificate>& peer_certs,
+ const MemoryRegion<byte>& session_ticket,
const std::string& sni_hostname = "",
const std::string& srp_identifier = "");
@@ -75,12 +76,15 @@ class BOTAN_DLL Session
* Encrypt a session (useful for serialization or session tickets)
*/
MemoryVector<byte> encrypt(const SymmetricKey& key,
- const MemoryRegion<byte>& key_name,
RandomNumberGenerator& rng);
+ /**
+ * Decrypt a session created by encrypt
+ * @param ctext the ciphertext returned by encrypt
+ * @param key the same key used by the encrypting side
+ */
static Session decrypt(const MemoryRegion<byte>& ctext,
- const SymmetricKey& key,
- const MemoryRegion<byte>& key_name);
+ const SymmetricKey& key);
/**
* Encode this session data for storage
@@ -158,12 +162,18 @@ class BOTAN_DLL Session
*/
u64bit start_time() const { return m_start_time; }
+ /**
+ * Return the session ticket the server gave us
+ */
+ const MemoryVector<byte>& session_ticket() const { return m_session_ticket; }
+
private:
- enum { TLS_SESSION_PARAM_STRUCT_VERSION = 1 };
+ enum { TLS_SESSION_PARAM_STRUCT_VERSION = 0x2994e300 };
u64bit m_start_time;
MemoryVector<byte> m_identifier;
+ MemoryVector<byte> m_session_ticket; // only used by client side
SecureVector<byte> m_master_secret;
Protocol_Version m_version;