REALITY.5a: dest server-flight template capture (Chrome-faithful probe, read-only foundation for 5b/c/d) #83

Merged
vxfemboy merged 8 commits from feat/reality-5a-dest-flight-capture into main 2026-07-19 00:49:12 +00:00
vxfemboy commented 2026-07-17 21:32:49 +00:00 (Migrated from github.com)

REALITY.5a — dest server-flight template capture

PR 1 of the REALITY.5 milestone (server-flight fidelity, #76). Read-only foundation — captures, per configured server_name, the structure of the real dest's TLS 1.3 server flight so later sub-milestones (5b/5c/5d) can emit an authed-path flight indistinguishable from a genuine Chrome↔dest session. No emission here.

Key insight

In TLS 1.3 only the ServerHello is cleartext (later sub-milestones must byte-match it); everything after (EncryptedExtensions, Certificate, CertificateVerify, Finished) is encrypted — a passive DPI sees only the encrypted records' lengths + framing. So the template captures the ServerHello structure and the encrypted flight's shape, not the cert contents. yip_utls is ideally placed: it reads the cleartext ServerHello raw and decrypts the flight, so it sees both.

What's in it

  • yip_utls::capture_dest_flight — a Chrome-faithful probe (a focused sibling of connect; connect's crux path is byte-for-byte untouched — the probe duplicates its ~15-line flight-read loop plus one bookkeeping line rather than refactor it). It sends the same Chrome ClientHello (random legacy_session_id, no REALITY seal — probing the real dest), reads + parses the ServerHello structure, derives handshake keys, decrypts + walks the flight, and returns a ServerFlightTemplate + the leaf DER — stopping after the server Finished (no client Finished, no app phase).
  • ServerFlightTemplate: ServerHelloShape (cipher, ordered extensions incl. GREASE, key_share_group) + EncryptedFlightShape (per-record ciphertext-payload lengths + per-message lengths — record_lengths[i] − 17 is the per-record plaintext 5c reproduces, 16-byte tag + 1 content-type) + CertChainShape { leaf_der_len, intermediates_der }intermediates captured verbatim (public CA certs; 5c appends them after the forged leaf for full chain parity at zero extra forging).
  • yip-rendezvous — the dest probe is unified on this Chrome-faithful capture (replacing the boring cert fetch, so dest now responds to the exact hello our clients send); the template is cached per SNI (template_for, dead-code-gated until 5b) alongside StolenFields, at prewarm + refresh. REALITY.3/4b (forged acceptor, per-SNI degrade, staleness, per-connection binding) and anti-replay are untouched (0 diff lines).

Review

Built subagent-driven (4 tasks, two-stage review each). The per-task review caught that Task 2's shared-helper refactor widened 4b's verify path to depend on the whole cert chain (safe per RFC 8446 §4.4.2, now covered by a multi-cert verify test). The final whole-branch review confirmed the capture chain composes correctly (proven by a mock with a non-canonical extension order + 2-record split + 2-cert chain), connect untouched, and the migration is fail-closed.

Follow-ups recorded for 5b/5c (in the milestone spec): record-framing and message-framing are independent knobs (5c pads both); the middlebox-compat CCS is a fixed invariant to emit unconditionally.

Tests

yip-utls 53 + JA4 diff, yip-rendezvous 81, all green. clippy --workspace -D warnings + fmt clean. forbid-unsafe (outside yip-io/yip-device); no as; no bare #[allow]. The dest probe migration preserves StolenFields (incl. #75 AIA); a live #[ignore] cloudflare capture is included.

## REALITY.5a — dest server-flight template capture PR 1 of the REALITY.5 milestone (server-flight fidelity, #76). **Read-only foundation** — captures, per configured `server_name`, the structure of the real `dest`'s TLS 1.3 server flight so later sub-milestones (5b/5c/5d) can emit an authed-path flight indistinguishable from a genuine Chrome↔`dest` session. No emission here. ### Key insight In TLS 1.3 only the **ServerHello is cleartext** (later sub-milestones must byte-match it); everything after (EncryptedExtensions, Certificate, CertificateVerify, Finished) is **encrypted** — a passive DPI sees only the encrypted records' **lengths + framing**. So the template captures the ServerHello *structure* and the encrypted flight's *shape*, not the cert contents. `yip_utls` is ideally placed: it reads the cleartext ServerHello raw and decrypts the flight, so it sees both. ### What's in it - **`yip_utls::capture_dest_flight`** — a Chrome-faithful probe (a focused sibling of `connect`; **`connect`'s crux path is byte-for-byte untouched** — the probe duplicates its ~15-line flight-read loop plus one bookkeeping line rather than refactor it). It sends the same Chrome ClientHello (random `legacy_session_id`, no REALITY seal — probing the real dest), reads + parses the ServerHello structure, derives handshake keys, decrypts + walks the flight, and returns a `ServerFlightTemplate` + the leaf DER — stopping after the server Finished (no client Finished, no app phase). - **`ServerFlightTemplate`**: `ServerHelloShape` (cipher, **ordered** extensions incl. GREASE, `key_share_group`) + `EncryptedFlightShape` (per-record ciphertext-payload lengths + per-message lengths — `record_lengths[i] − 17` is the per-record plaintext 5c reproduces, 16-byte tag + 1 content-type) + `CertChainShape { leaf_der_len, intermediates_der }` — **intermediates captured verbatim** (public CA certs; 5c appends them after the forged leaf for full chain parity at zero extra forging). - **`yip-rendezvous`** — the dest probe is **unified on this Chrome-faithful capture** (replacing the boring cert fetch, so dest now responds to the exact hello our clients send); the template is cached per SNI (`template_for`, dead-code-gated until 5b) alongside `StolenFields`, at prewarm + refresh. REALITY.3/4b (forged acceptor, per-SNI degrade, staleness, per-connection binding) and anti-replay are untouched (0 diff lines). ### Review Built subagent-driven (4 tasks, two-stage review each). The per-task review caught that Task 2's shared-helper refactor widened 4b's *verify* path to depend on the whole cert chain (safe per RFC 8446 §4.4.2, now covered by a multi-cert verify test). The final whole-branch review confirmed the capture chain composes correctly (proven by a mock with a non-canonical extension order + 2-record split + 2-cert chain), `connect` untouched, and the migration is fail-closed. Follow-ups recorded for 5b/5c (in the milestone spec): record-framing and message-framing are independent knobs (5c pads both); the middlebox-compat CCS is a fixed invariant to emit unconditionally. ### Tests `yip-utls` 53 + JA4 diff, `yip-rendezvous` 81, all green. `clippy --workspace -D warnings` + `fmt` clean. `forbid-unsafe` (outside yip-io/yip-device); no `as`; no bare `#[allow]`. The dest probe migration preserves `StolenFields` (incl. #75 AIA); a live `#[ignore]` cloudflare capture is included.
Sign in to join this conversation.
No description provided.