Skip to content

tls: key the session_id marker with a shared secret (HMAC), dual-accept - #315

Open
Diffechento wants to merge 1 commit into
fptn-project:masterfrom
Diffechento:feature/keyed-session-id
Open

tls: key the session_id marker with a shared secret (HMAC), dual-accept#315
Diffechento wants to merge 1 commit into
fptn-project:masterfrom
Diffechento:feature/keyed-session-id

Conversation

@Diffechento

Copy link
Copy Markdown

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).

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).
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