aboutsummaryrefslogtreecommitdiffstats
path: root/src/tls
diff options
context:
space:
mode:
authorlloyd <[email protected]>2012-03-22 13:57:21 +0000
committerlloyd <[email protected]>2012-03-22 13:57:21 +0000
commit2ed0f752f195a962f7c4d84ee40e2ecfe0928290 (patch)
tree2a1627fb6610bd44c42b6f4bd1f5e134ad199829 /src/tls
parentff2154e7998b44aa242e55daeeb79c6d5ab9e5df (diff)
parent697d63169705b9ce0dabb46b656b1b26777a3e5d (diff)
propagate from branch 'net.randombit.botan.tls-state-machine' (head f761c340d4390c232d1a9896f3fde5c9dec7858b)
to branch 'net.randombit.botan.tls-session-ticket' (head bf9feb245aa7185e22948a21a3099acac7237b44)
Diffstat (limited to 'src/tls')
-rw-r--r--src/tls/sessions_sqlite/info.txt7
-rw-r--r--src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp241
-rw-r--r--src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h63
-rw-r--r--src/tls/tls_session.cpp2
4 files changed, 311 insertions, 2 deletions
diff --git a/src/tls/sessions_sqlite/info.txt b/src/tls/sessions_sqlite/info.txt
new file mode 100644
index 000000000..ef5811151
--- /dev/null
+++ b/src/tls/sessions_sqlite/info.txt
@@ -0,0 +1,7 @@
+define TLS_SQLITE_SESSION_MANAGER
+
+load_on request
+
+<libs>
+all -> sqlite3
+</libs>
diff --git a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp
new file mode 100644
index 000000000..7605313ff
--- /dev/null
+++ b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp
@@ -0,0 +1,241 @@
+/*
+* SQLite TLS Session Manager
+* (C) 2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_sqlite_sess_mgr.h>
+#include <botan/internal/assert.h>
+#include <botan/hex.h>
+#include <botan/time.h>
+#include <sqlite3.h>
+
+namespace Botan {
+
+namespace TLS {
+
+namespace {
+
+class sqlite3_statement
+ {
+ public:
+ sqlite3_statement(sqlite3* db, const std::string& base_sql)
+ {
+ int rc = sqlite3_prepare_v2(db, base_sql.c_str(), -1, &m_stmt, 0);
+
+ if(rc != SQLITE_OK)
+ throw std::runtime_error("sqlite3_prepare failed " + base_sql + ", code " + to_string(rc));
+ }
+
+ void bind(int column, const std::string& val)
+ {
+ int rc = sqlite3_bind_text(m_stmt, column, val.c_str(), -1, SQLITE_TRANSIENT);
+ if(rc != SQLITE_OK)
+ throw std::runtime_error("sqlite3_bind_text failed, code " + to_string(rc));
+ }
+
+ void bind(int column, int val)
+ {
+ int rc = sqlite3_bind_int(m_stmt, column, val);
+ if(rc != SQLITE_OK)
+ throw std::runtime_error("sqlite3_bind_int failed, code " + to_string(rc));
+ }
+
+ void bind(int column, const MemoryRegion<byte>& val)
+ {
+ int rc = sqlite3_bind_blob(m_stmt, column, &val[0], val.size(), SQLITE_TRANSIENT);
+ if(rc != SQLITE_OK)
+ throw std::runtime_error("sqlite3_bind_text failed, code " + to_string(rc));
+ }
+
+ void spin()
+ {
+ while(sqlite3_step(m_stmt) == SQLITE_ROW)
+ {}
+ }
+
+ int step()
+ {
+ return sqlite3_step(m_stmt);
+ }
+
+ sqlite3_stmt* stmt() { return m_stmt; }
+
+ ~sqlite3_statement() { sqlite3_finalize(m_stmt); }
+ private:
+ sqlite3_stmt* m_stmt;
+ };
+
+}
+
+Session_Manager_SQLite::Session_Manager_SQLite(const std::string& db_filename,
+ const std::string& table_name,
+ size_t max_sessions,
+ size_t session_lifetime) :
+ m_table_name(table_name),
+ m_max_sessions(max_sessions),
+ m_session_lifetime(session_lifetime)
+ {
+ int rc = sqlite3_open(db_filename.c_str(), &m_db);
+ if(rc)
+ {
+ const std::string err_msg = sqlite3_errmsg(m_db);
+ sqlite3_close(m_db);
+ throw std::runtime_error("sqlite3_open failed - " + err_msg);
+ }
+
+ const std::string table_sql =
+ "create table if not exists " +
+ m_table_name + "(" +
+ "session_id TEXT PRIMARY KEY, "
+ "session_start INTEGER, "
+ "hostname TEXT, "
+ "hostport INTEGER, "
+ "session BLOB"
+ ")";
+
+ char* errmsg = 0;
+ rc = sqlite3_exec(m_db, table_sql.c_str(), 0, 0, &errmsg);
+
+ if(rc != SQLITE_OK)
+ {
+ const std::string err_msg = errmsg;
+ sqlite3_free(errmsg);
+ sqlite3_close(m_db);
+ throw std::runtime_error("sqlite3_exec for table failed - " + err_msg);
+ }
+ }
+
+Session_Manager_SQLite::~Session_Manager_SQLite()
+ {
+ sqlite3_close(m_db);
+ }
+
+bool Session_Manager_SQLite::load_from_session_id(const MemoryRegion<byte>& session_id,
+ Session& session)
+ {
+ sqlite3_statement stmt(m_db, "select session from " + m_table_name + " where session_id = ?1");
+
+ stmt.bind(1, hex_encode(session_id));
+
+ int rc = stmt.step();
+
+ while(rc == SQLITE_ROW)
+ {
+ BOTAN_ASSERT(sqlite3_column_type(stmt.stmt(), 0) == SQLITE_BLOB,
+ "Return value is a text");
+
+ const void* session_blob = sqlite3_column_blob(stmt.stmt(), 0);
+ const int session_blob_size = sqlite3_column_bytes(stmt.stmt(), 0);
+
+ try
+ {
+ session = Session(static_cast<const byte*>(session_blob), session_blob_size);
+ return true;
+ }
+ catch(...)
+ {
+ }
+
+ rc = stmt.step();
+ }
+
+ return false;
+ }
+
+bool Session_Manager_SQLite::load_from_host_info(const std::string& hostname,
+ u16bit port,
+ Session& session)
+ {
+ sqlite3_statement stmt(m_db, "select session from " + m_table_name +
+ " where hostname = ?1 and hostport = ?2"
+ " order by session_start desc");
+
+ stmt.bind(1, hostname);
+ stmt.bind(2, port);
+
+ int rc = stmt.step();
+
+ while(rc == SQLITE_ROW)
+ {
+ BOTAN_ASSERT(sqlite3_column_type(stmt.stmt(), 0) == SQLITE_BLOB,
+ "Return value is a blob");
+
+ const void* session_blob = sqlite3_column_blob(stmt.stmt(), 0);
+ const int session_blob_size = sqlite3_column_bytes(stmt.stmt(), 0);
+
+ try
+ {
+ session = Session(static_cast<const byte*>(session_blob), session_blob_size);
+ return true;
+ }
+ catch(...)
+ {
+ }
+
+ rc = stmt.step();
+ }
+
+ return false;
+ }
+
+void Session_Manager_SQLite::remove_entry(const MemoryRegion<byte>& session_id)
+ {
+ sqlite3_statement stmt(m_db, "delete from " + m_table_name + " where session_id = ?1");
+
+ stmt.bind(1, hex_encode(session_id));
+
+ stmt.spin();
+ }
+
+void Session_Manager_SQLite::save(const Session& session)
+ {
+ sqlite3_statement stmt(m_db, "insert into " + m_table_name + " values(?1, ?2, ?3, ?4, ?5)");
+
+ 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(5, session.DER_encode());
+
+ stmt.spin();
+
+ prune_session_cache();
+ }
+
+void Session_Manager_SQLite::prune_session_cache()
+ {
+ sqlite3_statement remove_expired(m_db, "delete from " + m_table_name + " where session_start <= ?1");
+
+ remove_expired.bind(1, system_time() - m_session_lifetime);
+
+ remove_expired.spin();
+
+ sqlite3_statement row_count(m_db, "select count(*) from " + m_table_name);
+
+ if(row_count.step() == SQLITE_ROW)
+ {
+ BOTAN_ASSERT(sqlite3_column_type(row_count.stmt(), 0) == SQLITE_INTEGER,
+ "Return count is a blob");
+
+ const int sessions_int = sqlite3_column_int(row_count.stmt(), 0);
+
+ BOTAN_ASSERT(sessions_int >= 0, "SQLite returned positive row count");
+
+ const size_t sessions = static_cast<size_t>(sessions_int);
+
+ if(sessions > m_max_sessions)
+ {
+ sqlite3_statement remove_some(m_db, "delete from " + m_table_name + " where session_id in "
+ "(select session_id from " + m_table_name + " limit ?1)");
+
+ remove_some.bind(1, sessions - m_max_sessions);
+ remove_some.spin();
+ }
+ }
+ }
+
+}
+
+}
diff --git a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h
new file mode 100644
index 000000000..35a37d206
--- /dev/null
+++ b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h
@@ -0,0 +1,63 @@
+/*
+* SQLite TLS Session Manager
+* (C) 2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef TLS_SQLITE_SESSION_MANAGER_H__
+#define TLS_SQLITE_SESSION_MANAGER_H__
+
+#include <botan/tls_session_manager.h>
+
+class sqlite3;
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+*/
+class BOTAN_DLL Session_Manager_SQLite : public Session_Manager
+ {
+ public:
+ /**
+ * @param db_filename filename of the SQLite database file
+ * @param table_name names the table to store sessions in
+ * @param max_sessions a hint on the maximum number of sessions
+ * to keep in memory at any one time. (If zero, don't cap)
+ * @param session_lifetime sessions are expired after this many
+ * seconds have elapsed from initial handshake.
+ */
+ Session_Manager_SQLite(const std::string& db_filename,
+ const std::string& table_name = "tls_sessions",
+ size_t max_sessions = 1000,
+ size_t session_lifetime = 7200);
+
+ ~Session_Manager_SQLite();
+
+ bool load_from_session_id(const MemoryRegion<byte>& session_id,
+ Session& session);
+
+ bool load_from_host_info(const std::string& hostname, u16bit port,
+ Session& session);
+
+ void remove_entry(const MemoryRegion<byte>& session_id);
+
+ void save(const Session& session_data);
+ private:
+ Session_Manager_SQLite(const Session_Manager_SQLite&) {}
+ Session_Manager_SQLite& operator=(const Session_Manager_SQLite&) { return (*this); }
+
+ void prune_session_cache();
+
+ std::string m_table_name;
+ size_t m_max_sessions, m_session_lifetime;
+ class sqlite3* m_db;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_session.cpp b/src/tls/tls_session.cpp
index 3d890210f..a9eb8f95c 100644
--- a/src/tls/tls_session.cpp
+++ b/src/tls/tls_session.cpp
@@ -56,8 +56,6 @@ Session::Session(const std::string& pem)
Session::Session(const byte ber[], size_t ber_len)
{
- BER_Decoder decoder(ber, ber_len);
-
byte side_code = 0;
ASN1_String sni_hostname_str;
ASN1_String srp_identifier_str;