/* * TLS Server Hello and Server Hello Done * (C) 2004-2011,2015,2016,2019 Jack Lloyd * 2021 Elektrobit Automotive GmbH * 2022 René Meusel, Hannes Rantzsch - neXenio GmbH * 2026 René Meusel - Rohde & Schwarz Cybersecurity GmbH * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include #include #include #include #include #include #include #include namespace Botan::TLS { const Server_Hello_13::Server_Hello_Tag Server_Hello_13::as_server_hello; const Server_Hello_13::Hello_Retry_Request_Tag Server_Hello_13::as_hello_retry_request; const Server_Hello_13::Hello_Retry_Request_Creation_Tag Server_Hello_13::as_new_hello_retry_request; std::variant Server_Hello_13::create(const Client_Hello_13& ch, bool hello_retry_request_allowed, Session_Manager& session_mgr, Credentials_Manager& credentials_mgr, RandomNumberGenerator& rng, const Policy& policy, Callbacks& cb) { const auto& exts = ch.extensions(); // RFC 8446 4.2.9 // [With PSK with (EC)DHE key establishment], the client and server MUST // supply "key_share" values [...]. // // Note: We currently do not support PSK without (EC)DHE, hence, we can // assume that those extensions are available. BOTAN_ASSERT_NOMSG(exts.has() && exts.has()); const auto& supported_by_client = exts.get()->groups(); const auto& offered_by_client = exts.get()->offered_groups(); const auto selected_group = policy.choose_key_exchange_group(supported_by_client, offered_by_client); // RFC 8446 4.1.1 // If there is no overlap between the received "supported_groups" and the // groups supported by the server, then the server MUST abort the // handshake with a "handshake_failure" or an "insufficient_security" alert. if(selected_group == Named_Group::NONE) { throw TLS_Exception(Alert::HandshakeFailure, "Client did not offer any acceptable group"); } // RFC 8446 4.2.8: // Servers MUST NOT send a KeyShareEntry for any group not indicated in the // client's "supported_groups" extension [...] if(!value_exists(supported_by_client, selected_group)) { throw TLS_Exception(Alert::InternalError, "Application selected a group that is not supported by the client"); } // RFC 8446 4.1.4 // The server will send this message in response to a ClientHello // message if it is able to find an acceptable set of parameters but the // ClientHello does not contain sufficient information to proceed with // the handshake. // // In this case, the Client Hello did not contain a key share offer for // the group selected by the application. if(!value_exists(offered_by_client, selected_group)) { // RFC 8446 4.1.4 // If a client receives a second HelloRetryRequest in the same // connection (i.e., where the ClientHello was itself in response to a // HelloRetryRequest), it MUST abort the handshake with an // "unexpected_message" alert. BOTAN_STATE_CHECK(hello_retry_request_allowed); return Hello_Retry_Request(ch, selected_group, policy, cb); } else { return Server_Hello_13(ch, selected_group, session_mgr, credentials_mgr, rng, cb, policy); } } std::variant Server_Hello_13::parse( const std::vector& buf) { auto data = std::make_unique(buf); const auto version = data->version(); // server hello that appears to be pre-TLS 1.3, takes precedence over... if(version.is_pre_tls_13()) { return Server_Hello_12_Shim(std::move(data)); } // ... the TLS 1.3 "special case" aka. Hello_Retry_Request if(version == Protocol_Version::TLS_V13) { if(data->is_hello_retry_request()) { return Hello_Retry_Request(std::move(data)); } return Server_Hello_13(std::move(data)); } throw TLS_Exception(Alert::ProtocolVersion, "unexpected server hello version: " + version.to_string()); } /** * Validation that applies to both Server Hello and Hello Retry Request */ void Server_Hello_13::basic_validation() const { BOTAN_ASSERT_NOMSG(m_data->version() == Protocol_Version::TLS_V13); // Note: checks that cannot be performed without contextual information // are done in the specific TLS client implementation. // Note: The Supported_Version extension makes sure internally that // exactly one entry is provided. // Note: Hello Retry Request basic validation is equivalent with the // basic validations required for Server Hello // // RFC 8446 4.1.4 // Upon receipt of a HelloRetryRequest, the client MUST check the // legacy_version, [...], and legacy_compression_method as specified in // Section 4.1.3 and then process the extensions, starting with determining // the version using "supported_versions". // RFC 8446 4.1.3 // In TLS 1.3, [...] the legacy_version field MUST be set to 0x0303 if(legacy_version() != Protocol_Version::TLS_V12) { throw TLS_Exception(Alert::ProtocolVersion, "legacy_version '" + legacy_version().to_string() + "' is not allowed"); } // RFC 8446 4.1.3 // legacy_compression_method: A single byte which MUST have the value 0. if(compression_method() != 0x00) { throw TLS_Exception(Alert::DecodeError, "compression is not supported in TLS 1.3"); } // RFC 8446 4.1.3 // All TLS 1.3 ServerHello messages MUST contain the "supported_versions" extension. if(!extensions().has()) { throw TLS_Exception(Alert::MissingExtension, "server hello did not contain 'supported version' extension"); } // RFC 8446 4.2.1 // A server which negotiates TLS 1.3 MUST respond by sending // a "supported_versions" extension containing the selected version // value (0x0304). if(selected_version() != Protocol_Version::TLS_V13) { throw TLS_Exception(Alert::IllegalParameter, "TLS 1.3 Server Hello selected a different version"); } } Server_Hello_13::Server_Hello_13(std::unique_ptr data, Server_Hello_13::Server_Hello_Tag /*tag*/) : Server_Hello(std::move(data)) { BOTAN_ASSERT_NOMSG(!m_data->is_hello_retry_request()); basic_validation(); const auto& exts = extensions(); // RFC 8446 4.1.3 // The ServerHello MUST only include extensions which are required to // establish the cryptographic context and negotiate the protocol version. // [...] // Other extensions (see Section 4.2) are sent separately in the // EncryptedExtensions message. // // Note that further validation dependent on the client hello is done in the // TLS client implementation. const std::set allowed = { Extension_Code::KeyShare, Extension_Code::SupportedVersions, Extension_Code::PresharedKey, }; // As the ServerHello shall only contain essential extensions, we don't give // any slack for extensions not implemented by Botan here. if(exts.contains_other_than(allowed)) { throw TLS_Exception(Alert::UnsupportedExtension, "Server Hello contained an extension that is not allowed"); } // RFC 8446 4.1.3 // Current ServerHello messages additionally contain // either the "pre_shared_key" extension or the "key_share" // extension, or both [...]. if(!exts.has() && !exts.has()) { throw TLS_Exception(Alert::MissingExtension, "server hello must contain key exchange information"); } } Server_Hello_13::Server_Hello_13(std::unique_ptr data, Server_Hello_13::Hello_Retry_Request_Tag /*tag*/) : Server_Hello(std::move(data)) { BOTAN_ASSERT_NOMSG(m_data->is_hello_retry_request()); basic_validation(); const auto& exts = extensions(); // RFC 8446 4.1.4 // The HelloRetryRequest extensions defined in this specification are: // - supported_versions (see Section 4.2.1) // - cookie (see Section 4.2.2) // - key_share (see Section 4.2.8) const std::set allowed = { Extension_Code::Cookie, Extension_Code::SupportedVersions, Extension_Code::KeyShare, }; // As the Hello Retry Request shall only contain essential extensions, we // don't give any slack for extensions not implemented by Botan here. if(exts.contains_other_than(allowed)) { throw TLS_Exception(Alert::UnsupportedExtension, "Hello Retry Request contained an extension that is not allowed"); } // RFC 8446 4.1.4 // Clients MUST abort the handshake with an "illegal_parameter" alert if // the HelloRetryRequest would not result in any change in the ClientHello. if(!exts.has() && !exts.has()) { throw TLS_Exception(Alert::IllegalParameter, "Hello Retry Request does not request any changes to Client Hello"); } } Server_Hello_13::Server_Hello_13(std::unique_ptr data, Hello_Retry_Request_Creation_Tag /*tag*/) : Server_Hello(std::move(data)) {} namespace { uint16_t choose_ciphersuite(const Client_Hello_13& ch, const Policy& policy) { auto pref_list = ch.ciphersuites(); // TODO: DTLS might need to make this version dynamic auto other_list = policy.ciphersuite_list(Protocol_Version::TLS_V13); if(policy.server_uses_own_ciphersuite_preferences()) { std::swap(pref_list, other_list); } for(auto suite_id : pref_list) { // TODO: take potentially available PSKs into account to select a // compatible ciphersuite. // // Assuming the client sent one or more PSKs, we would first need to find // the hash functions they are associated to. For session tickets, that // would mean decrypting the ticket and comparing the cipher suite used in // those tickets. For (currently not yet supported) pre-assigned PSKs, the // hash function needs to be specified along with them. // // Then we could refine the ciphersuite selection using the required hash // function for the PSK(s) we are wishing to use down the road. // // For now, we just negotiate the cipher suite blindly and hope for the // best. As long as PSKs are used for session resumption only, this has a // high chance of success. Previous handshakes with this client have very // likely selected the same ciphersuite anyway. // // See also RFC 8446 4.2.11 // When session resumption is the primary use case of PSKs, the most // straightforward way to implement the PSK/cipher suite matching // requirements is to negotiate the cipher suite first [...]. if(value_exists(other_list, suite_id)) { return suite_id; } } // RFC 8446 4.1.1 // If the server is unable to negotiate a supported set of parameters // [...], it MUST abort the handshake with either a "handshake_failure" // or "insufficient_security" fatal alert [...]. throw TLS_Exception(Alert::HandshakeFailure, "Can't agree on a ciphersuite with client"); } } // namespace Server_Hello_13::Server_Hello_13(const Client_Hello_13& ch, std::optional key_exchange_group, Session_Manager& session_mgr, Credentials_Manager& credentials_mgr, RandomNumberGenerator& rng, Callbacks& cb, const Policy& policy) : Server_Hello(std::make_unique( Protocol_Version::TLS_V12, ch.session_id(), make_server_hello_random(rng, Protocol_Version::TLS_V13, cb, policy), choose_ciphersuite(ch, policy), uint8_t(0) /* compression method */ )) { // RFC 8446 4.2.1 // A server which negotiates TLS 1.3 MUST respond by sending a // "supported_versions" extension containing the selected version // value (0x0304). It MUST set the ServerHello.legacy_version field to // 0x0303 (TLS 1.2). // // Note that the legacy version (TLS 1.2) is set in this constructor's // initializer list, accordingly. m_data->extensions().add(new Supported_Versions(Protocol_Version::TLS_V13)); // NOLINT(*-owning-memory) if(key_exchange_group.has_value()) { BOTAN_ASSERT_NOMSG(ch.extensions().has()); m_data->extensions().add(Key_Share::create_as_encapsulation( key_exchange_group.value(), *ch.extensions().get(), policy, cb, rng)); } const auto& ch_exts = ch.extensions(); if(ch_exts.has()) { const auto cs = Ciphersuite::by_id(m_data->ciphersuite()); BOTAN_ASSERT_NOMSG(cs); // RFC 8446 4.2.9 // A client MUST provide a "psk_key_exchange_modes" extension if it // offers a "pre_shared_key" extension. // // Note: Client_Hello_13 constructor already performed a graceful check. auto* const psk_modes = ch_exts.get(); BOTAN_ASSERT_NONNULL(psk_modes); // TODO: also support PSK_Key_Exchange_Mode::PSK_KE // (PSK-based handshake without an additional ephemeral key exchange) if(value_exists(psk_modes->modes(), PSK_Key_Exchange_Mode::PSK_DHE_KE)) { if(auto server_psk = ch_exts.get()->select_offered_psk( ch.sni_hostname(), cs.value(), session_mgr, credentials_mgr, cb, policy)) { // RFC 8446 4.2.11 // In order to accept PSK key establishment, the server sends a // "pre_shared_key" extension indicating the selected identity. m_data->extensions().add(std::move(server_psk)); } } } cb.tls_modify_extensions(m_data->extensions(), Connection_Side::Server, type()); } std::optional Server_Hello_13::random_signals_downgrade() const { const uint64_t last8 = load_be(m_data->random().data(), 3); if(last8 == DOWNGRADE_TLS11) { return Protocol_Version::TLS_V11; } if(last8 == DOWNGRADE_TLS12) { return Protocol_Version::TLS_V12; } return std::nullopt; } Protocol_Version Server_Hello_13::selected_version() const { auto* const versions_ext = m_data->extensions().get(); BOTAN_ASSERT_NOMSG(versions_ext); const auto& versions = versions_ext->versions(); BOTAN_ASSERT_NOMSG(versions.size() == 1); return versions.front(); } Hello_Retry_Request::Hello_Retry_Request(std::unique_ptr data) : Server_Hello_13(std::move(data), Server_Hello_13::as_hello_retry_request) {} Hello_Retry_Request::Hello_Retry_Request(const Client_Hello_13& ch, Named_Group selected_group, const Policy& policy, Callbacks& cb) : Server_Hello_13(std::make_unique( Protocol_Version::TLS_V12 /* legacy_version */, ch.session_id(), std::vector(HELLO_RETRY_REQUEST_MARKER.begin(), HELLO_RETRY_REQUEST_MARKER.end()), choose_ciphersuite(ch, policy), uint8_t(0) /* compression method */, true /* is Hello Retry Request */ ), as_new_hello_retry_request) { // RFC 8446 4.1.4 // As with the ServerHello, a HelloRetryRequest MUST NOT contain any // extensions that were not first offered by the client in its // ClientHello, with the exception of optionally the "cookie" [...] // extension. BOTAN_STATE_CHECK(ch.extensions().has()); BOTAN_STATE_CHECK(ch.extensions().has()); BOTAN_STATE_CHECK(!value_exists(ch.extensions().get()->offered_groups(), selected_group)); // RFC 8446 4.1.4 // The server's extensions MUST contain "supported_versions". // // RFC 8446 4.2.1 // A server which negotiates TLS 1.3 MUST respond by sending a // "supported_versions" extension containing the selected version // value (0x0304). It MUST set the ServerHello.legacy_version field to // 0x0303 (TLS 1.2). // // Note that the legacy version (TLS 1.2) is set in this constructor's // initializer list, accordingly. // NOLINTBEGIN(*-owning-memory) m_data->extensions().add(new Supported_Versions(Protocol_Version::TLS_V13)); m_data->extensions().add(new Key_Share(selected_group)); // NOLINTEND(*-owning-memory) cb.tls_modify_extensions(m_data->extensions(), Connection_Side::Server, type()); } } // namespace Botan::TLS