From 02f07322b3e2d0880441f65a35b9566d41761b5a Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 25 Jun 2026 21:36:11 +0200 Subject: [PATCH] quic: add support for custom app ticket data config & 0RTT validation Signed-off-by: Tim Perry --- doc/api/quic.md | 25 +++- lib/internal/quic/quic.js | 22 ++++ src/quic/application.cc | 44 ++++++- src/quic/application.h | 18 ++- src/quic/bindingdata.h | 1 + src/quic/session.cc | 23 ++-- src/quic/session.h | 7 ++ test/parallel/test-quic-appticketdata.mjs | 140 ++++++++++++++++++++++ 8 files changed, 261 insertions(+), 19 deletions(-) create mode 100644 test/parallel/test-quic-appticketdata.mjs diff --git a/doc/api/quic.md b/doc/api/quic.md index d36825d6943264..35fa21518fb7bb 100644 --- a/doc/api/quic.md +++ b/doc/api/quic.md @@ -379,7 +379,9 @@ Two pieces of state from a prior connection make this possible: If the server accepts the session ticket, any data sent before the handshake completes is 0-RTT early data. On the server side, `stream.early` is `true` for streams carrying early data. The server can reject the 0-RTT attempt -(for example, if its configuration has changed since the ticket was issued). +(for example, if its configuration has changed since the ticket was issued); +[`sessionOptions.appTicketData`][] lets a server gate this explicitly, rejecting +early data whose ticket does not exactly match the server's current value. When this happens, all streams opened during the 0-RTT phase are destroyed and the client's [`session.onearlyrejected`][] callback fires. The connection falls back to a normal 1-RTT handshake and the application can reopen streams. @@ -2880,6 +2882,26 @@ await listen((session) => { /* ... */ }, { }); ``` +#### `sessionOptions.appTicketData` (server only) + + + +* Type: {ArrayBufferView} + +Opaque application data to embed in the session tickets this server issues. +On resumption, the data carried by the presented ticket is compared +against the value currently configured here; if it does not match exactly, +the ticket's 0-RTT early data is rejected and the connection falls back to a +full 1-RTT handshake. Use it to bind 0-RTT acceptance to server-side state +that must agree between the original and resumed connection - rotating the +value invalidates the 0-RTT of all previously issued tickets. + +This applies to the default QUIC application. HTTP/3 sessions carry their own +session-ticket data, so `appTicketData` is ignored when the negotiated ALPN +is `h3`. + #### `sessionOptions.ca` (client only)