Skip to content

REALITY.5d: serve the hand-rolled flight on the relay's authed path (last of REALITY.5)#87

Merged
vxfemboy merged 6 commits into
mainfrom
feat/reality-5d-wire-server-flight
Jul 19, 2026
Merged

REALITY.5d: serve the hand-rolled flight on the relay's authed path (last of REALITY.5)#87
vxfemboy merged 6 commits into
mainfrom
feat/reality-5d-wire-server-flight

Conversation

@vxfemboy

Copy link
Copy Markdown
Member

REALITY.5d — wire the hand-rolled server flight into the relay

Stacked on #86 (REALITY.5c). Base is feat/reality-5c-server-flight-emit; review the 5d delta here, merge after #86. PR 4 of 4 — the LAST of REALITY.5 (#76), and the last anti-DPI item.

The relay's authed REALITY path now serves the dest-faithful hand-rolled flight it can build (5b ServerHello + 5c encrypted flight), replacing the BoringSSL SslAcceptor. After this, an authed connection to the relay is byte/length-indistinguishable from a genuine Chrome↔dest TLS 1.3 session end to end — closing the passive-DPI gap REALITY.3 explicitly left open for the authed path.

What's here (all yip-rendezvous)

  • ParserClientHelloInfo.key_share_mlkem_x25519: the x25519 bundled in the client's group-4588 key_share entry (mlkem_ek(1184) ‖ x25519(32)), fail-closed. The authed path keys the 4588 hybrid DH against this (and the standalone 0x001d share for group 29) — correct-by-construction, not relying on the client reusing one ephemeral.
  • Genericized pumphandle_connection + read_and_classify + into_decoy + run_tunnel now flow any AsyncRead+AsyncWrite+Unpin+Send stream, so a yip_utls::RealityStream runs through the same relay logic as an SslStream (the non-REALITY relay-Trojan path is unchanged).
  • The authed-path rewrite (run_reality_conn's Decision::Accept): look up the captured template + fields for the SNI → forge the leaf (forge_leaf, SPKI = derive_cert_key(shared), natural size) → emit_server_hello (5b) and write it → serve the 5c flight under HANDSHAKE_TIMEOUT → pump the tunnel. The dead build_forged_acceptor* / CacheEntry.acceptor / RealityCertCache.key are removed.

The splice-vs-drop fail-safe boundary

Splicing forwards a pristine connection to the real dest (a prober sees a genuine site) — but only works before we've written our own bytes. So: every failure before the ServerHello write (no template, unsupported group, missing client share, forge/emit error, OS-rng failure) → splice; every failure after (serve error/timeout/IO) → drop (the client's 4b fallback covers it). The final review traced every early-return and confirmed the boundary holds in both directions.

Design decisions

  • Natural forged leaf, no exact-length padding (your call): the passive DPI can't see the Certificate message size (it's inside the AEAD); a real dest's leaf carries SCTs that forge_leaf drops, so a forged flight is reliably smaller than dest's and fits the captured record budget. FlightTooLarge → splice is the fail-safe if it ever doesn't.
  • OS-CSPRNG rng for the ServerHello (never seeded); serve bounded by HANDSHAKE_TIMEOUT (its CCS-drain is otherwise unbounded); anti-replay unchanged, runs before the branch.

The gate — a live end-to-end money test

bin/yipd/tests/run-netns-reality-5d.sh (ran under sudo, PASS): a real yipd client dialing reality://…&verify=on tunnels A→B through the relay whose authed path hand-rolls the flight — relay-forwarded=2106 packets (that counter is reachable only via the authed tunnel path, so >0 proves the 5b+5c+5d handshake completed and the 4b binding verified). A wrong-key client fails closed (0 packets, no retry-storm). The dest is a local openssl s_server -tls1_3 (hermetic). Wired into CI.

Scope / non-goals

Follow-ups (non-blocking, from the final review)

  • Hoist the CertVerify signing-key load above the ServerHello write (keeps all fallible steps on the splice side — its failure is currently unreachable).
  • A group-29-dest test (the 4588 path is netns-covered; group-29 is functionally sound but untested).
  • Exact-leaf-length padding (deferred by design) + the 5c cleanups (Error::MessageTooLarge, u24-helper extraction).

Final whole-branch review (opus): READY WITH FOLLOW-UPS — splice-vs-drop correct in both directions, no fail-open / no panic-on-input / no dangling reference, yip_utls untouched, forbid-unsafe / no as / no bare #[allow].

With this, REALITY.5 (5a/5b/5c/5d) is complete — the authed REALITY path is end-to-end dest-faithful.

vxfemboy added 6 commits July 18, 2026 13:17
…he relay

Replace BoringSSL SslAcceptor on the authed REALITY path with 5b emit_server_hello
+ 5c serve. Natural forged leaf (no exact leaf_der_len padding, user decision);
parse+thread the 4588-tail x25519; genericize handle_connection over the stream;
splice pre-write / drop post-write fail-safe boundary; OS-CSPRNG rng; serve bounded
by HANDSHAKE_TIMEOUT. netns money test = real verify=on client through 5d relay.
Last PR of REALITY.5. yip-rendezvous.
Parser 4588-x25519-tail / genericize handle_connection chain / authed-path
rewrite (splice pre-write, drop post-write) + reality_cert cleanup / netns
money test. Threads info through the decision tuple; r.certs/r.dest; deps
(p256/getrandom/rcgen) already present.
… the hand-rolled relay

Forks run-netns-reality-relay.sh into a focused run-netns-reality-5d.sh
proving the REALITY.5d wiring end-to-end: a real yipd client dialing
reality://...&verify=on completes the relay's hand-rolled server flight
(tls_front::run_reality_conn's Decision::Accept branch — 5b emit_server_hello
+ 5c emit_server_flight/serve, replacing the old BoringSSL SslAcceptor),
verifies the REALITY.4b binding against the forged leaf, and tunnels to a
peer THROUGH the relay (relay-forwarded>0). A wrong-pbk client gets no
tunnel: the relay's seal-open fails so it splices to --reality-dest
pre-ServerHello-write, never entering the hand-rolled emit path.

Ran under sudo twice, exit 0 both times: verify=on ping succeeded
(relay-forwarded=2106), wrong-pbk ping failed with no retry-storm (1
verification attempt in ~16s).

Wired into .github/workflows/integration.yml alongside the sibling
run-netns-reality-relay.sh step, same job/binaries.
Base automatically changed from feat/reality-5c-server-flight-emit to main July 19, 2026 01:19
@vxfemboy
vxfemboy merged commit 4d70812 into main Jul 19, 2026
9 checks passed
@vxfemboy
vxfemboy deleted the feat/reality-5d-wire-server-flight branch July 19, 2026 01:19
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