/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

#include <string.h>

#include "crypto/s2n_ecc_evp.h"
#include "crypto/s2n_pq.h"
#include "s2n_test.h"
#include "testlib/s2n_testlib.h"
#include "tls/s2n_cipher_suites.h"
#include "tls/s2n_connection.h"
#include "tls/s2n_security_policies.h"

static s2n_result s2n_conn_set_chosen_psk(struct s2n_connection *conn)
{
    RESULT_ENSURE_REF(conn);

    uint8_t psk_identity[] = "psk identity";
    RESULT_GUARD(s2n_array_pushback(&conn->psk_params.psk_list, (void **) &conn->psk_params.chosen_psk));
    RESULT_ENSURE_REF(conn->psk_params.chosen_psk);
    RESULT_GUARD(s2n_psk_init(conn->psk_params.chosen_psk, S2N_PSK_TYPE_EXTERNAL));
    RESULT_GUARD_POSIX(s2n_psk_set_identity(conn->psk_params.chosen_psk, psk_identity, sizeof(psk_identity)));

    return S2N_RESULT_OK;
}

int main(int argc, char **argv)
{
    BEGIN_TEST();
    EXPECT_SUCCESS(s2n_disable_tls13_in_test());

    char dhparams_pem[S2N_MAX_TEST_PEM_SIZE] = { 0 };
    EXPECT_SUCCESS(s2n_read_test_pem(S2N_DEFAULT_TEST_DHPARAMS, dhparams_pem,
            S2N_MAX_TEST_PEM_SIZE));

    /* Test client cipher selection */
    {
        /* Setup connections */
        struct s2n_connection *conn = NULL;
        EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_CLIENT));

        /* Setup config */
        struct s2n_cert_chain_and_key *chain_and_key = NULL;
        EXPECT_SUCCESS(s2n_test_cert_chain_and_key_new(&chain_and_key,
                S2N_DEFAULT_TEST_CERT_CHAIN, S2N_DEFAULT_TEST_PRIVATE_KEY));
        struct s2n_config *config = NULL;
        EXPECT_NOT_NULL(config = s2n_config_new());
        EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, chain_and_key));
        EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

        /* Test that the client allows the server to select ciphers that were offered in ClientHello */
        {
            conn->client_protocol_version = S2N_TLS13;
            conn->actual_protocol_version = S2N_TLS13;
            conn->server_protocol_version = S2N_TLS13;

            /* The client will offer the default tls13 ciphersuites */
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "default_tls13"));

            /* The server will send a TLS13 cipher over the wire */
            uint8_t valid_wire_ciphers[] = {
                TLS_AES_128_GCM_SHA256
            };

            /* We expect to succeed because the cipher was offered by the client */
            EXPECT_SUCCESS(s2n_set_cipher_as_client(conn, valid_wire_ciphers));

            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* Test that the client rejects a cipher that was not originally offered in ClientHello */
        {
            conn->client_protocol_version = S2N_TLS13;
            conn->actual_protocol_version = S2N_TLS13;
            conn->server_protocol_version = S2N_TLS13;

            /* The client will offer the default tls13 ciphersuites */
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all_tls13"));

            /* The server will send a TLS12 cipher over the wire */
            uint8_t invalid_wire_ciphers[] = {
                TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
            };

            /* We expect to fail because the cipher was not offered by the client */
            EXPECT_FAILURE_WITH_ERRNO(s2n_set_cipher_as_client(conn, invalid_wire_ciphers), S2N_ERR_CIPHER_NOT_SUPPORTED);

            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /** Clients MUST verify
         *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.11
         *= type=test
         *# that the server selected a cipher suite
         *# indicating a Hash associated with the PSK
         **/
        {
            /* If chosen PSK is set, test error case for incorrect hash match */
            {
                s2n_connection_set_cipher_preferences(conn, "default_tls13");

                EXPECT_OK(s2n_conn_set_chosen_psk(conn));

                uint8_t valid_tls13_wire_ciphers[] = {
                    TLS_AES_128_GCM_SHA256,
                };

                /* S2N_HMAC_SHA1 is not a matching hmac algorithm */
                conn->psk_params.chosen_psk->hmac_alg = S2N_HMAC_SHA1;
                EXPECT_FAILURE_WITH_ERRNO(s2n_set_cipher_as_client(conn, valid_tls13_wire_ciphers),
                        S2N_ERR_CIPHER_NOT_SUPPORTED);
                EXPECT_EQUAL(conn->secure->cipher_suite, &s2n_null_cipher_suite);

                EXPECT_SUCCESS(s2n_connection_wipe(conn));
            };

            /* If chosen PSK is set, test success case for matching hash algorithm */
            {
                s2n_connection_set_cipher_preferences(conn, "default_tls13");

                EXPECT_OK(s2n_conn_set_chosen_psk(conn));

                uint8_t valid_tls13_wire_ciphers[] = {
                    TLS_AES_128_GCM_SHA256,
                };

                /* S2N_HMAC_SHA256 is a matching hmac algorithm for the cipher suite present in valid_tls13_wire_ciphers */
                conn->psk_params.chosen_psk->hmac_alg = S2N_HMAC_SHA256;
                EXPECT_SUCCESS(s2n_set_cipher_as_client(conn, valid_tls13_wire_ciphers));
                EXPECT_EQUAL(conn->secure->cipher_suite, &s2n_tls13_aes_128_gcm_sha256);

                EXPECT_SUCCESS(s2n_connection_wipe(conn));
            };
        };

        EXPECT_SUCCESS(s2n_connection_free(conn));
        EXPECT_SUCCESS(s2n_cert_chain_and_key_free(chain_and_key));
        EXPECT_SUCCESS(s2n_config_free(config));
    };

    /* Test server cipher selection and scsv detection */
    {
        struct s2n_connection *conn = NULL;
        struct s2n_config *server_config = NULL;
        char *rsa_cert_chain_pem = NULL, *rsa_private_key_pem = NULL, *ecdsa_cert_chain_pem = NULL, *ecdsa_private_key_pem = NULL;
        struct s2n_cert_chain_and_key *rsa_cert = NULL, *ecdsa_cert = NULL;
        /* Allocate all of the objects and PEMs we'll need for this test. */
        EXPECT_NOT_NULL(rsa_cert_chain_pem = malloc(S2N_MAX_TEST_PEM_SIZE));
        EXPECT_NOT_NULL(rsa_private_key_pem = malloc(S2N_MAX_TEST_PEM_SIZE));
        EXPECT_NOT_NULL(ecdsa_cert_chain_pem = malloc(S2N_MAX_TEST_PEM_SIZE));
        EXPECT_NOT_NULL(ecdsa_private_key_pem = malloc(S2N_MAX_TEST_PEM_SIZE));
        EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER));
        EXPECT_NOT_NULL(rsa_cert = s2n_cert_chain_and_key_new());
        EXPECT_NOT_NULL(ecdsa_cert = s2n_cert_chain_and_key_new());
        EXPECT_SUCCESS(s2n_read_test_pem(S2N_DEFAULT_TEST_CERT_CHAIN, rsa_cert_chain_pem, S2N_MAX_TEST_PEM_SIZE));
        EXPECT_SUCCESS(s2n_read_test_pem(S2N_DEFAULT_TEST_PRIVATE_KEY, rsa_private_key_pem, S2N_MAX_TEST_PEM_SIZE));
        EXPECT_SUCCESS(s2n_read_test_pem(S2N_ECDSA_P384_PKCS1_CERT_CHAIN, ecdsa_cert_chain_pem, S2N_MAX_TEST_PEM_SIZE));
        EXPECT_SUCCESS(s2n_read_test_pem(S2N_ECDSA_P384_PKCS1_KEY, ecdsa_private_key_pem, S2N_MAX_TEST_PEM_SIZE));
        EXPECT_SUCCESS(s2n_cert_chain_and_key_load_pem(rsa_cert, rsa_cert_chain_pem, rsa_private_key_pem));
        EXPECT_SUCCESS(s2n_cert_chain_and_key_load_pem(ecdsa_cert, ecdsa_cert_chain_pem, ecdsa_private_key_pem));

        uint8_t wire_ciphers[] = {
            TLS_RSA_WITH_RC4_128_MD5,
            TLS_RSA_WITH_RC4_128_SHA,
            TLS_RSA_WITH_3DES_EDE_CBC_SHA,
            TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
            TLS_RSA_WITH_AES_128_CBC_SHA,
            TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
            TLS_RSA_WITH_AES_256_CBC_SHA,
            TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
            TLS_RSA_WITH_AES_128_CBC_SHA256,
            TLS_RSA_WITH_AES_256_CBC_SHA256,
            TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
            TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
            TLS_RSA_WITH_AES_128_GCM_SHA256,
            TLS_RSA_WITH_AES_256_GCM_SHA384,
            TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
            TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
            TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
            TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
            TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
            TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
            TLS_ECDHE_KYBER_RSA_WITH_AES_256_GCM_SHA384,
        };
        const uint8_t cipher_count = sizeof(wire_ciphers) / S2N_TLS_CIPHER_SUITE_LEN;

        uint8_t wire_ciphers_fallback[] = {
            TLS_RSA_WITH_RC4_128_MD5,
            TLS_RSA_WITH_RC4_128_SHA,
            TLS_RSA_WITH_3DES_EDE_CBC_SHA,
            TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
            TLS_RSA_WITH_AES_128_CBC_SHA,
            TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
            TLS_RSA_WITH_AES_256_CBC_SHA,
            TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
            TLS_RSA_WITH_AES_128_CBC_SHA256,
            TLS_RSA_WITH_AES_256_CBC_SHA256,
            TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
            TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
            TLS_RSA_WITH_AES_128_GCM_SHA256,
            TLS_RSA_WITH_AES_256_GCM_SHA384,
            TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
            TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
            TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
            TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
            TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
            TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
            TLS_FALLBACK_SCSV, /* At the end to verify it isn't missed */
        };
        const uint8_t cipher_count_fallback = sizeof(wire_ciphers_fallback) / S2N_TLS_CIPHER_SUITE_LEN;

        uint8_t wire_ciphers_renegotiation[] = {
            TLS_RSA_WITH_RC4_128_MD5,
            TLS_RSA_WITH_RC4_128_SHA,
            TLS_RSA_WITH_3DES_EDE_CBC_SHA,
            TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
            TLS_RSA_WITH_AES_128_CBC_SHA,
            TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
            TLS_RSA_WITH_AES_256_CBC_SHA,
            TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
            TLS_RSA_WITH_AES_128_CBC_SHA256,
            TLS_RSA_WITH_AES_256_CBC_SHA256,
            TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
            TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
            TLS_RSA_WITH_AES_128_GCM_SHA256,
            TLS_RSA_WITH_AES_256_GCM_SHA384,
            TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
            TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
            TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
            TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
            TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
            TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
            TLS_EMPTY_RENEGOTIATION_INFO_SCSV, /* At the end to verify it isn't missed */
        };
        const uint8_t cipher_count_renegotiation = sizeof(wire_ciphers_renegotiation) / S2N_TLS_CIPHER_SUITE_LEN;

        /* Only two ciphers for testing RSA vs ECDSA. */
        uint8_t wire_ciphers_with_ecdsa[] = {
            TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
            TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
        };
        const uint8_t cipher_count_ecdsa = sizeof(wire_ciphers_with_ecdsa) / S2N_TLS_CIPHER_SUITE_LEN;

        /* Only ECDSA ciphers */
        uint8_t wire_ciphers_only_ecdsa[] = {
            TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
            TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
            TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
            TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
        };
        const uint8_t cipher_count_only_ecdsa = sizeof(wire_ciphers_only_ecdsa) / S2N_TLS_CIPHER_SUITE_LEN;

        uint8_t wire_ciphers_rsa_fallback[] = {
            TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
            TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
            TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
            TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
            TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
            TLS_RSA_WITH_AES_256_GCM_SHA384,
        };
        const uint8_t cipher_count_rsa_fallback = sizeof(wire_ciphers_rsa_fallback) / S2N_TLS_CIPHER_SUITE_LEN;

        EXPECT_NOT_NULL(server_config = s2n_config_new());
        EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, rsa_cert));
        /* Security policy must allow all test cipher suites */
        EXPECT_SUCCESS(s2n_config_set_cipher_preferences(server_config, "test_all"));
        EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));

        /* TEST RSA */
        conn->actual_protocol_version = S2N_TLS10;
        EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers, cipher_count));
        EXPECT_EQUAL(conn->secure_renegotiation, 0);
        EXPECT_EQUAL(1, s2n_connection_is_valid_for_cipher_preferences(conn, "test_all"));
        EXPECT_EQUAL(0, s2n_connection_is_valid_for_cipher_preferences(conn, "null"));
        EXPECT_SUCCESS(s2n_connection_wipe(conn));

        /* TEST RENEGOTIATION
         *
         *= https://www.rfc-editor.org/rfc/rfc5746#3.6
         *= type=test
         *# o  When a ClientHello is received, the server MUST check if it
         *#    includes the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.  If it does,
         *#    set the secure_renegotiation flag to TRUE.
         */
        conn->actual_protocol_version = S2N_TLS12;
        EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_renegotiation, cipher_count_renegotiation));
        EXPECT_EQUAL(conn->secure_renegotiation, 1);
        EXPECT_EQUAL(1, s2n_connection_is_valid_for_cipher_preferences(conn, "test_all"));
        EXPECT_EQUAL(-1, s2n_connection_is_valid_for_cipher_preferences(conn, "not_exist"));
        EXPECT_SUCCESS(s2n_connection_wipe(conn));

        /* Simulate a TLSv11 client to trigger the fallback error */
        conn->actual_protocol_version = S2N_TLS11;
        EXPECT_FAILURE(s2n_set_cipher_as_tls_server(conn, wire_ciphers_fallback, cipher_count_fallback));
        EXPECT_EQUAL(conn->secure_renegotiation, 0);
        EXPECT_EQUAL(1, s2n_connection_is_valid_for_cipher_preferences(conn, "null"));
        EXPECT_EQUAL(0, s2n_connection_is_valid_for_cipher_preferences(conn, "CloudFront-TLS-1-2-2018"));
        EXPECT_EQUAL(0, s2n_connection_is_valid_for_cipher_preferences(conn, "CloudFront-TLS-1-2-2019"));
        EXPECT_SUCCESS(s2n_connection_wipe(conn));

        /* TEST RSA cipher chosen when ECDSA cipher is at top */
        EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority"));

        const struct s2n_ecc_preferences *ecc_pref = NULL;
        EXPECT_SUCCESS(s2n_connection_get_ecc_preferences(conn, &ecc_pref));
        EXPECT_NOT_NULL(ecc_pref);

        /* Assume default for negotiated curve. */
        /* Shouldn't be necessary unless the test fails, but we want the failure to be obvious. */
        conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
        conn->actual_protocol_version = conn->server_protocol_version;
        const struct s2n_cipher_suite *expected_rsa_wire_choice = &s2n_ecdhe_rsa_with_aes_128_cbc_sha;
        EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa));
        EXPECT_EQUAL(conn->secure_renegotiation, 0);
        EXPECT_EQUAL(conn->secure->cipher_suite, expected_rsa_wire_choice);
        EXPECT_SUCCESS(s2n_connection_wipe(conn));

        /* Clean+free to setup for ECDSA tests */
        EXPECT_SUCCESS(s2n_config_free(server_config));

        /* Set ECDSA CERT in s2n_config */
        EXPECT_NOT_NULL(server_config = s2n_config_new());
        EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, ecdsa_cert));
        EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));

        EXPECT_SUCCESS(s2n_connection_get_ecc_preferences(conn, &ecc_pref));
        EXPECT_NOT_NULL(ecc_pref);

        /* TEST ECDSA */
        EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all_ecdsa"));
        const struct s2n_cipher_suite *expected_ecdsa_wire_choice = &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256;
        /* Assume default for negotiated curve. */
        conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
        conn->actual_protocol_version = conn->server_protocol_version;
        EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa));
        EXPECT_EQUAL(conn->secure_renegotiation, 0);
        EXPECT_EQUAL(conn->secure->cipher_suite, expected_ecdsa_wire_choice);
        EXPECT_SUCCESS(s2n_connection_wipe(conn));

        /* TEST ECDSA cipher chosen when RSA cipher is at top */
        EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all"));
        /* Assume default for negotiated curve. */
        conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
        conn->actual_protocol_version = conn->server_protocol_version;
        EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa));
        EXPECT_EQUAL(conn->secure_renegotiation, 0);
        EXPECT_EQUAL(conn->secure->cipher_suite, expected_ecdsa_wire_choice);
        EXPECT_SUCCESS(s2n_connection_wipe(conn));
        EXPECT_SUCCESS(s2n_config_free(server_config));

        /* TEST two certificates. Use two certs with different key types(RSA, ECDSA) and add them to a single
         * s2n_config.
         */
        EXPECT_NOT_NULL(server_config = s2n_config_new());
        EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, rsa_cert));
        EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, ecdsa_cert));
        EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));

        /* Client sends RSA and ECDSA ciphers, server prioritizes ECDSA, ECDSA + RSA cert is configured */
        {
            const struct s2n_cipher_suite *expected_wire_choice = &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256;
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority"));
            conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
            conn->actual_protocol_version = conn->server_protocol_version;
            EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa));
            EXPECT_EQUAL(conn->secure_renegotiation, 0);
            EXPECT_EQUAL(conn->secure->cipher_suite, expected_wire_choice);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* Client sends RSA and ECDSA ciphers, server prioritizes RSA, ECDSA + RSA cert is configured */
        {
            const struct s2n_cipher_suite *expected_wire_choice = &s2n_ecdhe_rsa_with_aes_128_cbc_sha;
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all"));
            conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
            conn->actual_protocol_version = conn->server_protocol_version;
            EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa));
            EXPECT_EQUAL(conn->secure_renegotiation, 0);
            EXPECT_EQUAL(conn->secure->cipher_suite, expected_wire_choice);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* Client sends both RSA and ECDSA ciphers, server only configures RSA ciphers,
         * ECDSA + RSA cert is configured.
         */
        {
            const struct s2n_cipher_suite *expected_wire_choice = &s2n_ecdhe_rsa_with_aes_128_cbc_sha;
            /* 20170328 only supports RSA ciphers */
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "20170328"));
            conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
            conn->actual_protocol_version = conn->server_protocol_version;
            EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa));
            EXPECT_EQUAL(conn->secure_renegotiation, 0);
            EXPECT_EQUAL(conn->secure->cipher_suite, expected_wire_choice);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* Client sends both RSA and ECDSA ciphers, server only configures ECDSA ciphers, ECDSA + RSA cert is
         * configured.
         */
        {
            const struct s2n_cipher_suite *expected_wire_choice = &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256;
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all_ecdsa"));
            conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
            conn->actual_protocol_version = conn->server_protocol_version;
            EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa));
            EXPECT_EQUAL(conn->secure_renegotiation, 0);
            EXPECT_EQUAL(conn->secure->cipher_suite, expected_wire_choice);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* Client only sends RSA ciphers, server prioritizes ECDSA ciphers, ECDSA + RSA cert is
         * configured.
         */
        {
            const struct s2n_cipher_suite *expected_wire_choice = &s2n_rsa_with_rc4_128_md5;
            if (!expected_wire_choice->available) {
                expected_wire_choice = &s2n_rsa_with_3des_ede_cbc_sha;
            }
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority"));
            conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
            conn->actual_protocol_version = conn->server_protocol_version;
            EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers, cipher_count));
            EXPECT_EQUAL(conn->secure_renegotiation, 0);
            EXPECT_EQUAL(conn->secure->cipher_suite, expected_wire_choice);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* Client only sends ECDSA ciphers, server prioritizes ECDSA ciphers, ECDSA + RSA cert is
         * configured.
         */
        {
            const struct s2n_cipher_suite *expected_wire_choice = &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha;
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority"));
            conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
            conn->actual_protocol_version = conn->server_protocol_version;
            EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_only_ecdsa, cipher_count_only_ecdsa));
            EXPECT_EQUAL(conn->secure_renegotiation, 0);
            EXPECT_EQUAL(conn->secure->cipher_suite, expected_wire_choice);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* Client sends ECDHE-ECDSA, RSA, ECDHE-RSA ciphers. Server prioritizes ECDSA but also supports RSA.
         * No mutually supported elliptic curves between client and server. ECDSA + RSA cert is configured.
         */
        {
            /* If there are no shared elliptic curves, we must fall through to a cipher that supports RSA kx.
             * This is the first RSA kx cipher that CloudFront-Upstream supports.
             */
            const struct s2n_cipher_suite *expected_wire_choice = &s2n_rsa_with_aes_256_gcm_sha384;
            /* Selecting this preference list because it prioritizes ECDHE-ECDSA and ECDHE-RSA over plain RSA kx. */
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "CloudFront-Upstream"));
            /* No shared curve */
            conn->kex_params.server_ecc_evp_params.negotiated_curve = NULL;
            conn->actual_protocol_version = conn->server_protocol_version;
            EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_rsa_fallback, cipher_count_rsa_fallback));
            EXPECT_EQUAL(conn->secure_renegotiation, 0);
            EXPECT_EQUAL(conn->secure->cipher_suite, expected_wire_choice);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };
        EXPECT_SUCCESS(s2n_config_free(server_config));

        EXPECT_NOT_NULL(server_config = s2n_config_new());
        EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, rsa_cert));
        EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, ecdsa_cert));
        /* Override auto-chosen defaults with only RSA cert default. ECDSA still loaded, but not default. */
        EXPECT_SUCCESS(s2n_config_set_cert_chain_and_key_defaults(server_config, &rsa_cert, 1));
        EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));

        /* Client sends RSA and ECDSA ciphers, server prioritizes ECDSA, ECDSA + RSA cert is configured,
         * only RSA is default. Expect default RSA used instead of previous test that expects ECDSA for this case. */
        {
            const struct s2n_cipher_suite *expected_wire_choice = &s2n_ecdhe_rsa_with_aes_128_cbc_sha;
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority"));
            conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
            conn->actual_protocol_version = conn->server_protocol_version;
            EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa));
            EXPECT_EQUAL(conn->secure_renegotiation, 0);
            EXPECT_EQUAL(conn->secure->cipher_suite, expected_wire_choice);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* Override auto-chosen defaults with only ECDSA cert default. RSA still loaded, but not default. */
        EXPECT_SUCCESS(s2n_config_set_cert_chain_and_key_defaults(server_config, &ecdsa_cert, 1));

        /* Client sends RSA and ECDSA ciphers, server prioritizes RSA, ECDSA + RSA cert is configured,
         * only ECDSA is default. Expect default ECDSA used instead of previous test that expects RSA for this case. */
        {
            const struct s2n_cipher_suite *expected_wire_choice = &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256;
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all"));
            conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
            conn->actual_protocol_version = conn->server_protocol_version;
            EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa));
            EXPECT_EQUAL(conn->secure_renegotiation, 0);
            EXPECT_EQUAL(conn->secure->cipher_suite, expected_wire_choice);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* Test override back to both RSA and ECDSA defaults. */
        struct s2n_cert_chain_and_key *certs_list[] = { rsa_cert, ecdsa_cert };
        EXPECT_SUCCESS(s2n_config_set_cert_chain_and_key_defaults(server_config, certs_list, 2));

        /* Client sends RSA and ECDSA ciphers, server prioritizes ECDSA, ECDSA + RSA cert is configured */
        {
            const struct s2n_cipher_suite *expected_wire_choice = &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256;
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_ecdsa_priority"));
            conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
            conn->actual_protocol_version = conn->server_protocol_version;
            EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa));
            EXPECT_EQUAL(conn->secure_renegotiation, 0);
            EXPECT_EQUAL(conn->secure->cipher_suite, expected_wire_choice);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* Test that defaults are not overriden after failures to set new default certificates */
        EXPECT_FAILURE_WITH_ERRNO_NO_RESET(s2n_config_set_cert_chain_and_key_defaults(server_config, NULL, 0), S2N_ERR_NULL);
        EXPECT_EQUAL(strcmp(s2n_strerror_name(s2n_errno), "S2N_ERR_NULL"), 0);
        EXPECT_FAILURE_WITH_ERRNO_NO_RESET(s2n_config_set_cert_chain_and_key_defaults(server_config, &rsa_cert, 0),
                S2N_ERR_NUM_DEFAULT_CERTIFICATES);
        EXPECT_EQUAL(strcmp(s2n_strerror_name(s2n_errno), "S2N_ERR_NUM_DEFAULT_CERTIFICATES"), 0);
        struct s2n_cert_chain_and_key *rsa_certs_list[] = { rsa_cert, rsa_cert };
        EXPECT_FAILURE_WITH_ERRNO_NO_RESET(s2n_config_set_cert_chain_and_key_defaults(server_config, rsa_certs_list, 2),
                S2N_ERR_MULTIPLE_DEFAULT_CERTIFICATES_PER_AUTH_TYPE);
        EXPECT_EQUAL(strcmp(s2n_strerror_name(s2n_errno), "S2N_ERR_MULTIPLE_DEFAULT_CERTIFICATES_PER_AUTH_TYPE"), 0);

        /* Client sends RSA and ECDSA ciphers, server prioritizes RSA, ECDSA + RSA cert is configured.
         * RSA default certificate should be chosen. */
        {
            const struct s2n_cipher_suite *expected_wire_choice = &s2n_ecdhe_rsa_with_aes_128_cbc_sha;
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all"));
            conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_pref->ecc_curves[0];
            conn->actual_protocol_version = conn->server_protocol_version;
            EXPECT_SUCCESS(s2n_connection_set_config(conn, server_config));
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_ecdsa, cipher_count_ecdsa));
            EXPECT_EQUAL(conn->secure_renegotiation, 0);
            EXPECT_EQUAL(conn->secure->cipher_suite, expected_wire_choice);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        struct s2n_cipher_suite *tls12_cipher_suite = cipher_preferences_20170210.suites[cipher_preferences_20170210.count - 1];
        uint8_t wire_ciphers_with_tls13[] = {
            TLS_AES_128_GCM_SHA256,
            TLS_AES_256_GCM_SHA384,
            TLS_CHACHA20_POLY1305_SHA256,
            tls12_cipher_suite->iana_value[0], tls12_cipher_suite->iana_value[1]
        };
        const uint8_t cipher_count_tls13 = sizeof(wire_ciphers_with_tls13) / S2N_TLS_CIPHER_SUITE_LEN;

        /* Client sends TLS1.3 cipher suites, but server does not support TLS1.3 */
        {
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all"));
            conn->client_protocol_version = S2N_TLS13;
            conn->actual_protocol_version = S2N_TLS12;
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_tls13, cipher_count_tls13));
            EXPECT_EQUAL(conn->secure->cipher_suite, tls12_cipher_suite);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* Client sends TLS1.3 cipher suites, server selects correct TLS1.3 ciphersuite */
        if (s2n_is_tls13_fully_supported()) {
            struct test_case {
                const char *cipher_pref;
                const struct s2n_cipher_suite *expected_cipher_wire;
            };

            struct test_case test_cases[] = {
                { .cipher_pref = "default_tls13", .expected_cipher_wire = &s2n_tls13_aes_128_gcm_sha256 },
                { .cipher_pref = "test_all", .expected_cipher_wire = &s2n_tls13_aes_128_gcm_sha256 },
                { .cipher_pref = "test_all_tls13", .expected_cipher_wire = &s2n_tls13_aes_128_gcm_sha256 },
            };

            for (size_t i = 0; i < s2n_array_len(test_cases); i++) {
                EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, test_cases[i].cipher_pref));
                conn->client_protocol_version = S2N_TLS13;
                conn->actual_protocol_version = S2N_TLS13;
                conn->server_protocol_version = S2N_TLS13;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_tls13, cipher_count_tls13));
                EXPECT_EQUAL(conn->secure->cipher_suite, test_cases[i].expected_cipher_wire);
                EXPECT_SUCCESS(s2n_connection_wipe(conn));
            }
        }

        /* Check wire's cipher suites with preferred tls12 ordering does not affect tls13 selection */
        {
            uint8_t wire_ciphers2[] = {
                TLS_RSA_WITH_3DES_EDE_CBC_SHA,
                TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
                TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* tls 1.2 */
                TLS_CHACHA20_POLY1305_SHA256,          /* tls 1.3 */
            };

            const uint8_t count = sizeof(wire_ciphers2) / S2N_TLS_CIPHER_SUITE_LEN;
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all"));
            conn->client_protocol_version = S2N_TLS13;
            conn->actual_protocol_version = S2N_TLS13;
            conn->server_protocol_version = S2N_TLS13;

            if (s2n_chacha20_poly1305.is_available()) {
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers2, count));
                EXPECT_EQUAL(conn->secure->cipher_suite, &s2n_tls13_chacha20_poly1305_sha256);
            } else {
                EXPECT_FAILURE(s2n_set_cipher_as_tls_server(conn, wire_ciphers2, count));
            }
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* Test cipher suite with a required version higher than what connection supports should not be selected */
        {
            uint8_t test_wire_ciphers[] = {
                TLS_AES_128_GCM_SHA256,                /* tls 1.3 */
                TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* tls 1.2 */
            };

            const uint8_t count = sizeof(test_wire_ciphers) / S2N_TLS_CIPHER_SUITE_LEN;
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all"));
            conn->actual_protocol_version = S2N_TLS12;
            conn->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];

            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, test_wire_ciphers, count));
            EXPECT_EQUAL(conn->secure->cipher_suite, &s2n_ecdhe_rsa_with_aes_128_gcm_sha256);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
        };

        /* We should skip cipher suites with a minimum protocol version unsupported by the connection.
         * If no valid cipher suite is found, we should fall back to a cipher suite with a higher protocol version,
         * but we should NEVER use a TLS1.3 suite on a pre-TLS1.3 connection or vice versa. */
        {
            /* Skip but fall back to cipher suite with protocol version higher than connection */
            {
                EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all"));
                conn->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];

                uint8_t test_wire_ciphers[] = {
                    TLS_AES_128_GCM_SHA256,                /* tls 1.3 */
                    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* tls 1.2 */
                    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,    /* ssl v3 */
                };

                conn->actual_protocol_version = S2N_TLS10;

                /* If a match exists, skip the invalid cipher and choose it */
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, test_wire_ciphers, 3));
                EXPECT_EQUAL(conn->secure->cipher_suite, &s2n_ecdhe_rsa_with_aes_128_cbc_sha);

                /* If a match does not exist, choose the invalid cipher */
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, test_wire_ciphers, 2));
                EXPECT_EQUAL(conn->secure->cipher_suite, &s2n_ecdhe_rsa_with_aes_128_gcm_sha256);

                EXPECT_SUCCESS(s2n_connection_wipe(conn));
            };

            /* Skip and do NOT fall back to a TLS1.3 cipher suite if using TLS1.2 */
            {
                EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all"));
                conn->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];

                uint8_t test_wire_ciphers[] = {
                    TLS_AES_128_GCM_SHA256,                /* tls 1.3 */
                    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* tls 1.2 */
                };

                conn->actual_protocol_version = S2N_TLS12;

                /* If a match exists, skip the invalid cipher and choose it */
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, test_wire_ciphers, 2));
                EXPECT_EQUAL(conn->secure->cipher_suite, &s2n_ecdhe_rsa_with_aes_128_gcm_sha256);

                /* If a match does not exist, fail to negotiate a cipher suite.
                 * We cannot fall back to the TLS1.3 choice. */
                EXPECT_FAILURE_WITH_ERRNO(s2n_set_cipher_as_tls_server(conn, test_wire_ciphers, 1),
                        S2N_ERR_CIPHER_NOT_SUPPORTED);

                EXPECT_SUCCESS(s2n_connection_wipe(conn));
            }

            /* Skip and do NOT fall back to a TLS1.2 cipher suite if using TLS1.3 */
            {
                EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "test_all"));
                conn->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];

                uint8_t test_wire_ciphers[] = {
                    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* tls 1.2 */
                    TLS_AES_128_GCM_SHA256,                /* tls 1.3 */
                };

                conn->actual_protocol_version = S2N_TLS13;

                /* If a match exists, skip the invalid cipher and choose it */
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, test_wire_ciphers, 2));
                EXPECT_EQUAL(conn->secure->cipher_suite, &s2n_tls13_aes_128_gcm_sha256);

                /* If a match does not exist, fail to negotiate a cipher suite.
                 * We cannot fall back to the TLS1.2 choice. */
                EXPECT_FAILURE_WITH_ERRNO(s2n_set_cipher_as_tls_server(conn, test_wire_ciphers, 1),
                        S2N_ERR_CIPHER_NOT_SUPPORTED);

                EXPECT_SUCCESS(s2n_connection_wipe(conn));
            }
        };

        /* If a PSK is being used, then the cipher suite must match the PSK's HMAC algorithm.
         *
         *= https://www.rfc-editor.org/rfc/rfc8446#section-4.2.11
         *= type=test
         *# The server MUST ensure that it selects a compatible PSK
         *# (if any) and cipher suite.
         **/
        {
            /* If chosen PSK is set, a cipher suite with matching HMAC algorithm must be selected */
            {
                s2n_connection_set_cipher_preferences(conn, "test_all");
                conn->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
                conn->actual_protocol_version = S2N_TLS13;

                EXPECT_OK(s2n_conn_set_chosen_psk(conn));

                conn->psk_params.chosen_psk->hmac_alg = S2N_HMAC_SHA256;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_tls13, cipher_count_tls13));
                EXPECT_EQUAL(conn->secure->cipher_suite->prf_alg, conn->psk_params.chosen_psk->hmac_alg);

                conn->psk_params.chosen_psk->hmac_alg = S2N_HMAC_SHA384;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_tls13, cipher_count_tls13));
                EXPECT_EQUAL(conn->secure->cipher_suite->prf_alg, conn->psk_params.chosen_psk->hmac_alg);

                EXPECT_SUCCESS(s2n_connection_wipe(conn));
            };

            /* If chosen PSK is set but there is no matching cipher, the server MUST fail to set a cipher */
            {
                s2n_connection_set_cipher_preferences(conn, "test_all");
                conn->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
                conn->actual_protocol_version = S2N_TLS13;

                /* S2N_HMAC_SHA1 is not a matching HMAC algorithm for any TLS1.3 cipher */
                EXPECT_OK(s2n_conn_set_chosen_psk(conn));
                conn->psk_params.chosen_psk->hmac_alg = S2N_HMAC_SHA1;

                EXPECT_FAILURE_WITH_ERRNO(s2n_set_cipher_as_tls_server(conn, wire_ciphers_with_tls13, cipher_count_tls13),
                        S2N_ERR_CIPHER_NOT_SUPPORTED);

                EXPECT_SUCCESS(s2n_connection_wipe(conn));
            };
        };

        /* Client sends cipher which is not in the configured suite */
        {
            EXPECT_SUCCESS(s2n_enable_tls13_in_test());
            uint8_t invalid_cipher_pref[] = {
                TLS_ECDHE_KYBER_RSA_WITH_AES_256_GCM_SHA384
            };

            const uint8_t invalid_cipher_count = sizeof(invalid_cipher_pref) / S2N_TLS_CIPHER_SUITE_LEN;
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(conn, "default_tls13"));
            conn->client_protocol_version = S2N_TLS13;
            conn->actual_protocol_version = S2N_TLS13;
            EXPECT_FAILURE_WITH_ERRNO(s2n_set_cipher_as_tls_server(conn, invalid_cipher_pref, invalid_cipher_count), S2N_ERR_CIPHER_NOT_SUPPORTED);
            EXPECT_SUCCESS(s2n_connection_wipe(conn));
            EXPECT_SUCCESS(s2n_disable_tls13_in_test());
        };

        /* Client sends cipher that requires DH params */
        {
            DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(),
                    s2n_config_ptr_free);
            EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, "test_all"));
            EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, rsa_cert));

            DEFER_CLEANUP(struct s2n_connection *server = s2n_connection_new(S2N_SERVER),
                    s2n_connection_ptr_free);
            EXPECT_NOT_NULL(server);
            EXPECT_SUCCESS(s2n_connection_set_config(server, config));

            /* The client only offers one cipher suite, which requires dh kex */
            uint8_t wire[] = { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 };

            /* By default, the server does not accept cipher suites with dh kex. */
            EXPECT_FAILURE_WITH_ERRNO(s2n_set_cipher_as_tls_server(server, wire, 1),
                    S2N_ERR_CIPHER_NOT_SUPPORTED);

            /* With dh params configured, the server accepts cipher suites with dh kex. */
            EXPECT_SUCCESS(s2n_config_add_dhparams(config, dhparams_pem));
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(server, wire, 1));
            EXPECT_EQUAL(server->secure->cipher_suite, &s2n_dhe_rsa_with_aes_128_gcm_sha256);
        };

        EXPECT_SUCCESS(s2n_config_free(server_config));
        EXPECT_SUCCESS(s2n_cert_chain_and_key_free(rsa_cert));
        EXPECT_SUCCESS(s2n_cert_chain_and_key_free(ecdsa_cert));
        free(ecdsa_cert_chain_pem);
        free(ecdsa_private_key_pem);
        free(rsa_cert_chain_pem);
        free(rsa_private_key_pem);
        EXPECT_SUCCESS(s2n_connection_free(conn));
    };

    /* Test chacha20 boosting behaviour */
    {
        /* Setup cipher preferences + security policy */
        struct s2n_cipher_preferences cipher_preferences = { 0 };
        struct s2n_security_policy security_policy = {
            .minimum_protocol_version = S2N_SSLv2,
            .cipher_preferences = &cipher_preferences,
            .kem_preferences = &kem_preferences_null,
            .signature_preferences = &s2n_signature_preferences_20201021,
            .ecc_preferences = &s2n_ecc_preferences_test_all,
        };

        /* Initialise config and relevant certs */
        DEFER_CLEANUP(struct s2n_config *server_config = s2n_config_new(), s2n_config_ptr_free);
        struct s2n_cert_chain_and_key *rsa_cert = NULL;
        struct s2n_cert_chain_and_key *ecdsa_cert = NULL;
        EXPECT_SUCCESS(s2n_test_cert_chain_and_key_new(&rsa_cert,
                S2N_DEFAULT_TEST_CERT_CHAIN, S2N_DEFAULT_TEST_PRIVATE_KEY));
        EXPECT_SUCCESS(s2n_test_cert_chain_and_key_new(&ecdsa_cert,
                S2N_DEFAULT_ECDSA_TEST_CERT_CHAIN, S2N_DEFAULT_ECDSA_TEST_PRIVATE_KEY));

        EXPECT_NOT_NULL(rsa_cert);
        EXPECT_NOT_NULL(ecdsa_cert);
        EXPECT_NOT_NULL(server_config);
        EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, rsa_cert));
        EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, ecdsa_cert));
        EXPECT_SUCCESS(s2n_config_set_cipher_preferences(server_config, "test_all"));

        if (s2n_chacha20_poly1305.is_available()) {
            /* Test chacha20 boosting when ciphersuites fail auth validation */
            {
                DEFER_CLEANUP(struct s2n_connection *connection = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
                EXPECT_NOT_NULL(connection);
                connection->security_policy_override = &security_policy;
                connection->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
                EXPECT_SUCCESS(s2n_connection_set_all_protocol_versions(connection, S2N_TLS12));
                DEFER_CLEANUP(struct s2n_config *rsa_only_config = s2n_config_new(), s2n_config_ptr_free);
                EXPECT_NOT_NULL(rsa_only_config);
                EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(rsa_only_config, rsa_cert));
                /* Connection only supports rsa auth. */
                EXPECT_SUCCESS(s2n_connection_set_config(connection, rsa_only_config));

                static struct s2n_cipher_suite *test_cipher_suite_list[] = {
                    /* Not negotiated because invalid (ecdsa) */
                    &s2n_ecdhe_ecdsa_with_chacha20_poly1305_sha256,
                    /* Only negotiated if chacha20 boosting is disabled */
                    &s2n_ecdhe_rsa_with_aes_256_gcm_sha384,
                    /* First valid chacha20 cipher suite and is negotiated */
                    &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256,
                };

                cipher_preferences = (struct s2n_cipher_preferences){
                    .count = s2n_array_len(test_cipher_suite_list),
                    .suites = test_cipher_suite_list,
                    .allow_chacha20_boosting = true,
                };

                uint8_t wire[] = {
                    /* Client signalled chacha20 boosting; valid chacha20 ciphersuite and is negotiated */
                    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
                    /* Not negotiated because invalid (ecdsa) */
                    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
                    /* Negotiated if chacha20 boosting is off */
                    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
                };
                uint8_t count = sizeof(wire) / S2N_TLS_CIPHER_SUITE_LEN;

                /* Verify chacha20 RSA ciphersuite chosen with chacha20 boosting enabled */
                cipher_preferences.allow_chacha20_boosting = true;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256);

                /* Sanity check: non-chacha20 RSA ciphersuite chosen without chacha20 boosting enabled */
                /* cppcheck-suppress redundantAssignment */
                cipher_preferences.allow_chacha20_boosting = false;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_rsa_with_aes_256_gcm_sha384);
            };

            /* Server is able to negotiate its most preferred chacha20 ciphersuite */
            {
                DEFER_CLEANUP(struct s2n_connection *connection = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
                EXPECT_NOT_NULL(connection);
                connection->security_policy_override = &security_policy;
                connection->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
                EXPECT_SUCCESS(s2n_connection_set_all_protocol_versions(connection, S2N_TLS12));
                EXPECT_SUCCESS(s2n_connection_set_config(connection, server_config));

                static struct s2n_cipher_suite *test_cipher_suite_list[] = {
                    /* Skipped because it is not a chacha20 ciphersuite. Is negotiated if chacha20 boosting is disabled.  */
                    &s2n_ecdhe_rsa_with_aes_256_cbc_sha384,
                    /* First chacha20 ciphersuite and is negotiated */
                    &s2n_ecdhe_ecdsa_with_chacha20_poly1305_sha256,
                    /* Second chacha20 ciphersuite and is not negotiated (not server's most preferred chacha20 ciphersuite) */
                    &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256,
                };

                cipher_preferences = (struct s2n_cipher_preferences){
                    .count = s2n_array_len(test_cipher_suite_list),
                    .suites = test_cipher_suite_list,
                    .allow_chacha20_boosting = true
                };

                uint8_t wire[] = {
                    /* Client signalled chacha20 boosting: not negotiated because it's not server's most preferred chacha20 ciphersuite */
                    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
                    /* Negotiated if chacha20 boosting is on */
                    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
                    /* Negotiated if chacha20 boosting is off */
                    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
                };
                uint8_t count = sizeof(wire) / S2N_TLS_CIPHER_SUITE_LEN;

                /* Verify most preferred chacha20 ciphersuite is chosen with chacha20 boosting enabled */
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_ecdsa_with_chacha20_poly1305_sha256);

                /* Sanity check: server's most preferred cipehrsuite is chosen when chacha20 boosting is off */
                cipher_preferences.allow_chacha20_boosting = false;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_rsa_with_aes_256_cbc_sha384);
            };

            /* Server's most preferred chacha20 is not offered by the client */
            {
                DEFER_CLEANUP(struct s2n_connection *connection = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
                EXPECT_NOT_NULL(connection);
                connection->security_policy_override = &security_policy;
                connection->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
                EXPECT_SUCCESS(s2n_connection_set_all_protocol_versions(connection, S2N_TLS12));
                EXPECT_SUCCESS(s2n_connection_set_config(connection, server_config));

                static struct s2n_cipher_suite *test_cipher_suite_list[] = {
                    /* Server's most preferred chacha20 ciphersuite; not offered by the client */
                    &s2n_ecdhe_ecdsa_with_chacha20_poly1305_sha256,
                    /* Negotiated if chacha20 boosting is off */
                    &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256,
                    /* First valid chacha20 ciphersuite; negotiated if chacha20 boosting is on */
                    &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256,
                };

                uint8_t wire[] = {
                    /* Client signalled chacha20 boosting; negotiated if chacha20 boosting is on */
                    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
                    /* Negotiated if chacha20 boosting is off */
                    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                };
                uint8_t count = sizeof(wire) / S2N_TLS_CIPHER_SUITE_LEN;

                cipher_preferences = (struct s2n_cipher_preferences){
                    .count = s2n_array_len(test_cipher_suite_list),
                    .suites = test_cipher_suite_list,
                    .allow_chacha20_boosting = true,
                };

                /* Verify server selects its second most preferred chacha20 ciphersuite */
                cipher_preferences.allow_chacha20_boosting = true;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256);

                /* Sanity check: server's most preferred ciphersuite is chosen without chacha20 boosting enabled */
                /* cppcheck-suppress redundantAssignment */
                cipher_preferences.allow_chacha20_boosting = false;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256);
            };

            /* Server does not negotiate the client's most preferred chacha20 ciphersuite */
            {
                DEFER_CLEANUP(struct s2n_connection *connection = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
                EXPECT_NOT_NULL(connection);
                connection->security_policy_override = &security_policy;
                connection->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
                EXPECT_SUCCESS(s2n_connection_set_all_protocol_versions(connection, S2N_TLS12));
                EXPECT_SUCCESS(s2n_connection_set_config(connection, server_config));

                static struct s2n_cipher_suite *test_cipher_suite_list[] = {
                    /* Skipped because not a chacha20 ciphersuite. If chacha20 boosting is off then this is negotiated.*/
                    &s2n_ecdhe_rsa_with_aes_256_cbc_sha384,
                    /* First chacha20 ciphersuite and is negotiated (client's second preferred ciphersuite) */
                    &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256,
                    /* Second chacha20 ciphersuite and is the client's most preferred ciphersuite. Not negotiated. */
                    &s2n_dhe_rsa_with_chacha20_poly1305_sha256,
                };

                cipher_preferences = (struct s2n_cipher_preferences){
                    .count = s2n_array_len(test_cipher_suite_list),
                    .suites = test_cipher_suite_list,
                    .allow_chacha20_boosting = true,
                };

                uint8_t wire[] = {
                    /* Client signalled chacha20 boosting. This is not negotiated as it's not the server's most preferred chacha20 ciphersuite */
                    TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
                    /* Negotiated if chacha20 boosting is on */
                    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
                    /* Negotiated if chacha20 boosting is off */
                    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
                };
                uint8_t count = sizeof(wire) / S2N_TLS_CIPHER_SUITE_LEN;

                /* Verify client's second preferred (ecdhe_rsa_chacha20) is negotiated when chacha20 boosting enabled */
                cipher_preferences.allow_chacha20_boosting = true;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256);

                /* Sanity check: server's most preferred ciphersuite is chosen without chacha20 boosting enabled */
                /* cppcheck-suppress redundantAssignment */
                cipher_preferences.allow_chacha20_boosting = false;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_rsa_with_aes_256_cbc_sha384);
            };

            /* Chacha20 boosting is disabled when client did not indicate chacha20 preference */
            {
                DEFER_CLEANUP(struct s2n_connection *connection = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
                EXPECT_NOT_NULL(connection);

                connection->security_policy_override = &security_policy;
                connection->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
                EXPECT_SUCCESS(s2n_connection_set_all_protocol_versions(connection, S2N_TLS12));

                EXPECT_SUCCESS(s2n_connection_set_config(connection, server_config));

                static struct s2n_cipher_suite *test_cipher_suite_list[] = {
                    /* Negotiated because client did not signal chacha20 boosting and it is present in client wire */
                    &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256,
                    /* Never considered; if client did signal chacha20 boosting we expect this to be negotiated */
                    &s2n_ecdhe_ecdsa_with_chacha20_poly1305_sha256,
                };

                cipher_preferences = (struct s2n_cipher_preferences){
                    .count = s2n_array_len(test_cipher_suite_list),
                    .suites = test_cipher_suite_list,
                    .allow_chacha20_boosting = true,
                };

                uint8_t wire[] = {
                    /* Chacha20 boosting is off. This ciphersuite is negotiated. */
                    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
                    /* Not negotiated */
                    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
                };
                uint8_t count = sizeof(wire) / S2N_TLS_CIPHER_SUITE_LEN;

                /* Verify that client negotiates non-chacha20 ciphersuite when chacha20 boosting is not signalled by client */
                cipher_preferences.allow_chacha20_boosting = true;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256);
            };

            /* Server negotiates its most preferred chacha20 ciphersuite for tls 1.3 */
            {
                DEFER_CLEANUP(struct s2n_connection *connection = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
                EXPECT_NOT_NULL(connection);

                connection->security_policy_override = &security_policy;
                connection->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
                EXPECT_SUCCESS(s2n_connection_set_all_protocol_versions(connection, S2N_TLS13));

                static struct s2n_cipher_suite *test_cipher_suite_list[] = {
                    /* Most preferred ciphersuite. If chacha20 boosting behaviour is on then this can't be negotiated. */
                    &s2n_tls13_aes_128_gcm_sha256,
                    /* Second preferred ciphersuite. If chacha20 boosting behaviour is on then this can't be negotiated. */
                    &s2n_tls13_aes_256_gcm_sha384,
                    /* Negotiated if chacha20 boosting behaviour is on. Otherwise, one of the two ciphersuites above is choosen. */
                    &s2n_tls13_chacha20_poly1305_sha256,
                };

                cipher_preferences = (struct s2n_cipher_preferences){
                    .count = s2n_array_len(test_cipher_suite_list),
                    .suites = test_cipher_suite_list,
                    .allow_chacha20_boosting = true,
                };

                uint8_t test_wire_1[] = {
                    /* Client signalled chacha20 boosting. Negotiated. */
                    TLS_CHACHA20_POLY1305_SHA256,
                    /* Not negotiated even when chacha20 boosting is off. Server prefers aes 128 gcm. */
                    TLS_AES_256_GCM_SHA384,
                    /* Negotiated if chacha20 boosting is off. This is the server's most preferred ciphersuite. */
                    TLS_AES_128_GCM_SHA256,
                };
                uint8_t count = sizeof(test_wire_1) / S2N_TLS_CIPHER_SUITE_LEN;

                cipher_preferences.allow_chacha20_boosting = true;
                /* Verify that client negotiates chacha20 when chacha20 boosting is on */
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, test_wire_1, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_tls13_chacha20_poly1305_sha256);

                /* Sanity check: server's most preferred ciphersuite is chosen without chacha20 boosting enabled */
                /* cppcheck-suppress redundantAssignment */
                cipher_preferences.allow_chacha20_boosting = false;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, test_wire_1, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_tls13_aes_128_gcm_sha256);

                /*
                 * Client did not signal chacha20 boosting.
                 * TLS_AES_256_GCM_SHA384 > TLS_CHACHA20_POLY1305_SHA256 
                 */
                uint8_t test_wire_2[] = {
                    /* Client did not signal chacha20 boosting. Negotiated if chacha20 boosting is off. */
                    TLS_AES_256_GCM_SHA384,
                    /* Not negotiated since the server prefers aes 256 gcm over chacha20 */
                    TLS_CHACHA20_POLY1305_SHA256,
                };
                count = sizeof(test_wire_2) / S2N_TLS_CIPHER_SUITE_LEN;

                /* Verify that client negotiates server preferred non-chacha20 aes_256 when client did not signal */
                /* cppcheck-suppress redundantAssignment */
                cipher_preferences.allow_chacha20_boosting = true;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, test_wire_2, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_tls13_aes_256_gcm_sha384);
            };

            /* Server can negotiate chacha20 ciphersuite, even when boosting is disabled */
            {
                DEFER_CLEANUP(struct s2n_connection *connection = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
                EXPECT_NOT_NULL(connection);

                connection->security_policy_override = &security_policy;
                connection->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
                EXPECT_SUCCESS(s2n_connection_set_all_protocol_versions(connection, S2N_TLS13));

                static struct s2n_cipher_suite *test_cipher_suite_list[] = {
                    /* Negotiated (only available option) */
                    &s2n_tls13_chacha20_poly1305_sha256,
                };

                cipher_preferences = (struct s2n_cipher_preferences){
                    .count = s2n_array_len(test_cipher_suite_list),
                    .suites = test_cipher_suite_list,
                    .allow_chacha20_boosting = false,
                };

                uint8_t wire[] = {
                    /* Client signalled chacha20 boosting. Negotiated as this is the only negotiable option. */
                    TLS_CHACHA20_POLY1305_SHA256,
                };
                uint8_t count = sizeof(wire) / S2N_TLS_CIPHER_SUITE_LEN;

                /* Verify server can still negotiate chacha20 if it's the only option even when chacha20 boosting is off */
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_tls13_chacha20_poly1305_sha256);
            };

            /*
             * sslv2 server correctly negotiates ciphersuite when chacha20 boosting is enabled.
             */
            {
                DEFER_CLEANUP(struct s2n_connection *connection = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
                EXPECT_NOT_NULL(connection);

                connection->security_policy_override = &security_policy;
                connection->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
                EXPECT_SUCCESS(s2n_connection_set_all_protocol_versions(connection, S2N_SSLv2));
                EXPECT_SUCCESS(s2n_connection_set_config(connection, server_config));

                static struct s2n_cipher_suite *test_cipher_suite_list[] = {
                    /* First 'valid' ciphersuite that is saved as a higher_vers_match and is negotiated */
                    &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha,
                    /* Not valid for connection (does not meet minimum version requirement and higher_vers_match already found) */
                    &s2n_dhe_rsa_with_chacha20_poly1305_sha256,
                    /* Not valid for connection (does not meet minimum version requirement and higher_vers_match already found) */
                    &s2n_dhe_rsa_with_aes_256_gcm_sha384
                };

                /* cppcheck-suppress redundantAssignment */
                cipher_preferences = (struct s2n_cipher_preferences){
                    .count = s2n_array_len(test_cipher_suite_list),
                    .suites = test_cipher_suite_list,
                    .allow_chacha20_boosting = true,
                };

                uint8_t wire[] = {
                    /* Client signalled chacha20 boosting. Not negotiated as it's not offered by the server. */
                    0x00,
                    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
                    /* Not saved as a higher_vers_match as ecdhe_ecdsa_aes_128 was already saved as one; not negotiated */
                    0x00,
                    TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
                    /* Saved by server as higher_vers_match; negotiated as a 'fall-back' ciphersuite */
                    0x00,
                    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
                };
                uint8_t count = sizeof(wire) / S2N_SSLv2_CIPHER_SUITE_LEN;

                /* Verify server negotiate its higher_vers_match ecdhe_ecdsa_aes_128_cbc instead of a chacha20 ciphersuite */
                cipher_preferences.allow_chacha20_boosting = true;
                /*
                 * For an sslv2 connection, all of the ciphersuites in test_cipher_suite_list will not meet the minimum
                 * required tls version validation (they all require at least sslv3). This means that the server will save this
                 * cipher as a higher_vers_match and will use this ciphersuite as a fallback if no other ciphersuite can be identified.
                 * When this logic happens, we bypass chacha20 boosting altogether; therefore because the first ciphersuite
                 * ecdhe_ecdsa_with_aes_128_cbc is offered by both the client and server and only fails the minimum required version check,
                 * then we save this ciphersuite as a higher_vers_match and continue.
                 */
                EXPECT_SUCCESS(s2n_set_cipher_as_sslv2_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha);
            };

            /* Server is able to negotiate a ciphersuite even without chacha20 in its cipher pref */
            {
                DEFER_CLEANUP(struct s2n_connection *connection = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
                EXPECT_NOT_NULL(connection);
                EXPECT_SUCCESS(s2n_enable_tls13_in_test());

                connection->security_policy_override = &security_policy;
                connection->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
                EXPECT_SUCCESS(s2n_connection_set_all_protocol_versions(connection, S2N_TLS13));

                static struct s2n_cipher_suite *test_cipher_suite_list[] = {
                    /* Negotiated because it is the server's most preferred */
                    &s2n_tls13_aes_128_gcm_sha256,
                    /* Not considered */
                    &s2n_tls13_aes_256_gcm_sha384,
                };

                cipher_preferences = (struct s2n_cipher_preferences){
                    .count = s2n_array_len(test_cipher_suite_list),
                    .suites = test_cipher_suite_list,
                    .allow_chacha20_boosting = true,
                };

                uint8_t wire[] = {
                    /* Client signalled chacha20 boosting; not negotiated as server does not have any chacha20 ciphersuites */
                    TLS_CHACHA20_POLY1305_SHA256,
                    /* Not negotiated as the server prefers aes 128 over aes 256 */
                    TLS_AES_256_GCM_SHA384,
                    /* Negotiated */
                    TLS_AES_128_GCM_SHA256,
                };
                uint8_t count = sizeof(wire) / S2N_TLS_CIPHER_SUITE_LEN;

                /* Verify that server is able to negotiate aes_128 even without any chacha20 ciphersuites in its preferences */
                cipher_preferences.allow_chacha20_boosting = false;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_tls13_aes_128_gcm_sha256);
                EXPECT_SUCCESS(s2n_disable_tls13_in_test());
            };

            /* Test chacha20 boosting when the most preferred ciphersuite fails version validation */
            {
                DEFER_CLEANUP(struct s2n_connection *connection = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
                EXPECT_NOT_NULL(connection);

                connection->security_policy_override = &security_policy;
                connection->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
                EXPECT_SUCCESS(s2n_connection_set_all_protocol_versions(connection, S2N_TLS12));

                EXPECT_SUCCESS(s2n_connection_set_config(connection, server_config));

                static struct s2n_cipher_suite *test_cipher_suite_list[] = {
                    /* Only negotiated if chacha20 boosting is off */
                    &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256,
                    /* Invalid; never use tls 1.3 ciphers on pre-tls 1.3 connections */
                    &s2n_tls13_chacha20_poly1305_sha256,
                    /* Negotiated (if chacha20 boosting is on) */
                    &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256,
                };

                cipher_preferences = (struct s2n_cipher_preferences){
                    .count = s2n_array_len(test_cipher_suite_list),
                    .suites = test_cipher_suite_list,
                    .allow_chacha20_boosting = true,
                };

                uint8_t wire[] = {
                    /* Client signalled chacha20 boosting. Not negotiated by server since it is invalid for the connection. */
                    TLS_CHACHA20_POLY1305_SHA256,
                    /* Negotiated if chacha20 boosting is off */
                    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
                    /* Negotiated if chacha20 boosting is on */
                    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
                };
                uint8_t count = sizeof(wire) / S2N_TLS_CIPHER_SUITE_LEN;

                /* Verify server negotiates second preferred chacha20 ciphersuite ecdhe_rsa_chacha20 */
                cipher_preferences.allow_chacha20_boosting = true;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256);

                /* Sanity check: server's most preferred ciphersuite is chosen without chacha20 boosting enabled */
                /* cppcheck-suppress redundantAssignment */
                cipher_preferences.allow_chacha20_boosting = false;
                EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
                EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256);
            };
        }

        if (!s2n_chacha20_poly1305.is_available()) {
            /* Chacha20 can't be negotiated when it's not available in libcrypto */
            DEFER_CLEANUP(struct s2n_connection *connection = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
            EXPECT_NOT_NULL(connection);
            connection->security_policy_override = &security_policy;
            connection->kex_params.server_ecc_evp_params.negotiated_curve = s2n_all_supported_curves_list[0];
            EXPECT_SUCCESS(s2n_connection_set_all_protocol_versions(connection, S2N_TLS12));
            EXPECT_SUCCESS(s2n_connection_set_config(connection, server_config));

            static struct s2n_cipher_suite *test_cipher_suite_list[] = {
                /* Invalid (no libcrypto) */
                &s2n_dhe_rsa_with_chacha20_poly1305_sha256,
                /* Negotiated (only valid option) */
                &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256,
                /* Not considered + invalid (no libcrypto) */
                &s2n_ecdhe_rsa_with_chacha20_poly1305_sha256,
            };

            cipher_preferences = (struct s2n_cipher_preferences){
                .count = s2n_array_len(test_cipher_suite_list),
                .suites = test_cipher_suite_list,
                .allow_chacha20_boosting = true,
            };

            uint8_t wire[] = {
                /* Client signalled chacha20 boosting. Not negotiated because of missing libcrypto for chacha20 */
                TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
                /* Not negotiated because of missing libcrypto for chacha20 */
                TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
                /* Negotiated whether chacha20 boosting is enabled or not by server */
                TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
            };
            uint8_t count = sizeof(wire) / S2N_TLS_CIPHER_SUITE_LEN;

            /* Verify that server negotiated non-chacha20 ciphersuite ecdhe_ecdsa_aes_128 */
            cipher_preferences.allow_chacha20_boosting = true;
            EXPECT_SUCCESS(s2n_set_cipher_as_tls_server(connection, wire, count));
            EXPECT_EQUAL(connection->secure->cipher_suite, &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256);
        }

        EXPECT_SUCCESS(s2n_cert_chain_and_key_free(rsa_cert));
        EXPECT_SUCCESS(s2n_cert_chain_and_key_free(ecdsa_cert));
    };

    END_TEST();
}
