Repository navigation
tls, quic, httpclient: a non-ASCII ALPN protocol name is refused at configuration instead of sent as other bytes - #370
Merged
Merged
Conversation
…onfiguration instead of sent as other bytes The three ALPN wire builders did not send a non-ASCII name as configured. The TLS server's and the TLS client's BuildAlpnWire cast each UTF-16 unit to a byte, so U+0168 went out as 0x68 and the configured "Ũ2" was the real "h2": the connection negotiated, and CaptureAlpn / NegotiatedAlpn reported, a protocol nobody configured. QUIC's AlpnWire encoded with Encoding.ASCII, which substitutes '?', so "Ũ2" became "?2" and a client offering the literal "?2" was admitted and served. Each builder now refuses a name that is not ASCII with an ArgumentException, next to its existing 1..255 length check. Refusing rather than encoding as UTF-8 because every reader of the negotiated name (CaptureAlpn, ReadNegotiatedAlpn, QuicEngineConnection's read-back) decodes ASCII, and with ASCII the existing length check counts bytes exactly. The pending tests "alpn: a non-ascii protocol name must not negotiate as a different protocol" (Tls), "quic/alpn: a non-ascii allow-list token must not admit a protocol nobody configured" (E2E) and "tls client: a non-ascii alpn protocol must not be offered as a different protocol" (Http) are now Tests; each already accepted a refusal at configuration.
This was referenced Oct 12, 2026
Merged
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.
Fixes #340.
A configured ALPN protocol name with a non-ASCII character did not go on the wire as configured, on the TLS server, the TLS client or QUIC:
BuildAlpnWire(inTlsServiceand inTlsClientContext) cast each UTF-16 unit to a byte.U+0168became0x68, so the configuredŨ2went out as the realh2. The connection negotiated, andCaptureAlpn/NegotiatedAlpnreported, a protocol nobody configured.QuicEngine.AlpnWireencoded withEncoding.ASCII, which substitutes?.Ũ2became?2, and a client offering the literal?2was admitted and served.What changed
Each of the three builders now refuses a name that is not ASCII (
System.Text.Ascii.IsValid) with anArgumentException, right next to its existing 1..255 length check:ALPN protocol 'Ũ2' must be ASCII.ALPN token 'Ũ2' must be ASCIIWhy refuse rather than encode as UTF-8:
CaptureAlpn, the client'sReadNegotiatedAlpn,QuicEngineConnection's read-back) decodes ASCII.TlsService.Start,TlsClientContext.Create, theQuicEngineconstructor), before anything is allocated, so a refusal leaks nothing.The
TlsServicechange is in the core and was approved for this fix.Proof
The three pending tests are now
Test()s. Each already accepted a refusal at configuration as a resolution.src/change revertedFAIL alpn: a non-ascii protocol name must not negotiate as a different protocol: a server configured to speak only 'U+0168 2' ACKed h2 - ...: 174 passed, 1 failed, 7 pendingPASS: 175 passed, 0 failed, 7 pendingFAIL quic/alpn: a non-ascii allow-list token must not admit a protocol nobody configured: a client offering '?2' completed the handshake against an allow list of 'Ũ2': 285 passed, 1 failed, 5 pendingPASS: 286 passed, 0 failed, 5 pendingFAIL tls client: a non-ascii alpn protocol must not be offered as a different protocol: ... body: 200|hello over h2, origin saw alpn=h2: 83 passed, 1 failed, 3 pendingPASS: 84 passed, 0 failed, 3 pendingThe pending tests left in each suite are the ones that were already pending, unrelated to this fix. In Http they are the tests for #342, #343 and #344.
TlsClientPostureTests' remarks listed both of that file's Pending defects, this one and #344's handshake deadline. The paragraph is removed rather than edited down to one bullet, because each Pending test states its own reason. #344's PR removes the same lines, so the two merge cleanly in either order.AlpnNegotiationTests' one-line "live defect" remark goes too.With its siblings
This batch is #356 (#342), #358 (#343), #366 (#344) and #370 (#340). They merge with each other without conflicts, checked pairwise and all four together. #358 and #366 both edit
RunHandshakeAsync, in separate hunks. With all four merged, the Http suite is 88 passed, 0 failed, 0 pending.