tls: key the session_id marker with a shared secret (HMAC), dual-accept - #315
Open
Diffechento wants to merge 1 commit into
Open
tls: key the session_id marker with a shared secret (HMAC), dual-accept#315Diffechento wants to merge 1 commit into
Diffechento wants to merge 1 commit into
Conversation
The stealth marker that the server uses to tell an FPTN client apart from
an unrelated connection is embedded in the TLS session_id and is currently
GenerateFptnKey = SHA1(timestamp)[0:4] -- no secret. Any on-path observer
can recompute SHA1(now +/- 5s)[0:4] and passively fingerprint FPTN, or
craft a valid marker and actively probe a host to confirm it runs FPTN.
The probing gate is pre-auth, so the marker alone flips server behavior.
Introduce a keyed marker:
marker = HMAC-SHA256(S, be32(timestamp))[0:4]
where S is a deployment-wide shared secret configured on the server and
distributed to clients in the connection token. Without S the marker is
indistinguishable from the random bytes browsers already put in
session_id, so a single ClientHello no longer identifies FPTN.
Server (fptn-server):
--session-key <s[,s2,...]> one or more accepted secrets; multiple keys
allow rotation (roll out the new key, then
retire the old one).
--session-id-accept-legacy (default true) also accept the old unkeyed
marker during migration; set false to require
keyed markers and close the fingerprint.
The keys/flag thread ServerConfig -> Server -> Listener -> Session and feed
the IsFptnClientSessionID / IsDecoyHandshakeSessionID(2) validators.
Client (cli + gui):
Token gains an optional service-level "session_key". It is carried
per-server on ServerInfo / WebsocketClient::Config (like md5_fingerprint)
and passed to SetHandshakeSessionID and the decoy/reality generators
(GenerateDecoyTlsHandshake, GenerateDecoyTlsSessionId2).
Fully backward compatible: an empty secret -> legacy marker, and tokens
without session_key keep working. With --session-id-accept-legacy=false a
deployment using Reality mode should first ship keyed clients, since the
decoy markers are keyed the same way.
Adds tests/fptnlib/tls/TlsMarkerTest.cpp (reference vectors, dual-accept,
rotation, decoy offsets).
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.
The stealth marker that the server uses to tell an FPTN client apart from an unrelated connection is embedded in the TLS session_id and is currently GenerateFptnKey = SHA1(timestamp)[0:4] -- no secret. Any on-path observer can recompute SHA1(now +/- 5s)[0:4] and passively fingerprint FPTN, or craft a valid marker and actively probe a host to confirm it runs FPTN. The probing gate is pre-auth, so the marker alone flips server behavior.
Introduce a keyed marker:
where S is a deployment-wide shared secret configured on the server and distributed to clients in the connection token. Without S the marker is indistinguishable from the random bytes browsers already put in session_id, so a single ClientHello no longer identifies FPTN.
Server (fptn-server):
--session-key <s[,s2,...]> one or more accepted secrets; multiple keys
allow rotation (roll out the new key, then
retire the old one).
--session-id-accept-legacy (default true) also accept the old unkeyed
marker during migration; set false to require
keyed markers and close the fingerprint.
The keys/flag thread ServerConfig -> Server -> Listener -> Session and feed
the IsFptnClientSessionID / IsDecoyHandshakeSessionID(2) validators.
Client (cli + gui):
Token gains an optional service-level "session_key". It is carried
per-server on ServerInfo / WebsocketClient::Config (like md5_fingerprint)
and passed to SetHandshakeSessionID and the decoy/reality generators
(GenerateDecoyTlsHandshake, GenerateDecoyTlsSessionId2).
Fully backward compatible: an empty secret -> legacy marker, and tokens without session_key keep working. With --session-id-accept-legacy=false a deployment using Reality mode should first ship keyed clients, since the decoy markers are keyed the same way.
Adds tests/fptnlib/tls/TlsMarkerTest.cpp (reference vectors, dual-accept, rotation, decoy offsets).