Botan 3.6.1
Crypto and TLS for C&
tls_session.h
Go to the documentation of this file.
1/*
2* TLS Session
3* (C) 2011-2012,2015 Jack Lloyd
4* (C) 2022 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_STATE_H_
10#define BOTAN_TLS_SESSION_STATE_H_
11
12#include <botan/secmem.h>
13#include <botan/strong_type.h>
14#include <botan/symkey.h>
15#include <botan/tls_ciphersuite.h>
16#include <botan/tls_magic.h>
17#include <botan/tls_server_info.h>
18#include <botan/tls_version.h>
19#include <botan/x509cert.h>
20
21#include <algorithm>
22#include <chrono>
23#include <span>
24#include <variant>
25
26namespace Botan::TLS {
27
28// Different flavors of session handles are used, depending on the usage
29// scenario and the TLS protocol version.
30
31/// @brief holds a TLS 1.2 session ID for stateful resumption
32using Session_ID = Strong<std::vector<uint8_t>, struct Session_ID_>;
33
34/// @brief holds a TLS 1.2 session ticket for stateless resumption
35using Session_Ticket = Strong<std::vector<uint8_t>, struct Session_Ticket_>;
36
37/// @brief holds an opaque session handle as used in TLS 1.3 that could be
38/// either a ticket for stateless resumption or a database handle.
39using Opaque_Session_Handle = Strong<std::vector<uint8_t>, struct Opaque_Session_Handle_>;
40
41inline auto operator<(const Session_ID& id1, const Session_ID& id2) {
42 // TODO: C++20 better use std::lexicographical_compare_three_way
43 // that was not available on all target platforms at the time
44 // of this writing.
45 return std::lexicographical_compare(id1.begin(), id1.end(), id2.begin(), id2.end());
46}
47
48/**
49 * @brief Helper class to embody a session handle in all protocol versions
50 *
51 * Sessions in TLS 1.2 are identified by an arbitrary and unique ID of up to
52 * 32 bytes or by a self-contained arbitrary-length ticket (RFC 5077).
53 *
54 * TLS 1.3 does not distinct between the two and handles both as tickets. Also
55 * a TLS 1.3 server can issue multiple tickets in one connection and the
56 * resumption mechanism is compatible with the PSK establishment.
57 *
58 * Concrete implementations of Session_Manager use this helper to distinguish
59 * the different states and manage sessions for TLS 1.2 and 1.3 connections.
60 *
61 * Note that all information stored in a Session_Handle might be transmitted in
62 * unprotected form. Hence, it should not contain any confidential information.
63 */
65 public:
66 /**
67 * Constructs a Session_Handle from a session ID which is an
68 * arbitrary byte vector that must be 32 bytes long at most.
69 */
70 Session_Handle(Session_ID id) : m_handle(std::move(id)) { validate_constraints(); }
71
72 /**
73 * Constructs a Session_Handle from a session ticket which is a
74 * non-empty byte vector that must be 64kB long at most.
75 * Typically, tickets facilitate stateless server implementations
76 * and contain all relevant context in encrypted/authenticated form.
77 *
78 * Note that (for technical reasons) we enforce that tickets are
79 * longer than 32 bytes.
80 */
81 Session_Handle(Session_Ticket ticket) : m_handle(std::move(ticket)) { validate_constraints(); }
82
83 /**
84 * Constructs a Session_Handle from an Opaque_Handle such as TLS 1.3
85 * uses them in its resumption mechanism. This could be either a
86 * Session_ID or a Session_Ticket and it is up to the Session_Manager
87 * to figure out what it actually is.
88 */
89 Session_Handle(Opaque_Session_Handle ticket) : m_handle(std::move(ticket)) { validate_constraints(); }
90
91 bool is_id() const { return std::holds_alternative<Session_ID>(m_handle); }
92
93 bool is_ticket() const { return std::holds_alternative<Session_Ticket>(m_handle); }
94
95 bool is_opaque_handle() const { return std::holds_alternative<Opaque_Session_Handle>(m_handle); }
96
97 /**
98 * Returns the Session_Handle as an opaque handle. If the object was not
99 * constructed as an Opaque_Session_Handle, the contained value is
100 * converted.
101 */
102 Opaque_Session_Handle opaque_handle() const;
103
104 /**
105 * If the Session_Handle was constructed with a Session_ID or an
106 * Opaque_Session_Handle that can be converted to a Session_ID (up to
107 * 32 bytes long), this returns the handle as a Session_ID. Otherwise,
108 * std::nullopt is returned.
109 */
110 std::optional<Session_ID> id() const;
111
112 /**
113 * If the Session_Handle was constructed with a Session_Ticket or an
114 * Opaque_Session_Handle this returns the handle as a Session_ID.
115 * Otherwise, std::nullopt is returned.
116 */
117 std::optional<Session_Ticket> ticket() const;
118
119 decltype(auto) get() const { return m_handle; }
120
121 private:
122 void validate_constraints() const;
123
124 private:
125 std::variant<Session_ID, Session_Ticket, Opaque_Session_Handle> m_handle;
126};
127
128class Client_Hello_13;
129class Server_Hello_13;
130class Callbacks;
131
132/**
133 * Represents basic information about a session that can be both
134 * persisted for resumption and presented to the application as
135 * a summary of a specific just-established TLS session.
136 */
138 public:
139 Session_Base(std::chrono::system_clock::time_point start_time,
140 Protocol_Version version,
141 uint16_t ciphersuite,
142 Connection_Side connection_side,
143 uint16_t srtp_profile,
144 bool extended_master_secret,
145 bool encrypt_then_mac,
146 std::vector<X509_Certificate> peer_certs,
147 std::shared_ptr<const Public_Key> peer_raw_public_key,
148 Server_Information server_info) :
149 m_start_time(start_time),
150 m_version(version),
151 m_ciphersuite(ciphersuite),
152 m_connection_side(connection_side),
153 m_srtp_profile(srtp_profile),
154 m_extended_master_secret(extended_master_secret),
155 m_encrypt_then_mac(encrypt_then_mac),
156 m_peer_certs(std::move(peer_certs)),
157 m_peer_raw_public_key(std::move(peer_raw_public_key)),
158 m_server_info(std::move(server_info)) {}
159
160 protected:
161 Session_Base() = default;
162
163 public:
164 /**
165 * Get the wall clock time this session began
166 */
167 std::chrono::system_clock::time_point start_time() const { return m_start_time; }
168
169 /**
170 * Get the negotiated protocol version of the TLS session
171 */
172 Protocol_Version version() const { return m_version; }
173
174 /**
175 * Get the ciphersuite code of the negotiated TLS session
176 */
177 uint16_t ciphersuite_code() const { return m_ciphersuite; }
178
179 /**
180 * Get the ciphersuite info of the negotiated TLS session
181 */
182 Ciphersuite ciphersuite() const;
183
184 /**
185 * Get which side of the connection we are/were acting as.
186 */
187 Connection_Side side() const { return m_connection_side; }
188
189 /**
190 * Get the negotiated DTLS-SRTP algorithm (RFC 5764)
191 */
192 uint16_t dtls_srtp_profile() const { return m_srtp_profile; }
193
194 /**
195 * Returns true if a TLS 1.2 session negotiated "encrypt then MAC";
196 * TLS 1.3 sessions will always return false as they always use an AEAD.
197 */
198 bool supports_encrypt_then_mac() const { return m_encrypt_then_mac; }
199
200 /**
201 * Returns true if a TLS 1.2 session negotiated "extended master secret";
202 * TLS 1.3 sessions will always return true (see RFC 8446 Appendix D).
203 */
204 bool supports_extended_master_secret() const { return m_extended_master_secret; }
205
206 /**
207 * Return the certificate chain of the peer (possibly empty)
208 */
209 const std::vector<X509_Certificate>& peer_certs() const { return m_peer_certs; }
210
211 /**
212 * Return the raw public key of the peer (possibly empty)
213 */
214 std::shared_ptr<const Public_Key> peer_raw_public_key() const { return m_peer_raw_public_key; }
215
216 /**
217 * Get information about the TLS server
218 *
219 * Returns information that identifies the server side of the connection.
220 * This is useful for the client in that it identifies what was originally
221 * passed to the constructor. For the server, it includes the name the
222 * client specified in the server name indicator extension.
223 */
224 const Server_Information& server_info() const { return m_server_info; }
225
226 protected:
227 std::chrono::system_clock::time_point m_start_time;
228
233
236
237 std::vector<X509_Certificate> m_peer_certs;
238 std::shared_ptr<const Public_Key> m_peer_raw_public_key;
240};
241
242/**
243 * Summarizes the negotiated features after a TLS handshake. Applications may
244 * query those in Callbacks::tls_session_established().
245 */
247 public:
248 /**
249 * The Session_ID negotiated during the handshake.
250 * Note that this does not carry any meaning in TLS 1.3 and might even
251 * be empty.
252 */
253 const Session_ID& session_id() const { return m_session_id; }
254
255 /**
256 * The session ticket a TLS 1.2 server issued for this session.
257 * Note that this may be set in TLS 1.2 clients only. It is _not_ the
258 * ticket used to establish this session.
259 */
260 const std::optional<Session_Ticket>& session_ticket() const { return m_session_ticket; }
261
262 /**
263 * The negotiated identity of an externally provided preshared key used to
264 * establish this session. For TLS 1.3 this may be any of the externally
265 * provided PSKs offered by the client. PSK identities used as session
266 * tickets for TLS 1.3 session resumption won't be shown here.
267 */
268 const std::optional<std::string>& external_psk_identity() const { return m_external_psk_identity; }
269
270 /**
271 * Indicates that the session was established using an externally provided
272 * PSK. Session resumptions in TLS 1.3 (while technically implemented
273 * using a PSK) are not considered here. @sa was_resumption()
274 *
275 * @note Botan 3.0 and 3.1 did incorrectly report true for session resumption.
276 *
277 * @returns true if the session was established using an externally
278 * provided PSK.
279 */
280 bool psk_used() const { return m_external_psk_identity.has_value(); }
281
282 /**
283 * Indicates that the session was resumed from a previous handshake state.
284 *
285 * @returns true if this session is a resumption, otherwise false
286 */
287 bool was_resumption() const { return m_was_resumption; }
288
289 std::string kex_algo() const { return m_kex_algo; }
290
291 std::string cipher_algo() const { return ciphersuite().cipher_algo(); }
292
293 std::string mac_algo() const { return ciphersuite().mac_algo(); }
294
295 std::string prf_algo() const { return ciphersuite().prf_algo(); }
296
297 private:
298 friend class Server_Impl_12;
299 friend class Server_Impl_13;
300 friend class Client_Impl_12;
301 friend class Client_Impl_13;
302
303 Session_Summary(const Session_Base& base, bool was_resumption, std::optional<std::string> psk_identity);
304
305#if defined(BOTAN_HAS_TLS_13)
306 Session_Summary(const Server_Hello_13& server_hello,
307 Connection_Side side,
308 std::vector<X509_Certificate> peer_certs,
309 std::shared_ptr<const Public_Key> peer_raw_public_key,
310 std::optional<std::string> psk_identity,
311 bool session_was_resumed,
312 Server_Information server_info,
313 std::chrono::system_clock::time_point current_timestamp);
314#endif
315
316 void set_session_id(Session_ID id) { m_session_id = std::move(id); }
317
318 void set_session_ticket(Session_Ticket ticket) { m_session_ticket = std::move(ticket); }
319
320 private:
321 Session_ID m_session_id;
322 std::optional<Session_Ticket> m_session_ticket;
323 std::optional<std::string> m_external_psk_identity;
324
325 bool m_was_resumption;
326 std::string m_kex_algo;
327};
328
329/**
330 * Represents a session's negotiated features along with all resumption
331 * information to re-establish a TLS connection later on.
332 */
334 public:
335 /**
336 * New TLS 1.2 session (sets session start time)
337 */
338 Session(const secure_vector<uint8_t>& master_secret,
339 Protocol_Version version,
340 uint16_t ciphersuite,
341 Connection_Side side,
342 bool supports_extended_master_secret,
343 bool supports_encrypt_then_mac,
344 const std::vector<X509_Certificate>& peer_certs,
345 const Server_Information& server_info,
346 uint16_t srtp_profile,
347 std::chrono::system_clock::time_point current_timestamp,
348 std::chrono::seconds lifetime_hint = std::chrono::seconds::max());
349
350#if defined(BOTAN_HAS_TLS_13)
351
352 /**
353 * New TLS 1.3 session (sets session start time)
354 */
355 Session(const secure_vector<uint8_t>& session_psk,
356 const std::optional<uint32_t>& max_early_data_bytes,
357 uint32_t ticket_age_add,
358 std::chrono::seconds lifetime_hint,
359 Protocol_Version version,
360 uint16_t ciphersuite,
361 Connection_Side side,
362 const std::vector<X509_Certificate>& peer_certs,
363 std::shared_ptr<const Public_Key> peer_raw_public_key,
364 const Server_Information& server_info,
365 std::chrono::system_clock::time_point current_timestamp);
366
367 /**
368 * Create a new TLS 1.3 session object from server data structures
369 * after a successful handshake with a TLS 1.3 client
370 */
371 Session(secure_vector<uint8_t>&& session_psk,
372 const std::optional<uint32_t>& max_early_data_bytes,
373 std::chrono::seconds lifetime_hint,
374 const std::vector<X509_Certificate>& peer_certs,
375 std::shared_ptr<const Public_Key> peer_raw_public_key,
376 const Client_Hello_13& client_hello,
377 const Server_Hello_13& server_hello,
378 Callbacks& callbacks,
380
381#endif
382
383 /**
384 * Load a session from DER representation (created by DER_encode)
385 * @param ber_data DER representation buffer
386 */
387 Session(std::span<const uint8_t> ber_data);
388
389 /**
390 * Load a session from PEM representation (created by PEM_encode)
391 * @param pem PEM representation
392 */
393 explicit Session(std::string_view pem);
394
395 /**
396 * Encode this session data for storage
397 * @warning if the master secret is compromised so is the
398 * session traffic
399 */
400 secure_vector<uint8_t> DER_encode() const;
401
402 /**
403 * Encrypt a session (useful for serialization or session tickets)
404 */
405 std::vector<uint8_t> encrypt(const SymmetricKey& key, RandomNumberGenerator& rng) const;
406
407 /**
408 * Decrypt a session created by encrypt
409 * @param ctext the ciphertext returned by encrypt
410 * @param ctext_size the size of ctext in bytes
411 * @param key the same key used by the encrypting side
412 */
413 static inline Session decrypt(const uint8_t ctext[], size_t ctext_size, const SymmetricKey& key) {
414 return Session::decrypt(std::span(ctext, ctext_size), key);
415 }
416
417 /**
418 * Decrypt a session created by encrypt
419 * @param ctext the ciphertext returned by encrypt
420 * @param key the same key used by the encrypting side
421 */
422 static Session decrypt(std::span<const uint8_t> ctext, const SymmetricKey& key);
423
424 /**
425 * Encode this session data for storage
426 * @warning if the master secret is compromised so is the
427 * session traffic
428 */
429 std::string PEM_encode() const;
430
431 /**
432 * Get a reference to the contained master secret
433 */
434 const secure_vector<uint8_t>& master_secret() const { return m_master_secret; }
435
436 /**
437 * Get the contained master secret as a moved-out object
438 */
439 secure_vector<uint8_t> extract_master_secret();
440
441 /**
442 * Get whether the saved session supports sending/receiving of early data
443 */
444 bool supports_early_data() const { return m_early_data_allowed; }
445
446 /**
447 * Return the ticket obfuscation adder
448 */
449 uint32_t session_age_add() const { return m_ticket_age_add; }
450
451 /**
452 * Return the number of bytes allowed for 0-RTT early data
453 */
454 uint32_t max_early_data_bytes() const { return m_max_early_data_bytes; }
455
456 /**
457 * @return the lifetime of the ticket as defined by the TLS server
458 */
459 std::chrono::seconds lifetime_hint() const { return m_lifetime_hint; }
460
461 private:
462 // Struct Version history
463 //
464 // 20160812 - Pre TLS 1.3
465 // 20220505 - Introduction of TLS 1.3 sessions
466 // - added fields:
467 // - m_early_data_allowed
468 // - m_max_early_data_bytes
469 // - m_ticket_age_add
470 // - m_lifetime_hint
471 // 20230112 - Remove Session_ID and Session_Ticket from this object
472 // (association is now in the hands of the Session_Manager)
473 // - Peer certificates are now stored as a SEQUENCE
474 // 20230222 - Remove deprecated and unused fields
475 // - compression method (always 0)
476 // - fragment size (always 0)
477 // - SRP identifier (always "")
478 // 20231031 - Allow storage of peer's raw public key
479 enum { TLS_SESSION_PARAM_STRUCT_VERSION = 20231031 };
480
481 secure_vector<uint8_t> m_master_secret;
482
483 bool m_early_data_allowed;
484 uint32_t m_max_early_data_bytes;
485 uint32_t m_ticket_age_add;
486 std::chrono::seconds m_lifetime_hint;
487};
488
489/**
490 * Helper struct to conveniently pass a Session and its Session_Handle around
491 */
496
497} // namespace Botan::TLS
498
499#endif
std::vector< X509_Certificate > m_peer_certs
Session_Base(std::chrono::system_clock::time_point start_time, Protocol_Version version, uint16_t ciphersuite, Connection_Side connection_side, uint16_t srtp_profile, bool extended_master_secret, bool encrypt_then_mac, std::vector< X509_Certificate > peer_certs, std::shared_ptr< const Public_Key > peer_raw_public_key, Server_Information server_info)
std::shared_ptr< const Public_Key > peer_raw_public_key() const
uint16_t dtls_srtp_profile() const
Protocol_Version version() const
Connection_Side side() const
bool supports_encrypt_then_mac() const
Protocol_Version m_version
std::chrono::system_clock::time_point m_start_time
Server_Information m_server_info
std::chrono::system_clock::time_point start_time() const
uint16_t ciphersuite_code() const
bool supports_extended_master_secret() const
const std::vector< X509_Certificate > & peer_certs() const
const Server_Information & server_info() const
std::shared_ptr< const Public_Key > m_peer_raw_public_key
Connection_Side m_connection_side
Helper class to embody a session handle in all protocol versions.
Definition tls_session.h:64
decltype(auto) get() const
Session_Handle(Session_Ticket ticket)
Definition tls_session.h:81
bool is_opaque_handle() const
Definition tls_session.h:95
Session_Handle(Session_ID id)
Definition tls_session.h:70
Session_Handle(Opaque_Session_Handle ticket)
Definition tls_session.h:89
std::string cipher_algo() const
std::string mac_algo() const
std::string kex_algo() const
const std::optional< Session_Ticket > & session_ticket() const
const std::optional< std::string > & external_psk_identity() const
const Session_ID & session_id() const
std::string prf_algo() const
std::chrono::seconds lifetime_hint() const
static Session decrypt(const uint8_t ctext[], size_t ctext_size, const SymmetricKey &key)
bool supports_early_data() const
uint32_t session_age_add() const
const secure_vector< uint8_t > & master_secret() const
uint32_t max_early_data_bytes() const
int(* final)(unsigned char *, CTX *)
#define BOTAN_PUBLIC_API(maj, min)
Definition compiler.h:31
bool operator<(const Server_Information &a, const Server_Information &b)
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61