in tls/s2n_client_hello.c [521:631]
int s2n_process_client_hello(struct s2n_connection *conn)
{
POSIX_ENSURE_REF(conn);
POSIX_ENSURE_REF(conn->secure);
POSIX_ENSURE_REF(conn->secure->cipher_suite);
/* Client hello is parsed and config is finalized.
* Negotiate protocol version, cipher suite, ALPN, select a cert, etc. */
struct s2n_client_hello *client_hello = &conn->client_hello;
const struct s2n_security_policy *security_policy = NULL;
POSIX_GUARD(s2n_connection_get_security_policy(conn, &security_policy));
if (!s2n_connection_supports_tls13(conn) || !s2n_security_policy_supports_tls13(security_policy)) {
conn->server_protocol_version = MIN(conn->server_protocol_version, S2N_TLS12);
conn->actual_protocol_version = MIN(conn->server_protocol_version, S2N_TLS12);
}
/* Set default key exchange curve.
* This is going to be our fallback if the client has no preference.
*
* P-256 is our preferred fallback option because the TLS1.3 RFC requires
* all implementations to support it:
*
* https://tools.ietf.org/rfc/rfc8446#section-9.1
* A TLS-compliant application MUST support key exchange with secp256r1 (NIST P-256)
* and SHOULD support key exchange with X25519 [RFC7748]
*
*= https://www.rfc-editor.org/rfc/rfc4492#section-4
*# A client that proposes ECC cipher suites may choose not to include these extensions.
*# In this case, the server is free to choose any one of the elliptic curves or point formats listed in Section 5.
*
*/
const struct s2n_ecc_preferences *ecc_pref = NULL;
POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref));
POSIX_ENSURE_REF(ecc_pref);
POSIX_ENSURE_GT(ecc_pref->count, 0);
if (s2n_ecc_preferences_includes_curve(ecc_pref, TLS_EC_CURVE_SECP_256_R1)) {
conn->kex_params.server_ecc_evp_params.negotiated_curve = &s2n_ecc_curve_secp256r1;
} else {
/* If P-256 isn't allowed by the current security policy, instead choose
* the first / most preferred curve.
*/
conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
}
POSIX_GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_CLIENT_HELLO, conn, &conn->client_hello.extensions));
/* After parsing extensions, select a curve and corresponding keyshare to use */
if (conn->actual_protocol_version >= S2N_TLS13) {
POSIX_GUARD(s2n_extensions_server_key_share_select(conn));
}
/* for pre TLS 1.3 connections, protocol selection is not done in supported_versions extensions, so do it here */
if (conn->actual_protocol_version < S2N_TLS13) {
conn->actual_protocol_version = MIN(conn->server_protocol_version, conn->client_protocol_version);
}
if (conn->client_protocol_version < security_policy->minimum_protocol_version) {
POSIX_GUARD(s2n_queue_reader_unsupported_protocol_version_alert(conn));
POSIX_BAIL(S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED);
}
if (s2n_connection_is_quic_enabled(conn)) {
POSIX_ENSURE(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED);
}
/* Find potential certificate matches before we choose the cipher. */
POSIX_GUARD(s2n_conn_find_name_matching_certs(conn));
/* Save the previous cipher suite */
uint8_t previous_cipher_suite_iana[S2N_TLS_CIPHER_SUITE_LEN] = { 0 };
POSIX_CHECKED_MEMCPY(previous_cipher_suite_iana, conn->secure->cipher_suite->iana_value, S2N_TLS_CIPHER_SUITE_LEN);
/* Now choose the ciphers we have certs for. */
if (conn->client_hello_version == S2N_SSLv2) {
POSIX_GUARD(s2n_set_cipher_as_sslv2_server(conn, client_hello->cipher_suites.data,
client_hello->cipher_suites.size / S2N_SSLv2_CIPHER_SUITE_LEN));
} else {
POSIX_GUARD(s2n_set_cipher_as_tls_server(conn, client_hello->cipher_suites.data,
client_hello->cipher_suites.size / 2));
}
/* Check if this is the second client hello in a hello retry handshake */
if (s2n_is_hello_retry_handshake(conn) && conn->handshake.message_number > 0) {
/**
*= https://www.rfc-editor.org/rfc/rfc8446#4.1.4
*# Servers MUST ensure that they negotiate the
*# same cipher suite when receiving a conformant updated ClientHello (if
*# the server selects the cipher suite as the first step in the
*# negotiation, then this will happen automatically).
**/
POSIX_ENSURE(s2n_constant_time_equals(previous_cipher_suite_iana, conn->secure->cipher_suite->iana_value,
S2N_TLS_CIPHER_SUITE_LEN),
S2N_ERR_BAD_MESSAGE);
}
/* If we're using a PSK, we don't need to choose a signature algorithm or certificate,
* because no additional auth is required. */
if (conn->psk_params.chosen_psk != NULL) {
return S2N_SUCCESS;
}
/* And set the signature and hash algorithm used for key exchange signatures */
POSIX_GUARD_RESULT(s2n_signature_algorithm_select(conn));
/* And finally, set the certs specified by the final auth + sig_alg combo. */
POSIX_GUARD(s2n_select_certs_for_server_auth(conn, &conn->handshake_params.our_chain_and_key));
return S2N_SUCCESS;
}