How XQUIC Handles TLS Session Resumption: Architecture and Implementation Guide
XQUIC implements TLS 1.3 session resumption using session tickets, where the server generates tickets via OpenSSL callbacks, forwards them to applications through save_session_cb, and clients load persisted tickets into xqc_conn_ssl_config_t.session_ticket to enable 0-RTT handshakes.
Alibaba's XQUIC library provides a complete implementation of QUIC protocol with optimized TLS 1.3 integration. Understanding how XQUIC handles TLS session resumption is essential for building high-performance applications that minimize connection latency through 0-RTT data transmission.
The TLS Session Resumption Architecture
XQUIC's session resumption flow relies on three coordinated components that bridge OpenSSL's TLS layer with the transport implementation:
| Component | Source File | Key Function |
|---|---|---|
| TLS Context | src/tls/xqc_tls_ctx.c |
Sets up SSL_CTX, registers ticket-key callbacks (SSL_CTX_set_tlsext_ticket_key_cb), and enables client session caching. |
| TLS Instance | src/tls/xqc_tls.c |
Implements xqc_ssl_new_session_cb for ticket generation and xqc_tls_cli_set_session_data for ticket loading. |
| Transport Glue | src/transport/xqc_conn.c |
Bridges TLS callbacks to user-defined save_session_cb via xqc_conn_tls_session_cb. |
This architecture ensures that session tickets flow securely from the TLS stack through the transport layer to application-level storage.
Server-Side Session Ticket Generation
When a TLS handshake completes, XQUIC generates a new session ticket through OpenSSL's new-session callback mechanism. In xqc_create_server_ssl_ctx (src/tls/xqc_tls_ctx.c, lines 60-64), the library registers the callback:
SSL_CTX_sess_set_new_cb(ssl_ctx, xqc_ssl_new_session_cb);
The callback implementation resides in src/tls/xqc_tls.c (lines 977-1004). The xqc_ssl_new_session_cb function performs three critical operations:
- Validates early data permissions using
xqc_ssl_session_is_early_data_enabled - Serializes the session into PEM format via memory BIO
- Invokes the application callback stored in
tls->cbs->session_cb
if (tls->cbs->session_cb != NULL) {
BIO *bio = BIO_new(BIO_s_mem());
PEM_write_bio_SSL_SESSION(bio, session);
size_t data_len = BIO_get_mem_data(bio, &data);
tls->cbs->session_cb(data, data_len, tls->user_data);
BIO_free(bio);
}
Application-Level Ticket Storage
The transport layer bridges the TLS callback to user-space storage. During connection initialization in src/transport/xqc_conn.c (line 6370), XQUIC wires the TLS session callback to the transport handler:
.conn_cbs.session_cb = xqc_conn_tls_session_cb,
The xqc_conn_tls_session_cb function forwards tickets to the application's save_session_cb:
void xqc_conn_tls_session_cb(const char *data, size_t data_len, void *user_data) {
xqc_connection_t *conn = (xqc_connection_t *)user_data;
conn->transport_cbs.save_session_cb(data, data_len, conn->user_data);
}
Applications must implement save_session_cb (defined as xqc_save_session_pt in include/xquic/xquic.h) to persist tickets to disk, database, or shared cache.
Client-Side Session Resumption and 0-RTT
To resume a session, the client loads a previously stored ticket into the connection configuration before initiating the handshake. In src/transport/xqc_client.c (lines 78-88), xqc_client_create_tls copies the ticket data:
cfg.session_ticket = xqc_malloc(conn_ssl_config->session_ticket_len + 1);
xqc_memcpy(cfg.session_ticket, conn_ssl_config->session_ticket_data,
conn_ssl_config->session_ticket_len);
cfg.session_ticket_len = conn_ssl_config->session_ticket_len;
During TLS initialization (xqc_tls_init_client_ssl), XQUIC injects the ticket via xqc_tls_cli_set_session_data (src/tls/xqc_tls.c, lines 22-30):
if (cfg->session_ticket && cfg->session_ticket_len > 0) {
if (xqc_tls_cli_set_session_data(tls, cfg->session_ticket,
cfg->session_ticket_len) == XQC_OK) {
tls->resumption = XQC_TRUE;
xqc_ssl_enable_max_early_data(ssl);
}
}
The xqc_tls_cli_set_session_data function loads the PEM ticket into an SSL_SESSION object and calls SSL_set_session. It also validates ticket expiration through xqc_tls_check_session_ticket_timeout. When successful, the client sets tls->resumption to true and enables 0-RTT data transmission.
Server-Side Ticket Key Management
Server instances require consistent ticket encryption keys to decrypt tickets across restarts or load-balanced deployments. XQUIC loads the session ticket key from engine configuration in xqc_tls_ctx_set_config (src/tls/xqc_tls_ctx.c, lines 268-280), storing it in xqc_tls_ctx_t.session_ticket_key.
The key is utilized by xqc_ssl_session_ticket_key_cb (src/tls/xqc_tls.c, lines 898-907), which OpenSSL invokes when encrypting or decrypting session tickets. This callback ensures that all servers in a cluster can validate tickets issued by peers sharing the same key material.
Complete Implementation Example
The following example demonstrates the application callbacks required for full session resumption support:
/* Application callback to persist session tickets */
static void save_session_cb(const char *data, size_t data_len, void *user_data) {
FILE *fp = fopen("session.ticket", "wb");
if (fp) {
fwrite(data, 1, data_len, fp);
fclose(fp);
}
}
/* Helper to load persisted tickets */
static xqc_int_t load_session_ticket(xqc_conn_ssl_config_t *cfg) {
FILE *fp = fopen("session.ticket", "rb");
if (!fp) return -XQC_EMALLOC;
fseek(fp, 0, SEEK_END);
long len = ftell(fp);
fseek(fp, 0, SEEK_SET);
unsigned char *buf = xqc_malloc(len);
if (!buf) { fclose(fp); return -XQC_EMALLOC; }
fread(buf, 1, len, fp);
fclose(fp);
cfg->session_ticket = buf;
cfg->session_ticket_len = (size_t)len;
return XQC_OK;
}
/* Connection setup with session resumption */
xqc_conn_ssl_config_t cfg = {0};
cfg.save_session_cb = save_session_cb;
/* Load previous ticket for resumption */
load_session_ticket(&cfg);
xqc_connection_t *conn = xqc_client_create_connection(
engine, dcid, scid, &settings, "example.com", 0, &cfg, "h3", NULL);
This implementation ensures that session tickets are preserved across application restarts, enabling subsequent connections to skip the full TLS handshake.
Summary
- XQUIC uses TLS 1.3 session tickets rather than session IDs for resumption, implemented through OpenSSL callbacks in
src/tls/xqc_tls.c. - Server ticket generation occurs in
xqc_ssl_new_session_cb, which serializes sessions to PEM and forwards them via the transport layer callbackxqc_conn_tls_session_cb. - Application integration requires implementing
save_session_cbto persist tickets and populatingxqc_conn_ssl_config_t.session_ticketbefore connection creation. - 0-RTT capability is automatically enabled when valid tickets are loaded via
xqc_tls_cli_set_session_data, which setstls->resumption = XQC_TRUE. - Ticket encryption relies on configurable keys set through
xqc_tls_ctx_set_config, allowing multi-instance deployments to share session state.
Frequently Asked Questions
What TLS version does XQUIC use for session resumption?
XQUIC implements TLS 1.3 session resumption exclusively. The codebase relies on TLS 1.3-specific features such as 0-RTT data and the SSL_CTX_sess_set_new_cb callback mechanism for ticket-based resumption, as defined in RFC 8446.
How does XQUIC handle session ticket expiration?
XQUIC validates ticket freshness through xqc_tls_check_session_ticket_timeout when loading sessions via xqc_tls_cli_set_session_data. Expired tickets are rejected, forcing a full handshake. Applications should implement rotation strategies for the session_ticket_key to ensure security while maintaining cluster-wide ticket validity periods.
Can XQUIC resume sessions across different server instances?
Yes, provided all instances share the same session ticket key. The key is configured through the engine's TLS context setup (xqc_tls_ctx_set_config in src/tls/xqc_tls_ctx.c) and used by xqc_ssl_session_ticket_key_cb for encryption and decryption. Without shared keys, tickets issued by one server will be rejected by others.
What callback must applications implement to save session tickets?
Applications must implement the xqc_save_session_pt callback (typically named save_session_cb) and register it in xqc_conn_ssl_config_t. This callback receives the serialized ticket data when xqc_ssl_new_session_cb generates a new ticket, allowing persistent storage for subsequent connection attempts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →