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

randombit / botan / 6546858227

17 Oct 2023 12:02PM UTC coverage: 91.71% (+0.002%) from 91.708%
6546858227

push

github

randombit
Merge GH #3760 Move constant time memory comparisons to ct_utils.h

80095 of 87335 relevant lines covered (91.71%)

8508512.25 hits per line

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

98.75
/src/lib/tls/tls_session.cpp
1
/*
2
* TLS Session State
3
* (C) 2011-2012,2015,2019 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/tls_session.h>
9

10
#include <botan/aead.h>
11
#include <botan/asn1_obj.h>
12
#include <botan/ber_dec.h>
13
#include <botan/der_enc.h>
14
#include <botan/mac.h>
15
#include <botan/pem.h>
16
#include <botan/rng.h>
17
#include <botan/internal/ct_utils.h>
18
#include <botan/internal/loadstor.h>
19

20
#include <botan/tls_callbacks.h>
21
#include <botan/tls_messages.h>
22

23
#include <botan/internal/stl_util.h>
24

25
#include <utility>
26

27
namespace Botan::TLS {
28

29
void Session_Handle::validate_constraints() const {
3,457✔
30
   std::visit(overloaded{
6,914✔
31
                 [](const Session_ID& id) {
636✔
32
                    // RFC 5246 7.4.1.2
33
                    //    opaque SessionID<0..32>;
34
                    BOTAN_ARG_CHECK(!id.empty(), "Session ID must not be empty");
636✔
35
                    BOTAN_ARG_CHECK(id.size() <= 32, "Session ID cannot be longer than 32 bytes");
636✔
36
                 },
636✔
37
                 [](const Session_Ticket& ticket) {
2,132✔
38
                    BOTAN_ARG_CHECK(!ticket.empty(), "Ticket most not be empty");
2,132✔
39
                    BOTAN_ARG_CHECK(ticket.size() <= std::numeric_limits<uint16_t>::max(),
2,132✔
40
                                    "Ticket cannot be longer than 64kB");
41
                 },
2,132✔
42
                 [](const Opaque_Session_Handle& handle) {
689✔
43
                    // RFC 8446 4.6.1
44
                    //    opaque ticket<1..2^16-1>;
45
                    BOTAN_ARG_CHECK(!handle.empty(), "Opaque session handle must not be empty");
689✔
46
                    BOTAN_ARG_CHECK(handle.size() <= std::numeric_limits<uint16_t>::max(),
689✔
47
                                    "Opaque session handle cannot be longer than 64kB");
48
                 },
689✔
49
              },
50
              m_handle);
3,457✔
51
}
3,457✔
52

53
Opaque_Session_Handle Session_Handle::opaque_handle() const {
366✔
54
   // both a Session_ID and a Session_Ticket could be an Opaque_Session_Handle
55
   return Opaque_Session_Handle(std::visit([](const auto& handle) { return handle.get(); }, m_handle));
732✔
56
}
57

58
std::optional<Session_ID> Session_Handle::id() const {
2,395✔
59
   if(is_id()) {
2,395✔
60
      return std::get<Session_ID>(m_handle);
581✔
61
   }
62

63
   // Opaque handles can mimick as a Session_ID if they are short enough
64
   if(is_opaque_handle()) {
1,814✔
65
      const auto& handle = std::get<Opaque_Session_Handle>(m_handle);
680✔
66
      if(handle.size() <= 32) {
680✔
67
         return Session_ID(handle.get());
26✔
68
      }
69
   }
70

71
   return std::nullopt;
1,788✔
72
}
73

74
std::optional<Session_Ticket> Session_Handle::ticket() const {
1,710✔
75
   if(is_ticket()) {
1,710✔
76
      return std::get<Session_Ticket>(m_handle);
1,205✔
77
   }
78

79
   // Opaque handles can mimick 'normal' Session_Tickets at any time
80
   if(is_opaque_handle()) {
505✔
81
      return Session_Ticket(std::get<Opaque_Session_Handle>(m_handle).get());
216✔
82
   }
83

84
   return std::nullopt;
289✔
85
}
86

87
Ciphersuite Session_Base::ciphersuite() const {
4,804✔
88
   auto suite = Ciphersuite::by_id(m_ciphersuite);
4,804✔
89
   if(!suite.has_value()) {
4,804✔
90
      throw Decoding_Error("Failed to find cipher suite for ID " + std::to_string(m_ciphersuite));
×
91
   }
92
   return suite.value();
4,804✔
93
}
94

95
Session_Summary::Session_Summary(const Session_Base& base,
1,734✔
96
                                 bool was_resumption,
97
                                 std::optional<std::string> psk_identity) :
1,734✔
98
      Session_Base(base), m_external_psk_identity(std::move(psk_identity)), m_was_resumption(was_resumption) {
1,846✔
99
   BOTAN_ARG_CHECK(version().is_pre_tls_13(), "Instantiated a TLS 1.2 session summary with an newer TLS version");
1,734✔
100

101
   const auto cs = ciphersuite();
1,734✔
102
   m_kex_algo = cs.kex_algo();
1,734✔
103
}
1,734✔
104

105
#if defined(BOTAN_HAS_TLS_13)
106

107
Session_Summary::Session_Summary(const Server_Hello_13& server_hello,
600✔
108
                                 Connection_Side side,
109
                                 std::vector<X509_Certificate> peer_certs,
110
                                 std::optional<std::string> psk_identity,
111
                                 bool session_was_resumed,
112
                                 Server_Information server_info,
113
                                 std::chrono::system_clock::time_point current_timestamp) :
600✔
114
      Session_Base(current_timestamp,
115
                   server_hello.selected_version(),
116
                   server_hello.ciphersuite(),
600✔
117
                   side,
118

119
                   // TODO: SRTP might become necessary when DTLS 1.3 is being implemented
120
                   0,
121

122
                   // RFC 8446 Appendix D
123
                   //    Because TLS 1.3 always hashes in the transcript up to the server
124
                   //    Finished, implementations which support both TLS 1.3 and earlier
125
                   //    versions SHOULD indicate the use of the Extended Master Secret
126
                   //    extension in their APIs whenever TLS 1.3 is used.
127
                   true,
128

129
                   // TLS 1.3 uses AEADs, so technically encrypt-then-MAC is not applicable.
130
                   false,
131
                   std::move(peer_certs),
600✔
132
                   std::move(server_info)),
600✔
133
      m_external_psk_identity(std::move(psk_identity)),
600✔
134
      m_was_resumption(session_was_resumed) {
1,204✔
135
   BOTAN_ARG_CHECK(version().is_tls_13_or_later(), "Instantiated a TLS 1.3 session summary with an older TLS version");
600✔
136
   set_session_id(server_hello.session_id());
1,200✔
137

138
   // In TLS 1.3 the key exchange algorithm is not negotiated in the ciphersuite
139
   // anymore. This provides a compatible identifier for applications to use.
140
   m_kex_algo = kex_method_to_string([&] {
600✔
141
      if(psk_used() || was_resumption()) {
600✔
142
         if(const auto keyshare = server_hello.extensions().get<Key_Share>()) {
165✔
143
            const auto group = keyshare->selected_group();
165✔
144
            if(group.is_dh_named_group()) {
165✔
145
               return Kex_Algo::DHE_PSK;
165✔
146
            } else if(group.is_ecdh_named_curve() || group.is_x25519()) {
165✔
147
               return Kex_Algo::ECDHE_PSK;
148
            } else if(group.is_pure_kyber()) {
165✔
149
               return Kex_Algo::KEM_PSK;
150
            } else if(group.is_pqc_hybrid()) {
×
151
               return Kex_Algo::HYBRID_PSK;
152
            }
153
         } else {
154
            return Kex_Algo::PSK;
155
         }
156
      } else {
157
         const auto keyshare = server_hello.extensions().get<Key_Share>();
435✔
158
         BOTAN_ASSERT_NONNULL(keyshare);
435✔
159
         const auto group = keyshare->selected_group();
435✔
160
         if(group.is_dh_named_group()) {
435✔
161
            return Kex_Algo::DH;
435✔
162
         } else if(group.is_ecdh_named_curve() || group.is_x25519()) {
435✔
163
            return Kex_Algo::ECDH;
164
         } else if(group.is_pure_kyber()) {
440✔
165
            return Kex_Algo::KEM;
166
         } else if(group.is_pqc_hybrid()) {
5✔
167
            return Kex_Algo::HYBRID;
168
         }
169
      }
170

171
      return Kex_Algo::UNDEFINED;
172
   }());
600✔
173
}
600✔
174

175
#endif
176

177
Session::Session(const secure_vector<uint8_t>& master_secret,
1,616✔
178
                 Protocol_Version version,
179
                 uint16_t ciphersuite,
180
                 Connection_Side side,
181
                 bool extended_master_secret,
182
                 bool encrypt_then_mac,
183
                 const std::vector<X509_Certificate>& certs,
184
                 const Server_Information& server_info,
185
                 uint16_t srtp_profile,
186
                 std::chrono::system_clock::time_point current_timestamp,
187
                 std::chrono::seconds lifetime_hint) :
1,616✔
188
      Session_Base(current_timestamp,
189
                   version,
190
                   ciphersuite,
191
                   side,
192
                   srtp_profile,
193
                   extended_master_secret,
194
                   encrypt_then_mac,
195
                   certs,
196
                   server_info),
197
      m_master_secret(master_secret),
1,616✔
198
      m_early_data_allowed(false),
1,616✔
199
      m_max_early_data_bytes(0),
1,616✔
200
      m_ticket_age_add(0),
1,616✔
201
      m_lifetime_hint(lifetime_hint) {
1,616✔
202
   BOTAN_ARG_CHECK(version.is_pre_tls_13(), "Instantiated a TLS 1.2 session object with a TLS version newer than 1.2");
1,616✔
203
}
1,616✔
204

205
#if defined(BOTAN_HAS_TLS_13)
206

207
Session::Session(const secure_vector<uint8_t>& session_psk,
575✔
208
                 const std::optional<uint32_t>& max_early_data_bytes,
209
                 uint32_t ticket_age_add,
210
                 std::chrono::seconds lifetime_hint,
211
                 Protocol_Version version,
212
                 uint16_t ciphersuite,
213
                 Connection_Side side,
214
                 const std::vector<X509_Certificate>& peer_certs,
215
                 const Server_Information& server_info,
216
                 std::chrono::system_clock::time_point current_timestamp) :
575✔
217
      Session_Base(current_timestamp,
218
                   version,
219
                   ciphersuite,
220
                   side,
221

222
                   // TODO: SRTP might become necessary when DTLS 1.3 is being implemented
223
                   0,
224

225
                   // RFC 8446 Appendix D
226
                   //    Because TLS 1.3 always hashes in the transcript up to the server
227
                   //    Finished, implementations which support both TLS 1.3 and earlier
228
                   //    versions SHOULD indicate the use of the Extended Master Secret
229
                   //    extension in their APIs whenever TLS 1.3 is used.
230
                   true,
231

232
                   // TLS 1.3 uses AEADs, so technically encrypt-then-MAC is not applicable.
233
                   false,
234
                   peer_certs,
235
                   server_info),
236
      m_master_secret(session_psk),
575✔
237
      m_early_data_allowed(max_early_data_bytes.has_value()),
575✔
238
      m_max_early_data_bytes(max_early_data_bytes.value_or(0)),
575✔
239
      m_ticket_age_add(ticket_age_add),
575✔
240
      m_lifetime_hint(lifetime_hint) {
575✔
241
   BOTAN_ARG_CHECK(!version.is_pre_tls_13(), "Instantiated a TLS 1.3 session object with a TLS version older than 1.3");
575✔
242
}
575✔
243

244
Session::Session(secure_vector<uint8_t>&& session_psk,
280✔
245
                 const std::optional<uint32_t>& max_early_data_bytes,
246
                 std::chrono::seconds lifetime_hint,
247
                 const std::vector<X509_Certificate>& peer_certs,
248
                 const Client_Hello_13& client_hello,
249
                 const Server_Hello_13& server_hello,
250
                 Callbacks& callbacks,
251
                 RandomNumberGenerator& rng) :
280✔
252
      Session_Base(callbacks.tls_current_timestamp(),
280✔
253
                   server_hello.selected_version(),
254
                   server_hello.ciphersuite(),
280✔
255
                   Connection_Side::Server,
256
                   0,
257
                   true,
258
                   false,  // see constructor above for rationales
259
                   peer_certs,
260
                   Server_Information(client_hello.sni_hostname())),
560✔
261
      m_master_secret(std::move(session_psk)),
280✔
262
      m_early_data_allowed(max_early_data_bytes.has_value()),
280✔
263
      m_max_early_data_bytes(max_early_data_bytes.value_or(0)),
280✔
264
      m_ticket_age_add(load_be<uint32_t>(rng.random_vec(4).data(), 0)),
280✔
265
      m_lifetime_hint(lifetime_hint) {
840✔
266
   BOTAN_ARG_CHECK(!m_version.is_pre_tls_13(),
280✔
267
                   "Instantiated a TLS 1.3 session object with a TLS version older than 1.3");
268
}
280✔
269

270
#endif
271

272
Session::Session(std::string_view pem) : Session(PEM_Code::decode_check_label(pem, "TLS SESSION")) {}
3✔
273

274
Session::Session(std::span<const uint8_t> ber_data) {
452✔
275
   uint8_t side_code = 0;
452✔
276

277
   ASN1_String server_hostname;
452✔
278
   ASN1_String server_service;
452✔
279
   size_t server_port;
452✔
280

281
   uint8_t major_version = 0, minor_version = 0;
452✔
282

283
   size_t start_time = 0;
452✔
284
   size_t srtp_profile = 0;
452✔
285
   uint16_t ciphersuite_code = 0;
452✔
286
   uint64_t lifetime_hint = 0;
452✔
287

288
   BER_Decoder(ber_data.data(), ber_data.size())
452✔
289
      .start_sequence()
904✔
290
      .decode_and_check(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION),
904✔
291
                        "Unknown version in serialized TLS session")
292
      .decode_integer_type(start_time)
452✔
293
      .decode_integer_type(major_version)
452✔
294
      .decode_integer_type(minor_version)
452✔
295
      .decode_integer_type(ciphersuite_code)
452✔
296
      .decode_integer_type(side_code)
452✔
297
      .decode(m_extended_master_secret)
452✔
298
      .decode(m_encrypt_then_mac)
452✔
299
      .decode(m_master_secret, ASN1_Type::OctetString)
452✔
300
      .decode_list<X509_Certificate>(m_peer_certs)
452✔
301
      .decode(server_hostname)
452✔
302
      .decode(server_service)
452✔
303
      .decode(server_port)
452✔
304
      .decode(srtp_profile)
452✔
305
      .decode(m_early_data_allowed)
452✔
306
      .decode_integer_type(m_max_early_data_bytes)
452✔
307
      .decode_integer_type(m_ticket_age_add)
452✔
308
      .decode_integer_type(lifetime_hint)
452✔
309
      .end_cons()
452✔
310
      .verify_end();
452✔
311

312
   if(!Ciphersuite::by_id(ciphersuite_code)) {
452✔
313
      throw Decoding_Error(
1✔
314
         "Serialized TLS session contains unknown cipher suite "
315
         "(" +
2✔
316
         std::to_string(ciphersuite_code) + ")");
4✔
317
   }
318

319
   m_ciphersuite = ciphersuite_code;
451✔
320
   m_version = Protocol_Version(major_version, minor_version);
451✔
321
   m_start_time = std::chrono::system_clock::from_time_t(start_time);
451✔
322
   m_connection_side = static_cast<Connection_Side>(side_code);
451✔
323
   m_srtp_profile = static_cast<uint16_t>(srtp_profile);
451✔
324

325
   m_server_info =
451✔
326
      Server_Information(server_hostname.value(), server_service.value(), static_cast<uint16_t>(server_port));
902✔
327

328
   m_lifetime_hint = std::chrono::seconds(lifetime_hint);
451✔
329
}
455✔
330

331
secure_vector<uint8_t> Session::DER_encode() const {
1,129✔
332
   return DER_Encoder()
1,129✔
333
      .start_sequence()
1,129✔
334
      .encode(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION))
1,129✔
335
      .encode(static_cast<size_t>(std::chrono::system_clock::to_time_t(m_start_time)))
1,129✔
336
      .encode(static_cast<size_t>(m_version.major_version()))
1,129✔
337
      .encode(static_cast<size_t>(m_version.minor_version()))
1,129✔
338
      .encode(static_cast<size_t>(m_ciphersuite))
1,129✔
339
      .encode(static_cast<size_t>(m_connection_side))
1,129✔
340
      .encode(m_extended_master_secret)
1,129✔
341
      .encode(m_encrypt_then_mac)
1,129✔
342
      .encode(m_master_secret, ASN1_Type::OctetString)
1,129✔
343
      .start_sequence()
1,503✔
344
      .encode_list(m_peer_certs)
1,129✔
345
      .end_cons()
1,129✔
346
      .encode(ASN1_String(m_server_info.hostname(), ASN1_Type::Utf8String))
3,636✔
347
      .encode(ASN1_String(m_server_info.service(), ASN1_Type::Utf8String))
3,387✔
348
      .encode(static_cast<size_t>(m_server_info.port()))
1,129✔
349
      .encode(static_cast<size_t>(m_srtp_profile))
1,129✔
350

351
      // the fields below were introduced for TLS 1.3 session tickets
352
      .encode(m_early_data_allowed)
1,129✔
353
      .encode(static_cast<size_t>(m_max_early_data_bytes))
1,129✔
354
      .encode(static_cast<size_t>(m_ticket_age_add))
1,129✔
355
      .encode(static_cast<size_t>(m_lifetime_hint.count()))
1,129✔
356
      .end_cons()
1,129✔
357
      .get_contents();
2,258✔
358
}
359

360
std::string Session::PEM_encode() const {
2✔
361
   return PEM_Code::encode(this->DER_encode(), "TLS SESSION");
6✔
362
}
363

364
secure_vector<uint8_t> Session::extract_master_secret() {
177✔
365
   BOTAN_STATE_CHECK(!m_master_secret.empty());
177✔
366
   return std::exchange(m_master_secret, {});
177✔
367
}
368

369
namespace {
370

371
// The output length of the HMAC must be a valid keylength for the AEAD
372
const char* const TLS_SESSION_CRYPT_HMAC = "HMAC(SHA-512-256)";
373
// SIV would be better, but we can't assume it is available
374
const char* const TLS_SESSION_CRYPT_AEAD = "AES-256/GCM";
375
const char* const TLS_SESSION_CRYPT_KEY_NAME = "BOTAN TLS SESSION KEY NAME";
376
const uint64_t TLS_SESSION_CRYPT_MAGIC = 0x068B5A9D396C0000;
377
const size_t TLS_SESSION_CRYPT_MAGIC_LEN = 8;
378
const size_t TLS_SESSION_CRYPT_KEY_NAME_LEN = 4;
379
const size_t TLS_SESSION_CRYPT_AEAD_NONCE_LEN = 12;
380
const size_t TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN = 16;
381
const size_t TLS_SESSION_CRYPT_AEAD_TAG_SIZE = 16;
382

383
const size_t TLS_SESSION_CRYPT_HDR_LEN = TLS_SESSION_CRYPT_MAGIC_LEN + TLS_SESSION_CRYPT_KEY_NAME_LEN +
384
                                         TLS_SESSION_CRYPT_AEAD_NONCE_LEN + TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN;
385

386
const size_t TLS_SESSION_CRYPT_OVERHEAD = TLS_SESSION_CRYPT_HDR_LEN + TLS_SESSION_CRYPT_AEAD_TAG_SIZE;
387

388
}  // namespace
389

390
std::vector<uint8_t> Session::encrypt(const SymmetricKey& key, RandomNumberGenerator& rng) const {
1,121✔
391
   auto hmac = MessageAuthenticationCode::create_or_throw(TLS_SESSION_CRYPT_HMAC);
1,121✔
392
   hmac->set_key(key);
1,121✔
393

394
   // First derive the "key name"
395
   std::vector<uint8_t> key_name(hmac->output_length());
1,121✔
396
   hmac->update(TLS_SESSION_CRYPT_KEY_NAME);
1,121✔
397
   hmac->final(key_name.data());
1,121✔
398
   key_name.resize(TLS_SESSION_CRYPT_KEY_NAME_LEN);
1,121✔
399

400
   std::vector<uint8_t> aead_nonce;
1,121✔
401
   std::vector<uint8_t> key_seed;
1,121✔
402

403
   rng.random_vec(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN);
1,121✔
404
   rng.random_vec(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN);
1,121✔
405

406
   hmac->update(key_seed);
1,121✔
407
   const secure_vector<uint8_t> aead_key = hmac->final();
1,121✔
408

409
   secure_vector<uint8_t> bits = this->DER_encode();
1,121✔
410

411
   // create the header
412
   std::vector<uint8_t> buf;
1,121✔
413
   buf.reserve(TLS_SESSION_CRYPT_OVERHEAD + bits.size());
1,121✔
414
   buf.resize(TLS_SESSION_CRYPT_MAGIC_LEN);
1,121✔
415
   store_be(TLS_SESSION_CRYPT_MAGIC, &buf[0]);
1,121✔
416
   buf += key_name;
1,121✔
417
   buf += key_seed;
1,121✔
418
   buf += aead_nonce;
1,121✔
419

420
   auto aead = AEAD_Mode::create_or_throw(TLS_SESSION_CRYPT_AEAD, Cipher_Dir::Encryption);
1,121✔
421
   BOTAN_ASSERT_NOMSG(aead->valid_nonce_length(TLS_SESSION_CRYPT_AEAD_NONCE_LEN));
1,121✔
422
   BOTAN_ASSERT_NOMSG(aead->tag_size() == TLS_SESSION_CRYPT_AEAD_TAG_SIZE);
1,121✔
423
   aead->set_key(aead_key);
1,121✔
424
   aead->set_associated_data(buf);
1,121✔
425
   aead->start(aead_nonce);
1,121✔
426
   aead->finish(bits, 0);
1,121✔
427

428
   // append the ciphertext
429
   buf += bits;
1,121✔
430
   return buf;
1,121✔
431
}
7,847✔
432

433
Session Session::decrypt(std::span<const uint8_t> in, const SymmetricKey& key) {
453✔
434
   try {
453✔
435
      const size_t min_session_size = 48 + 4;  // serious under-estimate
453✔
436
      if(in.size() < TLS_SESSION_CRYPT_OVERHEAD + min_session_size) {
453✔
437
         throw Decoding_Error("Encrypted session too short to be valid");
3✔
438
      }
439

440
      BufferSlicer sub(in);
450✔
441
      const auto magic = sub.take(TLS_SESSION_CRYPT_MAGIC_LEN).data();
450✔
442
      const auto key_name = sub.take(TLS_SESSION_CRYPT_KEY_NAME_LEN).data();
450✔
443
      const auto key_seed = sub.take(TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN).data();
450✔
444
      const auto aead_nonce = sub.take(TLS_SESSION_CRYPT_AEAD_NONCE_LEN).data();
450✔
445
      auto ctext = sub.copy_as_secure_vector(sub.remaining());
450✔
446

447
      if(load_be<uint64_t>(magic, 0) != TLS_SESSION_CRYPT_MAGIC) {
450✔
448
         throw Decoding_Error("Missing expected magic numbers");
×
449
      }
450

451
      auto hmac = MessageAuthenticationCode::create_or_throw(TLS_SESSION_CRYPT_HMAC);
454✔
452
      hmac->set_key(key);
450✔
453

454
      // First derive and check the "key name"
455
      std::vector<uint8_t> cmp_key_name(hmac->output_length());
454✔
456
      hmac->update(TLS_SESSION_CRYPT_KEY_NAME);
450✔
457
      hmac->final(cmp_key_name.data());
450✔
458

459
      if(CT::is_equal(cmp_key_name.data(), key_name, TLS_SESSION_CRYPT_KEY_NAME_LEN).as_bool() == false) {
900✔
460
         throw Decoding_Error("Wrong key name for encrypted session");
1✔
461
      }
462

463
      hmac->update(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN);
449✔
464
      const secure_vector<uint8_t> aead_key = hmac->final();
449✔
465

466
      auto aead = AEAD_Mode::create_or_throw(TLS_SESSION_CRYPT_AEAD, Cipher_Dir::Decryption);
452✔
467
      aead->set_key(aead_key);
449✔
468
      aead->set_associated_data(in.data(), TLS_SESSION_CRYPT_HDR_LEN);
449✔
469
      aead->start(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN);
449✔
470
      aead->finish(ctext, 0);
449✔
471
      return Session(ctext);
449✔
472
   } catch(std::exception& e) {
2,251✔
473
      throw Decoding_Error("Failed to decrypt serialized TLS session: " + std::string(e.what()));
14✔
474
   }
7✔
475
}
476

477
}  // namespace Botan::TLS
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

© 2026 Coveralls, Inc