diff options
author | lloyd <[email protected]> | 2012-03-22 13:57:21 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-03-22 13:57:21 +0000 |
commit | 2ed0f752f195a962f7c4d84ee40e2ecfe0928290 (patch) | |
tree | 2a1627fb6610bd44c42b6f4bd1f5e134ad199829 /src/tls | |
parent | ff2154e7998b44aa242e55daeeb79c6d5ab9e5df (diff) | |
parent | 697d63169705b9ce0dabb46b656b1b26777a3e5d (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.txt | 7 | ||||
-rw-r--r-- | src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp | 241 | ||||
-rw-r--r-- | src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h | 63 | ||||
-rw-r--r-- | src/tls/tls_session.cpp | 2 |
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; |