Repository navigation
quic: a second ClientHello naming a different host than the first is refused instead of answered - #376
Open
MDA2AV wants to merge 1 commit into
Open
quic: a second ClientHello naming a different host than the first is refused instead of answered#376MDA2AV wants to merge 1 commit into
MDA2AV wants to merge 1 commit into
Conversation
…refused instead of answered
This was referenced Oct 17, 2026
This branch has not been deployed
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 #349.
What was wrong. After a HelloRetryRequest, a QUIC client could send a second ClientHello that named a different host than its first, and the server carried on. picotls runs
on_client_hellofor the first ClientHello only, so the certificate is chosen from that one. picotls does compare the second ClientHello's server_name with the first and fails the handshake on a mismatch. It does so only when the callback saved the name withptls_set_server_name, andiq_on_client_hellonever did. So the check never ran.What changed.
iq_on_client_hellosaves the name when the name selects a host context. A retry that changes the name now fails inside picotls (PTLS_ALERT_HANDSHAKE_FAILURE), and the peer gets a CONNECTION_CLOSE.Saving the name has one visible side effect: picotls acknowledges it with an empty
server_nameextension in EncryptedExtensions (RFC 6066 section 3). That is why the name is saved only when it selected a host. TCP acknowledges under the same rule:ServerNameCallbackreturnsSSL_TLSEXT_ERR_OKonly for a name it served.I read picotls at the pinned ref for anything else on the server that reads
server_name. None of it applies here:Native build.
libioxide_ngtcp2.sowas rebuilt withscripts/build-ngtcp2-native.shat its pinned refs (ngtcp2 7f7e24b, picotls f07f1c8, BoringSSL 5b83e5d), using the script's defaultWORK.4ce1b7a8…). With a differentWORKpath, the only difference is the 193assert()source paths compiled into the binary. So this .so differs from main's only by the shim change, and it embeds no local path.Proof. The pending
sni/quic: a second ClientHello naming a different host is refusedis now aTest.FAIL ... the second ClientHello asked for beta.test where the first asked for alpha.test, and the certificate was already chosen from the first - the server should have refused the change instead of continuing; it sent a ServerHello.control: a second ClientHello keeping the name continues the handshakepasses both ways, so the refusal comes from the name change alone. All 25sni/quictests pass, including the validating-client ones that now receive the acknowledgement.Suites.
Overlap with #377 (the fix for #200). That PR also rebuilds
libioxide_ngtcp2.so.git merge-treeof the two branches auto-merges the shim (the result carries both fixes and compiles), and only the .so conflicts, since it is binary. Whichever PR merges second needsscripts/build-ngtcp2-native.shrerun on the merged shim, and the resulting .so committed.All eight together. This batch's PRs (#376 to #383) were merged onto main 71aab91 in one scratch tree. The only conflict is the binary
libioxide_ngtcp2.sobetween #376 and #377, rebuilt there from the merged shim with the script's defaults. Everything builds, and Unit 102, E2E 309, Http 88, Chaos 80, Tls 169 (14 kTLS cases skipped) and File 5 pass, with 0 failed and 0 pending. The repo's only pending test left is the Redis suite's (#336).Noticed, not changed.
tls13_server.cc, "We perform all our negotiation based on the first ClientHello"), which is what QUIC did until now. Both stacks serve the certificate chosen from the first hello. After this change, QUIC is the stricter of the two.