/*
 * 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_early_data.h"

#define BUFFER_SIZE 100

#define EXPECT_NOT_BLOCKED(conn, blocked, expected_msg) \
    EXPECT_EQUAL((blocked), S2N_NOT_BLOCKED);           \
    EXPECT_EQUAL(s2n_conn_get_current_message_type(conn), (expected_msg))
#define EXPECT_BLOCKED_ON_EARLY_DATA(result) EXPECT_FAILURE_WITH_ERRNO((result), S2N_ERR_EARLY_DATA_BLOCKED)
#define EXPECT_BLOCKED_ON_IO(result)         EXPECT_FAILURE_WITH_ERRNO((result), S2N_ERR_IO_BLOCKED)
#define EXPECT_BLOCKED_ON(conn, blocked, expected_blocked, expected_msg) \
    EXPECT_EQUAL((blocked), (expected_blocked));                         \
    EXPECT_EQUAL(s2n_conn_get_current_message_type(conn), (expected_msg))

static S2N_RESULT s2n_test_client_and_server_new(struct s2n_connection **client_conn, struct s2n_connection **server_conn)
{
    *client_conn = s2n_connection_new(S2N_CLIENT);
    EXPECT_NOT_NULL(*client_conn);
    EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(*client_conn, "default_tls13"));

    *server_conn = s2n_connection_new(S2N_SERVER);
    EXPECT_NOT_NULL(*server_conn);
    EXPECT_SUCCESS(s2n_connection_set_blinding(*server_conn, S2N_SELF_SERVICE_BLINDING));
    EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(*server_conn, "default_tls13"));

    struct s2n_test_io_pair io_pair = { 0 };
    EXPECT_SUCCESS(s2n_io_pair_init_non_blocking(&io_pair));
    EXPECT_SUCCESS(s2n_connections_set_io_pair(*client_conn, *server_conn, &io_pair));

    return S2N_RESULT_OK;
}

uint8_t s2n_allowed_reads = 0;
static int s2n_blocking_buffer_read(void *io_context, uint8_t *buf, uint32_t len)
{
    struct s2n_stuffer *in = (struct s2n_stuffer *) io_context;

    bool would_block = s2n_stuffer_data_available(in) < len;
    if (would_block || !s2n_allowed_reads) {
        errno = EAGAIN;
        return -1;
    }
    s2n_allowed_reads--;
    POSIX_GUARD(s2n_stuffer_read_bytes(in, buf, len));
    return len;
}

uint8_t s2n_allowed_writes = 0;
static int s2n_blocking_buffer_write(void *io_context, const uint8_t *buf, uint32_t len)
{
    struct s2n_stuffer *out = (struct s2n_stuffer *) io_context;

    bool would_block = !out->growable && s2n_stuffer_space_remaining(out) < len;
    if (would_block || !s2n_allowed_writes) {
        errno = EAGAIN;
        return -1;
    }
    s2n_allowed_writes--;
    POSIX_GUARD(s2n_stuffer_write_bytes(out, buf, len));
    return len;
}

static S2N_RESULT s2n_test_set_blocking_stuffer_io(
        struct s2n_connection *client_conn, struct s2n_connection *server_conn,
        struct s2n_stuffer *client_in, struct s2n_stuffer *server_in)
{
    RESULT_GUARD_POSIX(s2n_stuffer_alloc(client_in, S2N_TLS_MAXIMUM_RECORD_LENGTH));
    RESULT_GUARD_POSIX(s2n_stuffer_alloc(server_in, S2N_TLS_MAXIMUM_RECORD_LENGTH));

    RESULT_GUARD_POSIX(s2n_connection_set_recv_cb(client_conn, &s2n_blocking_buffer_read));
    RESULT_GUARD_POSIX(s2n_connection_set_recv_ctx(client_conn, client_in));
    RESULT_GUARD_POSIX(s2n_connection_set_recv_cb(server_conn, &s2n_blocking_buffer_read));
    RESULT_GUARD_POSIX(s2n_connection_set_recv_ctx(server_conn, server_in));

    RESULT_GUARD_POSIX(s2n_connection_set_send_cb(client_conn, &s2n_blocking_buffer_write));
    RESULT_GUARD_POSIX(s2n_connection_set_send_ctx(client_conn, server_in));
    RESULT_GUARD_POSIX(s2n_connection_set_send_cb(server_conn, &s2n_blocking_buffer_write));
    RESULT_GUARD_POSIX(s2n_connection_set_send_ctx(server_conn, client_in));

    return S2N_RESULT_OK;
}

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

    if (!s2n_is_tls13_fully_supported()) {
        END_TEST();
    }

    const uint8_t test_data[] = "hello world";

    /* Malformed record: empty handshake record */
    uint8_t malformed_record[] = {
        TLS_HANDSHAKE, 0x03, 0x03, 0x00, 0x04,
        TLS_FINISHED, 0x00, 0x00, 0x00
    };

    DEFER_CLEANUP(struct s2n_psk *test_psk = s2n_external_psk_new(), s2n_psk_free);
    EXPECT_SUCCESS(s2n_psk_set_identity(test_psk, test_data, sizeof(test_data)));
    EXPECT_SUCCESS(s2n_psk_set_secret(test_psk, test_data, sizeof(test_data)));
    EXPECT_SUCCESS(s2n_psk_configure_early_data(test_psk, UINT32_MAX, 0x13, 0x01));

    DEFER_CLEANUP(struct s2n_psk *test_psk_without_early_data = s2n_external_psk_new(), s2n_psk_free);
    EXPECT_SUCCESS(s2n_psk_set_identity(test_psk_without_early_data, test_data, sizeof(test_data)));
    EXPECT_SUCCESS(s2n_psk_set_secret(test_psk_without_early_data, test_data, sizeof(test_data)));

    DEFER_CLEANUP(struct s2n_psk *test_psk_with_wrong_early_data = s2n_external_psk_new(), s2n_psk_free);
    EXPECT_SUCCESS(s2n_psk_set_identity(test_psk_with_wrong_early_data, test_data, sizeof(test_data)));
    EXPECT_SUCCESS(s2n_psk_set_secret(test_psk_with_wrong_early_data, test_data, sizeof(test_data)));
    EXPECT_SUCCESS(s2n_psk_configure_early_data(test_psk_with_wrong_early_data, UINT32_MAX, 0x13, 0x03));
    EXPECT_SUCCESS(s2n_psk_set_application_protocol(test_psk_with_wrong_early_data, test_data, sizeof(test_data)));

    /* Test s2n_send_early_data */
    {
        /* Safety checks */
        {
            struct s2n_connection conn = { 0 };
            conn.mode = S2N_CLIENT;
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;
            uint8_t data = 0;
            EXPECT_FAILURE_WITH_ERRNO(s2n_send_early_data(NULL, &data, 1, &data_size, &blocked), S2N_ERR_NULL);
            EXPECT_FAILURE_WITH_ERRNO(s2n_send_early_data(&conn, &data, 1, NULL, &blocked), S2N_ERR_NULL);
            EXPECT_FAILURE_WITH_ERRNO(s2n_send_early_data(&conn, &data, 1, &data_size, NULL), S2N_ERR_NULL);

            conn.mode = S2N_SERVER;
            EXPECT_FAILURE_WITH_ERRNO(s2n_send_early_data(&conn, &data, 1, &data_size, &blocked), S2N_ERR_SERVER_MODE);
        };

        /* Propagate errors from s2n_negotiate */
        {
            struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT);
            EXPECT_NOT_NULL(client_conn);
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(client_conn, "default_tls13"));
            EXPECT_SUCCESS(s2n_connection_append_psk(client_conn, test_psk));

            DEFER_CLEANUP(struct s2n_stuffer input = { 0 }, s2n_stuffer_free);
            DEFER_CLEANUP(struct s2n_stuffer output = { 0 }, s2n_stuffer_free);
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, S2N_DEFAULT_RECORD_LENGTH));
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&output, S2N_DEFAULT_RECORD_LENGTH));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&input, &output, client_conn));

            EXPECT_SUCCESS(s2n_stuffer_write_bytes(&input, malformed_record, sizeof(malformed_record)));

            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;

            EXPECT_FAILURE_WITH_ERRNO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked),
                    S2N_ERR_BAD_MESSAGE);
            EXPECT_EQUAL(s2n_conn_get_current_message_type(client_conn), SERVER_HELLO);
            EXPECT_EQUAL(data_size, 0);

            EXPECT_SUCCESS(s2n_stuffer_free(&input));
            EXPECT_SUCCESS(s2n_stuffer_free(&output));
            EXPECT_SUCCESS(s2n_connection_free(client_conn));
        };

        /* Propagate errors from s2n_send */
        {
            struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT);
            EXPECT_NOT_NULL(client_conn);
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(client_conn, "default_tls13"));
            EXPECT_SUCCESS(s2n_connection_append_psk(client_conn, test_psk));

            DEFER_CLEANUP(struct s2n_stuffer input = { 0 }, s2n_stuffer_free);
            DEFER_CLEANUP(struct s2n_stuffer output = { 0 }, s2n_stuffer_free);
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&output, S2N_DEFAULT_RECORD_LENGTH));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&input, &output, client_conn));

            /* Indicate that we're already sending. That will cause an error. */
            client_conn->send_in_use = true;

            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;

            EXPECT_FAILURE_WITH_ERRNO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked),
                    S2N_ERR_REENTRANCY);
            EXPECT_EQUAL(s2n_conn_get_current_message_type(client_conn), SERVER_HELLO);
            EXPECT_EQUAL(data_size, 0);

            EXPECT_SUCCESS(s2n_stuffer_free(&output));
            EXPECT_SUCCESS(s2n_connection_free(client_conn));
        };
    };

    /* s2n_recv_early_data */
    {
        /* Safety checks */
        {
            struct s2n_connection conn = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;
            uint8_t data = 0;
            EXPECT_FAILURE_WITH_ERRNO(s2n_recv_early_data(NULL, &data, 1, &data_size, &blocked), S2N_ERR_NULL);
            EXPECT_FAILURE_WITH_ERRNO(s2n_recv_early_data(&conn, &data, 1, NULL, &blocked), S2N_ERR_NULL);
            EXPECT_FAILURE_WITH_ERRNO(s2n_recv_early_data(&conn, &data, 1, &data_size, NULL), S2N_ERR_NULL);

            conn.mode = S2N_CLIENT;
            EXPECT_FAILURE_WITH_ERRNO(s2n_recv_early_data(&conn, &data, 1, &data_size, &blocked), S2N_ERR_CLIENT_MODE);
        };

        /* Propagate errors from s2n_negotiate */
        {
            struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(server_conn);
            EXPECT_SUCCESS(s2n_connection_set_blinding(server_conn, S2N_SELF_SERVICE_BLINDING));
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(server_conn, "default_tls13"));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, test_psk));

            DEFER_CLEANUP(struct s2n_stuffer input = { 0 }, s2n_stuffer_free);
            DEFER_CLEANUP(struct s2n_stuffer output = { 0 }, s2n_stuffer_free);
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, S2N_DEFAULT_RECORD_LENGTH));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&input, &output, server_conn));

            EXPECT_SUCCESS(s2n_stuffer_write_bytes(&input, malformed_record, sizeof(malformed_record)));

            uint8_t payload[BUFFER_SIZE] = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;

            EXPECT_FAILURE_WITH_ERRNO(s2n_recv_early_data(server_conn, payload, sizeof(payload), &data_size, &blocked),
                    S2N_ERR_BAD_MESSAGE);
            EXPECT_EQUAL(s2n_conn_get_current_message_type(server_conn), CLIENT_HELLO);
            EXPECT_EQUAL(data_size, 0);

            EXPECT_SUCCESS(s2n_stuffer_free(&input));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };

        /* Propagate errors from s2n_recv */
        {
            struct s2n_connection *client_conn = NULL, *server_conn = NULL;
            EXPECT_OK(s2n_test_client_and_server_new(&client_conn, &server_conn));
            EXPECT_SUCCESS(s2n_connection_append_psk(client_conn, test_psk));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, test_psk));

            /* Indicate that we're already receiving. That will cause an error. */
            server_conn->recv_in_use = true;

            uint8_t payload[BUFFER_SIZE] = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;

            EXPECT_BLOCKED_ON_IO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked));
            EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_READ, SERVER_HELLO);

            EXPECT_FAILURE_WITH_ERRNO(s2n_recv_early_data(server_conn, payload, sizeof(payload), &data_size, &blocked),
                    S2N_ERR_REENTRANCY);
            EXPECT_EQUAL(s2n_conn_get_current_message_type(server_conn), END_OF_EARLY_DATA);
            EXPECT_EQUAL(data_size, 0);

            EXPECT_SUCCESS(s2n_connection_free(client_conn));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };
    };

    /* Test sending and receiving early data */
    {
        /* Send zero-length early data */
        {
            struct s2n_connection *client_conn = NULL, *server_conn = NULL;
            EXPECT_OK(s2n_test_client_and_server_new(&client_conn, &server_conn));

            EXPECT_SUCCESS(s2n_connection_append_psk(client_conn, test_psk));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, test_psk));

            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;
            s2n_early_data_status_t status = 0;

            EXPECT_BLOCKED_ON_IO(s2n_send_early_data(client_conn, NULL, 0, &data_size, &blocked));
            EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_READ, SERVER_HELLO);
            EXPECT_EQUAL(data_size, 0);

            EXPECT_SUCCESS(s2n_connection_get_early_data_status(client_conn, &status));
            EXPECT_EQUAL(status, S2N_EARLY_DATA_STATUS_OK);

            EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, NULL, 0, &data_size, &blocked));
            EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, END_OF_EARLY_DATA);
            EXPECT_EQUAL(data_size, 0);

            EXPECT_SUCCESS(s2n_connection_get_early_data_status(server_conn, &status));
            EXPECT_EQUAL(status, S2N_EARLY_DATA_STATUS_OK);

            EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server_conn, client_conn));

            EXPECT_SUCCESS(s2n_connection_free(client_conn));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };

        /* Send early data once */
        {
            struct s2n_connection *client_conn = NULL, *server_conn = NULL;
            EXPECT_OK(s2n_test_client_and_server_new(&client_conn, &server_conn));

            EXPECT_SUCCESS(s2n_connection_append_psk(client_conn, test_psk));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, test_psk));

            uint8_t actual_payload[BUFFER_SIZE] = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;
            s2n_early_data_status_t status = 0;

            EXPECT_BLOCKED_ON_IO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked));
            EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_READ, SERVER_HELLO);
            EXPECT_EQUAL(data_size, sizeof(test_data));

            EXPECT_SUCCESS(s2n_connection_get_early_data_status(client_conn, &status));
            EXPECT_EQUAL(status, S2N_EARLY_DATA_STATUS_OK);

            EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_size, &blocked));
            EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, END_OF_EARLY_DATA);
            EXPECT_EQUAL(data_size, sizeof(test_data));
            EXPECT_BYTEARRAY_EQUAL(actual_payload, test_data, sizeof(test_data));

            EXPECT_SUCCESS(s2n_connection_get_early_data_status(server_conn, &status));
            EXPECT_EQUAL(status, S2N_EARLY_DATA_STATUS_OK);

            EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server_conn, client_conn));

            EXPECT_SUCCESS(s2n_connection_free(client_conn));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };

        /* Receive early data too large for buffer */
        {
            struct s2n_connection *client_conn = NULL, *server_conn = NULL;
            EXPECT_OK(s2n_test_client_and_server_new(&client_conn, &server_conn));

            EXPECT_SUCCESS(s2n_connection_append_psk(client_conn, test_psk));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, test_psk));

            uint8_t actual_payload[BUFFER_SIZE] = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;

            EXPECT_BLOCKED_ON_IO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked));
            EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_READ, SERVER_HELLO);
            EXPECT_EQUAL(data_size, sizeof(test_data));

            EXPECT_BLOCKED_ON_EARLY_DATA(s2n_recv_early_data(server_conn, NULL, 0, &data_size, &blocked));
            EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_EARLY_DATA, END_OF_EARLY_DATA);
            EXPECT_EQUAL(data_size, 0);

            EXPECT_BLOCKED_ON_EARLY_DATA(s2n_recv_early_data(server_conn, actual_payload, 1, &data_size, &blocked));
            EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_EARLY_DATA, END_OF_EARLY_DATA);
            EXPECT_EQUAL(data_size, 1);
            EXPECT_BYTEARRAY_EQUAL(actual_payload, test_data, 1);

            /* Remaining early data should block handshake.
             * We can't successfully call s2n_negotiate again until we've drained all the early data
             * via s2n_recv_early_data. For safety, we are not allowed to arbitrarily discard any early data.
             */
            EXPECT_FAILURE_WITH_ERRNO(s2n_negotiate_test_server_and_client(server_conn, client_conn),
                    S2N_ERR_BAD_MESSAGE);

            /* Pretend we didn't test the above error condition.
             * The S2N_ERR_BAD_MESSAGE error triggered S2N to close the connection. */
            s2n_atomic_flag_clear(&server_conn->write_closed);
            s2n_atomic_flag_clear(&client_conn->write_closed);

            /* Read the remaining early data properly */
            EXPECT_SUCCESS(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload),
                    &data_size, &blocked));

            EXPECT_NOT_BLOCKED(server_conn, blocked, APPLICATION_DATA);
            EXPECT_EQUAL(data_size, sizeof(test_data) - 1);
            EXPECT_BYTEARRAY_EQUAL(actual_payload, test_data + 1, sizeof(test_data) - 1);

            EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server_conn, client_conn));

            EXPECT_SUCCESS(s2n_connection_free(client_conn));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };

        /* Send multiple early data messages */
        {
            struct s2n_connection *client_conn = NULL, *server_conn = NULL;
            EXPECT_OK(s2n_test_client_and_server_new(&client_conn, &server_conn));

            EXPECT_SUCCESS(s2n_connection_append_psk(client_conn, test_psk));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, test_psk));

            uint8_t actual_payload[BUFFER_SIZE] = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;

            EXPECT_BLOCKED_ON_IO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked));
            EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_READ, SERVER_HELLO);
            EXPECT_EQUAL(data_size, sizeof(test_data));

            EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_size, &blocked));
            EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, END_OF_EARLY_DATA);
            EXPECT_EQUAL(data_size, sizeof(test_data));
            EXPECT_BYTEARRAY_EQUAL(actual_payload, test_data, sizeof(test_data));

            for (size_t i = 0; i < 10; i++) {
                EXPECT_SUCCESS(s2n_send_early_data(client_conn, test_data, sizeof(test_data),
                        &data_size, &blocked));
                EXPECT_NOT_BLOCKED(client_conn, blocked, END_OF_EARLY_DATA);
                EXPECT_EQUAL(data_size, sizeof(test_data));

                EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_size, &blocked));
                EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_READ, END_OF_EARLY_DATA);
                EXPECT_EQUAL(data_size, sizeof(test_data));
                EXPECT_BYTEARRAY_EQUAL(actual_payload, test_data, sizeof(test_data));
            }

            EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server_conn, client_conn));

            EXPECT_SUCCESS(s2n_connection_free(client_conn));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };

        /* Receive and combine multiple early data records */
        {
            struct s2n_connection *client_conn = NULL, *server_conn = NULL;
            EXPECT_OK(s2n_test_client_and_server_new(&client_conn, &server_conn));

            EXPECT_SUCCESS(s2n_connection_append_psk(client_conn, test_psk));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, test_psk));

            uint8_t actual_payload[BUFFER_SIZE] = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;

            const size_t send_count = 5;
            for (size_t i = 0; i < send_count; i++) {
                EXPECT_BLOCKED_ON_IO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked));
                EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_READ, SERVER_HELLO);
                EXPECT_EQUAL(data_size, sizeof(test_data));
            }

            EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_size, &blocked));
            EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, END_OF_EARLY_DATA);
            EXPECT_EQUAL(data_size, sizeof(test_data) * send_count);

            struct s2n_blob payload_blob = { 0 };
            struct s2n_stuffer payload_stuffer = { 0 };
            EXPECT_SUCCESS(s2n_blob_init(&payload_blob, actual_payload, sizeof(actual_payload)));
            EXPECT_SUCCESS(s2n_stuffer_init(&payload_stuffer, &payload_blob));
            EXPECT_SUCCESS(s2n_stuffer_skip_write(&payload_stuffer, data_size));

            uint8_t payload_chunk[sizeof(test_data)] = { 0 };
            for (size_t i = 0; i < send_count; i++) {
                EXPECT_SUCCESS(s2n_stuffer_read_bytes(&payload_stuffer, payload_chunk, sizeof(test_data)));
                EXPECT_BYTEARRAY_EQUAL(payload_chunk, test_data, sizeof(test_data));
            }
            EXPECT_EQUAL(s2n_stuffer_data_available(&payload_stuffer), 0);

            EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server_conn, client_conn));

            EXPECT_SUCCESS(s2n_connection_free(client_conn));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };

        /* Early data not requested */
        {
            struct s2n_connection *client_conn = NULL, *server_conn = NULL;
            EXPECT_OK(s2n_test_client_and_server_new(&client_conn, &server_conn));

            EXPECT_SUCCESS(s2n_connection_append_psk(client_conn, test_psk_with_wrong_early_data));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, test_psk));

            uint8_t actual_payload[BUFFER_SIZE] = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;
            s2n_early_data_status_t status = 0;

            EXPECT_SUCCESS(s2n_send_early_data(client_conn, test_data, sizeof(test_data),
                    &data_size, &blocked));
            EXPECT_NOT_BLOCKED(client_conn, blocked, SERVER_HELLO);
            EXPECT_EQUAL(data_size, 0);

            EXPECT_SUCCESS(s2n_connection_get_early_data_status(client_conn, &status));
            EXPECT_EQUAL(status, S2N_EARLY_DATA_STATUS_NOT_REQUESTED);

            EXPECT_SUCCESS(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload),
                    &data_size, &blocked));
            EXPECT_NOT_BLOCKED(server_conn, blocked, CLIENT_FINISHED);
            EXPECT_EQUAL(data_size, 0);

            EXPECT_SUCCESS(s2n_connection_get_early_data_status(server_conn, &status));
            EXPECT_EQUAL(status, S2N_EARLY_DATA_STATUS_NOT_REQUESTED);

            EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server_conn, client_conn));

            EXPECT_SUCCESS(s2n_connection_free(client_conn));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };

        /* Early data rejected */
        {
            struct s2n_connection *client_conn = NULL, *server_conn = NULL;
            EXPECT_OK(s2n_test_client_and_server_new(&client_conn, &server_conn));

            EXPECT_SUCCESS(s2n_connection_append_psk(client_conn, test_psk));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, test_psk_with_wrong_early_data));

            uint8_t actual_payload[BUFFER_SIZE] = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_size = 0;
            s2n_early_data_status_t status = 0;

            EXPECT_BLOCKED_ON_IO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked));
            EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_READ, SERVER_HELLO);
            EXPECT_EQUAL(data_size, sizeof(test_data));

            EXPECT_SUCCESS(s2n_connection_get_early_data_status(client_conn, &status));
            EXPECT_EQUAL(status, S2N_EARLY_DATA_STATUS_OK);

            EXPECT_SUCCESS(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload),
                    &data_size, &blocked));
            EXPECT_NOT_BLOCKED(server_conn, blocked, CLIENT_FINISHED);
            EXPECT_EQUAL(data_size, 0);

            EXPECT_SUCCESS(s2n_connection_get_early_data_status(server_conn, &status));
            EXPECT_EQUAL(status, S2N_EARLY_DATA_STATUS_REJECTED);

            EXPECT_SUCCESS(s2n_send_early_data(client_conn, test_data, sizeof(test_data),
                    &data_size, &blocked));
            EXPECT_NOT_BLOCKED(client_conn, blocked, APPLICATION_DATA);
            EXPECT_EQUAL(data_size, 0);

            EXPECT_SUCCESS(s2n_connection_get_early_data_status(client_conn, &status));
            EXPECT_EQUAL(status, S2N_EARLY_DATA_STATUS_REJECTED);

            EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server_conn, client_conn));

            EXPECT_SUCCESS(s2n_connection_free(client_conn));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };
    };

    /* Test blocking behavior when sending and receiving early data.
     *
     * We override the send and recv callbacks to allow us to block on every
     * call to s2n_negotiate, s2n_send, and s2n_recv. This lets us exercise all
     * possible blocking paths.
     */
    {
        /* To read a record, we need to both read its header and read its data */
        const uint8_t full_record_reads = 2;

        struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT);
        EXPECT_NOT_NULL(client_conn);
        EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(client_conn, "default_tls13"));
        EXPECT_SUCCESS(s2n_connection_append_psk(client_conn, test_psk));

        struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
        EXPECT_NOT_NULL(server_conn);
        EXPECT_SUCCESS(s2n_connection_set_blinding(server_conn, S2N_SELF_SERVICE_BLINDING));
        EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(server_conn, "default_tls13"));
        EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, test_psk));

        DEFER_CLEANUP(struct s2n_stuffer client_in = { 0 }, s2n_stuffer_free);
        DEFER_CLEANUP(struct s2n_stuffer server_in = { 0 }, s2n_stuffer_free);
        EXPECT_OK(s2n_test_set_blocking_stuffer_io(client_conn, server_conn, &client_in, &server_in));

        uint8_t actual_payload[BUFFER_SIZE] = { 0 };
        s2n_blocked_status blocked = S2N_NOT_BLOCKED;
        ssize_t data_size = 0;

        /* Block writing the ClientHello */
        s2n_allowed_writes = 0;
        EXPECT_BLOCKED_ON_IO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked));
        EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_WRITE, CLIENT_HELLO);
        EXPECT_EQUAL(data_size, 0);

        /* Write the ClientHello, but block on writing the Client CCS message */
        s2n_allowed_writes = 1;
        EXPECT_BLOCKED_ON_IO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked));
        EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_WRITE, CLIENT_CHANGE_CIPHER_SPEC);
        EXPECT_EQUAL(data_size, 0);

        /* Write the Client CCS message, but block on writing the early data */
        s2n_allowed_writes = 1;
        EXPECT_BLOCKED_ON_IO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked));
        EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_WRITE, SERVER_HELLO);
        EXPECT_EQUAL(data_size, 0);

        /* Write the early data, but block on reading the ServerHello */
        s2n_allowed_writes = 1;
        s2n_allowed_reads = 0;
        EXPECT_BLOCKED_ON_IO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked));
        EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_READ, SERVER_HELLO);
        EXPECT_EQUAL(data_size, sizeof(test_data));

        /* Block reading the ClientHello */
        s2n_allowed_reads = 0;
        EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_size, &blocked));
        EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, CLIENT_HELLO);
        EXPECT_EQUAL(data_size, 0);

        /* Read the ClientHello, but block on writing the ServerHello */
        s2n_allowed_reads = full_record_reads;
        s2n_allowed_writes = 0;
        EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_size, &blocked));
        EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_WRITE, SERVER_HELLO);
        EXPECT_EQUAL(data_size, 0);

        /* Write the server messages */
        while (s2n_conn_get_current_message_type(server_conn) != SERVER_FINISHED) {
            s2n_allowed_writes = 1;
            EXPECT_FAILURE_WITH_ERRNO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_size, &blocked),
                    S2N_ERR_IO_BLOCKED);
            EXPECT_EQUAL(blocked, S2N_BLOCKED_ON_WRITE);
            EXPECT_EQUAL(data_size, 0);
        };

        /* Write the last server message, but block on reading the early data */
        s2n_allowed_writes = 1;
        s2n_allowed_reads = 0;
        EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_size, &blocked));
        EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, END_OF_EARLY_DATA);
        EXPECT_EQUAL(data_size, 0);

        /* Read the Client CCS message */
        s2n_allowed_reads = full_record_reads;
        EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_size, &blocked));
        EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, END_OF_EARLY_DATA);
        EXPECT_EQUAL(data_size, 0);

        /* Read the early data */
        s2n_allowed_reads = full_record_reads;
        EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_size, &blocked));
        EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, END_OF_EARLY_DATA);
        EXPECT_EQUAL(data_size, sizeof(test_data));

        /* Read the ServerHello, but block on writing more early data */
        s2n_allowed_reads = full_record_reads;
        s2n_allowed_writes = 0;
        EXPECT_BLOCKED_ON_IO(s2n_send_early_data(client_conn, test_data, sizeof(test_data), &data_size, &blocked));
        EXPECT_BLOCKED_ON(client_conn, blocked, S2N_BLOCKED_ON_WRITE, ENCRYPTED_EXTENSIONS);
        EXPECT_EQUAL(data_size, 0);

        EXPECT_SUCCESS(s2n_connection_free(client_conn));
        EXPECT_SUCCESS(s2n_connection_free(server_conn));
    };

    /* Test blocking behavior with partial successes when sending early data.
     *
     * Parital successes should be reported to the application.
     * Partial successes should count towards the early data limit.
     */
    {
        const uint32_t max_early_data = UINT16_MAX;
        DEFER_CLEANUP(struct s2n_psk *psk_with_early_data_limit = s2n_external_psk_new(), s2n_psk_free);
        EXPECT_SUCCESS(s2n_psk_set_identity(psk_with_early_data_limit, test_data, sizeof(test_data)));
        EXPECT_SUCCESS(s2n_psk_set_secret(psk_with_early_data_limit, test_data, sizeof(test_data)));
        EXPECT_SUCCESS(s2n_psk_configure_early_data(psk_with_early_data_limit, max_early_data, 0x13, 0x01));

        DEFER_CLEANUP(struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT),
                s2n_connection_ptr_free);
        EXPECT_NOT_NULL(client_conn);
        EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(client_conn, "default_tls13"));
        EXPECT_SUCCESS(s2n_connection_append_psk(client_conn, psk_with_early_data_limit));

        DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
                s2n_connection_ptr_free);
        EXPECT_NOT_NULL(server_conn);
        EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(server_conn, "default_tls13"));
        EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, psk_with_early_data_limit));

        DEFER_CLEANUP(struct s2n_stuffer client_in = { 0 }, s2n_stuffer_free);
        DEFER_CLEANUP(struct s2n_stuffer server_in = { 0 }, s2n_stuffer_free);
        EXPECT_OK(s2n_test_set_blocking_stuffer_io(client_conn, server_conn, &client_in, &server_in));

        /* We will send more than one record worth of data,
         * so that we can block after one record worth.
         */
        uint8_t large_data[S2N_DEFAULT_FRAGMENT_LENGTH * 2] = "hello world";

        s2n_blocked_status blocked = S2N_NOT_BLOCKED;
        ssize_t data_size = 0;

        /* Block after each record write.
         * Eventually, we expect a partial success when we write one record of early data.
         * That partial success should correctly report the number of bytes written,
         * and record the correct number of early data bytes consumed.
         */
        size_t max_attempts = 100;
        size_t attempts = 0;
        while (true) {
            s2n_allowed_writes = 1;
            EXPECT_FAILURE_WITH_ERRNO(s2n_send_early_data(client_conn, large_data, sizeof(large_data), &data_size, &blocked),
                    S2N_ERR_IO_BLOCKED);

            if (data_size != 0) {
                /* We blocked on both reading the next handshake message (S2N_BLOCKED_ON_READ)
                 * and writing the early data (S2N_BLOCKED_ON_WRITE).
                 * We prefer the negotiate result.
                 */
                EXPECT_EQUAL(blocked, S2N_BLOCKED_ON_READ);

                /* Part of the early data sent */
                EXPECT_EQUAL(data_size, S2N_DEFAULT_FRAGMENT_LENGTH);
                EXPECT_EQUAL(client_conn->early_data_bytes, S2N_DEFAULT_FRAGMENT_LENGTH);
                break;
            } else {
                /* We blocked sending a handshake message,
                 * since we haven't gotten to early data yet.
                 */
                EXPECT_EQUAL(blocked, S2N_BLOCKED_ON_WRITE);

                /* No early data sent yet */
                EXPECT_EQUAL(client_conn->early_data_bytes, 0);
            }

            attempts++;
            EXPECT_TRUE(attempts < max_attempts);
        }
    };

    /* Known-value early data tests.
     * The RFC8848s ClientHello uses x25519, which is only available if evp APIs are supported.
     * Otherwise, skip these tests. */
    if (s2n_is_evp_apis_supported()) {
        DEFER_CLEANUP(struct s2n_psk resumption_psk = { 0 }, s2n_psk_wipe);
        EXPECT_OK(s2n_psk_init(&resumption_psk, S2N_PSK_TYPE_RESUMPTION));
        struct s2n_psk *known_psk = &resumption_psk;

        /**
         *= https://tools.ietf.org/rfc/rfc8448#section-3
         *= type=test
         *# {server}  generate resumption secret "tls13 resumption":
         *#
         *#    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
         *#
         *#    hash (2 octets):  00 00
         *#
         *#    info (22 octets):  00 20 10 74 6c 73 31 33 20 72 65 73 75 6d 70 74
         *#       69 6f 6e 02 00 00
         *#
         *#    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
         */
        S2N_BLOB_FROM_HEX(psk_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");

        EXPECT_SUCCESS(s2n_psk_set_secret(known_psk, psk_secret.data, psk_secret.size));

        /**
         *= https://tools.ietf.org/rfc/rfc8448#section-3
         *= type=test
         *# {server}  construct a NewSessionTicket handshake message:
         *#
         *#    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
         */
        /* Skip past the message type, message size, ticket lifetime,
         * ticket age add, nonce, and ticket size:
         *                                     04 00 00 c9 00 00 00 1e fa d6 aa
         *        c5 02 00 00 00 b2
         */
        S2N_BLOB_FROM_HEX(psk_identity, "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");
        EXPECT_SUCCESS(s2n_psk_set_identity(known_psk, psk_identity.data, psk_identity.size));
        /* Skip past the total extensions size, early data extension type,
         * and early data extension size:                         00 08 00 2a 00
         *        04
         */
        const uint32_t max_early_data = 0x00000400;
        EXPECT_SUCCESS(s2n_psk_configure_early_data(known_psk, max_early_data, 0x13, 0x01));

        /** ClientHello record
         *
         *= https://tools.ietf.org/rfc/rfc8448#section-4
         *= type=test
         *#
         *#    complete record (517 octets):  16 03 01 02 00 01 00 01 fc 03 03 1b
         *#       c3 ce b6 bb e3 9c ff 93 83 55 b5 a5 0a db 6d b2 1b 7a 6a f6 49
         *#       d7 b4 bc 41 9d 78 76 48 7d 95 00 00 06 13 01 13 03 13 02 01 00
         *#       01 cd 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01
         *#       00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02
         *#       01 03 01 04 00 33 00 26 00 24 00 1d 00 20 e4 ff b6 8a c0 5f 8d
         *#       96 c9 9d a2 66 98 34 6c 6b e1 64 82 ba dd da fe 05 1a 66 b4 f1
         *#       8d 66 8f 0b 00 2a 00 00 00 2b 00 03 02 03 04 00 0d 00 20 00 1e
         *#       04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02
         *#       01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
         *#       00 15 00 57 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
         *#       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
         *#       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
         *#       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
         *#       00 00 00 00 00 00 00 00 29 00 dd 00 b8 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 fa d6 aa cb 00 21 20 3a dd 4f b2 d8 fd f8 22 a0 ca
         *#       3c f7 67 8e f5 e8 8d ae 99 01 41 c5 92 4d 57 bb 6f a3 1b 9e 5f
         *#       9d
         */
        S2N_BLOB_FROM_HEX(ch_record, "16 03 01 02 00 01 00 01 fc 03 03 1b \
                  c3 ce b6 bb e3 9c ff 93 83 55 b5 a5 0a db 6d b2 1b 7a 6a f6 49 \
                  d7 b4 bc 41 9d 78 76 48 7d 95 00 00 06 13 01 13 03 13 02 01 00 \
                  01 cd 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 \
                  00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 \
                  01 03 01 04 00 33 00 26 00 24 00 1d 00 20 e4 ff b6 8a c0 5f 8d \
                  96 c9 9d a2 66 98 34 6c 6b e1 64 82 ba dd da fe 05 1a 66 b4 f1 \
                  8d 66 8f 0b 00 2a 00 00 00 2b 00 03 02 03 04 00 0d 00 20 00 1e \
                  04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 \
                  01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 \
                  00 15 00 57 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
                  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
                  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
                  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
                  00 00 00 00 00 00 00 00 29 00 dd 00 b8 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 fa d6 aa cb 00 21 20 3a dd 4f b2 d8 fd f8 22 a0 ca \
                  3c f7 67 8e f5 e8 8d ae 99 01 41 c5 92 4d 57 bb 6f a3 1b 9e 5f \
                  9d");

        /* ApplicationData record containing early data
         *
         *= https://tools.ietf.org/rfc/rfc8448#section-4
         *= type=test
         *# {client}  send application_data record:
         *#
         *#    payload (6 octets):  41 42 43 44 45 46
         *#
         *#    complete record (28 octets):  17 03 03 00 17 ab 1d f4 20 e7 5c 45
         *#       7a 7c c5 d2 84 4f 76 d5 ae e4 b4 ed bf 04 9b e0
         */
        S2N_BLOB_FROM_HEX(payload, "41 42 43 44 45 46");
        S2N_BLOB_FROM_HEX(early_record, "17 03 03 00 17 ab 1d f4 20 e7 5c 45 \
                  7a 7c c5 d2 84 4f 76 d5 ae e4 b4 ed bf 04 9b e0")

        /* EndOfEarlyData record
         *
         *= https://tools.ietf.org/rfc/rfc8448#section-4
         *= type=test
         *#
         *#    complete record (26 octets):  17 03 03 00 15 ac a6 fc 94 48 41 29
         *#       8d f9 95 93 72 5f 9b f9 75 44 29 b1 2f 09
         */
        S2N_BLOB_FROM_HEX(end_record, "17 03 03 00 15 ac a6 fc 94 48 41 29 \
                  8d f9 95 93 72 5f 9b f9 75 44 29 b1 2f 09");

        /* Test s2n_recv_early_data without any blocking */
        {
            struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(server_conn);
            EXPECT_SUCCESS(s2n_connection_set_blinding(server_conn, S2N_SELF_SERVICE_BLINDING));
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(server_conn, "default_tls13"));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, known_psk));
            EXPECT_SUCCESS(s2n_connection_set_server_max_early_data_size(server_conn, max_early_data));
            /* We need to explicitly set the psk_params type to skip our stateless session resumption recv 
             * code because the handshake traces we're using are meant for stateful session resumption.
             * TODO: https://github.com/aws/s2n-tls/issues/2742 */
            server_conn->psk_params.type = S2N_PSK_TYPE_EXTERNAL;

            DEFER_CLEANUP(struct s2n_stuffer input = { 0 }, s2n_stuffer_free);
            DEFER_CLEANUP(struct s2n_stuffer output = { 0 }, s2n_stuffer_free);
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, S2N_DEFAULT_RECORD_LENGTH));
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&output, S2N_DEFAULT_RECORD_LENGTH));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&input, &output, server_conn));

            EXPECT_SUCCESS(s2n_stuffer_write(&input, &ch_record));
            EXPECT_SUCCESS(s2n_stuffer_write(&input, &early_record));
            EXPECT_SUCCESS(s2n_stuffer_write(&input, &end_record));

            uint8_t actual_payload[BUFFER_SIZE] = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_read = 0;

            EXPECT_SUCCESS(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload),
                    &data_read, &blocked));
            EXPECT_NOT_BLOCKED(server_conn, blocked, CLIENT_FINISHED);
            EXPECT_EQUAL(data_read, payload.size);
            EXPECT_BYTEARRAY_EQUAL(actual_payload, payload.data, payload.size);
            EXPECT_EQUAL(server_conn->early_data_state, S2N_END_OF_EARLY_DATA);

            EXPECT_SUCCESS(s2n_stuffer_free(&input));
            EXPECT_SUCCESS(s2n_stuffer_free(&output));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };

        /* Test s2n_recv_early_data with blocking */
        {
            /* When we block, we should continue to block regardless of how many times the API is called.
             * Let's choose an arbitrary "retry" test value > 1.
             */
            const size_t repeat_count = 5;

            struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(server_conn);
            EXPECT_SUCCESS(s2n_connection_set_blinding(server_conn, S2N_SELF_SERVICE_BLINDING));
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(server_conn, "default_tls13"));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, known_psk));
            EXPECT_SUCCESS(s2n_connection_set_server_max_early_data_size(server_conn, max_early_data));
            /* We need to explicitly set the psk_params type to skip our stateless session resumption recv 
             * code because the handshake traces we're using are meant for stateful session resumption.
             * TODO: https://github.com/aws/s2n-tls/issues/2742 */
            server_conn->psk_params.type = S2N_PSK_TYPE_EXTERNAL;

            DEFER_CLEANUP(struct s2n_stuffer input = { 0 }, s2n_stuffer_free);
            DEFER_CLEANUP(struct s2n_stuffer output = { 0 }, s2n_stuffer_free);
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, S2N_DEFAULT_RECORD_LENGTH));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&input, &output, server_conn));

            uint8_t actual_payload[BUFFER_SIZE] = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_read = 0;

            for (size_t i = 0; i < repeat_count; i++) {
                EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_read, &blocked));
                EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, CLIENT_HELLO);
                EXPECT_EQUAL(data_read, 0);
            }

            EXPECT_SUCCESS(s2n_stuffer_write(&input, &ch_record));

            for (size_t i = 0; i < repeat_count; i++) {
                EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_read, &blocked));
                EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_WRITE, SERVER_HELLO);
                EXPECT_EQUAL(data_read, 0);
            }

            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&output, S2N_DEFAULT_RECORD_LENGTH));

            for (size_t i = 0; i < repeat_count; i++) {
                EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_read, &blocked));
                EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, END_OF_EARLY_DATA);
                EXPECT_EQUAL(data_read, 0);
            }
            EXPECT_EQUAL(server_conn->early_data_state, S2N_EARLY_DATA_ACCEPTED);

            EXPECT_SUCCESS(s2n_stuffer_write(&input, &early_record));

            EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_read, &blocked));
            EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, END_OF_EARLY_DATA);
            EXPECT_EQUAL(data_read, payload.size);
            EXPECT_BYTEARRAY_EQUAL(actual_payload, payload.data, payload.size);

            for (size_t i = 0; i < repeat_count; i++) {
                EXPECT_BLOCKED_ON_IO(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload), &data_read, &blocked));
                EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, END_OF_EARLY_DATA);
                EXPECT_EQUAL(data_read, 0);
            }
            EXPECT_EQUAL(server_conn->early_data_state, S2N_EARLY_DATA_ACCEPTED);

            EXPECT_SUCCESS(s2n_stuffer_write(&input, &end_record));

            for (size_t i = 0; i < repeat_count; i++) {
                EXPECT_SUCCESS(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload),
                        &data_read, &blocked));
                EXPECT_NOT_BLOCKED(server_conn, blocked, CLIENT_FINISHED);
                EXPECT_EQUAL(data_read, 0);
                EXPECT_EQUAL(server_conn->early_data_state, S2N_END_OF_EARLY_DATA);
            }

            EXPECT_BLOCKED_ON_IO(s2n_negotiate(server_conn, &blocked));
            EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, CLIENT_FINISHED);
            EXPECT_EQUAL(server_conn->early_data_state, S2N_END_OF_EARLY_DATA);

            EXPECT_SUCCESS(s2n_stuffer_free(&input));
            EXPECT_SUCCESS(s2n_stuffer_free(&output));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };

        /* Test s2n_recv_early_data when early data not allowed for PSK */
        {
            struct s2n_psk psk_copy = *known_psk;
            EXPECT_SUCCESS(s2n_psk_configure_early_data(&psk_copy, 0, 0x13, 0x01));
            struct s2n_psk *known_psk_without_early_data = &psk_copy;

            struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(server_conn);
            EXPECT_SUCCESS(s2n_connection_set_blinding(server_conn, S2N_SELF_SERVICE_BLINDING));
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(server_conn, "default_tls13"));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, known_psk_without_early_data));
            EXPECT_SUCCESS(s2n_connection_set_server_max_early_data_size(server_conn, max_early_data));
            /* We need to explicitly set the psk_params type to skip our stateless session resumption recv 
             * code because the handshake traces we're using are meant for stateful session resumption.
             * TODO: https://github.com/aws/s2n-tls/issues/2742 */
            server_conn->psk_params.type = S2N_PSK_TYPE_EXTERNAL;

            DEFER_CLEANUP(struct s2n_stuffer input = { 0 }, s2n_stuffer_free);
            DEFER_CLEANUP(struct s2n_stuffer output = { 0 }, s2n_stuffer_free);
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, S2N_DEFAULT_RECORD_LENGTH));
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&output, S2N_DEFAULT_RECORD_LENGTH));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&input, &output, server_conn));

            EXPECT_SUCCESS(s2n_stuffer_write(&input, &ch_record));
            EXPECT_SUCCESS(s2n_stuffer_write(&input, &early_record));
            EXPECT_SUCCESS(s2n_stuffer_write(&input, &end_record));

            uint8_t actual_payload[BUFFER_SIZE] = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_read = 0;

            EXPECT_SUCCESS(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload),
                    &data_read, &blocked));
            EXPECT_NOT_BLOCKED(server_conn, blocked, CLIENT_HELLO);
            EXPECT_EQUAL(data_read, 0);

            EXPECT_BLOCKED_ON_IO(s2n_negotiate(server_conn, &blocked));
            EXPECT_BLOCKED_ON(server_conn, blocked, S2N_BLOCKED_ON_READ, CLIENT_FINISHED);
            EXPECT_EQUAL(server_conn->early_data_state, S2N_EARLY_DATA_REJECTED);

            EXPECT_SUCCESS(s2n_stuffer_free(&input));
            EXPECT_SUCCESS(s2n_stuffer_free(&output));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };

        /* Test s2n_recv_early_data when early data rejected */
        {
            struct s2n_psk psk_copy = *known_psk;
            EXPECT_SUCCESS(s2n_psk_configure_early_data(&psk_copy, max_early_data, 0x13, 0x03));
            struct s2n_psk *known_psk_with_wrong_cipher_suite = &psk_copy;

            struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
            EXPECT_NOT_NULL(server_conn);
            EXPECT_SUCCESS(s2n_connection_set_blinding(server_conn, S2N_SELF_SERVICE_BLINDING));
            EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(server_conn, "default_tls13"));
            EXPECT_SUCCESS(s2n_connection_append_psk(server_conn, known_psk_with_wrong_cipher_suite));
            EXPECT_SUCCESS(s2n_connection_set_server_max_early_data_size(server_conn, max_early_data));
            /* We need to explicitly set the psk_params type to skip our stateless session resumption recv 
             * code because the handshake traces we're using are meant for stateful session resumption.
             * TODO: https://github.com/aws/s2n-tls/issues/2742 */
            server_conn->psk_params.type = S2N_PSK_TYPE_EXTERNAL;

            DEFER_CLEANUP(struct s2n_stuffer input = { 0 }, s2n_stuffer_free);
            DEFER_CLEANUP(struct s2n_stuffer output = { 0 }, s2n_stuffer_free);
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, S2N_DEFAULT_RECORD_LENGTH));
            EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&output, S2N_DEFAULT_RECORD_LENGTH));
            EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&input, &output, server_conn));

            EXPECT_SUCCESS(s2n_stuffer_write(&input, &ch_record));
            EXPECT_SUCCESS(s2n_stuffer_write(&input, &early_record));
            EXPECT_SUCCESS(s2n_stuffer_write(&input, &end_record));

            uint8_t actual_payload[BUFFER_SIZE] = { 0 };
            s2n_blocked_status blocked = S2N_NOT_BLOCKED;
            ssize_t data_read = 0;

            EXPECT_SUCCESS(s2n_recv_early_data(server_conn, actual_payload, sizeof(actual_payload),
                    &data_read, &blocked));
            EXPECT_NOT_BLOCKED(server_conn, blocked, CLIENT_FINISHED);
            EXPECT_EQUAL(data_read, 0);
            EXPECT_EQUAL(server_conn->early_data_state, S2N_EARLY_DATA_REJECTED);

            EXPECT_SUCCESS(s2n_stuffer_free(&input));
            EXPECT_SUCCESS(s2n_stuffer_free(&output));
            EXPECT_SUCCESS(s2n_connection_free(server_conn));
        };
    }

    END_TEST();
}
