/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 |