Skip to content

Draw the GREASE signature algorithm from the per-connection seed - #412

Open
nihiloid wants to merge 1 commit into
refraction-networking:masterfrom
nihiloid:grease-signature-algorithms
Open

Draw the GREASE signature algorithm from the per-connection seed#412
nihiloid wants to merge 1 commit into
refraction-networking:masterfrom
nihiloid:grease-signature-algorithms

Conversation

@nihiloid

@nihiloid nihiloid commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Problem

Chrome 152 introduced a GREASE value in the signature_algorithms extension. Chrome sends that value first in the list and draws a new value for each connection. Chrome 151 and earlier sent no GREASE value there.

utls replaces GREASE placeholders in the cipher suites, the supported groups, the key shares, the supported versions, and the GREASE extensions. It does not replace them in signature_algorithms. A spec that writes SignatureScheme(GREASE_PLACEHOLDER) therefore sends the literal value 0x0a0a on every connection. That constant is a reliable "this is not Chrome" signal.

Change

  • u_tls_extensions.go: add the seed index ssl_grease_signature_algorithm. It comes before ssl_grease_ticket_extension, so the indexes of the older positions keep their values. ssl_grease_last_index grows by one, and UConn.greaseSeed grows with it.
  • u_parrots.go: add a case *SignatureAlgorithmsExtension to the reGREASE switch in ApplyPreset. It replaces each entry for which isGREASEUint16 reports true with GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_signature_algorithm), the same way the existing curve, key share, and version cases work. The value now comes from the one per-connection seed, so the GREASE values in one ClientHello relate to each other the way BoringSSL relates them.
  • u_grease_sigalg_test.go: new tests. They check that the placeholder becomes a 0x?a?a value, that the other signature algorithms stay unchanged, that the value changes across 64 connections, and that the value equals the seeded value for the new index.

This change adds the mechanism only. The newest bundled Chrome profile is HelloChrome_133, which predates Chrome 152, so no shipped profile writes SignatureScheme(GREASE_PLACEHOLDER) yet. A future Chrome 152 profile, or any caller that builds its own ClientHelloSpec, can use it. Existing profiles send the same bytes as before.

SignatureAlgorithmsCertExtension gets no substitution, because BoringSSL does not GREASE it.

Test

go build ./..., go vet ./..., and go test ./... pass.

The same change for the bogdanfinn/utls fork: bogdanfinn/utls#9.

…e 152)

Add the seed index ssl_grease_signature_algorithm. ApplyPreset now replaces the GREASE placeholder in SignatureAlgorithmsExtension with the seeded value.
Add u_grease_sigalg_test.go for the substitution, the per-connection draw, and the seed index.
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