int s2n_connection_wipe()

in tls/s2n_connection.c [514:661]


int s2n_connection_wipe(struct s2n_connection *conn)
{
    /* First make a copy of everything we'd like to save, which isn't very much. */
    int mode = conn->mode;
    struct s2n_config *config = conn->config;
    struct s2n_stuffer alert_in = {0};
    struct s2n_stuffer reader_alert_out = {0};
    struct s2n_stuffer writer_alert_out = {0};
    struct s2n_stuffer client_ticket_to_decrypt = {0};
    struct s2n_stuffer handshake_io = {0};
    struct s2n_stuffer client_hello_raw_message = {0};
    struct s2n_stuffer header_in = {0};
    struct s2n_stuffer in = {0};
    struct s2n_stuffer out = {0};
    /* Session keys will be wiped. Preserve structs to avoid reallocation */
    struct s2n_session_key initial_client_key = {0};
    struct s2n_session_key initial_server_key = {0};
    struct s2n_session_key secure_client_key = {0};
    struct s2n_session_key secure_server_key = {0};
    /* Parts of the hmac states will be wiped. Preserve structs to avoid reallocation */
    struct s2n_connection_hmac_handles hmac_handles = {0};

    /* Some required structures might have been freed to conserve memory between handshakes.
     * Restore them.
     */

    if (!conn->handshake.hashes) {
        POSIX_GUARD_RESULT(s2n_handshake_hashes_new(&conn->handshake.hashes));
    }
    POSIX_GUARD_RESULT(s2n_handshake_hashes_wipe(conn->handshake.hashes));
    struct s2n_handshake_hashes *handshake_hashes = conn->handshake.hashes;

    if (!conn->prf_space) {
        POSIX_GUARD_RESULT(s2n_prf_new(conn));
    }
    POSIX_GUARD_RESULT(s2n_prf_wipe(conn));
    struct s2n_prf_working_space *prf_workspace = conn->prf_space;

    /* Wipe all of the sensitive stuff */
    POSIX_GUARD(s2n_connection_wipe_keys(conn));
    POSIX_GUARD(s2n_connection_reset_hmacs(conn));
    POSIX_GUARD(s2n_stuffer_wipe(&conn->alert_in));
    POSIX_GUARD(s2n_stuffer_wipe(&conn->reader_alert_out));
    POSIX_GUARD(s2n_stuffer_wipe(&conn->writer_alert_out));
    POSIX_GUARD(s2n_stuffer_wipe(&conn->client_ticket_to_decrypt));
    POSIX_GUARD(s2n_stuffer_wipe(&conn->handshake.io));
    POSIX_GUARD(s2n_stuffer_wipe(&conn->client_hello.raw_message));
    POSIX_GUARD(s2n_stuffer_wipe(&conn->header_in));
    POSIX_GUARD(s2n_stuffer_wipe(&conn->in));
    POSIX_GUARD(s2n_stuffer_wipe(&conn->out));

    POSIX_GUARD_RESULT(s2n_psk_parameters_wipe(&conn->psk_params));

    /* Wipe the I/O-related info and restore the original socket if necessary */
    POSIX_GUARD(s2n_connection_wipe_io(conn));

    POSIX_GUARD(s2n_free(&conn->client_ticket));
    POSIX_GUARD(s2n_free(&conn->status_response));
    POSIX_GUARD(s2n_free(&conn->application_protocols_overridden));
    POSIX_GUARD(s2n_free(&conn->our_quic_transport_parameters));
    POSIX_GUARD(s2n_free(&conn->peer_quic_transport_parameters));
    POSIX_GUARD(s2n_free(&conn->server_early_data_context));
    POSIX_GUARD(s2n_free(&conn->tls13_ticket_fields.session_secret));

    /* Allocate memory for handling handshakes */
    POSIX_GUARD(s2n_stuffer_resize(&conn->handshake.io, S2N_LARGE_RECORD_LENGTH));

    /* Truncate the message buffers to save memory, we will dynamically resize it as needed */
    POSIX_GUARD(s2n_stuffer_resize(&conn->client_hello.raw_message, 0));
    POSIX_GUARD(s2n_stuffer_resize(&conn->in, 0));
    POSIX_GUARD(s2n_stuffer_resize(&conn->out, 0));

    /* Remove context associated with connection */
    conn->context = NULL;
    conn->verify_host_fn_overridden = 0;
    conn->verify_host_fn = NULL;
    conn->data_for_verify_host = NULL;

    /* Clone the stuffers */
    /* ignore gcc 4.7 address warnings because dest is allocated on the stack */
    /* pragma gcc diagnostic was added in gcc 4.6 */
#if S2N_GCC_VERSION_AT_LEAST(4,6,0)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Waddress"
#endif
    POSIX_CHECKED_MEMCPY(&alert_in, &conn->alert_in, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&reader_alert_out, &conn->reader_alert_out, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&writer_alert_out, &conn->writer_alert_out, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&client_ticket_to_decrypt, &conn->client_ticket_to_decrypt, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&handshake_io, &conn->handshake.io, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&client_hello_raw_message, &conn->client_hello.raw_message, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&header_in, &conn->header_in, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&in, &conn->in, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&out, &conn->out, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&initial_client_key, &conn->initial.client_key, sizeof(struct s2n_session_key));
    POSIX_CHECKED_MEMCPY(&initial_server_key, &conn->initial.server_key, sizeof(struct s2n_session_key));
    POSIX_CHECKED_MEMCPY(&secure_client_key, &conn->secure.client_key, sizeof(struct s2n_session_key));
    POSIX_CHECKED_MEMCPY(&secure_server_key, &conn->secure.server_key, sizeof(struct s2n_session_key));
    POSIX_GUARD(s2n_connection_save_hmac_state(&hmac_handles, conn));
#if S2N_GCC_VERSION_AT_LEAST(4,6,0)
#pragma GCC diagnostic pop
#endif

    POSIX_GUARD(s2n_connection_zero(conn, mode, config));

    POSIX_CHECKED_MEMCPY(&conn->alert_in, &alert_in, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&conn->reader_alert_out, &reader_alert_out, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&conn->writer_alert_out, &writer_alert_out, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&conn->client_ticket_to_decrypt, &client_ticket_to_decrypt, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&conn->handshake.io, &handshake_io, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&conn->client_hello.raw_message, &client_hello_raw_message, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&conn->header_in, &header_in, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&conn->in, &in, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&conn->out, &out, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&conn->initial.client_key, &initial_client_key, sizeof(struct s2n_session_key));
    POSIX_CHECKED_MEMCPY(&conn->initial.server_key, &initial_server_key, sizeof(struct s2n_session_key));
    POSIX_CHECKED_MEMCPY(&conn->secure.client_key, &secure_client_key, sizeof(struct s2n_session_key));
    POSIX_CHECKED_MEMCPY(&conn->secure.server_key, &secure_server_key, sizeof(struct s2n_session_key));
    POSIX_GUARD(s2n_connection_restore_hmac_state(conn, &hmac_handles));
    conn->handshake.hashes = handshake_hashes;
    conn->prf_space = prf_workspace;

    /* Re-initialize hash and hmac states */
    POSIX_GUARD(s2n_connection_init_hmacs(conn));

    POSIX_GUARD_RESULT(s2n_psk_parameters_init(&conn->psk_params));
    conn->server_keying_material_lifetime = ONE_WEEK_IN_SEC;

    /* Require all handshakes hashes. This set can be reduced as the handshake progresses. */
    POSIX_GUARD(s2n_handshake_require_all_hashes(&conn->handshake));

    if (conn->mode == S2N_SERVER) {
        /* Start with the highest protocol version so that the highest common protocol version can be selected */
        /* during handshake. */
        conn->server_protocol_version = s2n_highest_protocol_version;
        conn->client_protocol_version = s2n_unknown_protocol_version;
        conn->actual_protocol_version = s2n_unknown_protocol_version;
    }
    else {
        /* For clients, also set actual_protocol_version.  Record generation uses that value for the initial */
        /* ClientHello record version. Not all servers ignore the record version in ClientHello. */
        conn->server_protocol_version = s2n_unknown_protocol_version;
        conn->client_protocol_version = s2n_highest_protocol_version;
        conn->actual_protocol_version = s2n_highest_protocol_version;
    }

    return 0;
}