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