Add Chrome 150 and Safari 18.5 profiles, with JA4 tests - #413
Open
nihiloid wants to merge 2 commits into
Open
Conversation
added 2 commits
August 29, 2026 13:35
Add HelloChrome_150 and HelloChrome_150_PSK. Chrome 150 sends the ML-DSA signature algorithms 0x0904, 0x0905 and 0x0906 before the classical ones. HelloChrome_Auto now selects HelloChrome_150. Add HelloSafari_18_5. Safari 18.5 sends no ML-KEM group, it offers TLS 1.0 and TLS 1.1 in supported_versions, and it ends with a padding extension. Add HelloSafari_26_0 to the HelloSafari_26_3 case. Safari 26.0 sends the same ClientHello as Safari 26.3. Add u_parrots_ja4_test.go. It computes the JA4 of each profile and compares it against a captured value. A second test checks that the extension shuffle keeps the JA4 the same on every connection.
Add u_psk_resumption_test.go. It runs two connections of a PSK profile against a TLS 1.3 server of this package. The first connection gets a session ticket. The second connection sends the pre_shared_key extension and resumes the session, which works only if utls computes the binders over the ClientHello that goes on the wire. The test runs HelloChrome_150_PSK and HelloChrome_114_Padding_PSK_Shuf. The second profile holds a padding extension, whose length comes from the length of the other extensions, and it shuffles its extensions, which must keep pre_shared_key last. A third connection uses HelloChrome_150, which holds no pre_shared_key extension. It must not resume, although the session cache holds a ticket.
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.
Profiles
HelloChrome_150andHelloChrome_150_PSK. Chrome 150 sends the ML-DSA signature algorithms0x0904,0x0905and0x0906before the classical ones. The rest of the ClientHello matches theHelloChrome_133profile that ships already.HelloChrome_Autonow selectsHelloChrome_150.HelloSafari_18_5. Safari 18.5 sends no ML-KEM group, its only key share is X25519, it offers TLS 1.0 and TLS 1.1 insupported_versions, and it ends with a padding extension.HelloSafari_26_0, added to the existingHelloSafari_26_3case. Safari 26.0 sends the same ClientHello as Safari 26.3, so the two names share one spec, the wayHelloFirefox_55andHelloFirefox_56already do.Tests
u_parrots_ja4_test.gois new. It builds the ClientHello of a profile, computes the JA4 fingerprint from the bytes on the wire, and compares it against a captured value:HelloChrome_150t13d1516h2_8daaf6152771_806a8c22fdeaHelloChrome_150_PSKt13d1517h2_8daaf6152771_a87ad97598a9HelloChrome_133t13d1516h2_8daaf6152771_d8a2da3f94cdHelloSafari_26_3t13d2013h2_a09f3c656075_7f0f34a4126dHelloSafari_26_0t13d2013h2_a09f3c656075_7f0f34a4126dHelloSafari_18_5t13d2014h2_a09f3c656075_e42f34c56612HelloSafari_16_0t13d2014h2_a09f3c656075_14788d8d241bThe test needs no network and no new dependency. It parses the ClientHello itself and implements JA4 in about 120 lines. Adding another profile to the table is one line, and a profile that holds a
pre_shared_keyextension is detected from its spec: the test then gives it a session, so the extension goes on the wire.A second test builds each profile 16 times and checks that the JA4 does not change. JA4 sorts the cipher suites and the extensions, so
ShuffleChromeTLSExtensionsmust not show up in the fingerprint. A fingerprint that moved with the shuffle would identify uTLS rather than the browser.A third test covers a PSK profile without a session: uTLS then conceals the empty
pre_shared_keyextension, and the fingerprint becomes the one of the profile without PSK.Session resumption
u_psk_resumption_test.gois new as well. It runs two connections of a PSK profile against a TLS 1.3 server of this package. The first connection gets a session ticket. The second connection sends thepre_shared_keyextension and resumes the session, which works only if uTLS computes the binders over the ClientHello that goes on the wire. A third connection usesHelloChrome_150, which holds nopre_shared_keyextension: it must not resume, although the session cache holds a ticket.The test runs
HelloChrome_150_PSKandHelloChrome_114_Padding_PSK_Shuf. The second profile covers the two features that change how the binders are written: a padding extension, whose length comes from the length of the other extensions, and the extension shuffle, which must keeppre_shared_keylast. The other PSK profiles follow the same path asHelloChrome_150_PSK. The test needs no network: it usesnewLocalListenerand the server of this package.go build ./...,go vet ./...andgo test ./...pass.