aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorlloyd <[email protected]>2011-12-31 02:15:18 +0000
committerlloyd <[email protected]>2011-12-31 02:15:18 +0000
commit074ea8fdee34a668c57b19b474468a7e4d581567 (patch)
tree56a6c62787c51ac2d5aa64316d91c2f20010c8a9 /src
parentbf41971fe4ee6a38609e0ea142010b03017e0329 (diff)
Add support for client-side session resumption
Diffstat (limited to 'src')
-rw-r--r--src/tls/hello.cpp23
-rw-r--r--src/tls/tls_channel.h13
-rw-r--r--src/tls/tls_client.cpp143
-rw-r--r--src/tls/tls_client.h2
-rw-r--r--src/tls/tls_handshake_state.h5
-rw-r--r--src/tls/tls_messages.h32
-rw-r--r--src/tls/tls_server.cpp42
-rw-r--r--src/tls/tls_session.h24
-rw-r--r--src/tls/tls_session_manager.cpp8
-rw-r--r--src/tls/tls_session_manager.h37
10 files changed, 228 insertions, 101 deletions
diff --git a/src/tls/hello.cpp b/src/tls/hello.cpp
index fc19f6802..08d8eee8e 100644
--- a/src/tls/hello.cpp
+++ b/src/tls/hello.cpp
@@ -17,7 +17,7 @@ namespace Botan {
/*
* Encode and send a Handshake message
*/
-void HandshakeMessage::send(Record_Writer& writer, TLS_Handshake_Hash& hash) const
+void Handshake_Message::send(Record_Writer& writer, TLS_Handshake_Hash& hash) const
{
MemoryVector<byte> buf = serialize();
MemoryVector<byte> send_buf(4);
@@ -86,6 +86,27 @@ Client_Hello::Client_Hello(Record_Writer& writer,
}
/*
+* Create a new Client Hello message
+*/
+Client_Hello::Client_Hello(Record_Writer& writer,
+ TLS_Handshake_Hash& hash,
+ RandomNumberGenerator& rng,
+ const TLS_Session& session) :
+ c_version(session.version()),
+ sess_id(session.session_id()),
+ c_random(rng.random_vec(32)),
+ requested_hostname(session.sni_hostname()),
+ requested_srp_id(session.srp_identifier()),
+ m_fragment_size(session.fragment_size()),
+ has_secure_renegotiation(session.secure_renegotiation())
+ {
+ suites.push_back(session.ciphersuite());
+ comp_methods.push_back(session.compression_method());
+
+ send(writer, hash);
+ }
+
+/*
* Serialize a Client Hello message
*/
MemoryVector<byte> Client_Hello::serialize() const
diff --git a/src/tls/tls_channel.h b/src/tls/tls_channel.h
index 8eca71305..c1e9e1fda 100644
--- a/src/tls/tls_channel.h
+++ b/src/tls/tls_channel.h
@@ -24,9 +24,8 @@ class BOTAN_DLL TLS_Channel
public:
/**
* Inject TLS traffic received from counterparty
-
* @return a hint as the how many more bytes we need to process the
- current record (this may be 0 if on a record boundary)
+ * current record (this may be 0 if on a record boundary)
*/
virtual size_t received_data(const byte buf[], size_t buf_size);
@@ -43,21 +42,23 @@ class BOTAN_DLL TLS_Channel
/**
* Send a TLS alert message. If the alert is fatal, the
* internal state (keys, etc) will be reset
+ * @param level is warning or fatal
+ * @param type is the type of alert
*/
void alert(Alert_Level level, Alert_Type type);
/**
- * Is the connection active for sending application data?
+ * @return true iff the connection is active for sending application data
*/
bool is_active() const { return handshake_completed && !is_closed(); }
/**
- * Has the connection been definitely closed
+ * @return true iff the connection has been definitely closed
*/
bool is_closed() const { return connection_closed; }
/**
- * Return the negotiated version (if session is currently active)
+ * @return negotiated version (if session is currently active)
*/
Version_Code protocol_version() const;
@@ -67,7 +68,7 @@ class BOTAN_DLL TLS_Channel
virtual void renegotiate() = 0;
/**
- * Return the certificates of the peer
+ * @return certificate chain of the peer (may be empty)
*/
std::vector<X509_Certificate> peer_cert_chain() const { return peer_certs; }
diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp
index 1790151f9..9942c2d44 100644
--- a/src/tls/tls_client.cpp
+++ b/src/tls/tls_client.cpp
@@ -8,10 +8,13 @@
#include <botan/tls_client.h>
#include <botan/internal/tls_session_key.h>
#include <botan/internal/tls_handshake_state.h>
+#include <botan/internal/stl_util.h>
#include <botan/rsa.h>
#include <botan/dsa.h>
#include <botan/dh.h>
+#include <stdio.h>
+
namespace Botan {
/*
@@ -24,7 +27,7 @@ TLS_Client::TLS_Client(std::tr1::function<void (const byte[], size_t)> output_fn
const TLS_Policy& policy,
RandomNumberGenerator& rng,
const std::string& hostname,
- const std::string& srp_username) :
+ const std::string& srp_identifier) :
TLS_Channel(output_fn, proc_fn, handshake_fn),
policy(policy),
rng(rng),
@@ -34,13 +37,36 @@ TLS_Client::TLS_Client(std::tr1::function<void (const byte[], size_t)> output_fn
state = new Handshake_State;
state->set_expected_next(SERVER_HELLO);
- state->client_hello = new Client_Hello(writer,
- state->hash,
- policy,
- rng,
- secure_renegotiation.for_client_hello(),
- hostname,
- srp_username);
+
+ if(hostname != "")
+ {
+ TLS_Session session_info;
+ if(session_manager.load_from_host_info(hostname, 0, session_info))
+ {
+ if(session_info.srp_identifier() == srp_identifier)
+ {
+ state->client_hello = new Client_Hello(
+ writer,
+ state->hash,
+ rng,
+ session_info);
+
+ state->resume_master_secret = session_info.master_secret();
+ }
+ }
+ }
+
+ if(!state->client_hello) // not resuming
+ {
+ state->client_hello = new Client_Hello(
+ writer,
+ state->hash,
+ policy,
+ rng,
+ secure_renegotiation.for_client_hello(),
+ hostname,
+ srp_identifier);
+ }
secure_renegotiation.update(state->client_hello);
}
@@ -128,19 +154,14 @@ void TLS_Client::process_handshake_msg(Handshake_Type type,
"TLS_Client: Server replied with bad ciphersuite");
}
- state->version = state->server_hello->version();
-
- if(state->version > state->client_hello->version())
+ if(!value_exists(state->client_hello->compression_methods(),
+ state->server_hello->compression_method()))
{
throw TLS_Exception(HANDSHAKE_FAILURE,
- "TLS_Client: Server replied with bad version");
+ "TLS_Client: Server replied with bad compression method");
}
- if(state->version < policy.min_version())
- {
- throw TLS_Exception(PROTOCOL_VERSION,
- "TLS_Client: Server is too old for specified policy");
- }
+ state->version = state->server_hello->version();
writer.set_version(state->version);
reader.set_version(state->version);
@@ -149,20 +170,56 @@ void TLS_Client::process_handshake_msg(Handshake_Type type,
state->suite = TLS_Cipher_Suite(state->server_hello->ciphersuite());
- // if resuming, next is HANDSHAKE_CCS
-
- if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON)
- {
- state->set_expected_next(CERTIFICATE);
- }
- else if(state->suite.kex_type() != TLS_ALGO_KEYEXCH_NOKEX)
+ if(!state->server_hello->session_id().empty() &&
+ (state->server_hello->session_id() == state->client_hello->session_id()))
{
- state->set_expected_next(SERVER_KEX);
+ // successful resumption
+
+ /*
+ In this case, we offered the original session and the server
+ must resume with it
+ */
+ if(state->server_hello->version() != state->client_hello->version())
+ throw TLS_Exception(HANDSHAKE_FAILURE,
+ "Server resumed session but with wrong version");
+
+ state->keys = SessionKeys(state->suite, state->version,
+ state->resume_master_secret,
+ state->client_hello->random(),
+ state->server_hello->random(),
+ true);
+
+ state->set_expected_next(HANDSHAKE_CCS);
}
else
{
- state->set_expected_next(CERTIFICATE_REQUEST); // optional
- state->set_expected_next(SERVER_HELLO_DONE);
+ // new session
+
+ if(state->version > state->client_hello->version())
+ {
+ throw TLS_Exception(HANDSHAKE_FAILURE,
+ "TLS_Client: Server replied with bad version");
+ }
+
+ if(state->version < policy.min_version())
+ {
+ throw TLS_Exception(PROTOCOL_VERSION,
+ "TLS_Client: Server is too old for specified policy");
+ }
+
+ if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON)
+ {
+ state->set_expected_next(CERTIFICATE);
+ }
+ else if(state->suite.kex_type() != TLS_ALGO_KEYEXCH_NOKEX)
+ {
+ state->set_expected_next(SERVER_KEX);
+ }
+ else
+ {
+ state->set_expected_next(CERTIFICATE_REQUEST); // optional
+ state->set_expected_next(SERVER_HELLO_DONE);
+ }
}
}
else if(type == CERTIFICATE)
@@ -308,6 +365,38 @@ void TLS_Client::process_handshake_msg(Handshake_Type type,
throw TLS_Exception(DECRYPT_ERROR,
"Finished message didn't verify");
+ state->hash.update(type, contents);
+
+ if(!state->client_finished) // session resume case
+ {
+ writer.send(CHANGE_CIPHER_SPEC, 1);
+
+ writer.activate(state->suite, state->keys, CLIENT);
+
+ state->client_finished = new Finished(writer, state->hash,
+ state->version, CLIENT,
+ state->keys.master_secret());
+ }
+
+ TLS_Session session_info(
+ state->server_hello->session_id(),
+ state->keys.master_secret(),
+ state->server_hello->version(),
+ state->server_hello->ciphersuite(),
+ state->server_hello->compression_method(),
+ CLIENT,
+ secure_renegotiation.supported(),
+ state->server_hello->fragment_size(),
+ peer_certs,
+ state->client_hello->sni_hostname(),
+ ""
+ );
+
+ session_manager.save(session_info);
+
+ if(handshake_fn)
+ handshake_fn(session_info);
+
secure_renegotiation.update(state->client_finished, state->server_finished);
delete state;
diff --git a/src/tls/tls_client.h b/src/tls/tls_client.h
index 75a85f74d..0f654a40f 100644
--- a/src/tls/tls_client.h
+++ b/src/tls/tls_client.h
@@ -25,7 +25,7 @@ class BOTAN_DLL TLS_Client : public TLS_Channel
* @param socket_output_fn is called with data for the outbound socket
* @param proc_fn is called when new data (application or alerts) is received
* @param handshake_complete is called when a handshake is completed
- * @param session_manager manages session resumption
+ * @param session_manager manages session state
* @param policy specifies other connection policy information
* @param rng a random number generator
* @param servername the server's DNS name, if known
diff --git a/src/tls/tls_handshake_state.h b/src/tls/tls_handshake_state.h
index 1602ca17c..f57538478 100644
--- a/src/tls/tls_handshake_state.h
+++ b/src/tls/tls_handshake_state.h
@@ -50,6 +50,11 @@ class Handshake_State
SecureQueue queue;
+ /*
+ * Only used by clients for session resumption
+ */
+ SecureVector<byte> resume_master_secret;
+
Version_Code version;
private:
u32bit hand_expecting_mask, hand_received_mask;
diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h
index 2d66dfa11..f0620003b 100644
--- a/src/tls/tls_messages.h
+++ b/src/tls/tls_messages.h
@@ -9,6 +9,7 @@
#define BOTAN_TLS_MESSAGES_H__
#include <botan/internal/tls_handshake_hash.h>
+#include <botan/tls_session.h>
#include <botan/tls_policy.h>
#include <botan/tls_magic.h>
#include <botan/tls_suites.h>
@@ -25,16 +26,16 @@ class Record_Reader;
/**
* TLS Handshake Message Base Class
*/
-class HandshakeMessage
+class Handshake_Message
{
public:
void send(Record_Writer& writer, TLS_Handshake_Hash& hash) const;
virtual Handshake_Type type() const = 0;
- virtual ~HandshakeMessage() {}
+ virtual ~Handshake_Message() {}
private:
- HandshakeMessage& operator=(const HandshakeMessage&) { return (*this); }
+ Handshake_Message& operator=(const Handshake_Message&) { return (*this); }
virtual MemoryVector<byte> serialize() const = 0;
virtual void deserialize(const MemoryRegion<byte>&) = 0;
};
@@ -42,7 +43,7 @@ class HandshakeMessage
/**
* Client Hello Message
*/
-class Client_Hello : public HandshakeMessage
+class Client_Hello : public Handshake_Message
{
public:
Handshake_Type type() const { return CLIENT_HELLO; }
@@ -82,6 +83,11 @@ class Client_Hello : public HandshakeMessage
const std::string& hostname = "",
const std::string& srp_identifier = "");
+ Client_Hello(Record_Writer& writer,
+ TLS_Handshake_Hash& hash,
+ RandomNumberGenerator& rng,
+ const TLS_Session& resumed_session);
+
Client_Hello(const MemoryRegion<byte>& buf,
Handshake_Type type)
{
@@ -111,7 +117,7 @@ class Client_Hello : public HandshakeMessage
/**
* Server Hello Message
*/
-class Server_Hello : public HandshakeMessage
+class Server_Hello : public Handshake_Message
{
public:
Handshake_Type type() const { return SERVER_HELLO; }
@@ -176,7 +182,7 @@ class Server_Hello : public HandshakeMessage
/**
* Client Key Exchange Message
*/
-class Client_Key_Exchange : public HandshakeMessage
+class Client_Key_Exchange : public Handshake_Message
{
public:
Handshake_Type type() const { return CLIENT_KEX; }
@@ -209,7 +215,7 @@ class Client_Key_Exchange : public HandshakeMessage
/**
* Certificate Message
*/
-class Certificate : public HandshakeMessage
+class Certificate : public Handshake_Message
{
public:
Handshake_Type type() const { return CERTIFICATE; }
@@ -232,7 +238,7 @@ class Certificate : public HandshakeMessage
/**
* Certificate Request Message
*/
-class Certificate_Req : public HandshakeMessage
+class Certificate_Req : public Handshake_Message
{
public:
Handshake_Type type() const { return CERTIFICATE_REQUEST; }
@@ -258,7 +264,7 @@ class Certificate_Req : public HandshakeMessage
/**
* Certificate Verify Message
*/
-class Certificate_Verify : public HandshakeMessage
+class Certificate_Verify : public Handshake_Message
{
public:
Handshake_Type type() const { return CERTIFICATE_VERIFY; }
@@ -291,7 +297,7 @@ class Certificate_Verify : public HandshakeMessage
/**
* Finished Message
*/
-class Finished : public HandshakeMessage
+class Finished : public Handshake_Message
{
public:
Handshake_Type type() const { return FINISHED; }
@@ -327,7 +333,7 @@ class Finished : public HandshakeMessage
/**
* Hello Request Message
*/
-class Hello_Request : public HandshakeMessage
+class Hello_Request : public Handshake_Message
{
public:
Handshake_Type type() const { return HELLO_REQUEST; }
@@ -342,7 +348,7 @@ class Hello_Request : public HandshakeMessage
/**
* Server Key Exchange Message
*/
-class Server_Key_Exchange : public HandshakeMessage
+class Server_Key_Exchange : public Handshake_Message
{
public:
Handshake_Type type() const { return SERVER_KEX; }
@@ -373,7 +379,7 @@ class Server_Key_Exchange : public HandshakeMessage
/**
* Server Hello Done Message
*/
-class Server_Hello_Done : public HandshakeMessage
+class Server_Hello_Done : public Handshake_Message
{
public:
Handshake_Type type() const { return SERVER_HELLO_DONE; }
diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp
index f0d1fb361..0e2e173cf 100644
--- a/src/tls/tls_server.cpp
+++ b/src/tls/tls_server.cpp
@@ -12,6 +12,8 @@
#include <botan/rsa.h>
#include <botan/dh.h>
+#include <stdio.h>
+
namespace Botan {
namespace {
@@ -180,6 +182,8 @@ void TLS_Server::process_handshake_msg(Handshake_Type type,
if(resuming)
{
// resume session
+
+ printf("Resuming a session\n");
state->server_hello = new Server_Hello(
writer,
state->hash,
@@ -377,27 +381,27 @@ void TLS_Server::process_handshake_msg(Handshake_Type type,
if(state->client_certs && state->client_verify)
peer_certs = state->client_certs->cert_chain();
-
- TLS_Session session_info(
- state->server_hello->session_id(),
- state->keys.master_secret(),
- state->server_hello->version(),
- state->server_hello->ciphersuite(),
- state->server_hello->compression_method(),
- SERVER,
- secure_renegotiation.supported(),
- state->server_hello->fragment_size(),
- peer_certs,
- client_requested_hostname,
- ""
- );
-
- session_manager.save(session_info);
-
- if(handshake_fn)
- handshake_fn(session_info);
}
+ TLS_Session session_info(
+ state->server_hello->session_id(),
+ state->keys.master_secret(),
+ state->server_hello->version(),
+ state->server_hello->ciphersuite(),
+ state->server_hello->compression_method(),
+ SERVER,
+ secure_renegotiation.supported(),
+ state->server_hello->fragment_size(),
+ peer_certs,
+ client_requested_hostname,
+ ""
+ );
+
+ session_manager.save(session_info);
+
+ if(handshake_fn)
+ handshake_fn(session_info);
+
secure_renegotiation.update(state->client_finished,
state->server_finished);
diff --git a/src/tls/tls_session.h b/src/tls/tls_session.h
index c713efc87..b4b3861ed 100644
--- a/src/tls/tls_session.h
+++ b/src/tls/tls_session.h
@@ -38,16 +38,16 @@ class BOTAN_DLL TLS_Session
* New session (sets session start time)
*/
TLS_Session(const MemoryRegion<byte>& session_id,
- const MemoryRegion<byte>& master_secret,
- Version_Code version,
- u16bit ciphersuite,
- byte compression_method,
- Connection_Side side,
- bool secure_renegotiation_supported,
- size_t fragment_size,
- const std::vector<X509_Certificate>& peer_certs,
- const std::string& sni_hostname = "",
- const std::string& srp_identifier = "");
+ const MemoryRegion<byte>& master_secret,
+ Version_Code version,
+ u16bit ciphersuite,
+ byte compression_method,
+ Connection_Side side,
+ bool secure_renegotiation_supported,
+ size_t fragment_size,
+ const std::vector<X509_Certificate>& peer_certs,
+ const std::string& sni_hostname = "",
+ const std::string& srp_identifier = "");
/**
* Load a session from BER (created by BER_encode)
@@ -111,9 +111,9 @@ class BOTAN_DLL TLS_Session
size_t fragment_size() const { return m_fragment_size; }
/**
- * Is secure negotiation supported?
+ * Is secure renegotiation supported?
*/
- bool secure_negotiation() const
+ bool secure_renegotiation() const
{ return m_secure_renegotiation_supported; }
/**
diff --git a/src/tls/tls_session_manager.cpp b/src/tls/tls_session_manager.cpp
index 7503b7c28..4a0126fc0 100644
--- a/src/tls/tls_session_manager.cpp
+++ b/src/tls/tls_session_manager.cpp
@@ -9,6 +9,8 @@
#include <botan/hex.h>
#include <botan/time.h>
+#include <stdio.h>
+
namespace Botan {
bool TLS_Session_Manager_In_Memory::load_from_session_str(
@@ -21,7 +23,7 @@ bool TLS_Session_Manager_In_Memory::load_from_session_str(
// session has expired, remove it
const u64bit now = system_time();
- if(i->second.start_time() + session_lifetime >= now)
+ if(i->second.start_time() + session_lifetime < now)
{
sessions.erase(i);
return false;
@@ -32,7 +34,7 @@ bool TLS_Session_Manager_In_Memory::load_from_session_str(
}
bool TLS_Session_Manager_In_Memory::load_from_session_id(
- const MemoryVector<byte>& session_id, TLS_Session& session)
+ const MemoryRegion<byte>& session_id, TLS_Session& session)
{
return load_from_session_str(hex_encode(session_id), session);
}
@@ -60,7 +62,7 @@ bool TLS_Session_Manager_In_Memory::load_from_host_info(
}
void TLS_Session_Manager_In_Memory::remove_entry(
- const MemoryVector<byte>& session_id)
+ const MemoryRegion<byte>& session_id)
{
std::map<std::string, TLS_Session>::iterator i =
sessions.find(hex_encode(session_id));
diff --git a/src/tls/tls_session_manager.h b/src/tls/tls_session_manager.h
index b30de7364..289b76a3b 100644
--- a/src/tls/tls_session_manager.h
+++ b/src/tls/tls_session_manager.h
@@ -28,39 +28,38 @@ class BOTAN_DLL TLS_Session_Manager
/**
* Try to load a saved session (server side)
* @param session_id the session identifier we are trying to resume
- * @param params will be set to the saved session data (if found),
+ * @param session will be set to the saved session data (if found),
or not modified if not found
- * @return true if params was modified
+ * @return true if session was modified
*/
- virtual bool load_from_session_id(const MemoryVector<byte>& session_id,
- TLS_Session& params) = 0;
+ virtual bool load_from_session_id(const MemoryRegion<byte>& session_id,
+ TLS_Session& session) = 0;
/**
* Try to load a saved session (client side)
* @param hostname of the host we are connecting to
* @param port the port number if we know it, or 0 if unknown
- * @param params will be set to the saved session data (if found),
+ * @param session will be set to the saved session data (if found),
or not modified if not found
- * @return true if params was modified
+ * @return true if session was modified
*/
virtual bool load_from_host_info(const std::string& hostname, u16bit port,
- TLS_Session& params) = 0;
+ TLS_Session& session) = 0;
/**
- * Remove this session id from the cache
+ * Remove this session id from the cache, if it exists
*/
- virtual void remove_entry(const MemoryVector<byte>& session_id) = 0;
+ virtual void remove_entry(const MemoryRegion<byte>& session_id) = 0;
/**
* Save a session on a best effort basis; the manager may not in
- * fact be able to save the session for whatever reason, this is
+ * fact be able to save the session for whatever reason; this is
* not an error. Caller cannot assume that calling save followed
- * immediately by find will result in a successful lookup.
+ * immediately by load_from_* will result in a successful lookup.
*
- * @param session_id the session identifier
- * @param params to save
+ * @param session to save
*/
- virtual void save(const TLS_Session& params) = 0;
+ virtual void save(const TLS_Session& session) = 0;
virtual ~TLS_Session_Manager() {}
};
@@ -86,19 +85,19 @@ class BOTAN_DLL TLS_Session_Manager_In_Memory : public TLS_Session_Manager
session_lifetime(session_lifetime)
{}
- bool load_from_session_id(const MemoryVector<byte>& session_id,
- TLS_Session& params);
+ bool load_from_session_id(const MemoryRegion<byte>& session_id,
+ TLS_Session& session);
bool load_from_host_info(const std::string& hostname, u16bit port,
- TLS_Session& params);
+ TLS_Session& session);
- void remove_entry(const MemoryVector<byte>& session_id);
+ void remove_entry(const MemoryRegion<byte>& session_id);
void save(const TLS_Session& session_data);
private:
bool load_from_session_str(const std::string& session_str,
- TLS_Session& params);
+ TLS_Session& session);
size_t max_sessions, session_lifetime;