Harden TLS 1.3 NewSessionTicket handling per RFC 9846 - #11178
Draft
julek-wolfssl wants to merge 5 commits into
Draft
Harden TLS 1.3 NewSessionTicket handling per RFC 9846#11178julek-wolfssl wants to merge 5 commits into
julek-wolfssl wants to merge 5 commits into
Conversation
RFC 9846 Section 4.3.9 says psk_key_exchange_modes restricts the PSKs the server may supply through NewSessionTicket, and Section 4.7.1 makes sending a ticket conditional on the ClientHello carrying a suitable extension. The send paths only checked that tickets were enabled. Record the modes from the ClientHello in Options - the extension object is freed with the rest of the handshake state, so wolfSSL_send_SessionTicket() cannot look it up. The automatic path skips the ticket; the explicit API returns MISSING_HANDSHAKE_DATA or PSK_KEY_ERROR. Define WOLFSSL_TLS13_TICKET_NO_PSK_MODES for the old behaviour. Fixes wolfSSL#11126
RFC 9846 Section 4.7.1 defines NewSessionTicket.extensions as a list of Section 4.3 Extension TLVs, and Section 6 requires a decode_error alert for a message that cannot be parsed. DoTls13NewSessionTicket() only validated the outer vector length unless WOLFSSL_EARLY_DATA was defined, so a client built without early data accepted malformed framing. Fixes wolfSSL#11127
wolfSSL_GetSessionClient() compared only the requested number of bytes, so a short server ID could match a cached entry that merely started with the same bytes and landed in the same cache row. Applications partitioning the cache with wolfSSL_SetServerID() could then offer a ticket across partitions, against RFC 9846 Appendix C.4. Fixes wolfSSL#11132
Withholding a ticket from a client that omits psk_key_exchange_modes is a behaviour change for peers that omit the extension but still expect a ticket. Keep the old behaviour by default and gate the RFC 9846 check behind WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES, including the Options fields that record the advertised modes.
RFC 9846 Section 4.7.1 requires clients to ignore unrecognized extensions, so cover an empty vector, one unknown type and two unknown types, and check that application data still flows both ways afterwards with no alert sent. These cases pass with or without the framing check and pin down what it must not reject.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR hardens wolfSSL’s TLS 1.3 NewSessionTicket handling for RFC 9846 compliance by (a) gating ticket sending on the client’s advertised psk_key_exchange_modes (opt-in) and (b) enforcing extension framing validation during NewSessionTicket parsing regardless of early-data support. It also fixes a client session-cache lookup flaw where a short server ID could prefix-match longer cached IDs, allowing cross-partition resumption.
Changes:
- Add an opt-in PSK-mode precondition (
WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES) for automatic and explicit TLS 1.3 ticket sending, persisting advertised modes inOptions. - Always parse/validate
NewSessionTicket.extensionsframing viaTLSX_Parse()to reject malformed TLVs withdecode_erroreven withoutWOLFSSL_EARLY_DATA. - Fix client cache serverID matching to require both byte-equality and length-equality; add regression tests for the above behaviors.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
wolfssl/internal.h |
Adds Options fields to persist client-advertised PSK modes across handshake-state cleanup when the opt-in macro is enabled. |
src/tls13.c |
Enforces NST extension TLV framing validation and adds the PSK-mode gate used by both automatic NST loop and wolfSSL_send_SessionTicket(). |
src/tls.c |
Records psk_key_exchange_modes presence/modes into Options for later ticket-send decisions. |
src/ssl_sess.c |
Fixes session cache lookup to prevent serverID prefix aliasing by requiring equal cached/requested ID lengths. |
tests/api/test_tls13.h |
Registers new TLS 1.3 ticket/framing tests. |
tests/api/test_tls13.c |
Adds tests for PSK-mode ticket gating and for accepting unknown NST extensions while rejecting malformed framing. |
tests/api/test_session.h |
Registers new client-cache prefix regression test. |
tests/api/test_session.c |
Adds regression test ensuring short server IDs don’t match longer cached IDs. |
.wolfssl_known_macro_extras |
Adds the new opt-in macro to the known-macros list. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+12917
to
+12921
| /* Keep the advertised modes for the NewSessionTicket decision. The | ||
| * extension object is dropped with the rest of the handshake state | ||
| * once the handshake is done. */ | ||
| ssl->options.pskKeModes = modes; | ||
| ssl->options.pskKeModesRecvd = 1; |
| WOLFSSL* ssl_s = NULL; | ||
| struct test_memio_ctx test_ctx; | ||
|
|
||
| /* A ClientHello without psk_key_exchange_modes gets no ticket. */ |
| * WOLFSSL_TICKET_HAVE_ID: Session tickets include ID default: off | ||
| * Forced on when WOLFSSL_EARLY_DATA is set. | ||
| * WOLFSSL_TICKET_NONCE_MALLOC: Dynamically allocate ticket nonce default: off | ||
| * WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES: Withhold NewSessionTicket default: off |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
psk_key_exchange_modes, per RFC 9846 §4.3.9/§4.7.1. The advertised modes are now recorded inOptionssince the extension object is freed with the rest of the handshake state; the automatic path skips the ticket, and the explicit API returnsMISSING_HANDSHAKE_DATAorPSK_KEY_ERROR. Old behaviour is available viaWOLFSSL_TLS13_TICKET_NO_PSK_MODES. Fixes wolfSSL sends TLS 1.3 NewSessionTicket without client PSK mode advertisement #11126.WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES(including theOptionsfields that record the advertised modes), since withholding a ticket from clients that omitpsk_key_exchange_modesbut still expect one is a behaviour change.NewSessionTicket.extensionsframing inDoTls13NewSessionTicket()even whenWOLFSSL_EARLY_DATAis not defined, so malformed framing is rejected with a decode_error alert regardless of build config. Fixes RFC9846 wolfSSL issue: NewSessionTicket extension TLV framing is skipped without early-data support #11127.wolfSSL_GetSessionClient()to compare the full cached server ID length instead of only the requested number of bytes, preventing a short server ID from matching an unrelated cached entry in the same cache row and crossingwolfSSL_SetServerID()partitions, per RFC 9846 Appendix C.4. Fixes TLS session ticket partition key prefix aliasing in wolfSSL client cache #11132.NewSessionTicketextensions (empty vector, one unknown type, two unknown types) are ignored per RFC 9846 §4.7.1, with the connection staying up and application data flowing both ways with no alert sent, both with and without the framing check.