aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/credentials_manager.rst16
-rw-r--r--doc/examples/tls_client.cpp17
-rw-r--r--doc/tls.rst18
-rw-r--r--src/tls/sessions_sqlite/tls_session_manager_sqlite.cpp7
-rw-r--r--src/tls/sessions_sqlite/tls_session_manager_sqlite.h18
-rw-r--r--src/tls/tls_client.cpp10
-rw-r--r--src/tls/tls_client.h15
-rw-r--r--src/tls/tls_session_manager.cpp23
-rw-r--r--src/tls/tls_session_manager.h24
9 files changed, 100 insertions, 48 deletions
diff --git a/doc/credentials_manager.rst b/doc/credentials_manager.rst
index b9718bf59..04e9e3f2e 100644
--- a/doc/credentials_manager.rst
+++ b/doc/credentials_manager.rst
@@ -122,6 +122,22 @@ authentication.
Return a symmetric key for use with *identity*
+ One important special case for ``psk`` is where *type* is
+ "tls-server", *context* is "session-ticket" and *identity* is an
+ empty string. If a key is returned for this case, a TLS server
+ will offer session tickets to clients who can use them, and the
+ returned key will be used to encrypt the ticket. The server is
+ allowed to change the key at any time (though changing the key
+ means old session tickets can no longer be used for resumption,
+ forcing a full re-handshake when the client next connects). One
+ simple approach to add support for session tickets in your server
+ is to generate a random key the first time ``psk`` is called to
+ retrieve the session ticket key, cache it for later use in the
+ ``Credentials_Manager``, and simply let it be thrown away when the
+ process terminates.
+
+ See :rfc:`4507` for more information about TLS session tickets.
+
.. cpp:function:: std::string psk_identity_hint(const std::string& type, \
const std::string& context)
diff --git a/doc/examples/tls_client.cpp b/doc/examples/tls_client.cpp
index d8d861e57..5373227ce 100644
--- a/doc/examples/tls_client.cpp
+++ b/doc/examples/tls_client.cpp
@@ -133,13 +133,14 @@ void doit(RandomNumberGenerator& rng,
int sockfd = connect_to_host(host, port);
TLS::Client client(std::bind(socket_write, sockfd, _1, _2),
- process_data,
- handshake_complete,
- session_manager,
- creds,
- policy,
- rng,
- host);
+ process_data,
+ handshake_complete,
+ session_manager,
+ creds,
+ policy,
+ rng,
+ host,
+ port);
fd_set readfds;
@@ -225,7 +226,7 @@ int main(int argc, char* argv[])
AutoSeeded_RNG rng;
TLS::Policy policy;
-#if defined(BOTAN_HAS_TLS_SQLITE_SESSION_MANAGER)
+#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
TLS::Session_Manager_SQLite session_manager("my secret passphrase", rng,
"sessions.db");
#else
diff --git a/doc/tls.rst b/doc/tls.rst
index e5e9dc91d..09b9da3d3 100644
--- a/doc/tls.rst
+++ b/doc/tls.rst
@@ -309,12 +309,17 @@ implementation to the ``TLS::Client`` or ``TLS::Server`` constructor.
.. cpp:class:: TLS::Session_Mananger
- .. cpp:function:: void save(const Session& session)
+ .. cpp:function:: void save(const Session& session, u16bit port)
Save a new *session*. It is possible that this sessions session
ID will replicate a session ID already stored, in which case the
new session information should overwrite the previous information.
+ Clients will specify *port* if they know it (it will be zero if
+ they do not, or for servers). It specifies the remote port of the
+ server which is used to assist with looking up the correct
+ session when using :cpp:func:`load_from_host_info`.
+
.. cpp:function:: void remove_entry(const std::vector<byte>& session_id)
Remove the session identified by *session_id*. Future attempts
@@ -328,13 +333,16 @@ implementation to the ``TLS::Client`` or ``TLS::Server`` constructor.
to *save*, and ``true`` is returned. Otherwise *session* is not
modified and ``false`` is returned.
- .. cpp:function:: bool load_from_host_info(const std::string& hostname, u16bit port, \
+ .. cpp:function:: bool load_from_host_info(const std::string& hostname, \
+ u16bit port, \
Session& session)
- Attempt to resume a session for *hostname* / *port*. If *port*
- is zero, try to find a session for *hostname* on any port. With
- the current client implementation, *port* is always zero.
+ Attempt to resume a session for *hostname* / *port*.
+ The session managers included in the library will, if they fail
+ to find an exact match for *hostname* and *port*, will also
+ check for a session saved using a matching hostname and a port
+ of zero.
.. cpp:function:: std::chrono::seconds session_lifetime() const
diff --git a/src/tls/sessions_sqlite/tls_session_manager_sqlite.cpp b/src/tls/sessions_sqlite/tls_session_manager_sqlite.cpp
index 9d0cffa08..d10366c60 100644
--- a/src/tls/sessions_sqlite/tls_session_manager_sqlite.cpp
+++ b/src/tls/sessions_sqlite/tls_session_manager_sqlite.cpp
@@ -167,6 +167,9 @@ bool Session_Manager_SQLite::load_from_host_info(const std::string& hostname,
}
}
+ if(port != 0)
+ return load_from_host_info(hostname, 0, session);
+
return false;
}
@@ -179,7 +182,7 @@ void Session_Manager_SQLite::remove_entry(const std::vector<byte>& session_id)
stmt.spin();
}
-void Session_Manager_SQLite::save(const Session& session)
+void Session_Manager_SQLite::save(const Session& session, u16bit port)
{
sqlite3_statement stmt(m_db, "insert or replace into tls_sessions"
" values(?1, ?2, ?3, ?4, ?5)");
@@ -187,7 +190,7 @@ void Session_Manager_SQLite::save(const Session& session)
stmt.bind(1, hex_encode(session.session_id()));
stmt.bind(2, session.start_time());
stmt.bind(3, session.sni_hostname());
- stmt.bind(4, 0);
+ stmt.bind(4, port);
stmt.bind(5, session.encrypt(m_session_key, m_rng));
stmt.spin();
diff --git a/src/tls/sessions_sqlite/tls_session_manager_sqlite.h b/src/tls/sessions_sqlite/tls_session_manager_sqlite.h
index 8950007ca..db74f54b7 100644
--- a/src/tls/sessions_sqlite/tls_session_manager_sqlite.h
+++ b/src/tls/sessions_sqlite/tls_session_manager_sqlite.h
@@ -21,9 +21,9 @@ namespace TLS {
* An implementation of Session_Manager that saves values in a SQLite3
* database file, with the session data encrypted using a passphrase.
*
-* @warning The hostnames associated with the saved sessions are stored
-* in the database in plaintext. This may be a serious privacy risk in
-* some applications.
+* @warning For clients, the hostnames associated with the saved
+* sessions are stored in the database in plaintext. This may be a
+* serious privacy risk in some situations.
*/
class BOTAN_DLL Session_Manager_SQLite : public Session_Manager
{
@@ -48,16 +48,18 @@ class BOTAN_DLL Session_Manager_SQLite : public Session_Manager
~Session_Manager_SQLite();
bool load_from_session_id(const std::vector<byte>& session_id,
- Session& session);
+ Session& session) override;
bool load_from_host_info(const std::string& hostname, u16bit port,
- Session& session);
+ Session& session) override;
- void remove_entry(const std::vector<byte>& session_id);
+ void remove_entry(const std::vector<byte>& session_id) override;
- void save(const Session& session_data);
+ void save(const Session& session_data, u16bit port) override;
+
+ std::chrono::seconds session_lifetime() const override
+ { return m_session_lifetime; }
- std::chrono::seconds session_lifetime() const { return m_session_lifetime; }
private:
Session_Manager_SQLite(const Session_Manager_SQLite&);
Session_Manager_SQLite& operator=(const Session_Manager_SQLite&);
diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp
index 5b9b4868c..e4652fd7e 100644
--- a/src/tls/tls_client.cpp
+++ b/src/tls/tls_client.cpp
@@ -26,12 +26,14 @@ Client::Client(std::function<void (const byte[], size_t)> output_fn,
const Policy& policy,
RandomNumberGenerator& rng,
const std::string& hostname,
+ u16bit port,
std::function<std::string (std::vector<std::string>)> next_protocol) :
Channel(output_fn, proc_fn, handshake_fn, session_manager, rng),
m_policy(policy),
m_rng(rng),
m_creds(creds),
- m_hostname(hostname)
+ m_hostname(hostname),
+ m_port(port)
{
m_writer.set_version(Protocol_Version::SSL_V3);
@@ -47,7 +49,7 @@ Client::Client(std::function<void (const byte[], size_t)> output_fn,
if(hostname != "")
{
Session session_info;
- if(m_session_manager.load_from_host_info(m_hostname, 0, session_info))
+ if(m_session_manager.load_from_host_info(m_hostname, m_port, session_info))
{
if(session_info.srp_identifier() == srp_identifier)
{
@@ -103,7 +105,7 @@ void Client::renegotiate(bool force_full_renegotiation)
if(!force_full_renegotiation)
{
Session session_info;
- if(m_session_manager.load_from_host_info(m_hostname, 0, session_info))
+ if(m_session_manager.load_from_host_info(m_hostname, m_port, session_info))
{
m_state->client_hello = new Client_Hello(
m_writer,
@@ -482,7 +484,7 @@ void Client::process_handshake_msg(Handshake_Type type,
if(!session_id.empty())
{
if(should_save)
- m_session_manager.save(session_info);
+ m_session_manager.save(session_info, m_port);
else
m_session_manager.remove_entry(session_info.session_id());
}
diff --git a/src/tls/tls_client.h b/src/tls/tls_client.h
index cd9da78b9..dcd7aab83 100644
--- a/src/tls/tls_client.h
+++ b/src/tls/tls_client.h
@@ -24,14 +24,27 @@ class BOTAN_DLL Client : public Channel
public:
/**
* Set up a new TLS client session
+ *
* @param socket_output_fn is called with data for the outbound socket
+ *
* @param proc_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 state
+ *
* @param creds manages application/user credentials
+ *
* @param policy specifies other connection policy information
+ *
* @param rng a random number generator
+ *
* @param servername the server's DNS name, if known
+ *
+ * @param port specifies the protocol port of the server (eg for
+ * TCP/UDP). Only used if servername is also specified.
+ * Use 0 if unknown.
+ *
* @param next_protocol allows the client to specify what the next
* protocol will be. For more information read
* http://technotes.googlecode.com/git/nextprotoneg.html.
@@ -49,6 +62,7 @@ class BOTAN_DLL Client : public Channel
const Policy& policy,
RandomNumberGenerator& rng,
const std::string& servername = "",
+ u16bit port = 0,
std::function<std::string (std::vector<std::string>)> next_protocol =
std::function<std::string (std::vector<std::string>)>());
@@ -65,6 +79,7 @@ class BOTAN_DLL Client : public Channel
RandomNumberGenerator& m_rng;
Credentials_Manager& m_creds;
const std::string m_hostname;
+ const u16bit m_port;
};
}
diff --git a/src/tls/tls_session_manager.cpp b/src/tls/tls_session_manager.cpp
index 55c06bc16..823f4c123 100644
--- a/src/tls/tls_session_manager.cpp
+++ b/src/tls/tls_session_manager.cpp
@@ -49,15 +49,16 @@ bool Session_Manager_In_Memory::load_from_host_info(
{
std::lock_guard<std::mutex> lock(m_mutex);
- std::map<std::string, std::string>::iterator i;
-
- if(port > 0)
- i = m_host_sessions.find(hostname + ":" + std::to_string(port));
- else
- i = m_host_sessions.find(hostname);
+ auto i = m_host_sessions.find(hostname + ":" + std::to_string(port));
if(i == m_host_sessions.end())
- return false;
+ {
+ if(port > 0)
+ i = m_host_sessions.find(hostname + ":" + std::to_string(0));
+
+ if(i == m_host_sessions.end())
+ return false;
+ }
if(load_from_session_str(i->second, session))
return true;
@@ -79,7 +80,7 @@ void Session_Manager_In_Memory::remove_entry(
m_sessions.erase(i);
}
-void Session_Manager_In_Memory::save(const Session& session)
+void Session_Manager_In_Memory::save(const Session& session, u16bit port)
{
std::lock_guard<std::mutex> lock(m_mutex);
@@ -97,8 +98,10 @@ void Session_Manager_In_Memory::save(const Session& session)
m_sessions[session_id_str] = session;
- if(session.side() == CLIENT && session.sni_hostname() != "")
- m_host_sessions[session.sni_hostname()] = session_id_str;
+ const std::string hostname = session.sni_hostname();
+
+ if(session.side() == CLIENT && hostname != "")
+ m_host_sessions[hostname + ":" + std::to_string(port)] = session_id_str;
}
}
diff --git a/src/tls/tls_session_manager.h b/src/tls/tls_session_manager.h
index c63ee39f6..4c979362f 100644
--- a/src/tls/tls_session_manager.h
+++ b/src/tls/tls_session_manager.h
@@ -62,8 +62,9 @@ class BOTAN_DLL Session_Manager
* immediately by load_from_* will result in a successful lookup.
*
* @param session to save
+ * @param port the protocol port (if known)
*/
- virtual void save(const Session& session) = 0;
+ virtual void save(const Session& session, u16bit port = 0) = 0;
/**
* Return the allowed lifetime of a session; beyond this time,
@@ -82,17 +83,17 @@ class BOTAN_DLL Session_Manager
class BOTAN_DLL Session_Manager_Noop : public Session_Manager
{
public:
- bool load_from_session_id(const std::vector<byte>&, Session&)
+ bool load_from_session_id(const std::vector<byte>&, Session&) override
{ return false; }
- bool load_from_host_info(const std::string&, u16bit, Session&)
+ bool load_from_host_info(const std::string&, u16bit, Session&) override
{ return false; }
- void remove_entry(const std::vector<byte>&) {}
+ void remove_entry(const std::vector<byte>&) override {}
- void save(const Session&) {}
+ void save(const Session&, u16bit) override {}
- std::chrono::seconds session_lifetime() const
+ std::chrono::seconds session_lifetime() const override
{ return std::chrono::seconds(0); }
};
@@ -115,16 +116,17 @@ class BOTAN_DLL Session_Manager_In_Memory : public Session_Manager
{}
bool load_from_session_id(const std::vector<byte>& session_id,
- Session& session);
+ Session& session) override;
bool load_from_host_info(const std::string& hostname, u16bit port,
- Session& session);
+ Session& session) override;
- void remove_entry(const std::vector<byte>& session_id);
+ void remove_entry(const std::vector<byte>& session_id) override;
- void save(const Session& session_data);
+ void save(const Session& session_data, u16bit port) override;
- std::chrono::seconds session_lifetime() const { return m_session_lifetime; }
+ std::chrono::seconds session_lifetime() const override
+ { return m_session_lifetime; }
private:
bool load_from_session_str(const std::string& session_str,