aboutsummaryrefslogtreecommitdiffstats
path: root/src/tls
diff options
context:
space:
mode:
authorlloyd <[email protected]>2012-04-04 15:09:51 +0000
committerlloyd <[email protected]>2012-04-04 15:09:51 +0000
commitf5d35f360a04acef3ad19b0abf9a830b0d52d5d8 (patch)
treeca23d42ebea4bdfb716e4b552b7befe1f494a53c /src/tls
parent0b7fb2651b187097e9c89e37e2672ff28830371a (diff)
Limit the lifetime of tickets to Policy::session_ticket_lifetime()
seconds and report that value to the client in the NewSessionTicket message. After that point, a session ticket is ignored and a full renegotiation is forced. Only send a new session ticket on a new session, or on a resumed session where the client indicated it supports session tickets but for whatever reason didn't send one in the hello. Perhaps in this case, we should also remove the session from the session manager? Clean up server selection of the ciphersuite a bit, all in an anon function in tls_server instead of scattered over Server, Policy, and Server_Hello. Add Session::session_age and Session_Manager::session_lifetime
Diffstat (limited to 'src/tls')
-rw-r--r--src/tls/s_hello.cpp81
-rw-r--r--src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp2
-rw-r--r--src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h7
-rw-r--r--src/tls/tls_ciphersuite.cpp12
-rw-r--r--src/tls/tls_ciphersuite.h3
-rw-r--r--src/tls/tls_client.cpp4
-rw-r--r--src/tls/tls_extensions.cpp13
-rw-r--r--src/tls/tls_messages.h33
-rw-r--r--src/tls/tls_policy.cpp63
-rw-r--r--src/tls/tls_policy.h7
-rw-r--r--src/tls/tls_server.cpp82
-rw-r--r--src/tls/tls_session.cpp5
-rw-r--r--src/tls/tls_session.h5
-rw-r--r--src/tls/tls_session_manager.cpp34
-rw-r--r--src/tls/tls_session_manager.h23
15 files changed, 196 insertions, 178 deletions
diff --git a/src/tls/s_hello.cpp b/src/tls/s_hello.cpp
index 7da9fdc57..bb93108d9 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,21 @@ 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,
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)
{
hash.update(writer.send(*this));
}
@@ -105,24 +64,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);
@@ -154,16 +113,16 @@ 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;
diff --git a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp
index 4d78a5365..cb831aadf 100644
--- a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp
+++ b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp
@@ -145,7 +145,7 @@ Session_Manager_SQLite::Session_Manager_SQLite(const std::string& passphrase,
RandomNumberGenerator& rng,
const std::string& db_filename,
size_t max_sessions,
- size_t session_lifetime) :
+ u32bit session_lifetime) :
m_rng(rng),
m_max_sessions(max_sessions),
m_session_lifetime(session_lifetime)
diff --git a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h
index 424db24e5..7ac2caeb2 100644
--- a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h
+++ b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.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,
- size_t session_lifetime = 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&);
@@ -57,7 +59,8 @@ class BOTAN_DLL Session_Manager_SQLite : public Session_Manager
SymmetricKey m_session_key;
RandomNumberGenerator& m_rng;
- size_t m_max_sessions, m_session_lifetime;
+ size_t m_max_sessions;
+ u32bit m_session_lifetime;
class sqlite3* m_db;
};
diff --git a/src/tls/tls_ciphersuite.cpp b/src/tls/tls_ciphersuite.cpp
index d3d8f061b..afe0e68ee 100644
--- a/src/tls/tls_ciphersuite.cpp
+++ b/src/tls/tls_ciphersuite.cpp
@@ -30,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)
diff --git a/src/tls/tls_ciphersuite.h b/src/tls/tls_ciphersuite.h
index 6081fc9eb..dcb4b6a6f 100644
--- a/src/tls/tls_ciphersuite.h
+++ b/src/tls/tls_ciphersuite.h
@@ -33,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; }
diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp
index ba9ec8082..2ec7eec2e 100644
--- a/src/tls/tls_client.cpp
+++ b/src/tls/tls_client.cpp
@@ -241,8 +241,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);
diff --git a/src/tls/tls_extensions.cpp b/src/tls/tls_extensions.cpp
index 1ca4e3eb4..59ab64374 100644
--- a/src/tls/tls_extensions.cpp
+++ b/src/tls/tls_extensions.cpp
@@ -468,11 +468,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_messages.h b/src/tls/tls_messages.h
index 2f8af5fd2..920a1c7a7 100644
--- a/src/tls/tls_messages.h
+++ b/src/tls/tls_messages.h
@@ -163,10 +163,10 @@ 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>& session_id() const { return m_session_id; }
- u16bit ciphersuite() const { return suite; }
- byte compression_method() const { return comp_method; }
+ u16bit ciphersuite() const { return m_ciphersuite; }
+ byte compression_method() const { return m_comp_method; }
std::vector<byte> session_id_vector() const
{
@@ -189,20 +189,7 @@ class Server_Hello : public Handshake_Message
const MemoryVector<byte>& renegotiation_info()
{ return m_renegotiation_info; }
- const MemoryVector<byte>& random() const { return s_random; }
-
- 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);
+ const MemoryVector<byte>& random() const { return m_random; }
Server_Hello(Record_Writer& writer,
Handshake_Hash& hash,
@@ -213,7 +200,7 @@ 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,
RandomNumberGenerator& rng);
@@ -222,10 +209,10 @@ class Server_Hello : public Handshake_Message
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;
@@ -479,7 +466,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 a2c0d01f8..3db517e56 100644
--- a/src/tls/tls_policy.cpp
+++ b/src/tls/tls_policy.cpp
@@ -51,9 +51,10 @@ std::vector<std::string> Policy::allowed_key_exchange_methods() const
//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;
}
@@ -87,6 +88,11 @@ std::vector<std::string> Policy::allowed_ecc_curves() const
return curves;
}
+u32bit Policy::session_ticket_lifetime() const
+ {
+ return 86400; // 1 day
+ }
+
Protocol_Version Policy::min_version() const
{
return Protocol_Version::SSL_V3;
@@ -199,13 +205,24 @@ 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(!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;
@@ -244,40 +261,6 @@ std::string Policy::choose_curve(const std::vector<std::string>& curve_names) co
}
/*
-* 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
diff --git a/src/tls/tls_policy.h b/src/tls/tls_policy.h
index f53b9bab6..b12f07125 100644
--- a/src/tls/tls_policy.h
+++ b/src/tls/tls_policy.h
@@ -95,6 +95,13 @@ class BOTAN_DLL Policy
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.
+ * Old session tickets cannot be used to resume as session.
+ */
+ virtual u32bit session_ticket_lifetime() const;
+
+ /**
* @return the minimum version that we are willing to negotiate
*/
virtual Protocol_Version min_version() const;
diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp
index 1f69d153e..43556e1bc 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,43 @@ bool check_for_resume(Session& session_info,
return true;
}
+/*
+* Choose which ciphersuite to use
+*/
+u16bit choose_ciphersuite(
+ const Policy& policy,
+ const std::map<std::string, std::vector<X509_Certificate> >& cert_chains,
+ const Client_Hello* client_hello)
+ {
+ const std::vector<u16bit> client_suites = client_hello->ciphersuites();
+ const std::vector<u16bit> server_suites = policy.ciphersuite_list(false);
+
+ 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;
+
+ return suite_id;
+ }
+
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Can't agree on a ciphersuite with client");
+ }
+
std::map<std::string, std::vector<X509_Certificate> >
get_server_certs(const std::string& hostname,
Credentials_Manager& creds)
@@ -215,7 +257,8 @@ void Server::process_handshake_msg(Handshake_Type type,
const bool resuming = check_for_resume(session_info,
session_manager,
creds,
- state->client_hello);
+ state->client_hello,
+ policy.session_ticket_lifetime());
bool have_session_ticket_key = false;
@@ -240,7 +283,9 @@ 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,
rng);
@@ -257,13 +302,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 +316,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,25 +346,17 @@ 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, cert_chains, state->client_hello),
+ policy.choose_compression(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,
rng);
@@ -505,7 +542,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(...) {}
}
diff --git a/src/tls/tls_session.cpp b/src/tls/tls_session.cpp
index 2a532196d..0e8bf3051 100644
--- a/src/tls/tls_session.cpp
+++ b/src/tls/tls_session.cpp
@@ -131,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;
diff --git a/src/tls/tls_session.h b/src/tls/tls_session.h
index 0c57201a4..9a3c242a8 100644
--- a/src/tls/tls_session.h
+++ b/src/tls/tls_session.h
@@ -177,6 +177,11 @@ class BOTAN_DLL Session
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
*/
const MemoryVector<byte>& session_ticket() const { return m_session_ticket; }
diff --git a/src/tls/tls_session_manager.cpp b/src/tls/tls_session_manager.cpp
index 59fc75b9f..812525d69 100644
--- a/src/tls/tls_session_manager.cpp
+++ b/src/tls/tls_session_manager.cpp
@@ -16,16 +16,16 @@ namespace TLS {
bool Session_Manager_In_Memory::load_from_session_str(
const std::string& session_str, Session& session)
{
- std::map<std::string, Session>::iterator i = sessions.find(session_str);
+ std::map<std::string, Session>::iterator i = m_sessions.find(session_str);
- if(i == sessions.end())
+ if(i == m_sessions.end())
return false;
// 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);
+ m_sessions.erase(i);
return false;
}
@@ -45,18 +45,18 @@ bool Session_Manager_In_Memory::load_from_host_info(
std::map<std::string, std::string>::iterator i;
if(port > 0)
- i = host_sessions.find(hostname + ":" + to_string(port));
+ i = m_host_sessions.find(hostname + ":" + to_string(port));
else
- i = host_sessions.find(hostname);
+ i = m_host_sessions.find(hostname);
- if(i == host_sessions.end())
+ if(i == m_host_sessions.end())
return false;
if(load_from_session_str(i->second, session))
return true;
- // was removed from sessions map, remove host_sessions entry
- host_sessions.erase(i);
+ // was removed from m_sessions map, remove m_host_sessions entry
+ m_host_sessions.erase(i);
return false;
}
@@ -65,30 +65,30 @@ void Session_Manager_In_Memory::remove_entry(
const MemoryRegion<byte>& session_id)
{
std::map<std::string, Session>::iterator i =
- sessions.find(hex_encode(session_id));
+ m_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)
{
- if(max_sessions != 0)
+ if(m_max_sessions != 0)
{
/*
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());
- sessions[session_id_str] = session;
+ m_sessions[session_id_str] = session;
if(session.side() == CLIENT && session.sni_hostname() != "")
- host_sessions[session.sni_hostname()] = session_id_str;
+ m_host_sessions[session.sni_hostname()] = session_id_str;
}
}
diff --git a/src/tls/tls_session_manager.h b/src/tls/tls_session_manager.h
index c0a9996e3..3a39bf50e 100644
--- a/src/tls/tls_session_manager.h
+++ b/src/tls/tls_session_manager.h
@@ -63,6 +63,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,
- size_t session_lifetime = 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,14 +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);
- size_t max_sessions, session_lifetime;
+ size_t m_max_sessions;
+
+ 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;
};
}