REALITY.5: server-flight (ServerHello) fidelity for the authed path #76

Closed
opened 2026-07-16 04:17:29 +00:00 by vxfemboy · 1 comment
vxfemboy commented 2026-07-16 04:17:29 +00:00 (Migrated from github.com)

Summary

REALITY.3 makes the relay's authenticated TLS branch present a certificate forged from the real dest site, but the ServerHello it emits is generated by the relay's own BoringSSL stack — not dest's stack (nginx/Cloudflare/etc.). In TLS 1.3 the ServerHello is cleartext (only the Certificate onward is encrypted), so its chosen cipher suite, chosen key-share group, extension set/order, GREASE placement, and cert-compression advertisement need not match dest's. A passive DPI box holding a per-dest ServerHello template could therefore distinguish an authenticated REALITY session from a genuine browser↔dest session.

This is the REALITY.5 milestone, spun out during REALITY.3's adversarial + cross-model review and recorded in the milestone spec. Filing as a tracked issue.

Scope of the gap (and what REALITY.3 does/doesn't claim)

  • REALITY.3 only claims passive-DPI indistinguishability for the un-authenticated splice path (which is literally dest's own bytes forwarded verbatim).
  • It does not claim it for the authed path's ServerHello — that is explicitly deferred here.
  • The un-authed prober / active-probe property (no key ⇒ spliced to dest, byte-identical) is unaffected; this is strictly about a passive observer of authed traffic with a per-dest fingerprint template.

Possible approaches

  • Configure the authed acceptor's TLS stack to emit a ServerHello matching dest's observed template (cipher preference order, extension set/order, GREASE, cert-compression), captured at pre-warm time alongside the leaf.
  • Or match a common CDN template as a first approximation.
  • Note: verbatim byte-replay of dest's ServerHello is not viable — the ServerHello carries dest's ephemeral key-share, which must correspond to keys we actually hold; the fields must be reproduced by our stack, not replayed.

References

  • Milestone spec follow-up: docs/superpowers/specs/2026-07-15-reality-tls-milestone-design.md ("REALITY.3 advisor review — follow-up spun out")
  • Spec §Threat model + Risks: docs/superpowers/specs/2026-07-15-reality-3-server-cert-steal-design.md
  • Deferred from the REALITY.3 PR.
## Summary REALITY.3 makes the relay's **authenticated** TLS branch present a certificate forged from the real `dest` site, but the **ServerHello** it emits is generated by the relay's own BoringSSL stack — **not** `dest`'s stack (nginx/Cloudflare/etc.). In TLS 1.3 the ServerHello is **cleartext** (only the Certificate onward is encrypted), so its chosen cipher suite, chosen key-share group, extension set/order, GREASE placement, and cert-compression advertisement need not match `dest`'s. A passive DPI box holding a per-`dest` ServerHello template could therefore distinguish an authenticated REALITY session from a genuine browser↔`dest` session. This is the **REALITY.5** milestone, spun out during REALITY.3's adversarial + cross-model review and recorded in the milestone spec. Filing as a tracked issue. ## Scope of the gap (and what REALITY.3 does/doesn't claim) - REALITY.3 **only claims passive-DPI indistinguishability for the un-authenticated splice path** (which is literally `dest`'s own bytes forwarded verbatim). - It **does not** claim it for the authed path's ServerHello — that is explicitly deferred here. - The un-authed prober / active-probe property (no key ⇒ spliced to `dest`, byte-identical) is unaffected; this is strictly about a passive observer of authed traffic with a per-dest fingerprint template. ## Possible approaches - Configure the authed acceptor's TLS stack to emit a ServerHello matching `dest`'s observed template (cipher preference order, extension set/order, GREASE, cert-compression), captured at pre-warm time alongside the leaf. - Or match a common CDN template as a first approximation. - Note: verbatim byte-replay of `dest`'s ServerHello is **not** viable — the ServerHello carries `dest`'s ephemeral key-share, which must correspond to keys we actually hold; the fields must be *reproduced* by our stack, not replayed. ## References - Milestone spec follow-up: `docs/superpowers/specs/2026-07-15-reality-tls-milestone-design.md` ("REALITY.3 advisor review — follow-up spun out") - Spec §Threat model + Risks: `docs/superpowers/specs/2026-07-15-reality-3-server-cert-steal-design.md` - Deferred from the REALITY.3 PR.
vxfemboy commented 2026-07-19 01:25:20 +00:00 (Migrated from github.com)

Done — merged to main (tip 8bfbd0c)

REALITY.5 is complete: the authed REALITY path now serves a byte/length-faithful, hand-rolled TLS 1.3 server flight instead of BoringSSL's, closing the passive-DPI gap this issue tracked. An authed session is now indistinguishable from a genuine browser↔dest session end to end (cleartext ServerHello and encrypted-flight framing).

Shipped across a stacked PR chain (all merged):

  • #83 — REALITY.5a: dest server-flight template capture (capture_dest_flightServerFlightTemplate per SNI)
  • #89 (recreated from #85) — REALITY.5b: byte-matching emit_server_hello + server key schedule (X25519MLKEM768/4588 + X25519/29), round-trip proven
  • #86 — REALITY.5c: emit_server_flight (EE/Certificate/CertificateVerify/Finished) framed to dest's record_lengths, + role-agnostic server stream
  • #87 — REALITY.5d: wired into the relay's authed path (emit_server_hello + serve), BoringSSL SslAcceptor removed; splice-pre-write / drop-post-write fail-safe
  • #88 — follow-up cleanups (Error::MessageTooLarge + u24_len, pre-write signing-key hoist, partial-record-stall splice, group-29 e2e test)

The core ask — ServerHello cipher/group/extension-order/GREASE fidelity to dest — is 5b; the deferred cert-flight size gap is 5c. Verified by 5b/5c byte-match tests, a client↔server round-trip, and a live netns money test (a real verify=on client tunnels through the hand-rolled relay; wrong-key fails closed).

Deferred (own issue): P256/P384 server KEX + HelloRetryRequest → #84 (a dest selecting those currently → splice, safe/no-fidelity).

## Done — merged to `main` (tip `8bfbd0c`) REALITY.5 is complete: the authed REALITY path now serves a byte/length-faithful, hand-rolled TLS 1.3 server flight instead of BoringSSL's, closing the passive-DPI gap this issue tracked. An authed session is now indistinguishable from a genuine browser↔`dest` session end to end (cleartext ServerHello **and** encrypted-flight framing). Shipped across a stacked PR chain (all merged): - **#83** — REALITY.5a: dest server-flight template capture (`capture_dest_flight` → `ServerFlightTemplate` per SNI) - **#89** (recreated from #85) — REALITY.5b: byte-matching `emit_server_hello` + server key schedule (X25519MLKEM768/4588 + X25519/29), round-trip proven - **#86** — REALITY.5c: `emit_server_flight` (EE/Certificate/CertificateVerify/Finished) framed to `dest`'s `record_lengths`, + role-agnostic server stream - **#87** — REALITY.5d: wired into the relay's authed path (`emit_server_hello` + `serve`), BoringSSL `SslAcceptor` removed; splice-pre-write / drop-post-write fail-safe - **#88** — follow-up cleanups (`Error::MessageTooLarge` + `u24_len`, pre-write signing-key hoist, partial-record-stall splice, group-29 e2e test) The core ask — ServerHello cipher/group/extension-order/GREASE fidelity to `dest` — is 5b; the deferred cert-flight size gap is 5c. Verified by 5b/5c byte-match tests, a client↔server round-trip, and a live netns money test (a real `verify=on` client tunnels through the hand-rolled relay; wrong-key fails closed). **Deferred (own issue):** P256/P384 server KEX + HelloRetryRequest → #84 (a `dest` selecting those currently → splice, safe/no-fidelity).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
femboy/yip#76
No description provided.