Coverage Report

Created: 2025-04-11 06:34

/src/botan/build/include/public/botan/tls_session_manager.h
Line
Count
Source
1
/*
2
* TLS Session Manager
3
* (C) 2011-2023 Jack Lloyd
4
*     2022-2023 René Meusel - Rohde & Schwarz Cybersecurity
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8
9
#ifndef BOTAN_TLS_SESSION_MANAGER_H_
10
#define BOTAN_TLS_SESSION_MANAGER_H_
11
12
#include <botan/mutex.h>
13
#include <botan/tls_session.h>
14
#include <botan/types.h>
15
16
#if defined(BOTAN_HAS_TLS_13)
17
   #include <botan/tls_psk_identity_13.h>
18
#endif
19
20
#include <chrono>
21
#include <map>
22
#include <utility>
23
#include <variant>
24
25
namespace Botan {
26
class RandomNumberGenerator;
27
}
28
29
namespace Botan::TLS {
30
31
class Callbacks;
32
class Policy;
33
34
/**
35
* Session_Manager is an interface to systems which can save session parameters
36
* for supporting session resumption.
37
*
38
* Saving sessions is done on a best-effort basis; an implementation is
39
* allowed to drop sessions due to space constraints or other issues.
40
*
41
* Implementations should strive to be thread safe. This base class provides a
42
* recursive mutex (via Session_Manager::mutex()). Derived classes may simply
43
* reuse this for their own locking.
44
*/
45
class BOTAN_PUBLIC_API(3, 0) Session_Manager {
46
   public:
47
      Session_Manager(const std::shared_ptr<RandomNumberGenerator>& rng);
48
49
      /**
50
       * @brief Save a new Session and assign a Session_Handle (TLS Server)
51
       *
52
       * Save a new session on a best effort basis; the manager may not in fact
53
       * be able to save the session for whatever reason; this is not an error.
54
       * Callers cannot assume that calling establish() followed immediately by
55
       * retrieve() or choose_from_offered_tickets() will result in a successful
56
       * lookup. In case no session was stored, std::nullopt is returned.
57
       *
58
       * This method is only called on TLS servers.
59
       *
60
       * Note that implementations will silently refrain from sending session
61
       * tickets to the client when this method returns std::nullopt.
62
       *
63
       * @param session to save
64
       * @param id to use (instead of an ID chosen by the manager)
65
       * @param tls12_no_ticket disable tickets for this establishment
66
       *                        (set when TLS 1.2 client does not support them)
67
       * @return a Session_Handle containing either an ID or a ticket
68
       *         if the session was saved, otherwise std::nullopt
69
       */
70
      virtual std::optional<Session_Handle> establish(const Session& session,
71
                                                      const std::optional<Session_ID>& id = std::nullopt,
72
                                                      bool tls12_no_ticket = false);
73
74
      /**
75
       * @brief Save a Session under a Session_Handle (TLS Client)
76
       *
77
       * Save a session on a best effort basis; the manager may not in fact be
78
       * able to save the session for whatever reason; this is not an error.
79
       * Callers cannot assume that calling store() followed immediately by
80
       * find() will result in a successful lookup.
81
       *
82
       * In contrast to establish(), this stores sessions that were created by
83
       * the server along with a Session_Handle also coined by the server.
84
       *
85
       * This method is only called on TLS clients.
86
       *
87
       * @param session to save
88
       * @param handle a Session_Handle on which this session shoud by stored
89
       */
90
      virtual void store(const Session& session, const Session_Handle& handle) = 0;
91
92
#if defined(BOTAN_HAS_TLS_13)
93
      /**
94
       * Lets the server application choose a PSK to use for a new TLS
95
       * connection. Implementers must make sure that the PSK's associated
96
       * hash function is equal to the passed @p hash_function.
97
       *
98
       * RFC 8446 4.2.11
99
       *    The server MUST ensure that it selects a compatible PSK (if any)
100
       *    and cipher suite.
101
       *
102
       * The default implementation simply tries to retrieve all tickets in
103
       * the order offered by the peer and picks the first that is found and
104
       * features a matching hash algorithm.
105
       *
106
       * This method is called only by TLS 1.3 servers.
107
       *
108
       * @param tickets a list of tickets that were offered by the client
109
       * @param hash_function the hash algorithm name we are going to use for
110
       *                      the to-be-negotiated connection
111
       * @param callbacks callbacks to be used for session policy decisions
112
       * @param policy policy to be used for session policy decisions
113
       *
114
       * @return a std::pair of the Session associated to the choosen PSK and
115
       *         the index of the selected ticket; std::nullopt if no PSK was
116
       *         chosen for usage (will result in a full handshake)
117
       *
118
       * @note if no PSK is chosen, the server will attempt a regular handshake.
119
       */
120
      virtual std::optional<std::pair<Session, uint16_t>> choose_from_offered_tickets(
121
         const std::vector<PskIdentity>& tickets,
122
         std::string_view hash_function,
123
         Callbacks& callbacks,
124
         const Policy& policy);
125
#endif
126
127
      /**
128
       * @brief Retrieves a specific session given a @p handle
129
       *
130
       * This is typically used by TLS servers to obtain resumption information
131
       * for a previous call to Session_Manager::establish() when a client
132
       * requested resumption using the @p handle.
133
       *
134
       * Even if the session is found successfully, it is returned only if it
135
       * passes policy validations. Most notably an expiry check. If the expiry
136
       * check fails, the default implementation calls Session_Manager::remove()
137
       * for the provided @p handle.
138
       *
139
       * Applications that wish to implement their own Session_Manager may
140
       * override the default implementation to add further policy checks.
141
       * Though, typically implementing Session_Manager::retrieve_one() and
142
       * relying on the default implementation is enough.
143
       *
144
       * @param handle     the Session_Handle to be retrieved
145
       * @param callbacks  callbacks to be used for session policy decisions
146
       * @param policy     policy to be used for session policy decisions
147
       * @return           the obtained session or std::nullopt if no session
148
       *                   was found or the policy checks failed
149
       */
150
      virtual std::optional<Session> retrieve(const Session_Handle& handle, Callbacks& callbacks, const Policy& policy);
151
152
      /**
153
       * @brief Find all sessions that match a given server @p info
154
       *
155
       * TLS clients use this to obtain session resumption information for a
156
       * server they are wishing to handshake with. Typically, session info will
157
       * have been received in prior connections to that same server and stored
158
       * using Session_Manager::store().
159
       *
160
       * The default implementation will invoke Session_Manager::find_some() and
161
       * filter the result against a policy. Most notably an expiry check.
162
       * Expired sessions will be removed via Session_Manager::remove().
163
       *
164
       * The TLS client implementations will query the session manager exactly
165
       * once per handshake attempt. If no reuse is desired, the session manager
166
       * may remove the sessions internally when handing them out to the client.
167
       * The default implementation adheres to Policy::reuse_session_tickets().
168
       *
169
       * For TLS 1.2 the client implementation will attempt a resumption with
170
       * the first session in the returned list. For TLS 1.3, it will offer all
171
       * found sessions to the server.
172
       *
173
       * Applications that wish to implement their own Session_Manager may
174
       * override the default implementation to add further policy checks.
175
       * Though, typically implementing Session_Manager::find_some() and
176
       * relying on the default implementation is enough.
177
       *
178
       * @param info       the info about the server we want to handshake with
179
       * @param callbacks  callbacks to be used for session policy decisions
180
       * @param policy     policy to be used for session policy decisions
181
       * @return           a list of usable sessions that might be empty if no
182
       *                   such session exists or passed the policy validation
183
       */
184
      virtual std::vector<Session_with_Handle> find(const Server_Information& info,
185
                                                    Callbacks& callbacks,
186
                                                    const Policy& policy);
187
188
      /**
189
       * Remove a specific session from the cache, if it exists.
190
       * The handle might contain either a session ID or a ticket.
191
       *
192
       * @param handle a Session_Handle of the session to be removed
193
       * @return the number of sessions that were removed
194
       */
195
      virtual size_t remove(const Session_Handle& handle) = 0;
196
197
      /**
198
       * Remove all sessions from the cache
199
       * @return the number of sessions that were removed
200
       */
201
      virtual size_t remove_all() = 0;
202
203
      /**
204
       * Declares whether the given Session_Manager implementation may emit
205
       * session tickets. Note that this _does not_ mean that the implementation
206
       * must always emit tickets.
207
       *
208
       * Concrete implementations should declare this, to allow the TLS
209
       * implementations to act accordingly. E.g. to advertise support for
210
       * session tickets in their Server Hello.
211
       *
212
       * @return true if the Session_Manager produces session tickets
213
       */
214
21.2k
      virtual bool emits_session_tickets() { return false; }
215
216
9.79k
      virtual ~Session_Manager() = default;
217
218
   protected:
219
      /**
220
       * @brief Internal retrieval function for a single session
221
       *
222
       * Try to obtain a Session from a Session_Handle that contains either
223
       * a session ID or a session ticket. This method should not apply any
224
       * policy decision (such as ticket expiry) but simply be a storage
225
       * interface.
226
       *
227
       * Applications that wish to implement their own Session_Manager will
228
       * have to provide an implementation for it.
229
       *
230
       * This method is called only by servers.
231
       *
232
       * @param handle a Session_Handle containing either an ID or a ticket
233
       * @return the obtained session or std::nullopt if none can be obtained
234
       */
235
      virtual std::optional<Session> retrieve_one(const Session_Handle& handle) = 0;
236
237
      /**
238
       * @brief Internal retrieval function to find sessions to resume
239
       *
240
       * Try to find saved sessions using info about the server we're planning
241
       * to connect to. It should return a list of sessions in preference order
242
       * of the session manager.
243
       *
244
       * Applications that wish to implement their own Session_Manager will
245
       * have to provide an implementation for it.
246
       *
247
       * Note that the TLS client implementations do not perform any checks on
248
       * the validity of the session for a given @p info. Particularly, it is
249
       * the Session_Manager's responsibility to ensure the restrictions posed
250
       * in RFC 8446 4.6.1 regarding server certificate validity for the given
251
       * @p info.
252
       *
253
       * This is called for TLS clients only.
254
       *
255
       * @param info               the information about the server
256
       * @param max_sessions_hint  a non-binding guideline for an upper bound of
257
       *                           sessions to return from this method
258
       *                           (will be at least 1 but potentially more)
259
       * @return the found sessions along with their handles (containing either a
260
       *         session ID or a ticket)
261
       */
262
      virtual std::vector<Session_with_Handle> find_some(const Server_Information& info, size_t max_sessions_hint) = 0;
263
264
      /**
265
       * Returns the base class' recursive mutex for reuse in derived classes
266
       */
267
2.85k
      recursive_mutex_type& mutex() { return m_mutex; }
268
269
   private:
270
      std::vector<Session_with_Handle> find_and_filter(const Server_Information& info,
271
                                                       Callbacks& callbacks,
272
                                                       const Policy& policy);
273
274
   protected:
275
      std::shared_ptr<RandomNumberGenerator> m_rng;
276
277
   private:
278
      recursive_mutex_type m_mutex;
279
};
280
281
}  // namespace Botan::TLS
282
283
#endif