in tls/s2n_server_new_session_ticket.c [175:242]
S2N_RESULT s2n_tls13_server_nst_send(struct s2n_connection *conn, s2n_blocked_status *blocked)
{
RESULT_ENSURE_REF(conn);
RESULT_ENSURE_GTE(conn->actual_protocol_version, S2N_TLS13);
/* Usually tickets are sent immediately after the handshake.
* If possible, reuse the handshake IO stuffer before it's wiped.
*
* Note: handshake.io isn't explicitly dedicated to only reading or only writing,
* so we have to be careful using it outside of s2n_negotiate.
* If we use it for writing here, we CAN'T use it for reading any post-handshake messages.
*/
struct s2n_stuffer *nst_stuffer = &conn->handshake.io;
if (conn->mode != S2N_SERVER || !conn->config->use_tickets) {
return S2N_RESULT_OK;
}
/* Legacy behavior is that the s2n server sends a NST even if the client did not indicate support
* for resumption or does not support the psk_dhe_ke mode. This is potentially wasteful so we
* choose to not extend this behavior to QUIC.
*/
if (conn->quic_enabled && conn->psk_params.psk_ke_mode != S2N_PSK_DHE_KE) {
return S2N_RESULT_OK;
}
/* No-op if all tickets already sent.
* Clean up the stuffer used for the ticket to conserve memory. */
if (conn->tickets_to_send == conn->tickets_sent) {
RESULT_GUARD_POSIX(s2n_stuffer_resize(nst_stuffer, 0));
return S2N_RESULT_OK;
}
/**
*= https://www.rfc-editor.org/rfc/rfc8446#section-4.6.1
*# 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.
*/
if (s2n_result_is_error(s2n_psk_validate_keying_material(conn))) {
conn->tickets_to_send = conn->tickets_sent;
return S2N_RESULT_OK;
}
RESULT_ENSURE(conn->tickets_sent <= conn->tickets_to_send, S2N_ERR_INTEGER_OVERFLOW);
size_t session_state_size = 0;
RESULT_GUARD(s2n_connection_get_session_state_size(conn, &session_state_size));
const size_t maximum_nst_size = session_state_size + S2N_TLS13_MAX_FIXED_NEW_SESSION_TICKET_SIZE;
if (s2n_stuffer_space_remaining(nst_stuffer) < maximum_nst_size) {
RESULT_GUARD_POSIX(s2n_stuffer_resize(nst_stuffer, maximum_nst_size));
}
while (conn->tickets_to_send - conn->tickets_sent > 0) {
if (s2n_result_is_error(s2n_tls13_server_nst_write(conn, nst_stuffer))) {
return S2N_RESULT_OK;
}
RESULT_GUARD(s2n_post_handshake_write_records(conn, blocked));
}
return S2N_RESULT_OK;
}