10#include <botan/internal/tls_client_impl_13.h>
12#include <botan/credentials_manager.h>
13#include <botan/tls_callbacks.h>
14#include <botan/tls_extensions_13.h>
15#include <botan/tls_messages_13.h>
16#include <botan/tls_policy.h>
17#include <botan/x509cert.h>
18#include <botan/internal/stl_util.h>
19#include <botan/internal/tls_channel_impl_13.h>
20#include <botan/internal/tls_cipher_state.h>
28 const std::shared_ptr<Credentials_Manager>& creds,
29 const std::shared_ptr<const Policy>&
policy,
30 const std::shared_ptr<RandomNumberGenerator>&
rng,
32 const std::vector<std::string>& next_protocols) :
34 m_info(std::move(info)),
35 m_handshake(std::make_unique<Pending_Handshake>()) {
36#if defined(BOTAN_HAS_TLS_DOWNGRADE_SUPPORT)
37 if(
policy->allow_tls12()) {
38 expect_downgrade(m_info, next_protocols);
42 if(
auto session = find_session_for_resumption()) {
43 if(session->session.version().is_tls_13_or_later()) {
44 m_handshake->resumed_session = std::move(session);
46#if defined(BOTAN_HAS_TLS_DOWNGRADE_SUPPORT)
50 request_downgrade_for_resumption(std::move(session.value()));
62 m_handshake->resumed_session,
75 m_handshake->transitions.confirm_transition_to(std::visit([](
const auto& msg) {
return msg.type(); }, message));
85 m_handshake->state.received(std::move(message)));
93 throw TLS_Exception(Alert::UnexpectedMessage,
"received an unexpected post-handshake message");
96 std::visit([&](
auto&& m) { handle(m); }, *msg);
104 if(!m_handshake || !m_handshake->state.has_client_hello() || m_handshake->state.has_server_finished()) {
105 throw TLS_Exception(Alert::UnexpectedMessage,
"Received an unexpected dummy Change Cipher Spec");
121std::optional<Session_with_Handle> Client_Impl_13::find_session_for_resumption() {
138 if(sessions.empty()) {
145 auto& session_to_resume = sessions.front();
147 return std::move(session_to_resume);
150void Client_Impl_13::handle(
const Server_Hello_12_Shim& server_hello_msg) {
153 if(m_handshake->state.has_hello_retry_request()) {
154 throw TLS_Exception(Alert::UnexpectedMessage,
"Version downgrade received after Hello Retry");
157#if !defined(BOTAN_HAS_TLS_DOWNGRADE_SUPPORT)
159 throw TLS_Exception(Alert::ProtocolVersion,
"Received an unsupported Server Hello");
167 throw TLS_Exception(Alert::ProtocolVersion,
"Received an unexpected legacy Server Hello");
180 if(server_hello_msg.random_signals_downgrade().has_value()) {
181 throw TLS_Exception(Alert::IllegalParameter,
"Downgrade attack detected");
190 if(server_hello_msg.extensions().has<Supported_Versions>()) {
191 throw TLS_Exception(Alert::IllegalParameter,
"Unexpected extension received");
198 const auto& client_hello_exts = m_handshake->state.client_hello().extensions();
200 if(!client_hello_exts.get<Supported_Versions>()->supports(server_hello_msg.selected_version())) {
201 throw TLS_Exception(Alert::ProtocolVersion,
"Protocol version was not offered");
204 if(
policy().tls_13_middlebox_compatibility_mode() &&
205 m_handshake->state.client_hello().session_id() == server_hello_msg.session_id()) {
210 throw TLS_Exception(Alert::IllegalParameter,
"Unexpected session ID during downgrade");
213 preserve_client_hello(m_handshake->state.take_client_hello());
218 m_handshake->transitions.set_expected_next({});
228 if(ch.session_id() != sh.session_id()) {
229 throw TLS_Exception(Alert::IllegalParameter,
"echoed session id did not match");
235 if(!ch.offered_suite(sh.ciphersuite())) {
236 throw TLS_Exception(Alert::IllegalParameter,
"Server replied with ciphersuite we didn't send");
247 throw TLS_Exception(Alert::IllegalParameter,
"Protocol version was not offered");
257 const auto& ch = m_handshake->state.client_hello();
259 validate_server_hello_ish(ch, sh);
267 if(sh.random_signals_downgrade().has_value()) {
268 throw TLS_Exception(Alert::IllegalParameter,
"Downgrade attack detected");
276 if(sh.extensions().contains_other_than(ch.extensions().extension_types())) {
277 throw TLS_Exception(Alert::UnsupportedExtension,
"Unsupported extension found in Server Hello");
280 if(m_handshake->state.has_hello_retry_request()) {
281 const auto& hrr = m_handshake->state.hello_retry_request();
287 if(hrr.ciphersuite() != sh.ciphersuite()) {
288 throw TLS_Exception(Alert::IllegalParameter,
"server changed its chosen ciphersuite");
295 if(hrr.selected_version() != sh.selected_version()) {
296 throw TLS_Exception(Alert::IllegalParameter,
"server changed its chosen protocol version");
307 if(!cipher->usable_in_version(Protocol_Version::TLS_V13)) {
308 throw TLS_Exception(Alert::IllegalParameter,
309 "Server replied using a ciphersuite not allowed in version it offered");
322 if(!sh.extensions().has<Key_Share>()) {
323 throw TLS_Exception(Alert::IllegalParameter,
"Server Hello did not contain a key share extension");
326 auto* my_keyshare = ch.extensions().get<Key_Share>();
327 auto shared_secret = my_keyshare->decapsulate(*sh.extensions().get<Key_Share>(),
policy(),
callbacks(),
rng());
331 if(sh.extensions().has<
PSK>()) {
333 ch.extensions().get<
PSK>()->take_selected_psk_info(*sh.extensions().get<
PSK>(), cipher.value());
338 if(m_handshake->psk_identity.has_value() && m_handshake->resumed_session.has_value()) {
339 m_handshake->resumed_session.reset();
349 m_handshake->resumed_session.reset();
365 auto& ch = m_handshake->state.client_hello();
367 validate_server_hello_ish(ch, hrr);
373 auto allowed_exts = ch.extensions().extension_types();
375 if(hrr.extensions().contains_other_than(allowed_exts)) {
376 throw TLS_Exception(Alert::UnsupportedExtension,
"Unsupported extension found in Hello Retry Request");
385 if(!cipher->usable_in_version(Protocol_Version::TLS_V13)) {
386 throw TLS_Exception(Alert::IllegalParameter,
"HelloRetryRequest selected a cipher suite not usable in TLS 1.3");
408 const auto& exts = encrypted_extensions_msg.extensions();
415 const auto& requested_exts = m_handshake->state.client_hello().extensions().extension_types();
416 if(exts.contains_other_than(requested_exts)) {
417 throw TLS_Exception(Alert::UnsupportedExtension,
418 "Encrypted Extensions contained an extension that was not offered");
424 if(exts.has<Application_Layer_Protocol_Notification>()) {
429 const auto* server_alpn = exts.get<Application_Layer_Protocol_Notification>();
430 const auto selected = server_alpn->single_protocol();
431 const auto* client_alpn =
432 m_handshake->state.client_hello().extensions().get<Application_Layer_Protocol_Notification>();
434 const auto& offered = client_alpn->protocols();
436 throw TLS_Exception(Alert::IllegalParameter,
"Server selected an ALPN protocol not offered by the client");
440 if(exts.has<Record_Size_Limit>() && m_handshake->state.client_hello().extensions().has<Record_Size_Limit>()) {
448 auto*
const outgoing_limit = exts.get<Record_Size_Limit>();
449 auto*
const incoming_limit = m_handshake->state.client_hello().extensions().get<Record_Size_Limit>();
453 if(exts.has<Server_Certificate_Type>()) {
455 BOTAN_ASSERT_NOMSG(m_handshake->state.client_hello().extensions().has<Server_Certificate_Type>());
456 const auto* server_cert_type = exts.get<Server_Certificate_Type>();
457 const auto* our_server_cert_types = m_handshake->state.client_hello().extensions().get<Server_Certificate_Type>();
458 our_server_cert_types->validate_selection(*server_cert_type);
472 if(m_handshake->state.server_hello().extensions().has<
PSK>()) {
489 throw TLS_Exception(Alert::DecodeError,
"Certificate_Request context must be empty in the main handshake");
497void Client_Impl_13::handle(
const Certificate_13& certificate_msg) {
503 if(!certificate_msg.request_context().empty()) {
504 throw TLS_Exception(Alert::DecodeError,
"Received a server certificate message with non-empty request context");
510 certificate_msg.validate_extensions(m_handshake->state.client_hello().extensions().extension_types(),
callbacks());
515 m_handshake->state.client_hello().extensions().has<Certificate_Status_Request>());
531 const auto offered = m_handshake->state.client_hello().signature_schemes();
532 if(!
value_exists(offered, certificate_verify_msg.signature_scheme())) {
533 throw TLS_Exception(Alert::IllegalParameter,
534 "We did not offer the usage of " + certificate_verify_msg.signature_scheme().to_string() +
535 " as a signature scheme");
538 const bool sig_valid = certificate_verify_msg.verify(
542 throw TLS_Exception(Alert::DecryptError,
"Server certificate verification failed");
550 const auto& cert_request = m_handshake->state.certificate_request();
552 const auto cert_type = [&] {
553 const auto& exts = m_handshake->state.encrypted_extensions().extensions();
554 const auto& chexts = m_handshake->state.client_hello().extensions();
555 if(exts.has<Client_Certificate_Type>()) {
558 const auto* client_cert_type = exts.get<Client_Certificate_Type>();
559 chexts.get<Client_Certificate_Type>()->validate_selection(*client_cert_type);
568 return client_cert_type->selected_certificate_type();
582 flight.add(m_handshake->state.sending(
591 if(!m_handshake->state.client_certificate().empty()) {
592 flight.add(m_handshake->state.sending(Certificate_Verify_13(m_handshake->state.client_certificate(),
593 cert_request.signature_schemes(),
604void Client_Impl_13::handle(
const Finished_13& finished_msg) {
612 throw TLS_Exception(Alert::DecryptError,
"Finished message didn't verify");
615 m_handshake->state.confirm_peer_finished_verified();
624 m_handshake->resumed_session.has_value(),
637 if(m_handshake->state.has_certificate_request()) {
638 send_client_authentication(flight);
655 m_handshake->transitions.set_expected_next({});
661 auto extract_certs = [&]() -> std::vector<X509_Certificate> {
662 if(m_handshake->state.has_server_certificate_msg() &&
663 m_handshake->state.server_certificate().has_certificate_chain()) {
664 return m_handshake->state.server_certificate().cert_chain();
666 if(m_handshake->resumed_session.has_value()) {
667 return m_handshake->resumed_session->session.peer_certs();
672 auto extract_raw_pk = [&]() -> std::shared_ptr<const Public_Key> {
673 if(m_handshake->state.has_server_certificate_msg() &&
674 m_handshake->state.server_certificate().is_raw_public_key()) {
675 return m_handshake->state.server_certificate().public_key();
677 if(m_handshake->resumed_session.has_value()) {
678 return m_handshake->resumed_session->session.peer_raw_public_key();
686 m_handshake->psk_identity,
699 if(
const size_t max_tickets = policy().maximum_session_tickets_per_connection();
700 max_tickets > 0 && m_session_tickets_received >= max_tickets) {
705 ++m_session_tickets_received;
707 callbacks().tls_examine_extensions(
710 const Session session(m_cipher_state->psk(new_session_ticket.nonce()),
711 new_session_ticket.early_data_byte_limit(),
712 new_session_ticket.ticket_age_add(),
713 new_session_ticket.lifetime_hint(),
714 m_active_state->version(),
715 m_active_state->ciphersuite_code(),
718 peer_raw_public_key(),
720 callbacks().tls_current_timestamp());
722 if(callbacks().tls_should_persist_resumption_information(session)) {
723 session_manager().store(session,
Session_Handle(new_session_ticket.handle()));
734 if(m_handshake->state.has_server_certificate_msg() &&
735 m_handshake->state.server_certificate().has_certificate_chain()) {
736 return m_handshake->state.server_certificate().cert_chain();
739 if(m_handshake->resumed_session.has_value()) {
740 return m_handshake->resumed_session->session.peer_certs();
754 if(m_handshake->state.has_server_certificate_msg() &&
755 m_handshake->state.server_certificate().is_raw_public_key()) {
756 return m_handshake->state.server_certificate().public_key();
759 if(m_handshake->resumed_session.has_value()) {
760 return m_handshake->resumed_session->session.peer_raw_public_key();
772 return m_handshake->psk_identity;
777void Client_Impl_13::maybe_handle_compatibility_mode(Compat_Mode_Situation situation) {
781 if(!
policy().tls_13_middlebox_compatibility_mode()) {
788 if(m_handshake ==
nullptr) {
814 if(!m_handshake->state.has_hello_retry_request()) {
827 if(
m_cipher_state !=
nullptr && !m_handshake->state.has_hello_retry_request()) {
838void Client_Impl_13::maybe_log_secret(std::string_view label, std::span<const uint8_t> secret)
const {
839 if(
policy().allow_ssl_key_log_file()) {
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_STATE_CHECK(expr)
#define BOTAN_ASSERT_NONNULL(ptr)
#define BOTAN_ASSERT_UNREACHABLE()
virtual void tls_session_activated()
virtual void tls_examine_extensions(const Extensions &extn, Connection_Side which_side, Handshake_Type which_message)
virtual void tls_session_established(const Session_Summary &session)
virtual void tls_ssl_key_log_data(std::string_view label, std::span< const uint8_t > client_random, std::span< const uint8_t > secret) const
virtual void tls_inspect_handshake_msg(const Handshake_Message &message)
const Policy & policy() const
void send_handshake_message(const std::variant< MsgTs... > &message)
AggregatedHandshakeMessages aggregate_handshake_messages()
Credentials_Manager & credentials_manager()
void send_dummy_change_cipher_spec()
RandomNumberGenerator & rng()
Transcript_Hash_State m_transcript_hash
@ BeforeSendingEncryptedClientFlight
@ AfterSendingFirstClientHello
@ BeforeSendingSecondClientHello
@ AfterSendingFirstServerHello
@ AfterSendingHelloRetryRequest
std::optional< Active_Connection_State_13 > m_active_state
Channel_Impl_13(const std::shared_ptr< Callbacks > &callbacks, const std::shared_ptr< Session_Manager > &session_manager, const std::shared_ptr< Credentials_Manager > &credentials_manager, const std::shared_ptr< RandomNumberGenerator > &rng, const std::shared_ptr< const Policy > &policy, bool is_server)
virtual void process_dummy_change_cipher_spec()=0
Session_Manager & session_manager()
std::unique_ptr< Cipher_State > m_cipher_state
const Connection_Side m_side
Callbacks & callbacks() const
void set_selected_certificate_type(Certificate_Type cert_type)
void set_record_size_limits(uint16_t outgoing_limit, uint16_t incoming_limit)
bool expects_downgrade() const
static std::unique_ptr< Cipher_State > init_with_server_hello(Connection_Side side, secure_vector< uint8_t > &&shared_secret, const Ciphersuite &cipher, const Transcript_Hash &transcript_hash, const Secret_Logger &channel)
static std::optional< Ciphersuite > by_id(uint16_t suite)
Client_Impl_13(const std::shared_ptr< Callbacks > &callbacks, const std::shared_ptr< Session_Manager > &session_manager, const std::shared_ptr< Credentials_Manager > &creds, const std::shared_ptr< const Policy > &policy, const std::shared_ptr< RandomNumberGenerator > &rng, Server_Information server_info=Server_Information(), const std::vector< std::string > &next_protocols={})
std::optional< std::string > external_psk_identity() const override
std::string application_protocol() const override
std::shared_ptr< const Public_Key > peer_raw_public_key() const override
bool is_handshake_complete() const override
std::vector< X509_Certificate > peer_cert_chain() const override
Helper class to embody a session handle in all protocol versions.
virtual std::vector< Session_with_Handle > find(const Server_Information &info, Callbacks &callbacks, const Policy &policy)
Find all sessions that match a given server info.
bool supports(Protocol_Version version) const
static Transcript_Hash_State recreate_after_hello_retry_request(std::string_view algo_spec, const Transcript_Hash_State &prev_transcript_hash_state)
std::variant< Client_Hello_13, Client_Hello_12_Shim, Server_Hello_13, Server_Hello_12_Shim, Hello_Retry_Request, Encrypted_Extensions, Certificate_13, Certificate_Request_13, Certificate_Verify_13, Finished_13 > Handshake_Message_13
std::variant< New_Session_Ticket_13, Key_Update > Post_Handshake_Message_13
constexpr std::optional< SpecificVariantT > specialize_to(GeneralVariantT &&v)
Converts a given variant into another variant whose type states are a subset of the given variant.
bool value_exists(const std::vector< T > &vec, const V &val)