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

randombit / botan / 5587580523

18 Jul 2023 12:45PM UTC coverage: 91.72% (+0.03%) from 91.691%
5587580523

Pull #3618

github

web-flow
Merge b6d23d19e into 65b754862
Pull Request #3618: [TLS 1.3] PSK Support

78438 of 85519 relevant lines covered (91.72%)

12184016.91 hits per line

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

99.16
/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/loadstor.h>
18

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

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

24
#include <utility>
25

26
namespace Botan::TLS {
27

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

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

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

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

70
   return std::nullopt;
1,781✔
71
}
72

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

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

83
   return std::nullopt;
293✔
84
}
85

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

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

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

104
#if defined(BOTAN_HAS_TLS_13)
105

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

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

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

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

137
   // In TLS 1.3 the key exchange algorithm is not negotiated in the ciphersuite
138
   // anymore. This provides a compatible identifier for applications to use.
139
   m_kex_algo = kex_method_to_string([&] {
589✔
140
      if(psk_used() || was_resumption()) {
589✔
141
         if(const auto keyshare = server_hello.extensions().get<Key_Share>()) {
163✔
142
            const auto group = keyshare->selected_group();
163✔
143
            if(is_dh(group)) {
163✔
144
               return Kex_Algo::DHE_PSK;
145
            } else if(is_ecdh(group) || is_x25519(group)) {
163✔
146
               return Kex_Algo::ECDHE_PSK;
163✔
147
            }
148
         } else {
149
            return Kex_Algo::PSK;
150
         }
151
      } else {
152
         const auto keyshare = server_hello.extensions().get<Key_Share>();
426✔
153
         BOTAN_ASSERT_NONNULL(keyshare);
426✔
154
         const auto group = keyshare->selected_group();
426✔
155
         if(is_dh(group)) {
426✔
156
            return Kex_Algo::DH;
157
         } else if(is_ecdh(group) || is_x25519(group)) {
426✔
158
            return Kex_Algo::ECDH;
426✔
159
         }
160
      }
161

162
      return Kex_Algo::UNDEFINED;
163
   }());
589✔
164
}
589✔
165

166
#endif
167

168
Session::Session(const secure_vector<uint8_t>& master_secret,
1,616✔
169
                 Protocol_Version version,
170
                 uint16_t ciphersuite,
171
                 Connection_Side side,
172
                 bool extended_master_secret,
173
                 bool encrypt_then_mac,
174
                 const std::vector<X509_Certificate>& certs,
175
                 const Server_Information& server_info,
176
                 uint16_t srtp_profile,
177
                 std::chrono::system_clock::time_point current_timestamp,
178
                 std::chrono::seconds lifetime_hint) :
1,616✔
179
      Session_Base(current_timestamp,
180
                   version,
181
                   ciphersuite,
182
                   side,
183
                   srtp_profile,
184
                   extended_master_secret,
185
                   encrypt_then_mac,
186
                   certs,
187
                   server_info),
188
      m_master_secret(master_secret),
1,616✔
189
      m_early_data_allowed(false),
1,616✔
190
      m_max_early_data_bytes(0),
1,616✔
191
      m_ticket_age_add(0),
1,616✔
192
      m_lifetime_hint(lifetime_hint) {
1,616✔
193
   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✔
194
}
1,616✔
195

196
#if defined(BOTAN_HAS_TLS_13)
197

198
Session::Session(const secure_vector<uint8_t>& session_psk,
567✔
199
                 const std::optional<uint32_t>& max_early_data_bytes,
200
                 uint32_t ticket_age_add,
201
                 std::chrono::seconds lifetime_hint,
202
                 Protocol_Version version,
203
                 uint16_t ciphersuite,
204
                 Connection_Side side,
205
                 const std::vector<X509_Certificate>& peer_certs,
206
                 const Server_Information& server_info,
207
                 std::chrono::system_clock::time_point current_timestamp) :
567✔
208
      Session_Base(current_timestamp,
209
                   version,
210
                   ciphersuite,
211
                   side,
212

213
                   // TODO: SRTP might become necessary when DTLS 1.3 is being implemented
214
                   0,
215

216
                   // RFC 8446 Appendix D
217
                   //    Because TLS 1.3 always hashes in the transcript up to the server
218
                   //    Finished, implementations which support both TLS 1.3 and earlier
219
                   //    versions SHOULD indicate the use of the Extended Master Secret
220
                   //    extension in their APIs whenever TLS 1.3 is used.
221
                   true,
222

223
                   // TLS 1.3 uses AEADs, so technically encrypt-then-MAC is not applicable.
224
                   false,
225
                   peer_certs,
226
                   server_info),
227
      m_master_secret(session_psk),
567✔
228
      m_early_data_allowed(max_early_data_bytes.has_value()),
567✔
229
      m_max_early_data_bytes(max_early_data_bytes.value_or(0)),
567✔
230
      m_ticket_age_add(ticket_age_add),
567✔
231
      m_lifetime_hint(lifetime_hint) {
567✔
232
   BOTAN_ARG_CHECK(!version.is_pre_tls_13(), "Instantiated a TLS 1.3 session object with a TLS version older than 1.3");
567✔
233
}
567✔
234

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

261
#endif
262

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

265
Session::Session(std::span<const uint8_t> ber_data) {
455✔
266
   uint8_t side_code = 0;
455✔
267

268
   ASN1_String server_hostname;
455✔
269
   ASN1_String server_service;
455✔
270
   size_t server_port;
455✔
271

272
   uint8_t major_version = 0, minor_version = 0;
455✔
273

274
   size_t start_time = 0;
455✔
275
   size_t srtp_profile = 0;
455✔
276
   uint16_t ciphersuite_code = 0;
455✔
277
   uint64_t lifetime_hint = 0;
455✔
278

279
   BER_Decoder(ber_data.data(), ber_data.size())
455✔
280
      .start_sequence()
910✔
281
      .decode_and_check(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION),
910✔
282
                        "Unknown version in serialized TLS session")
283
      .decode_integer_type(start_time)
455✔
284
      .decode_integer_type(major_version)
455✔
285
      .decode_integer_type(minor_version)
455✔
286
      .decode_integer_type(ciphersuite_code)
455✔
287
      .decode_integer_type(side_code)
455✔
288
      .decode(m_extended_master_secret)
455✔
289
      .decode(m_encrypt_then_mac)
455✔
290
      .decode(m_master_secret, ASN1_Type::OctetString)
455✔
291
      .decode_list<X509_Certificate>(m_peer_certs)
455✔
292
      .decode(server_hostname)
455✔
293
      .decode(server_service)
455✔
294
      .decode(server_port)
455✔
295
      .decode(srtp_profile)
455✔
296
      .decode(m_early_data_allowed)
455✔
297
      .decode_integer_type(m_max_early_data_bytes)
455✔
298
      .decode_integer_type(m_ticket_age_add)
455✔
299
      .decode_integer_type(lifetime_hint)
455✔
300
      .end_cons()
455✔
301
      .verify_end();
455✔
302

303
   if(!Ciphersuite::by_id(ciphersuite_code)) {
455✔
304
      throw Decoding_Error(
1✔
305
         "Serialized TLS session contains unknown cipher suite "
306
         "(" +
2✔
307
         std::to_string(ciphersuite_code) + ")");
4✔
308
   }
309

310
   m_ciphersuite = ciphersuite_code;
454✔
311
   m_version = Protocol_Version(major_version, minor_version);
454✔
312
   m_start_time = std::chrono::system_clock::from_time_t(start_time);
454✔
313
   m_connection_side = static_cast<Connection_Side>(side_code);
454✔
314
   m_srtp_profile = static_cast<uint16_t>(srtp_profile);
454✔
315

316
   m_server_info =
454✔
317
      Server_Information(server_hostname.value(), server_service.value(), static_cast<uint16_t>(server_port));
908✔
318

319
   m_lifetime_hint = std::chrono::seconds(lifetime_hint);
454✔
320
}
458✔
321

322
secure_vector<uint8_t> Session::DER_encode() const {
1,124✔
323
   return DER_Encoder()
1,124✔
324
      .start_sequence()
1,124✔
325
      .encode(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION))
1,124✔
326
      .encode(static_cast<size_t>(std::chrono::system_clock::to_time_t(m_start_time)))
1,124✔
327
      .encode(static_cast<size_t>(m_version.major_version()))
1,124✔
328
      .encode(static_cast<size_t>(m_version.minor_version()))
1,124✔
329
      .encode(static_cast<size_t>(m_ciphersuite))
1,124✔
330
      .encode(static_cast<size_t>(m_connection_side))
1,124✔
331
      .encode(m_extended_master_secret)
1,124✔
332
      .encode(m_encrypt_then_mac)
1,124✔
333
      .encode(m_master_secret, ASN1_Type::OctetString)
1,124✔
334
      .start_sequence()
1,492✔
335
      .encode_list(m_peer_certs)
1,124✔
336
      .end_cons()
1,124✔
337
      .encode(ASN1_String(m_server_info.hostname(), ASN1_Type::Utf8String))
3,618✔
338
      .encode(ASN1_String(m_server_info.service(), ASN1_Type::Utf8String))
3,372✔
339
      .encode(static_cast<size_t>(m_server_info.port()))
1,124✔
340
      .encode(static_cast<size_t>(m_srtp_profile))
1,124✔
341

342
      // the fields below were introduced for TLS 1.3 session tickets
343
      .encode(m_early_data_allowed)
1,124✔
344
      .encode(static_cast<size_t>(m_max_early_data_bytes))
1,124✔
345
      .encode(static_cast<size_t>(m_ticket_age_add))
1,124✔
346
      .encode(static_cast<size_t>(m_lifetime_hint.count()))
1,124✔
347
      .end_cons()
1,124✔
348
      .get_contents();
2,248✔
349
}
350

351
std::string Session::PEM_encode() const {
2✔
352
   return PEM_Code::encode(this->DER_encode(), "TLS SESSION");
6✔
353
}
354

355
secure_vector<uint8_t> Session::extract_master_secret() {
177✔
356
   BOTAN_STATE_CHECK(!m_master_secret.empty());
177✔
357
   return std::exchange(m_master_secret, {});
177✔
358
}
359

360
namespace {
361

362
// The output length of the HMAC must be a valid keylength for the AEAD
363
const char* const TLS_SESSION_CRYPT_HMAC = "HMAC(SHA-512-256)";
364
// SIV would be better, but we can't assume it is available
365
const char* const TLS_SESSION_CRYPT_AEAD = "AES-256/GCM";
366
const char* const TLS_SESSION_CRYPT_KEY_NAME = "BOTAN TLS SESSION KEY NAME";
367
const uint64_t TLS_SESSION_CRYPT_MAGIC = 0x068B5A9D396C0000;
368
const size_t TLS_SESSION_CRYPT_MAGIC_LEN = 8;
369
const size_t TLS_SESSION_CRYPT_KEY_NAME_LEN = 4;
370
const size_t TLS_SESSION_CRYPT_AEAD_NONCE_LEN = 12;
371
const size_t TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN = 16;
372
const size_t TLS_SESSION_CRYPT_AEAD_TAG_SIZE = 16;
373

374
const size_t TLS_SESSION_CRYPT_HDR_LEN = TLS_SESSION_CRYPT_MAGIC_LEN + TLS_SESSION_CRYPT_KEY_NAME_LEN +
375
                                         TLS_SESSION_CRYPT_AEAD_NONCE_LEN + TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN;
376

377
const size_t TLS_SESSION_CRYPT_OVERHEAD = TLS_SESSION_CRYPT_HDR_LEN + TLS_SESSION_CRYPT_AEAD_TAG_SIZE;
378

379
}  // namespace
380

381
std::vector<uint8_t> Session::encrypt(const SymmetricKey& key, RandomNumberGenerator& rng) const {
1,116✔
382
   auto hmac = MessageAuthenticationCode::create_or_throw(TLS_SESSION_CRYPT_HMAC);
1,116✔
383
   hmac->set_key(key);
1,116✔
384

385
   // First derive the "key name"
386
   std::vector<uint8_t> key_name(hmac->output_length());
1,116✔
387
   hmac->update(TLS_SESSION_CRYPT_KEY_NAME);
1,116✔
388
   hmac->final(key_name.data());
1,116✔
389
   key_name.resize(TLS_SESSION_CRYPT_KEY_NAME_LEN);
1,116✔
390

391
   std::vector<uint8_t> aead_nonce;
1,116✔
392
   std::vector<uint8_t> key_seed;
1,116✔
393

394
   rng.random_vec(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN);
1,116✔
395
   rng.random_vec(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN);
1,116✔
396

397
   hmac->update(key_seed);
1,116✔
398
   const secure_vector<uint8_t> aead_key = hmac->final();
1,116✔
399

400
   secure_vector<uint8_t> bits = this->DER_encode();
1,116✔
401

402
   // create the header
403
   std::vector<uint8_t> buf;
1,116✔
404
   buf.reserve(TLS_SESSION_CRYPT_OVERHEAD + bits.size());
1,116✔
405
   buf.resize(TLS_SESSION_CRYPT_MAGIC_LEN);
1,116✔
406
   store_be(TLS_SESSION_CRYPT_MAGIC, &buf[0]);
1,116✔
407
   buf += key_name;
1,116✔
408
   buf += key_seed;
1,116✔
409
   buf += aead_nonce;
1,116✔
410

411
   auto aead = AEAD_Mode::create_or_throw(TLS_SESSION_CRYPT_AEAD, Cipher_Dir::Encryption);
1,116✔
412
   BOTAN_ASSERT_NOMSG(aead->valid_nonce_length(TLS_SESSION_CRYPT_AEAD_NONCE_LEN));
1,116✔
413
   BOTAN_ASSERT_NOMSG(aead->tag_size() == TLS_SESSION_CRYPT_AEAD_TAG_SIZE);
1,116✔
414
   aead->set_key(aead_key);
1,116✔
415
   aead->set_associated_data(buf);
1,116✔
416
   aead->start(aead_nonce);
1,116✔
417
   aead->finish(bits, 0);
1,116✔
418

419
   // append the ciphertext
420
   buf += bits;
1,116✔
421
   return buf;
1,116✔
422
}
7,812✔
423

424
Session Session::decrypt(std::span<const uint8_t> in, const SymmetricKey& key) {
456✔
425
   try {
456✔
426
      const size_t min_session_size = 48 + 4;  // serious under-estimate
456✔
427
      if(in.size() < TLS_SESSION_CRYPT_OVERHEAD + min_session_size) {
456✔
428
         throw Decoding_Error("Encrypted session too short to be valid");
3✔
429
      }
430

431
      // TODO: replace those raw pointers with sub-spans into `in`
432
      const uint8_t* magic = in.data();
453✔
433
      const uint8_t* key_name = magic + TLS_SESSION_CRYPT_MAGIC_LEN;
453✔
434
      const uint8_t* key_seed = key_name + TLS_SESSION_CRYPT_KEY_NAME_LEN;
453✔
435
      const uint8_t* aead_nonce = key_seed + TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN;
453✔
436
      const uint8_t* ctext = aead_nonce + TLS_SESSION_CRYPT_AEAD_NONCE_LEN;
453✔
437
      const size_t ctext_len = in.size() - TLS_SESSION_CRYPT_HDR_LEN;  // includes the tag
453✔
438

439
      if(load_be<uint64_t>(magic, 0) != TLS_SESSION_CRYPT_MAGIC) {
453✔
440
         throw Decoding_Error("Missing expected magic numbers");
×
441
      }
442

443
      auto hmac = MessageAuthenticationCode::create_or_throw(TLS_SESSION_CRYPT_HMAC);
453✔
444
      hmac->set_key(key);
453✔
445

446
      // First derive and check the "key name"
447
      std::vector<uint8_t> cmp_key_name(hmac->output_length());
457✔
448
      hmac->update(TLS_SESSION_CRYPT_KEY_NAME);
453✔
449
      hmac->final(cmp_key_name.data());
453✔
450

451
      if(same_mem(cmp_key_name.data(), key_name, TLS_SESSION_CRYPT_KEY_NAME_LEN) == false) {
906✔
452
         throw Decoding_Error("Wrong key name for encrypted session");
1✔
453
      }
454

455
      hmac->update(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN);
452✔
456
      const secure_vector<uint8_t> aead_key = hmac->final();
452✔
457

458
      auto aead = AEAD_Mode::create_or_throw(TLS_SESSION_CRYPT_AEAD, Cipher_Dir::Decryption);
455✔
459
      aead->set_key(aead_key);
452✔
460
      aead->set_associated_data(in.data(), TLS_SESSION_CRYPT_HDR_LEN);
452✔
461
      aead->start(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN);
452✔
462
      secure_vector<uint8_t> buf(ctext, ctext + ctext_len);
455✔
463
      aead->finish(buf, 0);
452✔
464
      return Session(buf);
452✔
465
   } catch(std::exception& e) {
2,265✔
466
      throw Decoding_Error("Failed to decrypt serialized TLS session: " + std::string(e.what()));
14✔
467
   }
7✔
468
}
469

470
}  // 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