Skip to content

docs(security): RFC — fix the mesh crypto handshake (N3-N5)#63

Draft
gHashTag wants to merge 1 commit into
mainfrom
feat/crypto-security-rfc
Draft

docs(security): RFC — fix the mesh crypto handshake (N3-N5)#63
gHashTag wants to merge 1 commit into
mainfrom
feat/crypto-security-rfc

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Proposal for review before implementation. Addresses the 3 crypto defects from the wave audit: unauthenticated handshake (ee+ss only, ss passed as es/se, no transcript hash, AllowList unused, MITM test inverted), constant HELLO MAC key with verify_mac never called, and NodeId-derived static keys. Specifies the fix over the existing X25519+ChaCha20 primitives + a test plan + owner decisions. Crypto stays hand-written Rust (t27 can't express it, #62). See docs/SECURITY_crypto_handshake_RFC.md. phi^2 + phi^-2 = 3

…view

Proposal only (no code). The wave audit found the mesh handshake is not
authenticated: complete_initiator/responder compute only ee+ss and pass ss in
both the es and se slots (real es/se DH never done, no transcript hash, AllowList
never consulted), and its own MITM test asserts the attacker decrypts. Plus a
constant HELLO MAC key with verify_mac never called, and static keys derived from
the public NodeId.

This RFC specifies the fix over the existing X25519 + ChaCha20 primitives
(Noise-IK-style key agreement with real es/se + transcript hash + allow-list
gating; per-link HELLO MAC from the session key with RX-path verification;
out-of-band static-key provisioning), a test plan (including rewriting the
inverted MITM test to assert failure), and the decisions needed from the owner.

Crypto stays hand-written Rust (t27 cannot express crate-based crypto — see #61,
#62). Needs sign-off on the approach before implementation. Refs #58.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

phi^2 + phi^-2 = 3
@gHashTag

Copy link
Copy Markdown
Owner Author

Implementation analysis — the two defects address DIFFERENT attacks (sharpens the design)

Started prototyping the handshake fix; found a subtlety that confirms this needs design review before coding, and sharpens the RFC:

es/se and the allow-list defend against different threats — both are required:

  • Real es/se + transcript hash gives forward secrecy and binds the statics into the key, defeating a PASSIVE relay that does not hold a valid static key. Implementation note: NoiseXX.ephemeral is an EphemeralSecret (consumed by the first diffie_hellman), so computing ee AND es AND se needs it changed to a reusable StaticSecret; the es/se args are role-swapped (initiator: es=e_i·s_r, se=s_i·e_r; responder mirrors). Verifiable by the existing handshake round-trip tests staying green.
  • Allow-list gating is what actually stops the noise_xx_resistant_to_mitm scenario. In that test Alice completes the handshake directly against Mallory's ephemeral+static; with correct es/se she and Mallory STILL derive the same key, because Mallory IS the endpoint she handshook with. The only defense is Alice REJECTING a peer_static that is not Bob's allow-listed key. That requires complete_initiator/responder to take the expected identity and return Result<Session, MeshError::Auth> — an API change touching every caller (daemon, StaticKey::session_with, tests).

Consequence for the plan: the fix is not a one-line es/se swap; it is (a) es/se+transcript for forward secrecy AND (b) a Result-returning allow-list gate for identity. (b) is the load-bearing authentication fix and is the API change that needs owner sign-off (how the daemon threads expected-peer identity into the handshake). So this stays a reviewed change, not a blind overnight edit — the RFC's decision list stands, with "how to thread the AllowList / expected peer id" now the primary decision.

phi^2 + phi^-2 = 3

gHashTag pushed a commit that referenced this pull request Jul 10, 2026
…rt 1 of N3

The handshake computed only ee + ss and passed `ss` in BOTH the es and se slots,
so it had no forward secrecy and did not bind ephemerals into the session.

Fix: NoiseXX.ephemeral becomes a reusable StaticSecret (EphemeralSecret is
consumed by its first diffie_hellman; we need two), and complete_initiator/
responder compute the real ee/es/se so both sides derive the same key. Verified:
handshake_and_roundtrip + independent_handshakes pass, full suite 103 passed.

SCOPE: forward-secrecy half of N3 only. Identity auth (allow-list gating -> the
actual MITM defense), N4 (HELLO MAC), N5 (keystore) remain open per RFC #63 and
need owner sign-off. Based on the pipeline-guard branch (needs #60's build fix).
Draft — needs crypto review. Refs #58, #63.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

phi^2 + phi^-2 = 3
@gHashTag

Copy link
Copy Markdown
Owner Author

Triage — KEEP

Verdict: KEEP — RFC document, chistyi add (80+ lines, 1 file). Pairs with code PR #65.

Same cascade as other docs PRs: baseline CI red due to committed gen/rust/ from three t27c optimizer scan bugs. Fix chain t27#1461 → t27#1462 → tri-net#80. After #80 lands, this PR goes green without touching a byte here.

No action required. Stays DRAFT.

phi^2 + phi^-2 = 3

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.

2 participants