REALITY.4b: client-side relay verification (ECDSA-P256 CertificateVerify, default ON, fail-closed) #82
No reviewers
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
femboy/yip!82
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/reality-4b-relay-verify"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
REALITY.4b — client-side relay verification (default ON)
PR 2 of the REALITY.4 pair (stacked on REALITY.4a, merged). Closes the REALITY loop: a yip client cryptographically verifies the relay holds
relay_reality_priv— not a MITM/impostor — without weakening the un-authed-prober camouflage.verify=on|offon thereality://URL, default ON, client-local (never negotiated on the wire).Mechanism
The only value tied to
relay_reality_privis the seal's ECDHsharedsecret (X25519(client_eph, relay_reality_priv), which the client also computes). So:shared(HKDF-Expand(shared,"yip-reality-cert-v1",48B)→ constant-time wide reduction mod the P-256 order n, domain-separated from the seal AEAD key), re-forge the borrowed-identity leaf per-connection with it (cachedStolenFields, no dest re-fetch), and let BoringSSL sign the standardCertificateVerifywith it.yip_utls) re-derives the same key, pins the leaf to it, and verifies theCertificateVerify— scheme hard-pinnedecdsa_secp256r1_sha256(the announced algorithm is never read → no algorithm confusion), RFC 8446 §4.4.3 signed content, fail-closed on every edge with no hostile-byte panic, run before any yip Register frame.A MITM holds neither private key, cannot compute
shared, and (transcript binding) cannot relay/replay/reflect the genuine relay's signature → cannot be accepted. On failure the client sends a browser-faithful TLS alert and jittered give-up (300s base + 0–120s, distinct from the sub-5s ladder → no fleet-wide fixed tell), revealing no yip-specific bytes.Why ECDSA-P256 (not Ed25519)
An adversarial advisor + cross-model review caught that Ed25519 would break the cleartext Chrome ClientHello fingerprint (Chrome doesn't advertise
ed25519) — a passive, keyless distinguisher that defeats REALITY. ECDSA-P256 (ecdsa_secp256r1_sha256, already in the Chrome-faithful sig-algs) keeps the ClientHello byte-faithful (JA4 diff stays green); it's what real Xray uses.Proven end-to-end
The netns verify=on money test (two UDP-blocked peers tunnel through a real REALITY relay) + wrong-relay-key fail-closed negative (wrong key → seal-open fails → spliced to dest → no tunnel, no retry-storm) ran live under sudo. The money test cross-validates the CertVerify §4.4.3 boundary against BoringSSL's signer (an independent-stack KAT in practice). Plus unit tests: client/server derive the same key; verify accepts a correct binder and rejects wrong-key / bad-sig / missing-CertVerify; a KAT guards the transcript boundary.
Preserved
Un-authed-prober camouflage unchanged (spliced to dest); REALITY.3 anti-replay untouched and still runs before the per-connection re-forge (a replay can't force a bind);
verify=false/ the 4atls://path / the sync data plane byte-unchanged; JA3/JA4 fidelity intact.Deferred (documented)
hash2curve; renamedecide_authed'ssni_has_acceptorparam.Tests
yip-utls47 + KATs,yip-rendezvous80,yipd198+27 (incl. live netns) — all green.clippy --workspace -D warnings+fmtclean.forbid-unsafe(outside yip-io/yip-device); noas; no bare#[allow].