Botan 3.4.0
Crypto and TLS for C&
tls_session.cpp
Go to the documentation of this file.
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/tls_callbacks.h>
18#include <botan/tls_messages.h>
19#include <botan/x509_key.h>
20#include <botan/internal/ct_utils.h>
21#include <botan/internal/loadstor.h>
22#include <botan/internal/stl_util.h>
23
24#include <utility>
25
26namespace Botan::TLS {
27
28void Session_Handle::validate_constraints() const {
29 std::visit(overloaded{
30 [](const Session_ID& id) {
31 // RFC 5246 7.4.1.2
32 // opaque SessionID<0..32>;
33 BOTAN_ARG_CHECK(!id.empty(), "Session ID must not be empty");
34 BOTAN_ARG_CHECK(id.size() <= 32, "Session ID cannot be longer than 32 bytes");
35 },
36 [](const Session_Ticket& ticket) {
37 BOTAN_ARG_CHECK(!ticket.empty(), "Ticket most not be empty");
38 BOTAN_ARG_CHECK(ticket.size() <= std::numeric_limits<uint16_t>::max(),
39 "Ticket cannot be longer than 64kB");
40 },
41 [](const Opaque_Session_Handle& handle) {
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");
45 BOTAN_ARG_CHECK(handle.size() <= std::numeric_limits<uint16_t>::max(),
46 "Opaque session handle cannot be longer than 64kB");
47 },
48 },
49 m_handle);
50}
51
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));
55}
56
57std::optional<Session_ID> Session_Handle::id() const {
58 if(is_id()) {
59 return std::get<Session_ID>(m_handle);
60 }
61
62 // Opaque handles can mimick as a Session_ID if they are short enough
63 if(is_opaque_handle()) {
64 const auto& handle = std::get<Opaque_Session_Handle>(m_handle);
65 if(handle.size() <= 32) {
66 return Session_ID(handle.get());
67 }
68 }
69
70 return std::nullopt;
71}
72
73std::optional<Session_Ticket> Session_Handle::ticket() const {
74 if(is_ticket()) {
75 return std::get<Session_Ticket>(m_handle);
76 }
77
78 // Opaque handles can mimick 'normal' Session_Tickets at any time
79 if(is_opaque_handle()) {
80 return Session_Ticket(std::get<Opaque_Session_Handle>(m_handle).get());
81 }
82
83 return std::nullopt;
84}
85
88 if(!suite.has_value()) {
89 throw Decoding_Error("Failed to find cipher suite for ID " + std::to_string(m_ciphersuite));
90 }
91 return suite.value();
92}
93
94Session_Summary::Session_Summary(const Session_Base& base,
95 bool was_resumption,
96 std::optional<std::string> psk_identity) :
97 Session_Base(base), m_external_psk_identity(std::move(psk_identity)), m_was_resumption(was_resumption) {
98 BOTAN_ARG_CHECK(version().is_pre_tls_13(), "Instantiated a TLS 1.2 session summary with an newer TLS version");
99
100 const auto cs = ciphersuite();
101 m_kex_algo = cs.kex_algo();
102}
103
104#if defined(BOTAN_HAS_TLS_13)
105
106Session_Summary::Session_Summary(const Server_Hello_13& server_hello,
107 Connection_Side side,
108 std::vector<X509_Certificate> peer_certs,
109 std::shared_ptr<const Public_Key> peer_raw_public_key,
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) :
114 Session_Base(current_timestamp,
115 server_hello.selected_version(),
116 server_hello.ciphersuite(),
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),
132 std::move(peer_raw_public_key),
133 std::move(server_info)),
134 m_external_psk_identity(std::move(psk_identity)),
135 m_was_resumption(session_was_resumed) {
136 BOTAN_ARG_CHECK(version().is_tls_13_or_later(), "Instantiated a TLS 1.3 session summary with an older TLS version");
137 set_session_id(server_hello.session_id());
138
139 // In TLS 1.3 the key exchange algorithm is not negotiated in the ciphersuite
140 // anymore. This provides a compatible identifier for applications to use.
141 m_kex_algo = kex_method_to_string([&] {
142 if(psk_used() || was_resumption()) {
143 if(const auto keyshare = server_hello.extensions().get<Key_Share>()) {
144 const auto group = keyshare->selected_group();
145 if(group.is_dh_named_group()) {
146 return Kex_Algo::DHE_PSK;
147 } else if(group.is_ecdh_named_curve() || group.is_x25519() || group.is_x448()) {
148 return Kex_Algo::ECDHE_PSK;
149 } else if(group.is_pure_kyber()) {
150 return Kex_Algo::KEM_PSK;
151 } else if(group.is_pqc_hybrid()) {
152 return Kex_Algo::HYBRID_PSK;
153 }
154 } else {
155 return Kex_Algo::PSK;
156 }
157 } else {
158 const auto keyshare = server_hello.extensions().get<Key_Share>();
159 BOTAN_ASSERT_NONNULL(keyshare);
160 const auto group = keyshare->selected_group();
161 if(group.is_dh_named_group()) {
162 return Kex_Algo::DH;
163 } else if(group.is_ecdh_named_curve() || group.is_x25519() || group.is_x448()) {
164 return Kex_Algo::ECDH;
165 } else if(group.is_pure_kyber()) {
166 return Kex_Algo::KEM;
167 } else if(group.is_pqc_hybrid()) {
168 return Kex_Algo::HYBRID;
169 }
170 }
171
172 return Kex_Algo::UNDEFINED;
173 }());
174}
175
176#endif
177
178Session::Session(const secure_vector<uint8_t>& master_secret,
179 Protocol_Version version,
180 uint16_t ciphersuite,
181 Connection_Side side,
182 bool extended_master_secret,
183 bool encrypt_then_mac,
184 const std::vector<X509_Certificate>& certs,
185 const Server_Information& server_info,
186 uint16_t srtp_profile,
187 std::chrono::system_clock::time_point current_timestamp,
188 std::chrono::seconds lifetime_hint) :
189 Session_Base(current_timestamp,
190 version,
191 ciphersuite,
192 side,
193 srtp_profile,
194 extended_master_secret,
195 encrypt_then_mac,
196 certs,
197 nullptr, // RFC 7250 (raw public keys) is NYI for TLS 1.2
198 server_info),
199 m_master_secret(master_secret),
200 m_early_data_allowed(false),
201 m_max_early_data_bytes(0),
202 m_ticket_age_add(0),
203 m_lifetime_hint(lifetime_hint) {
204 BOTAN_ARG_CHECK(version.is_pre_tls_13(), "Instantiated a TLS 1.2 session object with a TLS version newer than 1.2");
205}
206
207#if defined(BOTAN_HAS_TLS_13)
208
210 const std::optional<uint32_t>& max_early_data_bytes,
211 uint32_t ticket_age_add,
212 std::chrono::seconds lifetime_hint,
213 Protocol_Version version,
214 uint16_t ciphersuite,
215 Connection_Side side,
216 const std::vector<X509_Certificate>& peer_certs,
217 std::shared_ptr<const Public_Key> peer_raw_public_key,
218 const Server_Information& server_info,
219 std::chrono::system_clock::time_point current_timestamp) :
220 Session_Base(current_timestamp,
221 version,
222 ciphersuite,
223 side,
224
225 // TODO: SRTP might become necessary when DTLS 1.3 is being implemented
226 0,
227
228 // RFC 8446 Appendix D
229 // Because TLS 1.3 always hashes in the transcript up to the server
230 // Finished, implementations which support both TLS 1.3 and earlier
231 // versions SHOULD indicate the use of the Extended Master Secret
232 // extension in their APIs whenever TLS 1.3 is used.
233 true,
234
235 // TLS 1.3 uses AEADs, so technically encrypt-then-MAC is not applicable.
236 false,
237 peer_certs,
238 std::move(peer_raw_public_key),
239 server_info),
240 m_master_secret(session_psk),
241 m_early_data_allowed(max_early_data_bytes.has_value()),
242 m_max_early_data_bytes(max_early_data_bytes.value_or(0)),
243 m_ticket_age_add(ticket_age_add),
244 m_lifetime_hint(lifetime_hint) {
245 BOTAN_ARG_CHECK(!version.is_pre_tls_13(), "Instantiated a TLS 1.3 session object with a TLS version older than 1.3");
246}
247
249 const std::optional<uint32_t>& max_early_data_bytes,
250 std::chrono::seconds lifetime_hint,
251 const std::vector<X509_Certificate>& peer_certs,
252 std::shared_ptr<const Public_Key> peer_raw_public_key,
253 const Client_Hello_13& client_hello,
254 const Server_Hello_13& server_hello,
255 Callbacks& callbacks,
257 Session_Base(callbacks.tls_current_timestamp(),
258 server_hello.selected_version(),
259 server_hello.ciphersuite(),
261 0,
262 true,
263 false, // see constructor above for rationales
264 peer_certs,
265 std::move(peer_raw_public_key),
266 Server_Information(client_hello.sni_hostname())),
267 m_master_secret(std::move(session_psk)),
268 m_early_data_allowed(max_early_data_bytes.has_value()),
269 m_max_early_data_bytes(max_early_data_bytes.value_or(0)),
270 m_ticket_age_add(load_be<uint32_t>(rng.random_vec(4).data(), 0)),
271 m_lifetime_hint(lifetime_hint) {
273 "Instantiated a TLS 1.3 session object with a TLS version older than 1.3");
274}
275
276#endif
277
278Session::Session(std::string_view pem) : Session(PEM_Code::decode_check_label(pem, "TLS SESSION")) {}
279
280Session::Session(std::span<const uint8_t> ber_data) {
281 uint8_t side_code = 0;
282
283 std::vector<uint8_t> raw_pubkey_or_empty;
284
285 ASN1_String server_hostname;
286 ASN1_String server_service;
287 size_t server_port;
288
289 uint8_t major_version = 0, minor_version = 0;
290
291 size_t start_time = 0;
292 size_t srtp_profile = 0;
293 uint16_t ciphersuite_code = 0;
294 uint64_t lifetime_hint = 0;
295
296 BER_Decoder(ber_data.data(), ber_data.size())
298 .decode_and_check(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION),
299 "Unknown version in serialized TLS session")
301 .decode_integer_type(major_version)
302 .decode_integer_type(minor_version)
304 .decode_integer_type(side_code)
307 .decode(m_master_secret, ASN1_Type::OctetString)
309 .decode(raw_pubkey_or_empty, ASN1_Type::OctetString)
310 .decode(server_hostname)
311 .decode(server_service)
312 .decode(server_port)
313 .decode(srtp_profile)
314 .decode(m_early_data_allowed)
315 .decode_integer_type(m_max_early_data_bytes)
316 .decode_integer_type(m_ticket_age_add)
317 .decode_integer_type(lifetime_hint)
318 .end_cons()
319 .verify_end();
320
322 throw Decoding_Error(
323 "Serialized TLS session contains unknown cipher suite "
324 "(" +
325 std::to_string(ciphersuite_code) + ")");
326 }
327
329 m_version = Protocol_Version(major_version, minor_version);
330 m_start_time = std::chrono::system_clock::from_time_t(start_time);
331 m_connection_side = static_cast<Connection_Side>(side_code);
332 m_srtp_profile = static_cast<uint16_t>(srtp_profile);
333
335 Server_Information(server_hostname.value(), server_service.value(), static_cast<uint16_t>(server_port));
336
337 if(!raw_pubkey_or_empty.empty()) {
338 m_peer_raw_public_key = X509::load_key(raw_pubkey_or_empty);
339 }
340
341 m_lifetime_hint = std::chrono::seconds(lifetime_hint);
342}
343
345 const auto raw_pubkey_or_empty =
346 m_peer_raw_public_key ? m_peer_raw_public_key->subject_public_key() : std::vector<uint8_t>{};
347
348 return DER_Encoder()
350 .encode(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION))
351 .encode(static_cast<size_t>(std::chrono::system_clock::to_time_t(m_start_time)))
352 .encode(static_cast<size_t>(m_version.major_version()))
353 .encode(static_cast<size_t>(m_version.minor_version()))
354 .encode(static_cast<size_t>(m_ciphersuite))
355 .encode(static_cast<size_t>(m_connection_side))
358 .encode(m_master_secret, ASN1_Type::OctetString)
361 .end_cons()
362 .encode(raw_pubkey_or_empty, ASN1_Type::OctetString)
365 .encode(static_cast<size_t>(m_server_info.port()))
366 .encode(static_cast<size_t>(m_srtp_profile))
367
368 // the fields below were introduced for TLS 1.3 session tickets
369 .encode(m_early_data_allowed)
370 .encode(static_cast<size_t>(m_max_early_data_bytes))
371 .encode(static_cast<size_t>(m_ticket_age_add))
372 .encode(static_cast<size_t>(m_lifetime_hint.count()))
373 .end_cons()
374 .get_contents();
375}
376
377std::string Session::PEM_encode() const {
378 return PEM_Code::encode(this->DER_encode(), "TLS SESSION");
379}
380
382 BOTAN_STATE_CHECK(!m_master_secret.empty());
383 return std::exchange(m_master_secret, {});
384}
385
386namespace {
387
388// The output length of the HMAC must be a valid keylength for the AEAD
389const char* const TLS_SESSION_CRYPT_HMAC = "HMAC(SHA-512-256)";
390// SIV would be better, but we can't assume it is available
391const char* const TLS_SESSION_CRYPT_AEAD = "AES-256/GCM";
392const char* const TLS_SESSION_CRYPT_KEY_NAME = "BOTAN TLS SESSION KEY NAME";
393const uint64_t TLS_SESSION_CRYPT_MAGIC = 0x068B5A9D396C0000;
394const size_t TLS_SESSION_CRYPT_MAGIC_LEN = 8;
395const size_t TLS_SESSION_CRYPT_KEY_NAME_LEN = 4;
396const size_t TLS_SESSION_CRYPT_AEAD_NONCE_LEN = 12;
397const size_t TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN = 16;
398const size_t TLS_SESSION_CRYPT_AEAD_TAG_SIZE = 16;
399
400const size_t TLS_SESSION_CRYPT_HDR_LEN = TLS_SESSION_CRYPT_MAGIC_LEN + TLS_SESSION_CRYPT_KEY_NAME_LEN +
401 TLS_SESSION_CRYPT_AEAD_NONCE_LEN + TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN;
402
403const size_t TLS_SESSION_CRYPT_OVERHEAD = TLS_SESSION_CRYPT_HDR_LEN + TLS_SESSION_CRYPT_AEAD_TAG_SIZE;
404
405} // namespace
406
407std::vector<uint8_t> Session::encrypt(const SymmetricKey& key, RandomNumberGenerator& rng) const {
408 auto hmac = MessageAuthenticationCode::create_or_throw(TLS_SESSION_CRYPT_HMAC);
409 hmac->set_key(key);
410
411 // First derive the "key name"
412 std::vector<uint8_t> key_name(hmac->output_length());
413 hmac->update(TLS_SESSION_CRYPT_KEY_NAME);
414 hmac->final(key_name.data());
415 key_name.resize(TLS_SESSION_CRYPT_KEY_NAME_LEN);
416
417 std::vector<uint8_t> aead_nonce;
418 std::vector<uint8_t> key_seed;
419
420 rng.random_vec(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN);
421 rng.random_vec(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN);
422
423 hmac->update(key_seed);
424 const secure_vector<uint8_t> aead_key = hmac->final();
425
426 secure_vector<uint8_t> bits = this->DER_encode();
427
428 // create the header
429 std::vector<uint8_t> buf;
430 buf.reserve(TLS_SESSION_CRYPT_OVERHEAD + bits.size());
431 buf.resize(TLS_SESSION_CRYPT_MAGIC_LEN);
432 store_be(TLS_SESSION_CRYPT_MAGIC, &buf[0]);
433 buf += key_name;
434 buf += key_seed;
435 buf += aead_nonce;
436
437 auto aead = AEAD_Mode::create_or_throw(TLS_SESSION_CRYPT_AEAD, Cipher_Dir::Encryption);
438 BOTAN_ASSERT_NOMSG(aead->valid_nonce_length(TLS_SESSION_CRYPT_AEAD_NONCE_LEN));
439 BOTAN_ASSERT_NOMSG(aead->tag_size() == TLS_SESSION_CRYPT_AEAD_TAG_SIZE);
440 aead->set_key(aead_key);
441 aead->set_associated_data(buf);
442 aead->start(aead_nonce);
443 aead->finish(bits, 0);
444
445 // append the ciphertext
446 buf += bits;
447 return buf;
448}
449
450Session Session::decrypt(std::span<const uint8_t> in, const SymmetricKey& key) {
451 try {
452 const size_t min_session_size = 48 + 4; // serious under-estimate
453 if(in.size() < TLS_SESSION_CRYPT_OVERHEAD + min_session_size) {
454 throw Decoding_Error("Encrypted session too short to be valid");
455 }
456
457 BufferSlicer sub(in);
458 const auto magic = sub.take(TLS_SESSION_CRYPT_MAGIC_LEN).data();
459 const auto key_name = sub.take(TLS_SESSION_CRYPT_KEY_NAME_LEN).data();
460 const auto key_seed = sub.take(TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN).data();
461 const auto aead_nonce = sub.take(TLS_SESSION_CRYPT_AEAD_NONCE_LEN).data();
462 auto ctext = sub.copy_as_secure_vector(sub.remaining());
463
464 if(load_be<uint64_t>(magic, 0) != TLS_SESSION_CRYPT_MAGIC) {
465 throw Decoding_Error("Missing expected magic numbers");
466 }
467
468 auto hmac = MessageAuthenticationCode::create_or_throw(TLS_SESSION_CRYPT_HMAC);
469 hmac->set_key(key);
470
471 // First derive and check the "key name"
472 std::vector<uint8_t> cmp_key_name(hmac->output_length());
473 hmac->update(TLS_SESSION_CRYPT_KEY_NAME);
474 hmac->final(cmp_key_name.data());
475
476 if(CT::is_equal(cmp_key_name.data(), key_name, TLS_SESSION_CRYPT_KEY_NAME_LEN).as_bool() == false) {
477 throw Decoding_Error("Wrong key name for encrypted session");
478 }
479
480 hmac->update(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN);
481 const secure_vector<uint8_t> aead_key = hmac->final();
482
483 auto aead = AEAD_Mode::create_or_throw(TLS_SESSION_CRYPT_AEAD, Cipher_Dir::Decryption);
484 aead->set_key(aead_key);
485 aead->set_associated_data(in.data(), TLS_SESSION_CRYPT_HDR_LEN);
486 aead->start(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN);
487 aead->finish(ctext, 0);
488 return Session(ctext);
489 } catch(std::exception& e) {
490 throw Decoding_Error("Failed to decrypt serialized TLS session: " + std::string(e.what()));
491 }
492}
493
494} // namespace Botan::TLS
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:41
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:86
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
static std::unique_ptr< AEAD_Mode > create_or_throw(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
Definition aead.cpp:43
const std::string & value() const
Definition asn1_obj.h:415
BER_Decoder & decode(bool &out)
Definition ber_dec.h:176
BER_Decoder & decode_list(std::vector< T > &out, ASN1_Type type_tag=ASN1_Type::Sequence, ASN1_Class class_tag=ASN1_Class::Universal)
Definition ber_dec.h:364
BER_Decoder start_sequence()
Definition ber_dec.h:113
BER_Decoder & decode_and_check(const T &expected, std::string_view error_msg)
Definition ber_dec.h:257
BER_Decoder & decode_integer_type(T &out)
Definition ber_dec.h:230
size_t remaining() const
Definition stl_util.h:185
auto copy_as_secure_vector(const size_t count)
Definition stl_util.h:154
std::span< const uint8_t > take(const size_t count)
Definition stl_util.h:156
secure_vector< uint8_t > get_contents()
Definition der_enc.cpp:132
DER_Encoder & encode_list(const std::vector< T > &values)
Definition der_enc.h:132
DER_Encoder & start_sequence()
Definition der_enc.h:65
DER_Encoder & end_cons()
Definition der_enc.cpp:171
DER_Encoder & encode(bool b)
Definition der_enc.cpp:250
static std::unique_ptr< MessageAuthenticationCode > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition mac.cpp:148
void random_vec(std::span< uint8_t > v)
Definition rng.h:179
static std::optional< Ciphersuite > by_id(uint16_t suite)
uint8_t major_version() const
Definition tls_version.h:78
uint8_t minor_version() const
Definition tls_version.h:83
std::vector< X509_Certificate > m_peer_certs
Protocol_Version version() 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
Ciphersuite ciphersuite() const
std::shared_ptr< const Public_Key > m_peer_raw_public_key
Connection_Side m_connection_side
std::optional< Session_Ticket > ticket() const
decltype(auto) get() const
bool is_opaque_handle() const
Definition tls_session.h:95
Opaque_Session_Handle opaque_handle() const
std::optional< Session_ID > id() 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)
std::string PEM_encode() 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())
secure_vector< uint8_t > extract_master_secret()
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:345
std::string encode(const uint8_t der[], size_t length, std::string_view label, size_t width)
Definition pem.cpp:39
std::string kex_method_to_string(Kex_Algo method)
Definition tls_algos.cpp:28
Strong< std::vector< uint8_t >, struct Session_ID_ > Session_ID
holds a TLS 1.2 session ID for stateful resumption
Definition tls_session.h:32
Strong< std::vector< uint8_t >, struct Session_Ticket_ > Session_Ticket
holds a TLS 1.2 session ticket for stateless resumption
Definition tls_session.h:35
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:39
std::unique_ptr< Public_Key > load_key(DataSource &source)
Definition x509_key.cpp:28
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:711
overloaded(Ts...) -> overloaded< Ts... >
constexpr auto load_be(ParamTs &&... params)
Definition loadstor.h:471