int s2n_process_client_hello()

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;
}