static int s2n_set_cipher_as_server()

in tls/s2n_cipher_suites.c [1178:1277]


static int s2n_set_cipher_as_server(struct s2n_connection *conn, uint8_t *wire, uint32_t count, uint32_t cipher_suite_len)
{
    uint8_t renegotiation_info_scsv[S2N_TLS_CIPHER_SUITE_LEN] = { TLS_EMPTY_RENEGOTIATION_INFO_SCSV };
    struct s2n_cipher_suite *higher_vers_match = NULL;

    /* RFC 7507 - If client is attempting to negotiate a TLS Version that is lower than the highest supported server
     * version, and the client cipher list contains TLS_FALLBACK_SCSV, then the server must abort the connection since
     * TLS_FALLBACK_SCSV should only be present when the client previously failed to negotiate a higher TLS version.
     */
    if (conn->client_protocol_version < conn->server_protocol_version) {
        uint8_t fallback_scsv[S2N_TLS_CIPHER_SUITE_LEN] = { TLS_FALLBACK_SCSV };
        if (s2n_wire_ciphers_contain(fallback_scsv, wire, count, cipher_suite_len)) {
            conn->closed = 1;
            POSIX_BAIL(S2N_ERR_FALLBACK_DETECTED);
        }
    }

    /* RFC5746 Section 3.6: A server must check if TLS_EMPTY_RENEGOTIATION_INFO_SCSV is included */
    if (s2n_wire_ciphers_contain(renegotiation_info_scsv, wire, count, cipher_suite_len)) {
        conn->secure_renegotiation = 1;
    }

    const struct s2n_security_policy *security_policy;
    POSIX_GUARD(s2n_connection_get_security_policy(conn, &security_policy));

    /* s2n supports only server order */
    for (int i = 0; i < security_policy->cipher_preferences->count; i++) {
        const uint8_t *ours = security_policy->cipher_preferences->suites[i]->iana_value;

        if (s2n_wire_ciphers_contain(ours, wire, count, cipher_suite_len)) {
            /* We have a match */
            struct s2n_cipher_suite *match = security_policy->cipher_preferences->suites[i];

            /* Never use TLS1.3 ciphers on a pre-TLS1.3 connection, and vice versa */
            if ((conn->actual_protocol_version >= S2N_TLS13) != (match->minimum_required_tls_version >= S2N_TLS13)) {
                continue;
            }

            /* If connection is for SSLv3, use SSLv3 version of suites */
            if (conn->client_protocol_version == S2N_SSLv3) {
                match = match->sslv3_cipher_suite;
            }

            /* Skip the suite if we don't have an available implementation */
            if (!match->available) {
                continue;
            }

            /* Make sure the cipher is valid for available certs */
            if (s2n_is_cipher_suite_valid_for_auth(conn, match) != S2N_SUCCESS) {
                continue;
            }

            /* TLS 1.3 does not include key exchange in cipher suites */
            if (match->minimum_required_tls_version < S2N_TLS13) {
                /* If the kex is not supported continue to the next candidate */
                bool kex_supported = false;
                POSIX_GUARD_RESULT(s2n_kex_supported(match, conn, &kex_supported));
                if (!kex_supported) {
                    continue;
                }

                /* If the kex is not configured correctly continue to the next candidate */
                if (s2n_result_is_error(s2n_configure_kex(match, conn))) {
                    continue;
                }
            }

            /**
             *= https://tools.ietf.org/rfc/rfc8446#section-4.2.11
             *# The server MUST ensure that it selects a compatible PSK
             *# (if any) and cipher suite.
             **/
            if (conn->psk_params.chosen_psk != NULL) {
                if (match->prf_alg != conn->psk_params.chosen_psk->hmac_alg) {
                    continue;
                }
            }

            /* Don't immediately choose a cipher the connection shouldn't be able to support */
            if (conn->actual_protocol_version < match->minimum_required_tls_version) {
                if (!higher_vers_match) {
                    higher_vers_match = match;
                }
                continue;
            }

            conn->secure.cipher_suite = match;
            return S2N_SUCCESS;
        }
    }

    /* Settle for a cipher with a higher required proto version, if it was set */
    if (higher_vers_match) {
        conn->secure.cipher_suite = higher_vers_match;
        return S2N_SUCCESS;
    }

    POSIX_BAIL(S2N_ERR_CIPHER_NOT_SUPPORTED);
}