Skip to content

feat(extensions): expose all utls TLS extensions in genMap parrot map#66

Merged
Danny-Dasilva merged 1 commit intomainfrom
feat/utls-extension-parrots
Apr 28, 2026
Merged

feat(extensions): expose all utls TLS extensions in genMap parrot map#66
Danny-Dasilva merged 1 commit intomainfrom
feat/utls-extension-parrots

Conversation

@Danny-Dasilva
Copy link
Copy Markdown
Owner

Summary

Full re-audit (not just version-delta) of utls v1.8.x extension types vs golang/utils.go::genMap() found three pre-existing parrot gaps that were never tied to a recent utls upgrade. Replace GenericExtension fallbacks with the proper utls types so the library owns the wire encoding.

Changes (golang/utils.go::genMap)

Ext ID Before After Notes
17 (status_request_v2) GenericExtension{Id: 17} StatusRequestV2Extension{} RFC 6961 — utls has had this type since v1.5.x. Empty GenericExtension produced an under-spec wire blob.
17613 (TLS ALPS new codepoint, 0x44cd) GenericExtension{Id:17613, Data:{0x00,0x03,0x02,0x68,0x32}} ApplicationSettingsExtensionNew{SupportedProtocols:["h2"]} utls added a dedicated type for the new ALPS codepoint; mirrors the existing 17513 mapping that already uses ApplicationSettingsExtension. Hand-rolled byte payload removed.
30032 (Channel ID, 0x7550) GenericExtension{Id:0x7550, Data:{0}} FakeChannelIDExtension{} Real Chrome Channel ID emits 4 bytes (id + 2-byte zero length). The previous GenericExtension emitted 5 bytes (length=1, data=0x00) — this is a wire-format bug-fix as well as a parrot upgrade.

Intentionally unchanged (verified via re-audit)

  • 10 (SupportedCurvesExtension), 11 (SupportedPointsExtension), 43 (SupportedVersionsExtension), 51 (KeyShareExtension) — populated by callers (StringToSpec, QUICStringToSpec) because their values depend on per-call inputs (TLS version, JA3 curves list, GREASE flag).
  • 22 (encrypt_then_mac) and 49 (post_handshake_auth) — utls does not expose dedicated types for these; GenericExtension is the correct path.
  • 65037 (GREASE_ECH, 0xfe0d) — already uses utls.BoringGREASEECH().
  • 41 (UtlsPreSharedKeyExtension), 24 (FakeTokenBindingExtension), 28 (FakeRecordSizeLimitExtension), 34 (DelegatedCredentialsExtension), 27 (UtlsCompressCertExtension), 13172 (NPNExtension) — already mapped to proper utls types.

What this enables

  • More authentic ClientHello fingerprints for Chrome-style stacks that send status_request_v2, the new ALPS codepoint, or Channel ID. The wire bytes now match what Chrome actually emits.
  • Future utls bugfixes/format updates flow through automatically (no hand-rolled byte arrays to maintain).

Test plan

  • go build ./... (golang/) — passes.
  • go test ./... -short — passes (ok github.com/Danny-Dasilva/CycleTLS/cycletls).
  • Live network smoke against tls.peet.ws / tools.scrapfly.io to confirm the on-the-wire JA3/JA4 hash for affected fingerprints matches Chrome (recommend running CI live-network suite).

Audit of utls 1.8.x parrot map (genMap) revealed three pre-existing gaps
where dedicated utls extension types existed but genMap fell back to
GenericExtension. Replacing them with the proper types lets utls own the
wire encoding (including any future bugfixes) and removes hand-rolled
byte payloads:

  - ID 17 (status_request_v2): GenericExtension -> StatusRequestV2Extension
    (proper RFC 6961 encoding instead of zero-length GenericExtension)
  - ID 17613 (TLS ALPS new codepoint): GenericExtension -> ApplicationSettingsExtensionNew
    Hand-rolled 5-byte payload {0x00,0x03,0x02,0x68,0x32} replaced by
    SupportedProtocols-driven encoding identical to ID 17513.
  - ID 30032 (Channel ID): GenericExtension(Id:0x7550, Data:{0}) ->
    FakeChannelIDExtension{}. Wire format also corrected: real Chrome
    ChannelID is a 4-byte zero-payload extension, the previous
    GenericExtension emitted 5 bytes (length=1).

ID 51 (KeyShare), ID 43 (SupportedVersions), IDs 10/11 (curves/points)
remain populated by callers because they depend on per-call inputs
(version, GREASE flag, JA3 curves). ID 65037 (GREASE_ECH) is already
correctly using utls.BoringGREASEECH(). IDs 22 (encrypt_then_mac) and
49 (post_handshake_auth) intentionally stay as GenericExtension because
utls does not provide dedicated types for them.

go build ./... and go test ./... -short pass.
@Danny-Dasilva Danny-Dasilva merged commit 085a0bb into main Apr 28, 2026
19 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant