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