Botan 3.3.0
Crypto and TLS for C&
tls_session_manager_memory.cpp
Go to the documentation of this file.
1/**
2 * TLS Session Management
3 * (C) 2011,2012 Jack Lloyd
4 * 2023 René Meusel - Rohde & Schwarz Cybersecurity
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8
9#include <botan/tls_session_manager_memory.h>
10
11#include <botan/rng.h>
12#include <botan/internal/stl_util.h>
13
14#include <algorithm>
15
16namespace Botan::TLS {
17
18Session_Manager_In_Memory::Session_Manager_In_Memory(const std::shared_ptr<RandomNumberGenerator>& rng,
19 size_t max_sessions) :
20 Session_Manager(rng), m_max_sessions(max_sessions) {
21 if(max_sessions > 0) {
22 m_fifo.emplace();
23 }
24}
25
26void Session_Manager_In_Memory::store(const Session& session, const Session_Handle& handle) {
27 // TODO: C++20 allows CTAD for template aliases (read: lock_guard_type), so
28 // technically we should be able to omit the explicit mutex type.
29 // Unfortuately clang does not agree, yet.
31
32 if(m_fifo.has_value()) {
33 while(m_sessions.size() >= capacity()) {
34 BOTAN_ASSERT_NOMSG(m_sessions.size() <= m_fifo->size());
35 m_sessions.erase(m_fifo->front());
36 m_fifo->pop_front();
37 }
38 }
39
40 // Generate a random session ID if the peer did not provide one. Note that
41 // this ID is just for internal use and won't be returned on ::find().
42 auto id = handle.id().value_or(m_rng->random_vec<Session_ID>(32));
43 m_sessions.emplace(id, Session_with_Handle{session, handle});
44
45 if(m_fifo.has_value()) {
46 m_fifo->emplace_back(std::move(id));
47 }
48}
49
50std::optional<Session> Session_Manager_In_Memory::retrieve_one(const Session_Handle& handle) {
52
53 if(auto id = handle.id()) {
54 const auto session = m_sessions.find(id.value());
55 if(session != m_sessions.end()) {
56 return session->second.session;
57 }
58 }
59
60 return std::nullopt;
61}
62
63std::vector<Session_with_Handle> Session_Manager_In_Memory::find_some(const Server_Information& info,
64 const size_t max_sessions_hint) {
65 BOTAN_UNUSED(max_sessions_hint);
66
68
69 std::vector<Session_with_Handle> found_sessions;
70 // TODO: std::copy_if?
71 for(const auto& [_, session_and_handle] : m_sessions) {
72 if(session_and_handle.session.server_info() == info) {
73 found_sessions.emplace_back(session_and_handle);
74 }
75 }
76
77 return found_sessions;
78}
79
82 return remove_internal(handle);
83}
84
85size_t Session_Manager_In_Memory::remove_internal(const Session_Handle& handle) {
86 return std::visit(overloaded{
87 // We deliberately leave the deleted session in m_fifo. Finding it would be
88 // another O(n) operation. Instead, purging will run in a loop and skip m_fifo
89 // entries that were not found anymore.
90 [&](const Session_Ticket& ticket) -> size_t {
91 // TODO: This is an O(n) operation. Typically, the Session_Manager will
92 // not contain a plethora of sessions and this should be fine. If
93 // it's not, we'll need to consider another index on tickets.
94 //
95 // TODO: C++20's std::erase_if should return the number of erased items
96 //
97 // Unfortunately, at the time of this writing Android NDK shipped with
98 // a std::erase_if that returns void. Hence, the workaround.
99 const auto before = m_sessions.size();
100 std::erase_if(m_sessions, [&](const auto& item) {
101 const auto& [_unused1, session_and_handle] = item;
102 const auto& [_unused2, this_handle] = session_and_handle;
103 return this_handle.is_ticket() && this_handle.ticket().value() == ticket;
104 });
105 return before - m_sessions.size();
106 },
107 [&](const Session_ID& id) -> size_t { return m_sessions.erase(id); },
108 [&](const Opaque_Session_Handle&) -> size_t {
109 if(auto id = handle.id()) {
110 auto removed = remove_internal(id.value());
111 if(removed > 0) {
112 return removed;
113 }
114 }
115
116 if(auto ticket = handle.ticket()) {
117 return remove_internal(ticket.value());
118 }
119
120 return 0;
121 },
122 },
123 handle.get());
124}
125
128
129 const auto sessions = m_sessions.size();
130 m_sessions.clear();
131 if(m_fifo.has_value()) {
132 m_fifo->clear();
133 }
134
135 return sessions;
136}
137
138} // namespace Botan::TLS
#define BOTAN_UNUSED
Definition assert.h:118
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
Helper class to embody a session handle in all protocol versions.
Definition tls_session.h:64
std::optional< Session_Ticket > ticket() const
decltype(auto) get() const
std::optional< Session_ID > id() const
void store(const Session &session, const Session_Handle &handle) override
Save a Session under a Session_Handle (TLS Client)
Session_Manager_In_Memory(const std::shared_ptr< RandomNumberGenerator > &rng, size_t max_sessions=1000)
std::vector< Session_with_Handle > find_some(const Server_Information &info, size_t max_sessions_hint) override
Internal retrieval function to find sessions to resume.
size_t remove(const Session_Handle &handle) override
std::optional< Session > retrieve_one(const Session_Handle &handle) override
Internal retrieval function for a single session.
recursive_mutex_type & mutex()
std::shared_ptr< RandomNumberGenerator > m_rng
Strong< std::vector< uint8_t >, struct Session_ID_ > Session_ID
holds a TLS 1.2 session ID for stateful resumption
Definition tls_session.h:32
Strong< std::vector< uint8_t >, struct Opaque_Session_Handle_ > Opaque_Session_Handle
holds an opaque session handle as used in TLS 1.3 that could be either a ticket for stateless resumpt...
Definition tls_session.h:39