Skip to main content

Module cid_chain

Module cid_chain 

Source
Expand description

Rotating connection-ID chain (WIRE v5 / ε).

After v4 header protection, the only per-connection cleartext left on the wire is the outer 8-byte routing ConnId. v5 collapses the two connection identifiers (the redundant 32-byte inner session_id is dropped from the data-plane wire) into this single CID and rotates it on every migration, closing the stable-CID linkability residual (threat-model §12.5).

§Construction

At session establishment each peer derives two per-direction chain secrets from the initial session secret (mirroring the AEAD / header-protection key layout):

cid_secret_c2s = derive_key_32("phantom-cid-c2s-v1", initial_secret)   // client→server
cid_secret_s2c = derive_key_32("phantom-cid-s2c-v1", initial_secret)   // server→client

The CID for migration index i truncates a per-index KDF output to 8 bytes:

CID_i = derive_key_32("phantom-cid-v1", cid_secret ‖ i.to_be_bytes())[0..8]

The client stamps its outbound ConnId from the c2s chain (the chain the server routes on); the server stamps from the s2c chain. So is_server swaps the outbound/inbound secrets, exactly like HeaderProtector::derive and the AEAD send/recv keys — one peer’s outbound chain is the other’s inbound chain.

§Properties

  • Session-stable, zeroized: the chain secrets are derived once and held for the session (they do not rotate with the AEAD epoch); they are zeroized on drop. The index advances on migrate() (held by Session, not here).
  • Unguessable / unlinkable: CID_i is a KDF output truncation, so without cid_secret the CIDs are independent-random to an observer — pre- and post-migration flows cannot be linked.
  • Not forward-secret (honest caveat): like the HP keys, a session-key compromise lets an attacker recompute the whole CID chain and link a recorded flow retroactively. The payload stays forward-secret (AEAD ratchets). See docs/plans/wire-v5-cid-collapse-design.md §5.

Structs§

CidChain
Per-direction, session-stable rotating-CID chain secrets. outbound_secret is the chain this peer stamps its outbound ConnId from (the peer routes on it); inbound_secret is the chain this peer routes inbound ConnIds on. Derived once from the initial session secret; zeroized on drop.

Constants§

CID_LEN
Wire width of a routing CID (the outer UDP ConnId): 8 bytes.
CID_WINDOW_LEADING
See CID_WINDOW_TRAILING.
CID_WINDOW_TRAILING
Default demux window — trailing T (in-flight reordering across a migration boundary) and leading K (migration lookahead: the sender may have migrated ahead of delivery). (T + K + 1) = 19 accepted CIDs per inbound direction.