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

randombit / botan / 12548935066

30 Dec 2024 04:04PM UTC coverage: 91.262% (+0.05%) from 91.208%
12548935066

Pull #4507

github

web-flow
Merge 3aca433ed into 9b8f3cc80
Pull Request #4507: Remove support for Kyber r3 key exchange in TLS

93394 of 102336 relevant lines covered (91.26%)

11408572.15 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 <algorithm>
22
#include <chrono>
23
#include <span>
24
#include <variant>
25

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

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

41
inline auto operator<(const Session_ID& id1, const Session_ID& id2) {
1,980✔
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());
1,962✔
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
 */
64
class BOTAN_PUBLIC_API(3, 0) Session_Handle {
16,399✔
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(); }
680✔
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(); }
2,167✔
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(); }
689✔
90

91
      bool is_id() const { return std::holds_alternative<Session_ID>(m_handle); }
2,831✔
92

93
      bool is_ticket() const { return std::holds_alternative<Session_Ticket>(m_handle); }
3,856✔
94

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

128
class Client_Hello_13;
129
class Server_Hello_13;
130
class 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
 */
137
class BOTAN_PUBLIC_API(3, 0) Session_Base {
138
   public:
139
      Session_Base(std::chrono::system_clock::time_point start_time,
3,126✔
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) :
3,126✔
149
            m_start_time(start_time),
3,126✔
150
            m_version(version),
3,126✔
151
            m_ciphersuite(ciphersuite),
3,126✔
152
            m_connection_side(connection_side),
3,126✔
153
            m_srtp_profile(srtp_profile),
3,126✔
154
            m_extended_master_secret(extended_master_secret),
3,126✔
155
            m_encrypt_then_mac(encrypt_then_mac),
3,126✔
156
            m_peer_certs(std::move(peer_certs)),
3,126✔
157
            m_peer_raw_public_key(std::move(peer_raw_public_key)),
3,126✔
158
            m_server_info(std::move(server_info)) {}
3,126✔
159

160
   protected:
161
      Session_Base() = default;
447✔
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; }
1,564✔
168

169
      /**
170
       * Get the negotiated protocol version of the TLS session
171
       */
172
      Protocol_Version version() const { return m_version; }
8,041✔
173

174
      /**
175
       * Get the ciphersuite code of the negotiated TLS session
176
       */
177
      uint16_t ciphersuite_code() const { return m_ciphersuite; }
682✔
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; }
1,148✔
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; }
439✔
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; }
2,470✔
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; }
806✔
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; }
379✔
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; }
1,896✔
225

226
   protected:
227
      std::chrono::system_clock::time_point m_start_time;
228

229
      Protocol_Version m_version;
230
      uint16_t m_ciphersuite;
231
      Connection_Side m_connection_side;
232
      uint16_t m_srtp_profile;
233

234
      bool m_extended_master_secret;
235
      bool m_encrypt_then_mac;
236

237
      std::vector<X509_Certificate> m_peer_certs;
238
      std::shared_ptr<const Public_Key> m_peer_raw_public_key;
239
      Server_Information m_server_info;
240
};
241

242
/**
243
 * Summarizes the negotiated features after a TLS handshake. Applications may
244
 * query those in Callbacks::tls_session_established().
245
 */
246
class BOTAN_PUBLIC_API(3, 0) Session_Summary : public Session_Base {
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; }
22✔
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; }
18✔
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; }
20✔
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(); }
1,232✔
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; }
1,212✔
288

289
      std::string kex_algo() const { return m_kex_algo; }
290

291
      std::optional<std::string> kex_parameters() const { return m_kex_parameters; }
9✔
292

293
      std::string cipher_algo() const { return ciphersuite().cipher_algo(); }
294

295
      std::string mac_algo() const { return ciphersuite().mac_algo(); }
296

297
      std::string prf_algo() const { return ciphersuite().prf_algo(); }
298

299
   private:
300
      friend class Server_Impl_12;
301
      friend class Server_Impl_13;
302
      friend class Client_Impl_12;
303
      friend class Client_Impl_13;
304

305
      Session_Summary(const Session_Base& base, bool was_resumption, std::optional<std::string> psk_identity);
306

307
#if defined(BOTAN_HAS_TLS_13)
308
      Session_Summary(const Server_Hello_13& server_hello,
309
                      Connection_Side side,
310
                      std::vector<X509_Certificate> peer_certs,
311
                      std::shared_ptr<const Public_Key> peer_raw_public_key,
312
                      std::optional<std::string> psk_identity,
313
                      bool session_was_resumed,
314
                      Server_Information server_info,
315
                      std::chrono::system_clock::time_point current_timestamp);
316
#endif
317

318
      void set_session_id(Session_ID id) { m_session_id = std::move(id); }
2,381✔
319

320
      void set_session_ticket(Session_Ticket ticket) { m_session_ticket = std::move(ticket); }
800✔
321

322
   private:
323
      Session_ID m_session_id;
324
      std::optional<Session_Ticket> m_session_ticket;
325
      std::optional<std::string> m_external_psk_identity;
326

327
      bool m_was_resumption;
328
      std::string m_kex_algo;
329
      std::optional<std::string> m_kex_parameters;
330
};
331

332
/**
333
 * Represents a session's negotiated features along with all resumption
334
 * information to re-establish a TLS connection later on.
335
 */
336
class BOTAN_PUBLIC_API(3, 0) Session final : public Session_Base {
337
   public:
338
      /**
339
      * New TLS 1.2 session (sets session start time)
340
      */
341
      Session(const secure_vector<uint8_t>& master_secret,
342
              Protocol_Version version,
343
              uint16_t ciphersuite,
344
              Connection_Side side,
345
              bool supports_extended_master_secret,
346
              bool supports_encrypt_then_mac,
347
              const std::vector<X509_Certificate>& peer_certs,
348
              const Server_Information& server_info,
349
              uint16_t srtp_profile,
350
              std::chrono::system_clock::time_point current_timestamp,
351
              std::chrono::seconds lifetime_hint = std::chrono::seconds::max());
352

353
#if defined(BOTAN_HAS_TLS_13)
354

355
      /**
356
      * New TLS 1.3 session (sets session start time)
357
      */
358
      Session(const secure_vector<uint8_t>& session_psk,
359
              const std::optional<uint32_t>& max_early_data_bytes,
360
              uint32_t ticket_age_add,
361
              std::chrono::seconds lifetime_hint,
362
              Protocol_Version version,
363
              uint16_t ciphersuite,
364
              Connection_Side side,
365
              const std::vector<X509_Certificate>& peer_certs,
366
              std::shared_ptr<const Public_Key> peer_raw_public_key,
367
              const Server_Information& server_info,
368
              std::chrono::system_clock::time_point current_timestamp);
369

370
      /**
371
       * Create a new TLS 1.3 session object from server data structures
372
       * after a successful handshake with a TLS 1.3 client
373
       */
374
      Session(secure_vector<uint8_t>&& session_psk,
375
              const std::optional<uint32_t>& max_early_data_bytes,
376
              std::chrono::seconds lifetime_hint,
377
              const std::vector<X509_Certificate>& peer_certs,
378
              std::shared_ptr<const Public_Key> peer_raw_public_key,
379
              const Client_Hello_13& client_hello,
380
              const Server_Hello_13& server_hello,
381
              Callbacks& callbacks,
382
              RandomNumberGenerator& rng);
383

384
#endif
385

386
      /**
387
      * Load a session from DER representation (created by DER_encode)
388
      * @param ber_data DER representation buffer
389
      */
390
      Session(std::span<const uint8_t> ber_data);
391

392
      /**
393
      * Load a session from PEM representation (created by PEM_encode)
394
      * @param pem PEM representation
395
      */
396
      explicit Session(std::string_view pem);
397

398
      /**
399
      * Encode this session data for storage
400
      * @warning if the master secret is compromised so is the
401
      * session traffic
402
      */
403
      secure_vector<uint8_t> DER_encode() const;
404

405
      /**
406
      * Encrypt a session (useful for serialization or session tickets)
407
      */
408
      std::vector<uint8_t> encrypt(const SymmetricKey& key, RandomNumberGenerator& rng) const;
409

410
      /**
411
      * Decrypt a session created by encrypt
412
      * @param ctext the ciphertext returned by encrypt
413
      * @param ctext_size the size of ctext in bytes
414
      * @param key the same key used by the encrypting side
415
      */
416
      static inline Session decrypt(const uint8_t ctext[], size_t ctext_size, const SymmetricKey& key) {
125✔
417
         return Session::decrypt(std::span(ctext, ctext_size), key);
125✔
418
      }
419

420
      /**
421
      * Decrypt a session created by encrypt
422
      * @param ctext the ciphertext returned by encrypt
423
      * @param key the same key used by the encrypting side
424
      */
425
      static Session decrypt(std::span<const uint8_t> ctext, const SymmetricKey& key);
426

427
      /**
428
      * Encode this session data for storage
429
      * @warning if the master secret is compromised so is the
430
      * session traffic
431
      */
432
      std::string PEM_encode() const;
433

434
      /**
435
      * Get a reference to the contained master secret
436
      */
437
      const secure_vector<uint8_t>& master_secret() const { return m_master_secret; }
432✔
438

439
      /**
440
      * Get the contained master secret as a moved-out object
441
      */
442
      secure_vector<uint8_t> extract_master_secret();
443

444
      /**
445
       * Get whether the saved session supports sending/receiving of early data
446
       */
447
      bool supports_early_data() const { return m_early_data_allowed; }
448

449
      /**
450
      * Return the ticket obfuscation adder
451
      */
452
      uint32_t session_age_add() const { return m_ticket_age_add; }
354✔
453

454
      /**
455
      * Return the number of bytes allowed for 0-RTT early data
456
      */
457
      uint32_t max_early_data_bytes() const { return m_max_early_data_bytes; }
458

459
      /**
460
      * @return the lifetime of the ticket as defined by the TLS server
461
      */
462
      std::chrono::seconds lifetime_hint() const { return m_lifetime_hint; }
3,734✔
463

464
   private:
465
      // Struct Version history
466
      //
467
      // 20160812 - Pre TLS 1.3
468
      // 20220505 - Introduction of TLS 1.3 sessions
469
      //            - added fields:
470
      //              - m_early_data_allowed
471
      //              - m_max_early_data_bytes
472
      //              - m_ticket_age_add
473
      //              - m_lifetime_hint
474
      // 20230112 - Remove Session_ID and Session_Ticket from this object
475
      //            (association is now in the hands of the Session_Manager)
476
      //          - Peer certificates are now stored as a SEQUENCE
477
      // 20230222 - Remove deprecated and unused fields
478
      //            - compression method (always 0)
479
      //            - fragment size (always 0)
480
      //            - SRP identifier (always "")
481
      // 20231031 - Allow storage of peer's raw public key
482
      enum { TLS_SESSION_PARAM_STRUCT_VERSION = 20231031 };
483

484
      secure_vector<uint8_t> m_master_secret;
485

486
      bool m_early_data_allowed;
487
      uint32_t m_max_early_data_bytes;
488
      uint32_t m_ticket_age_add;
489
      std::chrono::seconds m_lifetime_hint;
490
};
491

492
/**
493
 * Helper struct to conveniently pass a Session and its Session_Handle around
494
 */
495
struct BOTAN_PUBLIC_API(3, 0) Session_with_Handle {
×
496
      Session session;
497
      Session_Handle handle;
498
};
499

500
}  // namespace Botan::TLS
501

502
#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