Skip to content

Merge branch 'main' into doogie/quic-proof-source-update

d7a87e4
Select commit
Loading
Failed to load commit list.
Open

quic: add TLS session ticket resumption support #42734

Merge branch 'main' into doogie/quic-proof-source-update
d7a87e4
Select commit
Loading
Failed to load commit list.
CI (Envoy) / Mobile/Coverage skipped Apr 28, 2026 in 0s

Check was skipped

This check was not triggered in this CI run

Details

Request (pr/42734/main@d7a87e4)

bellatoris @bellatoris d7a87e4 #42734 merge main@27ea276

quic: add TLS session ticket resumption support

Commit Message: quic: add session ticket resumption support using configured session ticket keys
Additional Description:

Summary

TLS session resumption is essential for QUIC performance. Without it, every connection requires a full TLS handshake, and 0-RTT becomes meaningless since there's no session state to resume from. As noted in #42682, TLS-related data accounts for roughly 1/3 of bytes during connection establishment - session resumption eliminates most of this overhead.

Currently, Envoy's QUIC implementation does not support session resumption across workers or processes. While users can configure session_ticket_keys or session_ticket_keys_sds_secret_config in downstream TLS context, these settings have no effect on QUIC connections. This limitation is documented in #25418, which explicitly states that session ticket key plumbing is missing from the QUIC implementation.

This PR bridges that gap by enabling QUIC to use the same session ticket keys configured for TCP TLS, allowing session resumption to work across workers and processes.

Implementation

We subclass QUICHE's TlsServerHandshaker as EnvoyTlsServerHandshaker and install a session-ticket key callback on the shared QUICHE SSL_CTX. The callback reuses ServerContextImpl::sessionTicketProcess() so QUIC and TCP TLS share identical session-ticket handling (same keys, same format, same rotation semantics).

Key design decisions:

  1. Per-connection pinning of ServerContextImpl: Each EnvoyTlsServerHandshaker holds a ServerContextSharedPtr captured at connection creation, and stores this in SSL ex_data. The static ticket callback retrieves the handshaker from ex_data and delegates to the pinned context's sessionTicketProcess(). Because the shared pointer keeps the context alive, an SDS update that rotates the factory's active context does not invalidate in-flight connections — matching TCP TLS behavior where each connection is bound to the ServerContextImpl active at connection creation.

  2. SSL_CTX_set_tlsext_ticket_key_cb over SSL_CTX_set_ticket_aead_method: We use the same callback mechanism as TCP TLS rather than QUICHE's TicketCrypter interface, so ServerContextImpl::sessionTicketProcess() can be reused unchanged.

  3. Graceful fallback: If the runtime guard is toggled between OnNewSslCtx (which installs the callback on the shared SSL_CTX) and connection creation (which may fall back to the vanilla handshaker), the ticket callback finds a null handshaker in ex_data and returns 0 to skip ticket issuance for that connection rather than crashing.

Flow

Server startup (once per SSL_CTX):
  EnvoyQuicProofSource::OnNewSslCtx()
    └─ if runtime flag on:
         SSL_CTX_set_tlsext_ticket_key_cb(ssl_ctx, EnvoyTlsServerHandshaker::ticketKeyCallback)

Per connection:
  EnvoyQuicCryptoServerStreamFactoryImpl::createEnvoyQuicCryptoServerStream()
    └─ reads SessionTicketConfig from QuicServerTransportSocketFactory
    └─ constructs EnvoyTlsServerHandshaker(session, crypto_config, factory.sslCtx(), disable_resumption)
         └─ pins ServerContextSharedPtr
         └─ SSL_set_ex_data(ssl, handshakerExDataIndex(), this)
         └─ if disable_resumption || no ticket keys: DisableResumption()  // SSL_OP_NO_TICKET

During handshake (BoringSSL-driven):
  ticketKeyCallback(ssl, ...)
    └─ handshaker = SSL_get_ex_data(ssl, handshakerExDataIndex())
    └─ if null: return 0  // guard toggled after OnNewSslCtx — skip ticket
    └─ return handshaker->pinnedServerContext()->sessionTicketProcess(ssl, ...)

Risk Level: Low (behind runtime guard, disabled by default)
Testing: New unit tests for EnvoyTlsServerHandshaker and EnvoyQuicProofSource; new integration coverage in sds_dynamic_integration_test (SessionTicketKeysViaSds, SessionTicketKeysRemovedViaSds) and in quic_http_integration_test (SessionTicketResumptionWithStaticKeys, NoSessionTicketResumptionWithoutKeys).
Docs Changes: N/A
Release Notes: Added
Platform Specific Features: N/A
[Optional Runtime guard:] envoy.reloadable_features.quic_session_ticket_support (default: false)
[Optional Fixes #Issue] Partially addresses #25418

Environment

Request variables

Key Value
ref dd8ba6f
sha d7a87e4
pr 42734
base-sha 27ea276
actor bellatoris @bellatoris
message quic: add TLS session ticket resumption support...
started 1777336846.015763
target-branch main
trusted false
Build image

Container image/s (as used in this CI run)

Key Value
default docker.io/envoyproxy/envoy-build:86873047235e9b8232df989a5999b9bebf9db69c
mobile docker.io/envoyproxy/envoy-build:mobile-86873047235e9b8232df989a5999b9bebf9db69c
Version

Envoy version (as used in this CI run)

Key Value
major 1
minor 39
patch 0
dev true