fix(rekey): complete relay-path session rekey (#91)#92
Open
vxfemboy wants to merge 8 commits into
Open
Conversation
Extract rekey_init_core/rekey_resp_core parameterized by RekeyEgress{Direct,Relay}
(single-source the 9a idempotent-ephemeral Critical fix); wire relayed_handshake_
init/resp to them; remove drive_rekey_schedule relay gate + restore relay-wrap Init
emit. Fail-closed; idempotency covers relay reordering. netns relay-forced money
test. Stacks on 9a (PR #90). Issue #91.
Extract rekey_init_core/rekey_resp_core (via_relay bool) behavior-preserving / wire relayed_handshake_init/resp to them / remove drive_rekey_schedule gate + relay-wrap Init emit / netns relay-forced money test. Single-sourced idempotent convergence; fail-closed relay_wrap-None no-op.
…y) — Direct path unchanged
…eaves egress untouched
…er the relay Task 4: prove relay-only sessions rotate loss-free over the rendezvous relay. run-netns-rekey-relay.sh forks run-netns-relay.sh's RELAY-FORCED topology (A/B mutually unreachable except via R's blind relay) with run-netns-rekey.sh's YIP_REKEY_INTERVAL_MS=2000 cadence, asserting (1) relay-forwarded=<N> N>0, (2) <=1% loss across ~10 rotations, (3) rekey_epoch_witness reports >=3 distinct completed rekey rounds. rekey_epoch_witness.rs grows an opt-in YIP_WITNESS_UNWRAP_RELAY=1 mode that strips the RelaySend (offset 33) / RelayDeliver (offset 17) rendezvous envelope before applying the existing distinct-ephemeral logic, so the direct-path 9a run-netns-rekey.sh is byte-for-byte unaffected (verified by re-running it). Wired into netns-tunnel-test in .github/workflows/integration.yml, both drivers, alongside the sibling 9a rekey steps.
…stent (final review)
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.
Closes #91. Stacked on #90 (base =
feat/rekey-9a-session-rotation) — review #90 first.What this does
9a rotates each peer's Noise-IK session ~120s for forward secrecy, but relay-reached peers were gated out of rekey scheduling (
drive_rekey_schedulereturned early onrelay): rekey completion was only wired into the direct handshake handlers, so scheduling a relay rekey would have churned a never-completing ~1 Hz handshake (a DPI fingerprint). #91 wires relay-path completion, removes the gate, and proves it on the wire — so relay-only sessions now get forward-secrecy rotation too.The security-critical idempotent logic is single-sourced, not duplicated: relay paths reorder more than direct, which makes 9a's ephemeral-keyed convergence fix more load-bearing there, and a copy would be free to drift from it.
Changes
c388cb4,b459dde) —rekey_init_core/rekey_resp_core(.., via_relay: bool)+push_rekey_egress;handle_rekey_init/handle_rekey_respbecome thinvia_relay=falsewrappers. The direct path is byte-identical.push_rekey_egresstakes the fullEgressDatagramso the prime-emit preserves each packet's FECfate(review fix — a collapsedfatewould defeat GSO coalescing).e60b7ba) —relayed_handshake_init's Established arm andrelayed_handshake_resproute to the cores withvia_relay=true. The cold-startcached_resp_init_ephdedup is preserved, so a cold-start Init retransmit still resends the cached Resp instead of being misread as a rekey.2fbe21e) — relay peers now schedule rekeys, emitting the Init viarelay_wrap. Arelay_wrapNoneskips that send only; the round stays in flight and retries.b163430) —run-netns-rekey-relay.sh: three namespaces with no direct A↔B path, so traffic must traverse the blind relay.rekey_epoch_witnessgained an opt-inYIP_WITNESS_UNWRAP_RELAY=1mode that strips theRelaySend/RelayDeliverenvelope before counting distinct on-wire ephemerals (env-gated, so the 9a direct test is unaffected). Wired into CI, both drivers.004c138) — see below.Defect caught by the final review
Removing 9a's gate silently dropped an invariant it had been providing: relay and direct rekey completion were implicitly mutually exclusive. Without that, a direct peer completing a rekey via a relayed Init/Resp built the new epoch with
peer_addr = server_addr()whilepeers[idx].relaystayedfalse— andon_tundecides relay-wrapping frompeers[idx].relay, not the stamped address. Result: bare datagrams to the relay placeholder, dropped by the server, outbound black-holed for a full rekey interval. Reachable via a source-spoofed server address or a malicious relay, and with no attacker at all under asymmetric reachability (peer relays to us while we reach it directly).Fixed by gating completion on
peers[idx].relayat all four sites (fail-closedDispatchOut::Noneon mismatch). Therelayflag only flips on aHandshaking → Establishedtransition, never mid-session, so this cannot block a legitimate same-path rekey. Regression testdirect_peer_ignores_relayed_rekey_respwas confirmed failing before the fix.Verification
clippy -D warnings,cargo fmt— clean. Full workspace: 0 failures.relay-forwarded= 3147/3151 (the blind relay carried it),COMPLETED_ROUNDS= 10/10 distinct rekey rounds observed on the relayed wire.Known deferred
[HandshakeResp]can abandon an in-flight rekey — rekey-liveness only (currentuntouched, session survives, rotation delayed). Rides with Handshake anti-replay (timestamp) + authenticated endpoint learning #34 (authenticated endpoint).No wire-format change;
yip-crypto/yip-wire/handshake.rsuntouched apart from reusing the read-onlyhandshake::init_ephemeralhelper.