8#include <botan/tls_session.h>
10#include <botan/aead.h>
11#include <botan/asn1_obj.h>
12#include <botan/ber_dec.h>
13#include <botan/der_enc.h>
17#include <botan/tls_callbacks.h>
18#include <botan/x509_key.h>
19#include <botan/x509cert.h>
20#include <botan/internal/buffer_slicer.h>
21#include <botan/internal/ct_utils.h>
22#include <botan/internal/loadstor.h>
23#include <botan/internal/stl_util.h>
25#if defined(BOTAN_HAS_TLS_13)
26 #include <botan/tls_extensions_13.h>
27 #include <botan/tls_messages_13.h>
34void Session_Handle::validate_constraints()
const {
40 BOTAN_ARG_CHECK(
id.size() <= 32,
"Session ID cannot be longer than 32 bytes");
45 "Ticket cannot be longer than 64kB");
50 BOTAN_ARG_CHECK(!handle.empty(),
"Opaque session handle must not be empty");
52 "Opaque session handle cannot be longer than 64kB");
65 return std::get<Session_ID>(m_handle);
70 const auto& handle = std::get<Opaque_Session_Handle>(m_handle);
71 if(handle.size() <= 32) {
81 return std::get<Session_Ticket>(m_handle);
106 uint16_t srtp_profile,
107 bool extended_master_secret,
108 bool encrypt_then_mac,
109 const std::vector<X509_Certificate>&
peer_certs,
125 if(!suite.has_value()) {
128 return suite.value();
131Session_Summary::Session_Summary(
const Session_Base& base,
133 std::optional<std::string> psk_identity) :
134 Session_Base(base), m_external_psk_identity(std::move(psk_identity)), m_was_resumption(was_resumption) {
135 BOTAN_ARG_CHECK(
version().is_pre_tls_13(),
"Instantiated a TLS 1.2 session summary with an newer TLS version");
138 m_kex_algo = cs.kex_algo();
141#if defined(BOTAN_HAS_TLS_13)
145std::string tls13_kex_to_string(
bool psk, std::optional<Named_Group> group) {
147 if(group->is_dh_named_group()) {
149 }
else if(group->is_ecdh_named_curve() || group->is_x25519() || group->is_x448()) {
151 }
else if(group->is_pure_ml_kem() || group->is_pure_frodokem()) {
153 }
else if(group->is_pqc_hybrid()) {
155 }
else if(
auto s = group->to_string()) {
162 if(group->is_dh_named_group()) {
164 }
else if(group->is_ecdh_named_curve() || group->is_x25519() || group->is_x448()) {
166 }
else if(group->is_pure_ml_kem() || group->is_pure_frodokem()) {
168 }
else if(group->is_pqc_hybrid()) {
170 }
else if(
auto s = group->to_string()) {
182 const std::vector<X509_Certificate>& peer_certs,
183 std::shared_ptr<const Public_Key> peer_raw_public_key,
184 std::optional<std::string> psk_identity,
185 bool session_was_resumed,
187 std::chrono::system_clock::time_point current_timestamp) :
189 server_hello.selected_version(),
190 server_hello.ciphersuite(),
206 std::move(peer_raw_public_key),
207 std::move(server_info)),
208 m_external_psk_identity(std::move(psk_identity)),
209 m_was_resumption(session_was_resumed) {
210 BOTAN_ARG_CHECK(
version().is_tls_13_or_later(),
"Instantiated a TLS 1.3 session summary with an older TLS version");
211 set_session_id(server_hello.session_id());
216 std::optional<Named_Group> group = [&]() -> std::optional<Named_Group> {
217 if(psk_used() || was_resumption()) {
218 if(
auto*
const keyshare = server_hello.extensions().get<Key_Share>()) {
219 return keyshare->selected_group();
224 auto*
const keyshare = server_hello.extensions().get<Key_Share>();
226 return keyshare->selected_group();
230 if(group.has_value()) {
231 m_kex_parameters = group->to_string();
234 m_kex_algo = tls13_kex_to_string(psk_used() || was_resumption(), group);
243 bool extended_master_secret,
244 bool encrypt_then_mac,
245 const std::vector<X509_Certificate>& certs,
247 uint16_t srtp_profile,
248 std::chrono::system_clock::time_point current_timestamp,
255 extended_master_secret,
261 m_early_data_allowed(false),
262 m_max_early_data_bytes(0),
265 BOTAN_ARG_CHECK(
version.is_pre_tls_13(),
"Instantiated a TLS 1.2 session object with a TLS version newer than 1.2");
268#if defined(BOTAN_HAS_TLS_13)
272 uint32_t ticket_age_add,
277 const std::vector<X509_Certificate>&
peer_certs,
280 std::chrono::system_clock::time_point current_timestamp) :
301 m_master_secret(session_psk),
304 m_ticket_age_add(ticket_age_add),
306 BOTAN_ARG_CHECK(!
version.is_pre_tls_13(),
"Instantiated a TLS 1.3 session object with a TLS version older than 1.3");
312 const std::vector<X509_Certificate>&
peer_certs,
319 server_hello.selected_version(),
328 m_master_secret(std::move(session_psk)),
331 m_ticket_age_add(
load_be<uint32_t>(rng.random_vec(4).data(), 0)),
334 "Instantiated a TLS 1.3 session object with a TLS version older than 1.3");
342 uint8_t side_code = 0;
344 std::vector<uint8_t> raw_pubkey_or_empty;
348 size_t server_port = 0;
350 uint8_t major_version = 0;
351 uint8_t minor_version = 0;
354 size_t srtp_profile = 0;
360 .
decode_and_check(TLS_SESSION_PARAM_STRUCT_VERSION,
"Unknown version in serialized TLS session")
371 .decode(server_hostname)
372 .decode(server_service)
374 .decode(srtp_profile)
375 .decode(m_early_data_allowed)
376 .decode_integer_type(m_max_early_data_bytes)
377 .decode_integer_type(m_ticket_age_add)
384 "Serialized TLS session contains unknown cipher suite "
398 if(!raw_pubkey_or_empty.empty()) {
406 const auto raw_pubkey_or_empty =
411 .
encode(TLS_SESSION_PARAM_STRUCT_VERSION)
430 .
encode(m_early_data_allowed)
431 .
encode(
static_cast<size_t>(m_max_early_data_bytes))
432 .
encode(
static_cast<size_t>(m_ticket_age_add))
433 .
encode(
static_cast<size_t>(m_lifetime_hint.count()))
444 return std::exchange(m_master_secret, {});
450const char*
const TLS_SESSION_CRYPT_HMAC =
"HMAC(SHA-512-256)";
452const char*
const TLS_SESSION_CRYPT_AEAD =
"AES-256/GCM";
453const char*
const TLS_SESSION_CRYPT_KEY_NAME =
"BOTAN TLS SESSION KEY NAME";
454const uint64_t TLS_SESSION_CRYPT_MAGIC = 0x068B5A9D396C0000;
455const size_t TLS_SESSION_CRYPT_MAGIC_LEN = 8;
456const size_t TLS_SESSION_CRYPT_KEY_NAME_LEN = 4;
457const size_t TLS_SESSION_CRYPT_AEAD_NONCE_LEN = 12;
458const size_t TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN = 16;
459const size_t TLS_SESSION_CRYPT_AEAD_TAG_SIZE = 16;
461const size_t TLS_SESSION_CRYPT_HDR_LEN = TLS_SESSION_CRYPT_MAGIC_LEN + TLS_SESSION_CRYPT_KEY_NAME_LEN +
462 TLS_SESSION_CRYPT_AEAD_NONCE_LEN + TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN;
464const size_t TLS_SESSION_CRYPT_OVERHEAD = TLS_SESSION_CRYPT_HDR_LEN + TLS_SESSION_CRYPT_AEAD_TAG_SIZE;
473 std::vector<uint8_t> key_name(hmac->output_length());
474 hmac->update(TLS_SESSION_CRYPT_KEY_NAME);
475 hmac->final(key_name.data());
476 key_name.resize(TLS_SESSION_CRYPT_KEY_NAME_LEN);
478 std::vector<uint8_t> aead_nonce;
479 std::vector<uint8_t> key_seed;
481 rng.
random_vec(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN);
482 rng.
random_vec(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN);
484 hmac->update(key_seed);
490 std::vector<uint8_t> buf;
491 buf.reserve(TLS_SESSION_CRYPT_OVERHEAD + bits.size());
492 buf.resize(TLS_SESSION_CRYPT_MAGIC_LEN);
493 store_be(TLS_SESSION_CRYPT_MAGIC, &buf[0]);
501 aead->set_key(aead_key);
502 aead->set_associated_data(buf);
503 aead->start(aead_nonce);
504 aead->finish(bits, 0);
513 const size_t min_session_size = 48 + 4;
514 if(in.size() < TLS_SESSION_CRYPT_OVERHEAD + min_session_size) {
519 const auto*
const magic = sub.
take(TLS_SESSION_CRYPT_MAGIC_LEN).data();
520 const auto*
const key_name = sub.
take(TLS_SESSION_CRYPT_KEY_NAME_LEN).data();
521 const auto*
const key_seed = sub.
take(TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN).data();
522 const auto*
const aead_nonce = sub.
take(TLS_SESSION_CRYPT_AEAD_NONCE_LEN).data();
533 std::vector<uint8_t> cmp_key_name(hmac->output_length());
534 hmac->update(TLS_SESSION_CRYPT_KEY_NAME);
535 hmac->final(cmp_key_name.data());
537 if(
CT::is_equal(cmp_key_name.data(), key_name, TLS_SESSION_CRYPT_KEY_NAME_LEN).as_bool() ==
false) {
541 hmac->update(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN);
545 aead->set_key(aead_key);
546 aead->set_associated_data(in.data(), TLS_SESSION_CRYPT_HDR_LEN);
547 aead->start(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN);
548 aead->finish(ctext, 0);
550 }
catch(std::exception& e) {
551 throw Decoding_Error(
"Failed to decrypt serialized TLS session: " + std::string(e.what()));
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_STATE_CHECK(expr)
#define BOTAN_ASSERT_NONNULL(ptr)
#define BOTAN_ARG_CHECK(expr, msg)
static std::unique_ptr< AEAD_Mode > create_or_throw(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
const std::string & value() const
BER_Decoder & decode(bool &out)
BER_Decoder & decode_list(std::vector< T > &out, ASN1_Type type_tag=ASN1_Type::Sequence, ASN1_Class class_tag=ASN1_Class::Universal)
BER_Decoder start_sequence()
BER_Decoder & decode_and_check(const T &expected, std::string_view error_msg)
BER_Decoder & decode_integer_type(T &out)
auto copy_as_secure_vector(const size_t count)
std::span< const uint8_t > take(const size_t count)
secure_vector< uint8_t > get_contents()
DER_Encoder & encode_list(const std::vector< T > &values)
DER_Encoder & start_sequence()
DER_Encoder & encode(bool b)
static std::unique_ptr< MessageAuthenticationCode > create_or_throw(std::string_view algo_spec, std::string_view provider="")
void random_vec(std::span< uint8_t > v)
static std::optional< Ciphersuite > by_id(uint16_t suite)
std::vector< X509_Certificate > m_peer_certs
Session_Base(std::chrono::system_clock::time_point start_time, Protocol_Version version, uint16_t ciphersuite, Connection_Side connection_side, uint16_t srtp_profile, bool extended_master_secret, bool encrypt_then_mac, const std::vector< X509_Certificate > &peer_certs, std::shared_ptr< const Public_Key > peer_raw_public_key, Server_Information server_info)
std::shared_ptr< const Public_Key > peer_raw_public_key() const
bool m_extended_master_secret
Protocol_Version version() const
Connection_Side side() 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
Session_Base & operator=(const Session_Base &other)
Ciphersuite ciphersuite() const
const std::vector< X509_Certificate > & peer_certs() const
const Server_Information & server_info() 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
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())
const secure_vector< uint8_t > & master_secret() const
secure_vector< uint8_t > extract_master_secret()
uint32_t max_early_data_bytes() const
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
std::string encode(const uint8_t der[], size_t length, std::string_view label, size_t width)
std::string kex_method_to_string(Kex_Algo method)
Strong< std::vector< uint8_t >, struct Session_ID_ > Session_ID
holds a TLS 1.2 session ID for stateful resumption
Strong< std::vector< uint8_t >, struct Session_Ticket_ > Session_Ticket
holds a TLS 1.2 session ticket for stateless resumption
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...
std::unique_ptr< Public_Key > load_key(DataSource &source)
std::vector< T, secure_allocator< T > > secure_vector
constexpr auto store_be(ParamTs &&... params)
overloaded(Ts...) -> overloaded< Ts... >
constexpr auto load_be(ParamTs &&... params)