• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 16829521929

08 Aug 2025 11:41AM UTC coverage: 90.666% (+0.003%) from 90.663%
16829521929

Pull #5055

github

web-flow
Merge 1ebf1b18d into eaad5c540
Pull Request #5055: Remove various uses of IEEE 1363's EME terminology for encryption padding

100015 of 110311 relevant lines covered (90.67%)

12168580.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.83
/src/lib/tls/tls_session.h
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

25
namespace 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
31
using Session_ID = Strong<std::vector<uint8_t>, struct Session_ID_>;
32

33
/// @brief holds a TLS 1.2 session ticket for stateless resumption
34
using 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.
38
using Opaque_Session_Handle = Strong<std::vector<uint8_t>, struct Opaque_Session_Handle_>;
39

40
inline auto operator<(const Session_ID& id1, const Session_ID& id2) {
1,997✔
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());
1,977✔
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
 */
63
class BOTAN_PUBLIC_API(3, 0) Session_Handle {
20,741✔
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(); }
693✔
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(); }
2,167✔
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(); }
689✔
91

92
      // NOLINTEND(*-explicit-conversions)
93

94
      bool is_id() const { return std::holds_alternative<Session_ID>(m_handle); }
2,845✔
95

96
      bool is_ticket() const { return std::holds_alternative<Session_Ticket>(m_handle); }
3,866✔
97

98
      bool is_opaque_handle() const { return std::holds_alternative<Opaque_Session_Handle>(m_handle); }
2,384✔
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; }
574✔
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

131
class Client_Hello_13;
132
class Server_Hello_13;
133
class 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
 */
140
class BOTAN_PUBLIC_API(3, 0) Session_Base {
141
   public:
142
      Session_Base(std::chrono::system_clock::time_point start_time,
3,133✔
143
                   Protocol_Version version,
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,
151
                   Server_Information server_info) :
3,133✔
152
            m_start_time(start_time),
3,133✔
153
            m_version(version),
3,133✔
154
            m_ciphersuite(ciphersuite),
3,133✔
155
            m_connection_side(connection_side),
3,133✔
156
            m_srtp_profile(srtp_profile),
3,133✔
157
            m_extended_master_secret(extended_master_secret),
3,133✔
158
            m_encrypt_then_mac(encrypt_then_mac),
3,133✔
159
            m_peer_certs(std::move(peer_certs)),
3,133✔
160
            m_peer_raw_public_key(std::move(peer_raw_public_key)),
3,133✔
161
            m_server_info(std::move(server_info)) {}
3,133✔
162

163
   protected:
164
      Session_Base() = default;
452✔
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; }
1,560✔
171

172
      /**
173
       * Get the negotiated protocol version of the TLS session
174
       */
175
      Protocol_Version version() const { return m_version; }
8,083✔
176

177
      /**
178
       * Get the ciphersuite code of the negotiated TLS session
179
       */
180
      uint16_t ciphersuite_code() const { return m_ciphersuite; }
685✔
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
       */
190
      Connection_Side side() const { return m_connection_side; }
1,152✔
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
       */
201
      bool supports_encrypt_then_mac() const { return m_encrypt_then_mac; }
440✔
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
       */
207
      bool supports_extended_master_secret() const { return m_extended_master_secret; }
2,472✔
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; }
808✔
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; }
379✔
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
       */
227
      const Server_Information& server_info() const { return m_server_info; }
1,903✔
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
 */
249
class 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; }
22✔
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; }
18✔
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; }
30✔
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(); }
1,220✔
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; }
1,212✔
291

292
      std::string kex_algo() const { return m_kex_algo; }
293

294
      std::optional<std::string> kex_parameters() const { return m_kex_parameters; }
9✔
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,
312
                      Connection_Side side,
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,
317
                      Server_Information server_info,
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); }
2,389✔
322

323
      void set_session_ticket(Session_Ticket ticket) { m_session_ticket = std::move(ticket); }
800✔
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
 */
339
class BOTAN_PUBLIC_API(3, 0) Session final : public Session_Base {
340
   public:
341
      /**
342
      * New TLS 1.2 session (sets session start time)
343
      */
344
      Session(const secure_vector<uint8_t>& master_secret,
345
              Protocol_Version version,
346
              uint16_t ciphersuite,
347
              Connection_Side side,
348
              bool supports_extended_master_secret,
349
              bool supports_encrypt_then_mac,
350
              const std::vector<X509_Certificate>& peer_certs,
351
              const Server_Information& server_info,
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,
365
              Protocol_Version version,
366
              uint16_t ciphersuite,
367
              Connection_Side side,
368
              const std::vector<X509_Certificate>& peer_certs,
369
              std::shared_ptr<const Public_Key> peer_raw_public_key,
370
              const Server_Information& server_info,
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,
385
              RandomNumberGenerator& rng);
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
      */
406
      secure_vector<uint8_t> DER_encode() const;
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) {
130✔
420
         return Session::decrypt(std::span(ctext, ctext_size), key);
130✔
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; }
434✔
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; }
354✔
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; }
3,730✔
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
 */
498
struct BOTAN_PUBLIC_API(3, 0) Session_with_Handle {
×
499
      Session session;
500
      Session_Handle handle;
501
};
502

503
}  // namespace Botan::TLS
504

505
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc