/*
 * 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 "s2n_test.h"
#include "testlib/s2n_testlib.h"
#include "tls/s2n_tls.h"
/* To test static functions */
#include "tls/s2n_server_new_session_ticket.c"

#define TEST_TICKET_AGE_ADD 0x01, 0x02, 0x03, 0x04
#define TEST_LIFETIME       0x00, 0x01, 0x01, 0x01
#define TEST_TICKET         0x01, 0xFF, 0x23

#define ONE_HOUR_IN_NANOS 3600000000000

#define TICKET_AGE_ADD_MARKER sizeof(uint8_t) + /* message id  */ \
        SIZEOF_UINT24 +                         /* message len */ \
        sizeof(uint32_t)                        /* ticket lifetime */
#define RECORD_LEN_MARKER sizeof(uint8_t) +     /* message type */ \
        sizeof(uint16_t)                        /* protocol version */

#define MAX_TEST_SESSION_SIZE 300

#define EXPECT_TICKETS_SENT(conn, count) EXPECT_OK(s2n_assert_tickets_sent(conn, count))
static S2N_RESULT s2n_assert_tickets_sent(struct s2n_connection *conn, uint16_t expected_tickets_sent)
{
    uint16_t tickets_sent = 0;
    RESULT_GUARD_POSIX(s2n_connection_get_tickets_sent(conn, &tickets_sent));
    RESULT_ENSURE_EQ(tickets_sent, expected_tickets_sent);
    return S2N_RESULT_OK;
}

size_t cb_session_data_len = 0;
uint8_t cb_session_data[MAX_TEST_SESSION_SIZE] = { 0 };
uint32_t cb_session_lifetime = 0;
static int s2n_test_session_ticket_cb(struct s2n_connection *conn, void *ctx, struct s2n_session_ticket *ticket)
{
    POSIX_ENSURE_REF(conn);
    POSIX_ENSURE_REF(ticket);

    EXPECT_SUCCESS(s2n_session_ticket_get_data_len(ticket, &cb_session_data_len));
    EXPECT_SUCCESS(s2n_session_ticket_get_data(ticket, cb_session_data_len, cb_session_data));
    EXPECT_SUCCESS(s2n_session_ticket_get_lifetime(ticket, &cb_session_lifetime));

    return S2N_SUCCESS;
}

static int s2n_setup_test_resumption_secret(struct s2n_connection *conn)
{
    POSIX_ENSURE_REF(conn);
    /**
     *= https://www.rfc-editor.org/rfc/rfc8448#section-3
     *# PRK (32 octets):  7d f2 35 f2 03 1d 2a 05 12 87 d0 2b 02 41 b0 bf
     *# da f8 6c c8 56 23 1f 2d 5a ba 46 c4 34 ec 19 6c
     **/
    S2N_BLOB_FROM_HEX(test_resumption_secret,
            "7d f2 35 f2 03 1d 2a 05 12 87 d0 2b 02 41 b0 bf \
             da f8 6c c8 56 23 1f 2d 5a ba 46 c4 34 ec 19 6c");

    /* Set up resumption secret */
    struct s2n_blob secret = { 0 };
    struct s2n_stuffer secret_stuffer = { 0 };
    EXPECT_SUCCESS(s2n_blob_init(&secret, conn->secrets.version.tls13.resumption_master_secret, S2N_TLS_SECRET_LEN));
    EXPECT_SUCCESS(s2n_stuffer_init(&secret_stuffer, &secret));
    EXPECT_SUCCESS(s2n_stuffer_write_bytes(&secret_stuffer, test_resumption_secret.data, test_resumption_secret.size));

    return S2N_SUCCESS;
}

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

    /* s2n_tls13_server_nst_write */
    {
        /* Check session ticket message is correctly written. */
        {
            struct s2n_config *config = NULL;
            struct s2n_connection *conn = NULL;
            EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER));
            EXPECT_NOT_NULL(config = s2n_config_new());

            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

            conn->actual_protocol_version = S2N_TLS13;
            conn->secure->cipher_suite = &s2n_tls13_aes_256_gcm_sha384;
            uint16_t test_tickets_sent = 10;
            conn->tickets_sent = test_tickets_sent;

            /* Set up output stuffer */
            struct s2n_stuffer output = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&output, 0));

            EXPECT_OK(s2n_tls13_server_nst_write(conn, &output));

            uint8_t message_type = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint8(&output, &message_type));
            EXPECT_EQUAL(TLS_SERVER_NEW_SESSION_TICKET, message_type);

            uint32_t message_size = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint24(&output, &message_size));
            EXPECT_EQUAL(message_size, s2n_stuffer_data_available(&output));

            uint32_t ticket_lifetime = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint32(&output, &ticket_lifetime));
            uint32_t key_lifetime_in_secs =
                    (S2N_TICKET_ENCRYPT_DECRYPT_KEY_LIFETIME_IN_NANOS + S2N_TICKET_DECRYPT_KEY_LIFETIME_IN_NANOS) / ONE_SEC_IN_NANOS;
            EXPECT_EQUAL(key_lifetime_in_secs, ticket_lifetime);

            /* Skipping random data */
            EXPECT_SUCCESS(s2n_stuffer_skip_read(&output, sizeof(uint32_t)));

            uint8_t ticket_nonce_len = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint8(&output, &ticket_nonce_len));
            EXPECT_EQUAL(sizeof(uint16_t), ticket_nonce_len);

            uint8_t ticket_nonce[sizeof(uint16_t)] = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_read_bytes(&output, ticket_nonce, ticket_nonce_len));

            uint8_t tickets_sent_array[sizeof(uint16_t)] = { 0 };
            struct s2n_blob blob = { 0 };
            EXPECT_SUCCESS(s2n_blob_init(&blob, tickets_sent_array, sizeof(uint16_t)));
            EXPECT_OK(s2n_generate_ticket_nonce(test_tickets_sent, &blob));
            EXPECT_BYTEARRAY_EQUAL(ticket_nonce, blob.data, ticket_nonce_len);

            uint16_t session_ticket_len = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint16(&output, &session_ticket_len));
            uint8_t size_of_extensions_size = sizeof(uint16_t);
            EXPECT_EQUAL(session_ticket_len, (s2n_stuffer_data_available(&output) - size_of_extensions_size));

            /* Skipping encrypted ticket data */
            EXPECT_SUCCESS(s2n_stuffer_skip_read(&output, session_ticket_len));

            uint16_t extensions_len = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint16(&output, &extensions_len));
            EXPECT_EQUAL(extensions_len, 0);

            EXPECT_EQUAL(s2n_stuffer_data_available(&output), 0);

            EXPECT_TRUE(conn->tickets_sent == test_tickets_sent + 1);

            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_stuffer_free(&output));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* tickets_sent overflow */
        {
            struct s2n_config *config = NULL;
            struct s2n_connection *conn = NULL;
            EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER));
            EXPECT_NOT_NULL(config = s2n_config_new());

            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

            conn->actual_protocol_version = S2N_TLS13;
            conn->secure->cipher_suite = &s2n_tls13_aes_256_gcm_sha384;
            conn->tickets_sent = UINT16_MAX;

            /* Set up output stuffer */
            struct s2n_stuffer output = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&output, 0));

            EXPECT_ERROR_WITH_ERRNO(s2n_tls13_server_nst_write(conn, &output), S2N_ERR_INTEGER_OVERFLOW);

            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_stuffer_free(&output));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /** ticket_age_add values do not repeat after sending multiple new session tickets
         *= https://www.rfc-editor.org/rfc/rfc8446#section-4.6.1
         *= type=test
         *#  The server MUST generate a fresh value
         *#  for each ticket it sends.
         **/
        {
            struct s2n_config *config = NULL;
            struct s2n_connection *conn = NULL;
            EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER));
            EXPECT_NOT_NULL(config = s2n_config_new());

            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

            conn->actual_protocol_version = S2N_TLS13;
            conn->secure->cipher_suite = &s2n_tls13_aes_256_gcm_sha384;

            /* Set up output stuffer */
            struct s2n_stuffer output = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&output, 0));

            EXPECT_OK(s2n_tls13_server_nst_write(conn, &output));

            uint32_t original_ticket_age_add = 0;
            EXPECT_SUCCESS(s2n_stuffer_skip_read(&output, TICKET_AGE_ADD_MARKER));
            EXPECT_SUCCESS(s2n_stuffer_read_uint32(&output, &original_ticket_age_add));

            EXPECT_SUCCESS(s2n_stuffer_wipe(&output));
            EXPECT_OK(s2n_tls13_server_nst_write(conn, &output));

            uint32_t new_ticket_age_add = 0;
            EXPECT_SUCCESS(s2n_stuffer_skip_read(&output, TICKET_AGE_ADD_MARKER));
            EXPECT_SUCCESS(s2n_stuffer_read_uint32(&output, &new_ticket_age_add));

            EXPECT_NOT_EQUAL(original_ticket_age_add, new_ticket_age_add);

            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_stuffer_free(&output));
            EXPECT_SUCCESS(s2n_config_free(config));
        }

        /* Test that the message written by the server includes extensions.
         * Specifically, check for the early_data_indication extension. */
        {
            const uint32_t expected_max_early_data_size = 10;

            /* Calculate extension list offset. Extension list should be last. */
            const uint32_t extension_list_offset = sizeof(uint32_t) /* max_early_data_size */
                    + sizeof(uint16_t)                              /* size of extension */
                    + sizeof(uint16_t);                             /* type of extension */

            struct s2n_config *config = s2n_config_new();
            EXPECT_NOT_NULL(config);
            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));

            struct s2n_connection *conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(conn);
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));
            EXPECT_SUCCESS(s2n_connection_set_server_max_early_data_size(conn, expected_max_early_data_size));
            conn->actual_protocol_version = S2N_TLS13;
            conn->secure->cipher_suite = &s2n_tls13_aes_256_gcm_sha384;

            struct s2n_stuffer output = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&output, 0));

            EXPECT_OK(s2n_tls13_server_nst_write(conn, &output));
            EXPECT_SUCCESS(s2n_stuffer_skip_read(&output,
                    s2n_stuffer_data_available(&output) - extension_list_offset));

            uint16_t extension_type = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint16(&output, &extension_type));
            EXPECT_EQUAL(extension_type, TLS_EXTENSION_EARLY_DATA);

            uint16_t extension_size = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint16(&output, &extension_size));
            EXPECT_EQUAL(extension_size, sizeof(uint32_t));

            uint32_t actual_max_early_data_size = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint32(&output, &actual_max_early_data_size));
            EXPECT_EQUAL(actual_max_early_data_size, expected_max_early_data_size);

            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_stuffer_free(&output));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* Can't write ticket larger than allowed size of a PSK identity */
        {
            struct s2n_config *config = s2n_config_new();
            EXPECT_NOT_NULL(config);
            EXPECT_SUCCESS(s2n_config_set_session_tickets_onoff(config, 1));
            EXPECT_SUCCESS(s2n_config_set_session_ticket_cb(config, s2n_test_session_ticket_cb, NULL));
            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));

            struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(server_conn);
            EXPECT_SUCCESS(s2n_connection_set_config(server_conn, config));
            server_conn->actual_protocol_version = S2N_TLS13;
            server_conn->secure->cipher_suite = &s2n_tls13_aes_256_gcm_sha384;
            EXPECT_SUCCESS(s2n_connection_set_server_max_early_data_size(server_conn, 10));

            /* Set context to be UINT16_MAX */
            uint8_t early_data_context[UINT16_MAX] = { 0 };
            EXPECT_SUCCESS(s2n_connection_set_server_early_data_context(server_conn,
                    early_data_context, sizeof(early_data_context)));

            DEFER_CLEANUP(struct s2n_stuffer stuffer = { 0 }, s2n_stuffer_free);
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));

            EXPECT_ERROR_WITH_ERRNO(s2n_tls13_server_nst_write(server_conn, &stuffer), S2N_ERR_SIZE_MISMATCH);

            EXPECT_SUCCESS(s2n_connection_free(server_conn));
            EXPECT_SUCCESS(s2n_config_free(config));
        };
    };

    /* s2n_generate_ticket_lifetime */
    {
        uint32_t min_lifetime = 0;
        struct s2n_connection *conn = NULL;
        EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER));

        /* Test: encrypt + decrypt key has shortest lifetime */
        conn->config->encrypt_decrypt_key_lifetime_in_nanos = ONE_HOUR_IN_NANOS;
        conn->config->decrypt_key_lifetime_in_nanos = ONE_HOUR_IN_NANOS;
        conn->config->session_state_lifetime_in_nanos = ONE_HOUR_IN_NANOS * 3;

        EXPECT_OK(s2n_generate_ticket_lifetime(conn, &min_lifetime));
        EXPECT_EQUAL(min_lifetime, (ONE_HOUR_IN_NANOS * 2) / ONE_SEC_IN_NANOS);

        /* Test: Session state has shortest lifetime */
        conn->config->encrypt_decrypt_key_lifetime_in_nanos = ONE_HOUR_IN_NANOS;
        conn->config->decrypt_key_lifetime_in_nanos = ONE_HOUR_IN_NANOS;
        conn->config->session_state_lifetime_in_nanos = ONE_HOUR_IN_NANOS;

        EXPECT_OK(s2n_generate_ticket_lifetime(conn, &min_lifetime));
        EXPECT_EQUAL(min_lifetime, ONE_HOUR_IN_NANOS / ONE_SEC_IN_NANOS);

        /** Test: Both session state and decrypt key have longer lifetimes than a week
         *= https://www.rfc-editor.org/rfc/rfc8446#section-4.6.1
         *= type=test
         *# Servers MUST NOT use any value greater than
         *# 604800 seconds (7 days).
         **/
        /* Note: We turn these integer literals into uint64_t values because otherwise
         * they will be interpreted as uint32_t values and an faulty integer overflow error
         * will be thrown. */
        uint64_t one_week_in_sec = ONE_WEEK_IN_SEC;
        uint64_t one_sec_in_nanos = ONE_SEC_IN_NANOS;
        uint64_t one_week_in_nanos = one_week_in_sec * one_sec_in_nanos;
        conn->config->encrypt_decrypt_key_lifetime_in_nanos = one_week_in_nanos;
        conn->config->decrypt_key_lifetime_in_nanos = one_week_in_nanos;
        conn->config->session_state_lifetime_in_nanos = one_week_in_nanos + 1;

        EXPECT_OK(s2n_generate_ticket_lifetime(conn, &min_lifetime));
        EXPECT_EQUAL(min_lifetime, ONE_WEEK_IN_SEC);

        EXPECT_SUCCESS(s2n_connection_free(conn));
    };

    /* s2n_generate_ticket_nonce */
    {
        struct {
            uint16_t value;
            uint8_t expected_output[2];
        } test_cases[] = {
            { .value = 0, .expected_output = { 0, 0 } },
            { .value = 1, .expected_output = { 0, 1 } },
            { .value = 20, .expected_output = { 0, 20 } },
            { .value = UINT8_MAX, .expected_output = { 0, UINT8_MAX } },
            { .value = UINT8_MAX + 1, .expected_output = { 1, 0 } },
            { .value = UINT16_MAX, .expected_output = { UINT8_MAX, UINT8_MAX } },
            { .value = UINT16_MAX - 1, .expected_output = { UINT8_MAX, UINT8_MAX - 1 } },
        };

        for (size_t i = 0; i < s2n_array_len(test_cases); i++) {
            uint8_t data[sizeof(uint16_t)] = { 0 };
            struct s2n_blob blob = { 0 };
            EXPECT_SUCCESS(s2n_blob_init(&blob, data, sizeof(data)));

            EXPECT_OK(s2n_generate_ticket_nonce(test_cases[i].value, &blob));

            EXPECT_EQUAL(test_cases[i].expected_output[0], data[0]);
            EXPECT_EQUAL(test_cases[i].expected_output[1], data[1]);
        }
    };

    /* s2n_generate_ticket_age_add */
    {
        struct {
            uint8_t value[4];
            uint32_t expected_output;
        } test_cases[] = {
            { .value = { 0, 0, 0, 0 }, .expected_output = 0 },
            { .value = { 0, 0, 0, 1 }, .expected_output = 1 },
            { .value = { 0, 0, 0, 20 }, .expected_output = 20 },
            { .value = { 0, 0, 1, 0 }, .expected_output = UINT8_MAX + 1 },
            { .value = { 0, 1, 0, 0 }, .expected_output = UINT16_MAX + 1 },
            { .value = { 0, 0, UINT8_MAX, UINT8_MAX }, .expected_output = UINT16_MAX },
            { .value = { UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX }, .expected_output = UINT32_MAX },
            { .value = { UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX - 1 }, .expected_output = UINT32_MAX - 1 },
        };

        for (size_t i = 0; i < s2n_array_len(test_cases); i++) {
            uint32_t output = 0;
            struct s2n_blob blob = { 0 };
            EXPECT_SUCCESS(s2n_blob_init(&blob, test_cases[i].value, sizeof(test_cases[i].value)));
            EXPECT_OK(s2n_generate_ticket_age_add(&blob, &output));

            EXPECT_EQUAL(output, test_cases[i].expected_output);
        }
    };

    /* s2n_generate_session_secret */
    {
        /**
         *= https://www.rfc-editor.org/rfc/rfc8448#section-3
         *# expanded (32 octets):  4e cd 0e b6 ec 3b 4d 87 f5 d6 02 8f 92 2c
         *# a4 c5 85 1a 27 7f d4 13 11 c9 e6 2d 2c 94 92 e1 c4 f3
         **/
        /* clang-format off */
        S2N_BLOB_FROM_HEX(expected_session_secret,
                       "4e cd 0e b6 ec 3b 4d 87 f5 d6 02 8f 92 2c \
            a4 c5 85 1a 27 7f d4 13 11 c9 e6 2d 2c 94 92 e1 c4 f3");
        /* clang-format on */

        struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT);
        EXPECT_NOT_NULL(conn);

        conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;
        EXPECT_SUCCESS(s2n_setup_test_resumption_secret(conn));

        uint8_t nonce_data[sizeof(uint16_t)] = { 0 };
        struct s2n_blob nonce = { 0 };
        EXPECT_SUCCESS(s2n_blob_init(&nonce, nonce_data, sizeof(nonce_data)));

        struct s2n_blob *output = &conn->tls13_ticket_fields.session_secret;
        EXPECT_SUCCESS(s2n_generate_session_secret(conn, &nonce, output));
        EXPECT_EQUAL(output->size, expected_session_secret.size);
        EXPECT_BYTEARRAY_EQUAL(output->data, expected_session_secret.data, expected_session_secret.size);

        EXPECT_SUCCESS(s2n_connection_free(conn));
    };

    /* s2n_tls13_server_nst_recv */
    {
        uint8_t test_ticket[] = { TEST_TICKET };
        uint8_t nst_data[] = {
            TEST_LIFETIME,       /* ticket lifetime */
            TEST_TICKET_AGE_ADD, /* ticket age add */
            0x02,                /* nonce len */
            0x00, 0x00,          /* nonce */
            0x00, 0x03,          /* ticket len */
            TEST_TICKET,         /* ticket */
            0x00, 0x00,          /* extensions len */
        };

        /* Does not read ticket message if config->use_tickets is not set */
        {
            struct s2n_config *config = s2n_config_new();
            struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT);
            EXPECT_NOT_NULL(conn);
            EXPECT_NOT_NULL(config);

            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

            /* Set up input stuffer */
            DEFER_CLEANUP(struct s2n_stuffer input = { 0 }, s2n_stuffer_free);
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, 0));

            struct s2n_blob nst_message = { 0 };
            EXPECT_SUCCESS(s2n_blob_init(&nst_message, nst_data, sizeof(nst_data)));
            EXPECT_SUCCESS(s2n_stuffer_write(&input, &nst_message));

            EXPECT_OK(s2n_tls13_server_nst_recv(conn, &input));

            EXPECT_EQUAL(conn->client_ticket.size, 0);
            EXPECT_TRUE(s2n_stuffer_data_available(&input) > 0);

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

        /* Not allowed in TLS1.2 */
        {
            struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT);
            EXPECT_NOT_NULL(conn);
            conn->actual_protocol_version = S2N_TLS12;

            /* Set up input stuffer */
            DEFER_CLEANUP(struct s2n_stuffer input = { 0 }, s2n_stuffer_free);
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, 0));

            struct s2n_blob nst_message = { 0 };
            EXPECT_SUCCESS(s2n_blob_init(&nst_message, nst_data, sizeof(nst_data)));
            EXPECT_SUCCESS(s2n_stuffer_write(&input, &nst_message));

            EXPECT_ERROR_WITH_ERRNO(s2n_tls13_server_nst_recv(conn, &input), S2N_ERR_BAD_MESSAGE);

            EXPECT_EQUAL(conn->client_ticket.size, 0);
            EXPECT_TRUE(s2n_stuffer_data_available(&input) > 0);

            EXPECT_SUCCESS(s2n_connection_free(conn));
        };

        /* Tests session_ticket_cb correctly serializes session data from an arbitrary new session ticket message */
        {
            struct s2n_config *config = s2n_config_new();
            struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT);
            EXPECT_NOT_NULL(conn);
            EXPECT_NOT_NULL(config);

            EXPECT_SUCCESS(s2n_config_set_session_tickets_onoff(config, 1));
            EXPECT_SUCCESS(s2n_config_set_session_ticket_cb(config, s2n_test_session_ticket_cb, NULL));
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

            conn->actual_protocol_version = S2N_TLS13;
            conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;

            /* Set up input stuffer */
            struct s2n_stuffer input = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, 0));

            struct s2n_blob nst_message = { 0 };
            EXPECT_SUCCESS(s2n_blob_init(&nst_message, nst_data, sizeof(nst_data)));
            EXPECT_SUCCESS(s2n_stuffer_write(&input, &nst_message));

            EXPECT_OK(s2n_tls13_server_nst_recv(conn, &input));
            EXPECT_BYTEARRAY_EQUAL(conn->client_ticket.data, test_ticket, sizeof(test_ticket));
            EXPECT_EQUAL(s2n_stuffer_data_available(&input), 0);

            /* Initialize a stuffer to examine the serialized data returned in the session ticket callback */
            struct s2n_blob session_blob = { 0 };
            struct s2n_stuffer session_stuffer = { 0 };
            EXPECT_SUCCESS(s2n_blob_init(&session_blob, cb_session_data, cb_session_data_len));
            EXPECT_SUCCESS(s2n_stuffer_init(&session_stuffer, &session_blob));
            EXPECT_SUCCESS(s2n_stuffer_skip_write(&session_stuffer, cb_session_data_len));

            /* Check the serialized ticket is what was in the arbitrary nst message */
            {
                /* Skip to encrypted ticket size */
                EXPECT_SUCCESS((s2n_stuffer_skip_read(&session_stuffer, sizeof(uint8_t))));

                uint16_t ticket_size = 0;
                EXPECT_SUCCESS(s2n_stuffer_read_uint16(&session_stuffer, &ticket_size));
                EXPECT_EQUAL(ticket_size, sizeof(test_ticket));

                uint8_t *ticket = s2n_stuffer_raw_read(&session_stuffer, ticket_size);
                EXPECT_NOT_NULL(ticket);
                EXPECT_BYTEARRAY_EQUAL(ticket, test_ticket, ticket_size);
            };

            /* Check the serialized ticket_age_add is what was in the arbitrary nst message */
            {
                uint8_t test_ticket_age_add[] = { TEST_TICKET_AGE_ADD };
                uint8_t ticket_age_add_marker = sizeof(uint8_t) + /* client state format */
                        sizeof(uint8_t) +                         /* protocol version */
                        sizeof(uint16_t) +                        /* cipher suite */
                        sizeof(uint64_t);                         /* time */
                /* Skip to ticket_age_add */
                EXPECT_SUCCESS((s2n_stuffer_skip_read(&session_stuffer, ticket_age_add_marker)));

                uint8_t ticket_age_add[sizeof(uint32_t)] = { 0 };
                EXPECT_SUCCESS(s2n_stuffer_read_bytes(&session_stuffer, ticket_age_add, sizeof(uint32_t)));
                EXPECT_BYTEARRAY_EQUAL(ticket_age_add, test_ticket_age_add, sizeof(uint32_t));
            };

            /* Check ticket lifetime is what was in the arbitrary nst message */
            {
                uint8_t test_lifetime[] = { TEST_LIFETIME };
                uint32_t expected_lifetime = test_lifetime[3] | (test_lifetime[2] << 8) | (test_lifetime[1] << 16) | (test_lifetime[0] << 24);
                EXPECT_EQUAL(expected_lifetime, cb_session_lifetime);
            };
            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_stuffer_free(&input));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* Known values test */
        {
            /**
             * NewSessionTicket handshake message
             * 
             *= https://www.rfc-editor.org/rfc/rfc8448#section-3
             *# NewSessionTicket (205 octets):  04 00 00 c9 00 00 00 1e fa d6 aa
             *#    c5 02 00 00 00 b2 2c 03 5d 82 93 59 ee 5f f7 af 4e c9 00 00 00
             *#    00 26 2a 64 94 dc 48 6d 2c 8a 34 cb 33 fa 90 bf 1b 00 70 ad 3c
             *#    49 88 83 c9 36 7c 09 a2 be 78 5a bc 55 cd 22 60 97 a3 a9 82 11
             *#    72 83 f8 2a 03 a1 43 ef d3 ff 5d d3 6d 64 e8 61 be 7f d6 1d 28
             *#    27 db 27 9c ce 14 50 77 d4 54 a3 66 4d 4e 6d a4 d2 9e e0 37 25
             *#    a6 a4 da fc d0 fc 67 d2 ae a7 05 29 51 3e 3d a2 67 7f a5 90 6c
             *#    5b 3f 7d 8f 92 f2 28 bd a4 0d da 72 14 70 f9 fb f2 97 b5 ae a6
             *#    17 64 6f ac 5c 03 27 2e 97 07 27 c6 21 a7 91 41 ef 5f 7d e6 50
             *#    5e 5b fb c3 88 e9 33 43 69 40 93 93 4a e4 d3 57 00 08 00 2a 00
             *#    04 00 00 04 00
             **/
            /* clang-format off */
            S2N_BLOB_FROM_HEX(nst_message,
                                             "04 00 00 c9 00 00 00 1e fa d6 aa \
                c5 02 00 00 00 b2 2c 03 5d 82 93 59 ee 5f f7 af 4e c9 00 00 00 \
                00 26 2a 64 94 dc 48 6d 2c 8a 34 cb 33 fa 90 bf 1b 00 70 ad 3c \
                49 88 83 c9 36 7c 09 a2 be 78 5a bc 55 cd 22 60 97 a3 a9 82 11 \
                72 83 f8 2a 03 a1 43 ef d3 ff 5d d3 6d 64 e8 61 be 7f d6 1d 28 \
                27 db 27 9c ce 14 50 77 d4 54 a3 66 4d 4e 6d a4 d2 9e e0 37 25 \
                a6 a4 da fc d0 fc 67 d2 ae a7 05 29 51 3e 3d a2 67 7f a5 90 6c \
                5b 3f 7d 8f 92 f2 28 bd a4 0d da 72 14 70 f9 fb f2 97 b5 ae a6 \
                17 64 6f ac 5c 03 27 2e 97 07 27 c6 21 a7 91 41 ef 5f 7d e6 50 \
                5e 5b fb c3 88 e9 33 43 69 40 93 93 4a e4 d3 57 00 08 00 2a 00 \
                04 00 00 04 00");
            /* clang-format on */

            struct s2n_config *config = s2n_config_new();
            struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT);
            EXPECT_NOT_NULL(conn);
            EXPECT_NOT_NULL(config);

            EXPECT_SUCCESS(s2n_config_set_session_tickets_onoff(config, 1));
            EXPECT_SUCCESS(s2n_config_set_session_ticket_cb(config, s2n_test_session_ticket_cb, NULL));
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

            conn->actual_protocol_version = S2N_TLS13;
            conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;

            /* Set up input stuffer */
            struct s2n_stuffer input = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, 0));

            EXPECT_SUCCESS(s2n_stuffer_write(&input, &nst_message));
            EXPECT_SUCCESS(s2n_stuffer_skip_read(&input, sizeof(uint8_t) + SIZEOF_UINT24));
            EXPECT_OK(s2n_tls13_server_nst_recv(conn, &input));

            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_stuffer_free(&input));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* Self-talk test */
        {
            struct s2n_config *config = s2n_config_new();
            struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT);
            EXPECT_NOT_NULL(client_conn);
            EXPECT_NOT_NULL(config);

            struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(server_conn);

            EXPECT_SUCCESS(s2n_config_set_session_tickets_onoff(config, 1));
            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));
            EXPECT_SUCCESS(s2n_connection_set_config(server_conn, config));

            EXPECT_SUCCESS(s2n_config_set_session_ticket_cb(config, s2n_test_session_ticket_cb, NULL));
            EXPECT_SUCCESS(s2n_connection_set_config(client_conn, config));

            client_conn->actual_protocol_version = S2N_TLS13;
            server_conn->actual_protocol_version = S2N_TLS13;
            client_conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;
            server_conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;

            struct s2n_stuffer stuffer = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));

            EXPECT_OK(s2n_tls13_server_nst_write(server_conn, &stuffer));
            EXPECT_SUCCESS(s2n_stuffer_skip_read(&stuffer, sizeof(uint8_t) + SIZEOF_UINT24));
            EXPECT_OK(s2n_tls13_server_nst_recv(client_conn, &stuffer));

            EXPECT_SUCCESS(s2n_connection_free(client_conn));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
            EXPECT_SUCCESS(s2n_stuffer_free(&stuffer));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* Test that the client processes extensions.
         * Specifically, check for the early_data_indication extension. */
        {
            const uint32_t expected_max_early_data_size = 17;

            struct s2n_config *config = s2n_config_new();
            EXPECT_NOT_NULL(config);
            EXPECT_SUCCESS(s2n_config_set_session_tickets_onoff(config, 1));
            EXPECT_SUCCESS(s2n_config_set_session_ticket_cb(config, s2n_test_session_ticket_cb, NULL));
            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));

            struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT);
            EXPECT_NOT_NULL(client_conn);
            client_conn->actual_protocol_version = S2N_TLS13;
            client_conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;
            EXPECT_SUCCESS(s2n_connection_set_config(client_conn, config));

            struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(server_conn);
            server_conn->actual_protocol_version = S2N_TLS13;
            server_conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;
            EXPECT_SUCCESS(s2n_connection_set_config(server_conn, config));
            EXPECT_SUCCESS(s2n_connection_set_server_max_early_data_size(server_conn, expected_max_early_data_size));

            struct s2n_stuffer stuffer = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));

            EXPECT_EQUAL(client_conn->server_max_early_data_size, 0);
            EXPECT_OK(s2n_tls13_server_nst_write(server_conn, &stuffer));
            EXPECT_SUCCESS(s2n_stuffer_skip_read(&stuffer, sizeof(uint8_t) + SIZEOF_UINT24));
            EXPECT_OK(s2n_tls13_server_nst_recv(client_conn, &stuffer));
            EXPECT_EQUAL(client_conn->server_max_early_data_size, expected_max_early_data_size);

            EXPECT_SUCCESS(s2n_connection_free(client_conn));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
            EXPECT_SUCCESS(s2n_stuffer_free(&stuffer));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* Test that the client can handle different max_early_data_size values. */
        {
            const uint32_t expected_max_early_data_sizes[] = { 17, 0, UINT16_MAX, 0, 20, UINT32_MAX, 5, 0 };

            struct s2n_config *config = s2n_config_new();
            EXPECT_NOT_NULL(config);
            EXPECT_SUCCESS(s2n_config_set_session_tickets_onoff(config, 1));
            EXPECT_SUCCESS(s2n_config_set_session_ticket_cb(config, s2n_test_session_ticket_cb, NULL));
            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));

            struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT);
            EXPECT_NOT_NULL(client_conn);
            client_conn->actual_protocol_version = S2N_TLS13;
            client_conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;
            EXPECT_SUCCESS(s2n_connection_set_config(client_conn, config));

            struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(server_conn);
            server_conn->actual_protocol_version = S2N_TLS13;
            server_conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;
            EXPECT_SUCCESS(s2n_connection_set_config(server_conn, config));

            struct s2n_stuffer stuffer = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));

            for (size_t i = 0; i < s2n_array_len(expected_max_early_data_sizes); i++) {
                EXPECT_SUCCESS(s2n_connection_set_server_max_early_data_size(server_conn, expected_max_early_data_sizes[i]));
                EXPECT_OK(s2n_tls13_server_nst_write(server_conn, &stuffer));
                EXPECT_SUCCESS(s2n_stuffer_skip_read(&stuffer, sizeof(uint8_t) + SIZEOF_UINT24));
                EXPECT_OK(s2n_tls13_server_nst_recv(client_conn, &stuffer));
                EXPECT_EQUAL(client_conn->server_max_early_data_size, expected_max_early_data_sizes[i]);
                EXPECT_SUCCESS(s2n_stuffer_wipe(&stuffer));
            }

            EXPECT_SUCCESS(s2n_connection_free(client_conn));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
            EXPECT_SUCCESS(s2n_stuffer_free(&stuffer));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* Test that the client rejects tickets with invalid ticket_lifetime */
        {
            const size_t lifetime_size = sizeof(uint32_t);
            const uint8_t *nst_data_without_lifetime = nst_data + lifetime_size;
            const size_t nst_data_without_lifetime_size = sizeof(nst_data) - lifetime_size;

            struct s2n_config *config = s2n_config_new();
            EXPECT_NOT_NULL(config);
            EXPECT_SUCCESS(s2n_config_set_session_tickets_onoff(config, 1));
            EXPECT_SUCCESS(s2n_config_set_session_ticket_cb(config, s2n_test_session_ticket_cb, NULL));

            /**
             *= https://www.rfc-editor.org/rfc/rfc8446#section-4.6.1
             *= type=test
             *# The value of zero indicates that the
             *# ticket should be discarded immediately.
             */
            {
                struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT);
                EXPECT_NOT_NULL(conn);
                EXPECT_SUCCESS(s2n_connection_set_config(conn, config));
                conn->actual_protocol_version = S2N_TLS13;

                DEFER_CLEANUP(struct s2n_stuffer input = { 0 }, s2n_stuffer_free);
                EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, sizeof(nst_data)));
                EXPECT_SUCCESS(s2n_stuffer_write_uint32(&input, 0));
                EXPECT_SUCCESS(s2n_stuffer_write_bytes(&input, nst_data_without_lifetime, nst_data_without_lifetime_size));

                EXPECT_OK(s2n_tls13_server_nst_recv(conn, &input));
                /* Verify that the client only got as far as the ticket_lifetime when parsing */
                EXPECT_EQUAL(s2n_stuffer_data_available(&input), nst_data_without_lifetime_size);
                /* Verify that the client did not accept + store the ticket */
                EXPECT_EQUAL(s2n_connection_get_session_length(conn), 0);

                EXPECT_SUCCESS(s2n_connection_free(conn));
            };

            /**
             *= https://www.rfc-editor.org/rfc/rfc8446#section-4.6.1
             *= type=test
             *# Servers MUST NOT use any value greater than
             *# 604800 seconds (7 days).
             */
            {
                struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT);
                EXPECT_NOT_NULL(conn);
                EXPECT_SUCCESS(s2n_connection_set_config(conn, config));
                conn->actual_protocol_version = S2N_TLS13;

                DEFER_CLEANUP(struct s2n_stuffer input = { 0 }, s2n_stuffer_free);
                EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, sizeof(nst_data)));
                EXPECT_SUCCESS(s2n_stuffer_write_uint32(&input, UINT32_MAX));
                EXPECT_SUCCESS(s2n_stuffer_write_bytes(&input, nst_data_without_lifetime, nst_data_without_lifetime_size));

                EXPECT_ERROR_WITH_ERRNO(s2n_tls13_server_nst_recv(conn, &input), S2N_ERR_BAD_MESSAGE);
                /* Verify that the client only got as far as the ticket_lifetime when parsing */
                EXPECT_EQUAL(s2n_stuffer_data_available(&input), nst_data_without_lifetime_size);
                /* Verify that the client did not accept + store the ticket */
                EXPECT_EQUAL(s2n_connection_get_session_length(conn), 0);

                EXPECT_SUCCESS(s2n_connection_free(conn));
            };

            EXPECT_SUCCESS(s2n_config_free(config));
        };
    };

    /* s2n_server_nst_send */
    {
        /* s2n_server_nst_send writes a non-zero ticket when a valid encryption key exists */
        {
            DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free);
            EXPECT_NOT_NULL(config);
            DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_SERVER),
                    s2n_connection_ptr_free);
            EXPECT_NOT_NULL(conn);
            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

            conn->session_ticket_status = S2N_NEW_TICKET;

            EXPECT_SUCCESS(s2n_server_nst_send(conn));
            EXPECT_TICKETS_SENT(conn, 1);

            uint32_t lifetime = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint32(&conn->handshake.io, &lifetime));
            EXPECT_TRUE(lifetime > 0);

            uint16_t ticket_len = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint16(&conn->handshake.io, &ticket_len));
            EXPECT_TRUE(ticket_len > 0);

            EXPECT_EQUAL(s2n_stuffer_data_available(&conn->handshake.io),
                    S2N_TLS12_TICKET_SIZE_IN_BYTES);
        };

        /* s2n_server_nst_send writes a zero-length ticket when no valid encryption key exists
         *
         *= https://www.rfc-editor.org/rfc/rfc5077#section-3.3
         *= type=test
         *# If the server determines that it does not want to include a
         *# ticket after it has included the SessionTicket extension in the
         *# ServerHello, then it sends a zero-length ticket in the
         *# NewSessionTicket handshake message.
         **/
        {
            DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free);
            EXPECT_NOT_NULL(config);
            DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_SERVER),
                    s2n_connection_ptr_free);
            EXPECT_NOT_NULL(conn);
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

            conn->session_ticket_status = S2N_NEW_TICKET;

            EXPECT_SUCCESS(s2n_server_nst_send(conn));
            EXPECT_TICKETS_SENT(conn, 0);

            uint32_t lifetime = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint32(&conn->handshake.io, &lifetime));
            EXPECT_TRUE(lifetime == 0);

            uint16_t ticket_len = 0;
            EXPECT_SUCCESS(s2n_stuffer_read_uint16(&conn->handshake.io, &ticket_len));
            EXPECT_TRUE(ticket_len == 0);
            EXPECT_EQUAL(s2n_stuffer_data_available(&conn->handshake.io), 0);
        };
    }

    /* s2n_tls13_server_nst_send */
    {
        /* Mode is not server */
        {
            struct s2n_connection *conn = NULL;
            EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_CLIENT));
            conn->actual_protocol_version = S2N_TLS13;
            conn->tickets_to_send = 1;

            /* Setup io */
            struct s2n_stuffer stuffer = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&stuffer, &stuffer, conn));

            s2n_blocked_status blocked = 0;
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));

            EXPECT_EQUAL(0, s2n_stuffer_data_available(&stuffer));
            EXPECT_ERROR_WITH_ERRNO(s2n_assert_tickets_sent(conn, 0), S2N_ERR_CLIENT_MODE);

            EXPECT_SUCCESS(s2n_stuffer_free(&stuffer));
            EXPECT_SUCCESS(s2n_connection_free(conn));
        };

        /* Protocol is less than TLS13 */
        {
            DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(),
                    s2n_config_ptr_free);
            EXPECT_NOT_NULL(config);
            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));

            DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_SERVER),
                    s2n_connection_ptr_free);
            EXPECT_NOT_NULL(conn);
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));
            conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;
            conn->tickets_to_send = 1;

            DEFER_CLEANUP(struct s2n_stuffer stuffer = { 0 }, s2n_stuffer_free);
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&stuffer, &stuffer, conn));

            s2n_blocked_status blocked = 0;

            conn->actual_protocol_version = S2N_TLS12;
            EXPECT_ERROR(s2n_tls13_server_nst_send(conn, &blocked));
            EXPECT_TICKETS_SENT(conn, 0);

            conn->actual_protocol_version = S2N_TLS13;
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
            EXPECT_TICKETS_SENT(conn, 1);
        };

        /* 0 tickets are requested */
        {
            struct s2n_config *config = s2n_config_new();
            EXPECT_NOT_NULL(config);
            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));

            struct s2n_connection *conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(conn);
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));
            conn->actual_protocol_version = S2N_TLS13;
            conn->tickets_to_send = 0;
            EXPECT_NOT_EQUAL(0, s2n_stuffer_space_remaining(&conn->handshake.io));

            /* Setup io */
            struct s2n_stuffer stuffer = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&stuffer, &stuffer, conn));

            s2n_blocked_status blocked = 0;
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));

            /* Check no tickets are written */
            EXPECT_EQUAL(0, s2n_stuffer_data_available(&stuffer));
            EXPECT_TICKETS_SENT(conn, 0);

            /* Check handshake.io is cleaned up */
            EXPECT_EQUAL(0, s2n_stuffer_space_remaining(&conn->handshake.io));

            EXPECT_SUCCESS(s2n_stuffer_free(&stuffer));
            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* QUIC mode is enabled */
        {
            DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(),
                    s2n_config_ptr_free);
            EXPECT_NOT_NULL(config);
            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));

            DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_SERVER),
                    s2n_connection_ptr_free);
            EXPECT_NOT_NULL(conn);
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));
            conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;
            conn->tickets_to_send = 1;
            conn->actual_protocol_version = S2N_TLS13;

            DEFER_CLEANUP(struct s2n_stuffer stuffer = { 0 }, s2n_stuffer_free);
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&stuffer, &stuffer, conn));

            s2n_blocked_status blocked = 0;

            conn->quic_enabled = true;
            /* No mutually-supported psk mode agreed upon */
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
            EXPECT_TICKETS_SENT(conn, 0);

            /* Client has indicated that it supports both resumption and psk_dhe_ke mode */
            conn->psk_params.psk_ke_mode = S2N_PSK_DHE_KE;
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
            EXPECT_TICKETS_SENT(conn, 1);
        };

        /* Sends one new session ticket */
        {
            struct s2n_config *config = NULL;
            struct s2n_connection *conn = NULL;
            EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER));
            EXPECT_NOT_NULL(config = s2n_config_new());
            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

            conn->actual_protocol_version = S2N_TLS13;
            conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;
            conn->tickets_to_send = 1;
            EXPECT_NOT_EQUAL(s2n_stuffer_space_remaining(&conn->handshake.io), 0);

            /* Setup io */
            struct s2n_stuffer stuffer = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&stuffer, &stuffer, conn));

            s2n_blocked_status blocked = 0;
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
            EXPECT_TICKETS_SENT(conn, 1);

            /* Check only one record was written */
            uint16_t record_len = 0;
            EXPECT_SUCCESS(s2n_stuffer_skip_read(&stuffer, RECORD_LEN_MARKER));
            EXPECT_SUCCESS(s2n_stuffer_read_uint16(&stuffer, &record_len));
            EXPECT_TRUE(record_len > 0);
            EXPECT_SUCCESS(s2n_stuffer_skip_read(&stuffer, record_len));
            EXPECT_EQUAL(s2n_stuffer_data_available(&stuffer), 0);

            EXPECT_SUCCESS(s2n_stuffer_free(&stuffer));
            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* Send no more tickets if keying material is expired
         *
         *= https://www.rfc-editor.org/rfc/rfc8446#section-4.6.1
         *= type=test
         *# Note that in principle it is possible to continue issuing new tickets
         *# which indefinitely extend the lifetime of the keying material
         *# originally derived from an initial non-PSK handshake (which was most
         *# likely tied to the peer's certificate). It is RECOMMENDED that
         *# implementations place limits on the total lifetime of such keying
         *# material; these limits should take into account the lifetime of the
         *# peer's certificate, the likelihood of intervening revocation, and the
         *# time since the peer's online CertificateVerify signature.
         */
        {
            const uint8_t current_tickets = 10;
            const uint8_t new_tickets = 5;

            struct s2n_config *config = s2n_config_new();
            EXPECT_NOT_NULL(config);
            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));

            struct s2n_connection *conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(conn);
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));
            conn->actual_protocol_version = S2N_TLS13;
            conn->tickets_sent = current_tickets;
            conn->tickets_to_send = current_tickets;
            EXPECT_TICKETS_SENT(conn, current_tickets);

            struct s2n_stuffer stuffer = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&stuffer, &stuffer, conn));

            /* Can request new tickets */
            EXPECT_SUCCESS(s2n_connection_add_new_tickets_to_send(conn, new_tickets));
            EXPECT_EQUAL(conn->tickets_sent, current_tickets);
            EXPECT_EQUAL(conn->tickets_to_send, current_tickets + new_tickets);
            EXPECT_TICKETS_SENT(conn, current_tickets);

            /* Add expired keying material */
            DEFER_CLEANUP(struct s2n_psk *chosen_psk = s2n_test_psk_new(conn), s2n_psk_free);
            EXPECT_NOT_NULL(chosen_psk);
            chosen_psk->type = S2N_PSK_TYPE_RESUMPTION;
            chosen_psk->keying_material_expiration = 0;
            conn->psk_params.chosen_psk = chosen_psk;

            /* Despite tickets requested, no tickets sent */
            s2n_blocked_status blocked = 0;
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
            EXPECT_EQUAL(s2n_stuffer_data_available(&stuffer), 0);
            EXPECT_EQUAL(conn->tickets_sent, current_tickets);
            EXPECT_EQUAL(conn->tickets_to_send, current_tickets);
            EXPECT_TICKETS_SENT(conn, current_tickets);

            /* Can't request more tickets */
            EXPECT_FAILURE_WITH_ERRNO(s2n_connection_add_new_tickets_to_send(conn, new_tickets),
                    S2N_ERR_KEYING_MATERIAL_EXPIRED);
            EXPECT_EQUAL(conn->tickets_sent, current_tickets);
            EXPECT_EQUAL(conn->tickets_to_send, current_tickets);
            EXPECT_TICKETS_SENT(conn, current_tickets);

            EXPECT_SUCCESS(s2n_stuffer_free(&stuffer));
            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* s2n_config_set_session_tickets_onoff used to enable tickets */
        {
            uint8_t test_data[S2N_TICKET_KEY_NAME_LEN] = "data";
            uint64_t current_time = 0;

            struct s2n_config *config = s2n_config_new();
            EXPECT_NOT_NULL(config);
            EXPECT_SUCCESS(s2n_config_set_session_tickets_onoff(config, true));
            EXPECT_SUCCESS(config->wall_clock(config->sys_clock_ctx, &current_time));
            EXPECT_SUCCESS(s2n_config_add_ticket_crypto_key(config, test_data, sizeof(test_data),
                    test_data, sizeof(test_data), current_time / ONE_SEC_IN_NANOS));

            struct s2n_connection *conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(conn);
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));
            conn->actual_protocol_version = S2N_TLS13;
            conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;

            /* Setup io */
            struct s2n_stuffer stuffer = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&stuffer, &stuffer, conn));

            s2n_blocked_status blocked = 0;
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
            EXPECT_TICKETS_SENT(conn, 1);
            EXPECT_NOT_EQUAL(0, s2n_stuffer_data_available(&stuffer));
            EXPECT_SUCCESS(s2n_stuffer_wipe(&stuffer));

            /* Request more tickets */
            EXPECT_SUCCESS(s2n_connection_add_new_tickets_to_send(conn, 1));
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
            EXPECT_TICKETS_SENT(conn, 2);
            EXPECT_NOT_EQUAL(0, s2n_stuffer_data_available(&stuffer));
            EXPECT_SUCCESS(s2n_stuffer_wipe(&stuffer));

            /* Turn tickets off */
            EXPECT_SUCCESS(s2n_config_set_session_tickets_onoff(config, false));

            /* Request more tickets */
            EXPECT_SUCCESS(s2n_connection_add_new_tickets_to_send(conn, 1));
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
            EXPECT_TICKETS_SENT(conn, 2);
            EXPECT_EQUAL(0, s2n_stuffer_data_available(&stuffer));

            EXPECT_SUCCESS(s2n_stuffer_free(&stuffer));
            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* s2n_config_set_initial_ticket_count used to enable tickets */
        {
            uint8_t test_data[S2N_TICKET_KEY_NAME_LEN] = "data";
            uint64_t current_time = 0;

            struct s2n_config *config = s2n_config_new();
            EXPECT_NOT_NULL(config);
            EXPECT_SUCCESS(s2n_config_set_initial_ticket_count(config, 1));
            EXPECT_SUCCESS(config->wall_clock(config->sys_clock_ctx, &current_time));
            EXPECT_SUCCESS(s2n_config_add_ticket_crypto_key(config, test_data, sizeof(test_data),
                    test_data, sizeof(test_data), current_time / ONE_SEC_IN_NANOS));

            struct s2n_connection *conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(conn);
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));
            conn->actual_protocol_version = S2N_TLS13;
            conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;

            /* Setup io */
            struct s2n_stuffer stuffer = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&stuffer, &stuffer, conn));

            s2n_blocked_status blocked = 0;
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
            EXPECT_TICKETS_SENT(conn, 1);
            EXPECT_NOT_EQUAL(0, s2n_stuffer_data_available(&stuffer));

            EXPECT_SUCCESS(s2n_stuffer_free(&stuffer));
            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* Sends multiple new session tickets */
        {
            struct s2n_config *config = NULL;
            struct s2n_connection *conn = NULL;
            EXPECT_NOT_NULL(conn = s2n_connection_new(S2N_SERVER));
            EXPECT_NOT_NULL(config = s2n_config_new());

            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

            conn->actual_protocol_version = S2N_TLS13;
            conn->secure->cipher_suite = &s2n_tls13_aes_128_gcm_sha256;
            uint16_t tickets_to_send = 5;
            conn->tickets_to_send = tickets_to_send;

            /* Setup io */
            struct s2n_stuffer stuffer = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&stuffer, &stuffer, conn));

            s2n_blocked_status blocked = 0;
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
            EXPECT_TICKETS_SENT(conn, tickets_to_send);

            /* Check five records were written */
            uint16_t record_len = 0;
            for (size_t i = 0; i < tickets_to_send; i++) {
                EXPECT_SUCCESS(s2n_stuffer_skip_read(&stuffer, RECORD_LEN_MARKER));
                EXPECT_SUCCESS(s2n_stuffer_read_uint16(&stuffer, &record_len));
                EXPECT_TRUE(record_len > 0);
                EXPECT_SUCCESS(s2n_stuffer_skip_read(&stuffer, record_len));
            }
            EXPECT_TRUE(s2n_stuffer_data_available(&stuffer) == 0);

            /* No more tickets to send */
            EXPECT_SUCCESS(s2n_stuffer_rewrite(&stuffer));
            EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
            EXPECT_EQUAL(0, s2n_stuffer_data_available(&stuffer));

            EXPECT_SUCCESS(s2n_stuffer_free(&stuffer));
            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_config_free(config));
        };

        /* Test S2N_TLS13_MAX_FIXED_NEW_SESSION_TICKET_SIZE */
        {
            struct s2n_config *config = s2n_config_new();
            EXPECT_NOT_NULL(config);
            EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));

            struct s2n_connection *conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(conn);
            EXPECT_SUCCESS(s2n_connection_set_config(conn, config));

            /* TLS1.3 tickets contain extra fields */
            conn->actual_protocol_version = S2N_TLS13;
            /* Largest possible TLS1.3 secret size */
            conn->secure->cipher_suite = &s2n_tls13_aes_256_gcm_sha384;
            /* Necessary for extensions, which contribute to size */
            EXPECT_SUCCESS(s2n_connection_set_server_max_early_data_size(conn, 10));

            /* Setup io */
            struct s2n_stuffer output = { 0 };
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&output, 0));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&output, &output, conn));

            /* Test with no variable fields */
            {
                size_t session_state_size = 0;
                EXPECT_OK(s2n_connection_get_session_state_size(conn, &session_state_size));
                EXPECT_NOT_EQUAL(session_state_size, 0);

                s2n_blocked_status blocked = 0;
                EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
                EXPECT_NOT_EQUAL(s2n_stuffer_data_available(&output), 0);

                uint32_t expected_max_size = s2n_stuffer_data_available(&output) - S2N_TLS_RECORD_HEADER_LENGTH;
                uint32_t expected_max_fixed_size = expected_max_size - session_state_size;
                if (S2N_TLS13_MAX_FIXED_NEW_SESSION_TICKET_SIZE != expected_max_fixed_size) {
                    fprintf(stdout, "\nS2N_TLS13_MAX_FIXED_NEW_SESSION_TICKET_SIZE (%i) should be %u\n",
                            (int) S2N_TLS13_MAX_FIXED_NEW_SESSION_TICKET_SIZE, expected_max_fixed_size);
                }
                EXPECT_EQUAL(S2N_TLS13_MAX_FIXED_NEW_SESSION_TICKET_SIZE, expected_max_fixed_size);
            };

            EXPECT_SUCCESS(s2n_stuffer_wipe(&output));
            conn->tickets_to_send++;

            /* Test with some variable fields */
            {
                const uint8_t early_data_context[] = "early data context";
                EXPECT_SUCCESS(s2n_connection_set_server_early_data_context(conn,
                        early_data_context, sizeof(early_data_context)));

                size_t session_state_size = 0;
                EXPECT_OK(s2n_connection_get_session_state_size(conn, &session_state_size));
                EXPECT_NOT_EQUAL(session_state_size, 0);

                s2n_blocked_status blocked = 0;
                EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
                EXPECT_NOT_EQUAL(s2n_stuffer_data_available(&output), 0);

                uint32_t expected_max_size = s2n_stuffer_data_available(&output) - S2N_TLS_RECORD_HEADER_LENGTH;
                uint32_t expected_max_fixed_size = expected_max_size - session_state_size;
                EXPECT_EQUAL(S2N_TLS13_MAX_FIXED_NEW_SESSION_TICKET_SIZE, expected_max_fixed_size);
            };

            EXPECT_SUCCESS(s2n_stuffer_wipe(&output));
            conn->tickets_to_send++;

            /* Test with all variable fields */
            {
                const uint8_t early_data_context[] = "different early data context";
                EXPECT_SUCCESS(s2n_connection_set_server_early_data_context(conn,
                        early_data_context, sizeof(early_data_context)));

                const uint8_t app_protocol[] = "https";
                EXPECT_MEMCPY_SUCCESS(conn->application_protocol, app_protocol, sizeof(app_protocol));

                size_t session_state_size = 0;
                EXPECT_OK(s2n_connection_get_session_state_size(conn, &session_state_size));
                EXPECT_NOT_EQUAL(session_state_size, 0);

                s2n_blocked_status blocked = 0;
                EXPECT_OK(s2n_tls13_server_nst_send(conn, &blocked));
                EXPECT_NOT_EQUAL(s2n_stuffer_data_available(&output), 0);

                uint32_t expected_max_size = s2n_stuffer_data_available(&output) - S2N_TLS_RECORD_HEADER_LENGTH;
                uint32_t expected_max_fixed_size = expected_max_size - session_state_size;
                EXPECT_EQUAL(S2N_TLS13_MAX_FIXED_NEW_SESSION_TICKET_SIZE, expected_max_fixed_size);
            };

            EXPECT_SUCCESS(s2n_stuffer_free(&output));
            EXPECT_SUCCESS(s2n_connection_free(conn));
            EXPECT_SUCCESS(s2n_config_free(config));
        };
    };

    /* Functional test: s2n_negotiate sends new session tickets after the handshake is complete */
    if (s2n_is_tls13_fully_supported()) {
        /* Setup connections */
        struct s2n_connection *client_conn = NULL, *server_conn = NULL;
        EXPECT_NOT_NULL(client_conn = s2n_connection_new(S2N_CLIENT));
        EXPECT_NOT_NULL(server_conn = s2n_connection_new(S2N_SERVER));

        /* 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_ECDSA_TEST_CERT_CHAIN, S2N_DEFAULT_ECDSA_TEST_PRIVATE_KEY));
        struct s2n_config *config = NULL;
        EXPECT_NOT_NULL(config = s2n_config_new());
        EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, "default_tls13"));
        EXPECT_SUCCESS(s2n_config_set_unsafe_for_testing(config));
        EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, chain_and_key));
        EXPECT_SUCCESS(s2n_config_set_session_tickets_onoff(config, 1));
        EXPECT_SUCCESS(s2n_connection_set_config(client_conn, config));

        EXPECT_OK(s2n_resumption_test_ticket_key_setup(config));
        EXPECT_SUCCESS(s2n_connection_set_config(server_conn, config));

        uint16_t tickets_to_send = 5;
        server_conn->tickets_to_send = tickets_to_send;

        struct s2n_stuffer client_to_server = { 0 };
        struct s2n_stuffer server_to_client = { 0 };

        EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&client_to_server, 0));
        EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&server_to_client, 0));

        EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&server_to_client, &client_to_server, client_conn));
        EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&client_to_server, &server_to_client, server_conn));

        /* Do handshake */
        EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server_conn, client_conn));
        EXPECT_TICKETS_SENT(server_conn, tickets_to_send);

        /* Check handshake.io was cleaned up.
         * If a ticket was written, this happens afterwards. */
        EXPECT_EQUAL(s2n_stuffer_space_remaining(&server_conn->handshake.io), 0);
        EXPECT_EQUAL(s2n_stuffer_space_remaining(&client_conn->handshake.io), 0);

        /* Check there are five records corresponding to five new session tickets
         * not read as part of the handshake */
        uint16_t record_len = 0;
        for (size_t i = 0; i < tickets_to_send; i++) {
            EXPECT_SUCCESS(s2n_stuffer_skip_read(&server_to_client, RECORD_LEN_MARKER));
            EXPECT_SUCCESS(s2n_stuffer_read_uint16(&server_to_client, &record_len));
            EXPECT_TRUE(record_len > 0);
            EXPECT_SUCCESS(s2n_stuffer_skip_read(&server_to_client, record_len));
        }
        EXPECT_TRUE(s2n_stuffer_data_available(&server_to_client) == 0);

        /* Call s2n_negotiate again to ensure no more tickets are sent */
        EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server_conn, client_conn));
        EXPECT_EQUAL(0, s2n_stuffer_data_available(&server_to_client));
        EXPECT_TICKETS_SENT(server_conn, tickets_to_send);

        EXPECT_SUCCESS(s2n_stuffer_free(&client_to_server));
        EXPECT_SUCCESS(s2n_stuffer_free(&server_to_client));
        EXPECT_SUCCESS(s2n_connection_free(server_conn));
        EXPECT_SUCCESS(s2n_connection_free(client_conn));
        EXPECT_SUCCESS(s2n_cert_chain_and_key_free(chain_and_key));
        EXPECT_SUCCESS(s2n_config_free(config));
    }

    END_TEST();
}
