int s2n_connection_wipe()

in tls/s2n_connection.c [467:614]


int s2n_connection_wipe(struct s2n_connection *conn)
{
    POSIX_ENSURE_REF(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 client_ticket_to_decrypt = { 0 };
    struct s2n_stuffer handshake_io = { 0 };
    struct s2n_stuffer header_in = { 0 };
    struct s2n_stuffer buffer_in = { 0 };
    struct s2n_stuffer out = { 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;
    if (!conn->initial) {
        POSIX_GUARD_RESULT(s2n_crypto_parameters_new(&conn->initial));
    } else {
        POSIX_GUARD_RESULT(s2n_crypto_parameters_wipe(conn->initial));
    }
    struct s2n_crypto_parameters *initial = conn->initial;
    if (!conn->secure) {
        POSIX_GUARD_RESULT(s2n_crypto_parameters_new(&conn->secure));
    } else {
        POSIX_GUARD_RESULT(s2n_crypto_parameters_wipe(conn->secure));
    }
    struct s2n_crypto_parameters *secure = conn->secure;

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

    /* Free stuffers we plan to just recreate */
    POSIX_GUARD(s2n_stuffer_free(&conn->post_handshake.in));
    POSIX_GUARD(s2n_stuffer_free(&conn->in));

    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));
    POSIX_GUARD(s2n_free(&conn->cookie));

    /* 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_free(&conn->client_hello.raw_message));
    POSIX_GUARD(s2n_stuffer_resize(&conn->buffer_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 address warnings because dest is allocated on the stack */
#ifdef S2N_DIAGNOSTICS_PUSH_SUPPORTED
    #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(&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(&header_in, &conn->header_in, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&buffer_in, &conn->buffer_in, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&out, &conn->out, sizeof(struct s2n_stuffer));
#ifdef S2N_DIAGNOSTICS_POP_SUPPORTED
    #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->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->header_in, &header_in, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&conn->buffer_in, &buffer_in, sizeof(struct s2n_stuffer));
    POSIX_CHECKED_MEMCPY(&conn->out, &out, sizeof(struct s2n_stuffer));

    /* conn->in will eventually point to part of conn->buffer_in, but we initialize
     * it as growable and allocated to support legacy tests.
     */
    POSIX_GUARD(s2n_stuffer_growable_alloc(&conn->in, 0));

    conn->handshake.hashes = handshake_hashes;
    conn->prf_space = prf_workspace;
    conn->initial = initial;
    conn->secure = secure;
    conn->client = conn->initial;
    conn->server = conn->initial;
    conn->handshake_params.client_cert_sig_scheme = &s2n_null_sig_scheme;
    conn->handshake_params.server_cert_sig_scheme = &s2n_null_sig_scheme;

    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;
    }

    /* Initialize remaining values */
    conn->blinding = S2N_BUILT_IN_BLINDING;
    conn->session_ticket_status = S2N_NO_TICKET;

    return 0;
}