S2N_RESULT s2n_tls13_server_nst_send()

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