Skip to content

Let a caller drop status_request, and stop hard-coding Proxy-Connection - #45

Merged
latentharbor merged 1 commit into
mainfrom
omit-extensions-and-proxy-connection
Aug 4, 2026
Merged

Let a caller drop status_request, and stop hard-coding Proxy-Connection#45
latentharbor merged 1 commit into
mainfrom
omit-extensions-and-proxy-connection

Conversation

@latentharbor

Copy link
Copy Markdown
Owner

Two more places where an identity could be described but not presented.

tls.omitExtensions

The subtractive counterpart to extraExtensions. status_request (5) is what it exists for
the one extension this package sends that curl does not, so a sample without it could not be matched
at all. Ordering cannot help (orderExtensions arranges what was built), and there was no other
way to unbuild it.

Dropping it gives up OCSP stapling, the only revocation signal this package consumes. With
trust.revocation: 'require-staple' that combination is not a stricter policy — it is one that can
never be satisfied: no staple is requested, so none arrives, so every connection fails on a
certificate never asked to carry one. Refused at configuration time, where both settings are
visible, rather than at handshake time where it looks like a server problem.

proxy.proxyConnection

Replaces a hard-coded Proxy-Connection: keep-alive on the CONNECT request. The header is
pre-standard and never reached a spec; clients disagree — some send keep-alive, some close, some
nothing. The origin never sees it; the proxy always does, so for anyone matching a client's
behaviour at the proxy it is part of the fingerprint.

Default unchanged (keep-alive avoids a class of proxy that closes the tunnel after one request).
null omits the header, which is not the same as sending close.

This nearly repeated a bug fixed twice already

normalise() rebuilds the proxy config rather than copying it, so a field not named in its
return literal is dropped without a word — exactly how http2ConnectionWindow came to be declared
in a profile and read by nothing. The field is listed explicitly with the reason written next to it.

Both omissions are reproduced on a HelloRetryRequest retry, for the same reason the extension order
is: a second hello that changed its extension set would be malformed under RFC 8446 §4.1.2 and a
signal in itself.

Version → 1.11.0. 1260 offline tests pass.

🤖 Generated with Claude Code

Two more places where an identity could be described but not presented.

**`tls.omitExtensions`** is the subtractive counterpart to `extraExtensions`. `status_request` (5) is
what it exists for: that is the one extension this package sends which curl does not, so a sample
without it could not be matched at all. Ordering cannot help — orderExtensions arranges what was
built — and there was no other way to unbuild it.

Dropping it gives up OCSP stapling, which is the only revocation signal this package consumes. With
`trust.revocation: 'require-staple'` that combination is not a stricter policy, it is one that can
never be satisfied: no staple is requested, so none arrives, so every connection fails on a
certificate that was never asked to carry one. Refused at configuration time, where both settings
are visible, rather than at handshake time where it looks like a server problem.

**`proxy.proxyConnection`** replaces a hard-coded `Proxy-Connection: keep-alive` on the CONNECT
request. The header is pre-standard and never reached a spec; clients disagree about it, some
sending keep-alive, some close, some nothing. The origin never sees it — the proxy always does — so
for anyone matching a client's behaviour AT THE PROXY it is part of the fingerprint. The default is
unchanged, since keep-alive avoids a class of proxy that closes the tunnel after one request. `null`
omits the header, which is not the same as sending `close`.

That one nearly repeated a bug this repo has now fixed twice. `normalise()` REBUILDS the proxy
config rather than copying it, so a field not named in its return literal is dropped without a word
— exactly how `http2ConnectionWindow` came to be declared in a profile and read by nothing. The
field is listed explicitly and the reason is written next to it.

Both omissions are reproduced on a HelloRetryRequest retry, for the same reason the extension order
is: a second hello that changed its extension set would be malformed under RFC 8446 s4.1.2 and a
signal in itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@latentharbor
latentharbor merged commit aee19b9 into main Aug 4, 2026
3 checks passed
@latentharbor
latentharbor deleted the omit-extensions-and-proxy-connection branch August 4, 2026 08:30
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