8#include <botan/tls_session_manager_sql.h>
9#include <botan/database.h>
10#include <botan/pbkdf.h>
13#include <botan/loadstor.h>
21 const std::string& passphrase,
24 std::chrono::seconds session_lifetime) :
27 m_max_sessions(max_sessions),
28 m_session_lifetime(session_lifetime)
31 "create table if not exists tls_sessions "
33 "session_id TEXT PRIMARY KEY, "
34 "session_start INTEGER, "
41 "create table if not exists tls_sessions_metadata "
43 "passphrase_salt BLOB, "
44 "passphrase_iterations INTEGER, "
45 "passphrase_check INTEGER "
48 const size_t salts = m_db->row_count(
"tls_sessions_metadata");
50 std::unique_ptr<PBKDF> pbkdf(
get_pbkdf(
"PBKDF2(SHA-512)"));
55 auto stmt = m_db->new_statement(
"select * from tls_sessions_metadata");
59 std::pair<const uint8_t*, size_t> salt = stmt->get_blob(0);
60 const size_t iterations = stmt->get_size_t(1);
61 const size_t check_val_db = stmt->get_size_t(2);
65 salt.first, salt.second,
68 const size_t check_val_created =
make_uint16(x[0], x[1]);
69 m_session_key.assign(x.begin() + 2, x.end());
71 if(check_val_created != check_val_db)
79 throw Internal_Error(
"Seemingly corrupted TLS session db, multiple salts found");
83 std::vector<uint8_t> salt;
85 size_t iterations = 0;
89 salt.data(), salt.size(),
90 std::chrono::milliseconds(100),
94 m_session_key.assign(x.begin() + 2, x.end());
96 auto stmt = m_db->new_statement(
"insert into tls_sessions_metadata values(?1, ?2, ?3)");
99 stmt->bind(2, iterations);
100 stmt->bind(3, check_val);
109 auto stmt = m_db->new_statement(
"select session from tls_sessions where session_id = ?1");
115 std::pair<const uint8_t*, size_t> blob = stmt->get_blob(0);
133 auto stmt = m_db->new_statement(
"select session from tls_sessions"
134 " where hostname = ?1 and hostport = ?2"
135 " order by session_start desc");
138 stmt->bind(2, server.
port());
142 std::pair<const uint8_t*, size_t> blob = stmt->get_blob(0);
159 auto stmt = m_db->new_statement(
"delete from tls_sessions where session_id = ?1");
168 auto stmt = m_db->new_statement(
"delete from tls_sessions");
177 auto stmt = m_db->new_statement(
"insert or replace into tls_sessions"
178 " values(?1, ?2, ?3, ?4, ?5)");
184 stmt->bind(5, session.
encrypt(m_session_key, m_rng));
188 prune_session_cache();
191void Session_Manager_SQL::prune_session_cache()
194 auto remove_expired = m_db->new_statement(
"delete from tls_sessions where session_start <= ?1");
195 remove_expired->bind(1, std::chrono::system_clock::now() - m_session_lifetime);
196 remove_expired->spin();
198 const size_t sessions = m_db->row_count(
"tls_sessions");
201 if(sessions > m_max_sessions)
203 auto remove_some = m_db->new_statement(
"delete from tls_sessions where session_id in "
204 "(select session_id from tls_sessions limit ?1)");
206 remove_some->bind(1, sessions - m_max_sessions);
secure_vector< uint8_t > random_vec(size_t bytes)
Session_Manager_SQL(std::shared_ptr< SQL_Database > db, const std::string &passphrase, RandomNumberGenerator &rng, size_t max_sessions=1000, std::chrono::seconds session_lifetime=std::chrono::seconds(7200))
void save(const Session &session_data) override
bool load_from_server_info(const Server_Information &info, Session &session) override
size_t remove_all() override
bool load_from_session_id(const std::vector< uint8_t > &session_id, Session &session) override
void remove_entry(const std::vector< uint8_t > &session_id) override
const Server_Information & server_info() const
std::vector< uint8_t > encrypt(const SymmetricKey &key, RandomNumberGenerator &rng) const
std::chrono::system_clock::time_point start_time() const
const std::vector< uint8_t > & session_id() const
static Session decrypt(const uint8_t ctext[], size_t ctext_size, const SymmetricKey &key)
PBKDF * get_pbkdf(const std::string &algo_spec, const std::string &provider="")
void hex_encode(char output[], const uint8_t input[], size_t input_length, bool uppercase)
std::vector< T, secure_allocator< T > > secure_vector
constexpr uint16_t make_uint16(uint8_t i0, uint8_t i1)