From ad088163cc05210e988214cbef112a7cd66a8686 Mon Sep 17 00:00:00 2001 From: "shoney.arickathil" Date: Tue, 8 Sep 2026 18:22:38 +0200 Subject: [PATCH] docs(rv2-tls,jarvis): TLS ladder through F3c-core + SAN landed - rv2 9 phase-F row + review_pending: F3c-core sans-io driver + SAN/host landed (KAT'd vs RFC 8448 record trace); remaining F3c-net = system CA trust-anchor walk + net.connect_tls VM plumbing (live-gated), then G - jarvis 00-story + 01 blocker tables: crypto/handshake engine landed; jarvis now waits only on net.connect_tls (the socket glue) - status board rv2 9 row updated to the full ladder state Co-Authored-By: Claude Opus 4.8 (cherry picked from commit 4fdf07196d01c32d0ab12d32d36fa4285ff34654) --- docs/stories/00-status.md | 2 +- docs/stories/jarvis/00-story.md | 17 ++++++++++------- docs/stories/jarvis/01-chat-loop.md | 6 ++++-- docs/stories/runtime-v2/09-in-process-tls.md | 4 ++-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/docs/stories/00-status.md b/docs/stories/00-status.md index 136462f..3bddb99 100644 --- a/docs/stories/00-status.md +++ b/docs/stories/00-status.md @@ -1543,7 +1543,7 @@ starts. Edges in [dependency graph section 6](../00-dependency-graph.md). | 6 | [term.size + term.width](runtime-v2/06-term-size-width.md) | ✅ **DONE 2026-09-02** — TIOCGWINSZ read twin (nil = not a tty) and libc wcwidth under C.UTF-8; the only runtime work the whole wmux parity ladder needs | | 7 | [observability](runtime-v2/07-observability.md) | ⬜ `refine` — **moved here 2026-09-06** from language iteration 30 (`was_language_iteration: 30`). Runtime metrics/gauges, a `pprof`-equivalent profile, stack-trace-on-trap; consumers named (porch [8](porch/08-static-and-lifecycle.md)/[39](language-runtime-database/39-web-framework-parity.md), databasev2 [5](databasev2/05-bounded-tables-eviction.md), the limiter's lazy expiry). Forks: counters-only vs profiling, exposition format, pull vs push, trace-on-trap as a separable first slice. Stretches the track's charter (instrumentation, not processes/terminals/signals) — noted in the story | | 8 | [symmetric cipher (AEAD)](runtime-v2/08-symmetric-cipher.md) | 🔄 **in-progress** — the **first rung of the TLS ladder** (gates rv2 9). **Phases A + B + C LANDED 2026-09-08**: A ChaCha20-Poly1305 (ids 111/112, RFC 8439 §2.8.2); B AES-128/256-GCM (ids 113/114) via AES-NI+PCLMULQDQ; C portable constant-time software AES-GCM fallback (S-box via GF-inverse ladder, bit-by-bit GHASH) — AES-GCM now on any CPU, dispatched hw-or-sw. All hand-rolled, constant-time, both AES paths NIST cases 4 & 16 byte-exact, KAT-gated in test_crypto (**48/0**), ASan/UBSan clean. Remaining: D cookie wrapper → E gate (ARMv8 hw path deferred). Consumers: rv2 9 TLS + porch encrypted cookies | -| 9 | [in-process TLS](runtime-v2/09-in-process-tls.md) | 🔄 **in-progress** (`ready` 2026-09-07) — TLS **both directions**, **retiring the "TLS is the proxy's job" doctrine** (34/38/porch). Locked: **hand-roll TLS 1.3**, **1.3-only**, **RSA+ECDSA+full X.509**. Ladder: **A AEAD ✅ → B HKDF ✅ → C X25519 ✅ → D signatures ✅ (RSA PKCS1+PSS + ECDSA-P256, 2026-09-08, KAT-gated)** → E ASN.1/X.509 → F record+FSM client → G server. `net.connect` (110) landed. The project's **highest-risk** work; mandatory reference-tested/constant-time/negative-test gates; C/D/E may each split into own iterations | +| 9 | [in-process TLS](runtime-v2/09-in-process-tls.md) | 🔄 **in-progress** (`ready` 2026-09-07) — TLS **both directions**, **retiring the "TLS is the proxy's job" doctrine** (34/38/porch). Locked: **hand-roll TLS 1.3**, **1.3-only**, **RSA+ECDSA+full X.509**. Ladder (all KAT'd vs **RFC 8448** / real certs, ASan/UBSan clean, 2026-09-08): **A AEAD ✅ → B HKDF ✅ → C X25519 ✅ → D signatures ✅ → E X.509 ✅ + SAN/hostname ✅ → F1 record ✅ → F2 key schedule ✅ → F3a messages ✅ → F3b offline handshake verify ✅ → F3c-core sans-io handshake driver ✅** (whole handshake driven offline vs the RFC 8448 record trace: client Finished + app records byte-for-byte, tampered flight refused). New `tls.c`/`tls.h`; test_tls 91/0, test_crypto 95/0. **Remaining F3c-net**: random ephemeral for production, system CA trust-anchor walk, `net.connect_tls` VM plumbing (live-gated) → then **G** server. `net.connect` (110) landed. Forks auto-approved 2026-09-08, marked `review_pending`. The project's **highest-risk** work; mandatory reference-tested/constant-time/negative-test gates | ### ▸ wmux — the terminal multiplexer track diff --git a/docs/stories/jarvis/00-story.md b/docs/stories/jarvis/00-story.md index e6f7ec9..dff29a1 100644 --- a/docs/stories/jarvis/00-story.md +++ b/docs/stories/jarvis/00-story.md @@ -30,12 +30,15 @@ runtime work, now **partly built**: `getaddrinfo` DNS + blocking connect; the outbound half language 38 named). - **An outbound TLS client** — HTTPS over that socket — owned by runtime-v2 [9](../runtime-v2/09-in-process-tls.md) (in-process TLS), which - **retires the standing "TLS is the proxy's job" doctrine**. In progress: its - crypto foundations are landed and vector-gated — **A AEAD** (ChaCha20-Poly1305 - + AES-GCM, runtime-v2 [8](../runtime-v2/08-symmetric-cipher.md) A–C), - **B HKDF**, **C X25519**, **D signatures** (RSA PKCS1/PSS + ECDSA-P256) — and - the remaining rungs (**E** ASN.1/X.509 chain, **F** record layer + handshake - FSM, **G** server) are what jarvis still waits on. + **retires the standing "TLS is the proxy's job" doctrine**. In progress and + mostly landed: **A AEAD** (ChaCha20-Poly1305 + AES-GCM), **B HKDF**, + **C X25519**, **D signatures** (RSA PKCS1/PSS + ECDSA-P256), **E X.509** + + **SAN/hostname**, **F1** record layer, **F2** key schedule, **F3a** message + layer, **F3b** offline handshake verification, and the **F3c-core sans-io + handshake driver** — all vector-gated against RFC 8448 and real cert chains. + What jarvis still waits on is **F3c-net**: the `net.connect_tls` builtin (the + socket glue driving that driver over a real fd) plus a system CA trust-anchor + walk — and **G** (inbound server) for porch, not jarvis. A **local-gateway alternative was considered and set aside**: jarvis could speak to a small companion process over a unix socket (`net.connect_unix`, id 107) or @@ -90,7 +93,7 @@ Blockers, which must land before iteration 1 starts: | Blocker | Owner | State | | --- | --- | --- | | outbound TCP (`net.connect`) | language [38](../language-runtime-database/38-content-platform-capabilities.md) | ✅ **landed 2026-09-07** (`wob.h` id 110) | -| outbound TLS client | runtime-v2 [9](../runtime-v2/09-in-process-tls.md) — in-process TLS; **retires the proxy-termination doctrine** | 🔄 in progress — A AEAD ✅, B HKDF ✅, C X25519 ✅, D signatures ✅ (RSA + ECDSA-P256); **E–G remain** | +| outbound TLS client | runtime-v2 [9](../runtime-v2/09-in-process-tls.md) — in-process TLS; **retires the proxy-termination doctrine** | 🔄 in progress — A AEAD ✅, B HKDF ✅, C X25519 ✅, D signatures ✅, E X.509 ✅, F1 record ✅, F2 key schedule ✅, F3a messages ✅, F3b offline verify ✅, F3c-core sans-io handshake driver ✅, SAN/hostname ✅ (all KAT'd vs RFC 8448 / real certs); **remaining F3c-net**: system CA trust-anchor walk + `net.connect_tls` VM plumbing (live-gated), then G server | ## What this track does NOT own diff --git a/docs/stories/jarvis/01-chat-loop.md b/docs/stories/jarvis/01-chat-loop.md index 04d6936..f29c495 100644 --- a/docs/stories/jarvis/01-chat-loop.md +++ b/docs/stories/jarvis/01-chat-loop.md @@ -20,8 +20,10 @@ review_pending: "forks auto-approved 2026-09-08 for autonomous execution — dev ## Blocked until the outbound seam lands This iteration cannot run until `net.connect` (✅ landed) and runtime-v2 -[9](../runtime-v2/09-in-process-tls.md) TLS reach **phase F** (`net.connect_tls` -+ the handshake). Crypto A–D are landed; E (X.509) and F (handshake) remain. +[9](../runtime-v2/09-in-process-tls.md) TLS expose **`net.connect_tls`**. The +crypto + handshake engine is landed and RFC-8448-gated (A–E, F1–F3c-core, the +sans-io client driver, SAN/hostname); what remains is **F3c-net** — the socket +glue that drives the driver over a real fd, plus a system CA trust-anchor walk. Everything below is buildable `.wo` on top of that seam plus porch 2/3/6/7. ## Decisions locked (auto-approved, review pending) diff --git a/docs/stories/runtime-v2/09-in-process-tls.md b/docs/stories/runtime-v2/09-in-process-tls.md index abbf31d..ba00c92 100644 --- a/docs/stories/runtime-v2/09-in-process-tls.md +++ b/docs/stories/runtime-v2/09-in-process-tls.md @@ -3,7 +3,7 @@ track: runtime-v2 iteration: "9" status: in-progress readiness: ready -review_pending: "forks auto-approved 2026-09-08 for autonomous execution — developer second review before this ships. Landed: A–E crypto, F1 record layer, F2 key schedule, F3a message layer, F3b offline handshake verification (all KAT'd vs RFC 8448 / real certs). Remaining: F3c socket FSM + net.connect_tls VM plumbing (live-gated) incl. the deferred SAN/hostname + system CA-bundle chain walk; G inbound server" +review_pending: "forks auto-approved 2026-09-08 for autonomous execution — developer second review before this ships. Landed: A–E crypto, F1 record layer, F2 key schedule, F3a message layer, F3b offline handshake verification, F3c-core sans-io client driver, SAN/hostname (all KAT'd vs RFC 8448 / real certs). Remaining F3c-net: random ephemeral for production, system CA trust-anchor chain walk, net.connect_tls VM plumbing (live-gated). Then G inbound server" --- # runtime-v2 9 — in-process TLS: retiring the proxy-termination doctrine @@ -79,7 +79,7 @@ they may split into their own runtime-v2 iterations as they are picked up. | C — key exchange | ✅ **LANDED 2026-09-08** — `wo_x25519` (RFC 7748), constant-time Montgomery ladder + mask-based cswap, radix-2⁵¹ field arithmetic (curve25519-donna-c64, `__int128`). Internal C. KAT-gated in `test_crypto.c`: RFC 7748 §5.2 both direct vectors **and the 1000-iteration test**, ASan/UBSan clean | | D — signatures | ✅ **LANDED 2026-09-08** — **RSA** `wo_rsa_pkcs1_sha256_verify` + `wo_rsa_pss_sha256_verify` (bignum Montgomery modexp) and **ECDSA-P256** `wo_ecdsa_p256_sha256_verify` (Jacobian point arithmetic, a=-3, on-curve check, Fermat inverses reusing the bignum). Verification is public data so **not** constant-time by design. Both match python vectors (RSA-2048 PKCS1+PSS; P-256), tamper/wrong-hash rejected, KAT-gated, ASan/UBSan clean | | E — X.509 | 🔄 **CORE LANDED 2026-09-08** — a defensive ASN.1/DER reader (every length/bound checked, malformation is rejection not over-read) + certificate parse (tbsCertificate span, sig-alg OID, signature, SubjectPublicKeyInfo→RSA n/e or EC P-256 x/y, validity) + `wo_x509_verify_one` (one chain link's signature, dispatching to D's RSA-PKCS1/PSS + ECDSA-P256) + `wo_x509_parse_spki` + `wo_x509_check_validity` (caller supplies the time). KAT-gated in `test_crypto.c` against **real python-generated chains** — RSA CA+leaf (SHA256withRSA) and EC P-256 CA+leaf (ecdsa-with-SHA256): leaf-vs-CA, self-signed CA, wrong-issuer/tampered/truncated rejected, validity window, SPKI extraction — ASan/UBSan clean. **Deferred to F**: SAN/hostname match (needs the target host) and the multi-cert chain walk to a system CA bundle | notoriously bug-prone; consumes D | -| F — record + handshake (client) | 🔄 **F1–F3b LANDED 2026-09-08** — new `tls.c`/`tls.h`. **F1 record layer** (`wo_tls_record_seal`/`open`, RFC 8446 §5.2, per-record nonce = iv XOR seq, both suites) KAT'd byte-for-byte vs python. **F2 key schedule** (`wo_tls_derive_handshake`/`_application`/`_traffic_keys`/`_finished_verify`, §7.1) KAT'd byte-for-byte vs **RFC 8448 §3**. **F3a message layer** (`wo_tls_parse_server_hello` — attacker input, bounded, rejects HRR/bad suite/truncation; `wo_tls_build_client_hello` — SNI, x25519, sig-algs) KAT'd vs RFC 8448 SH + validated by an independent parser. **F3b offline handshake verification** (`wo_tls_verify_cert_verify` over phase E+D; server + client Finished) — the whole handshake **crypto** proven end-to-end offline vs RFC 8448. **Remaining F3c**: the socket FSM (drive CH→Finished over a real TCP fd, record read/write buffering, multi-cert chain walk + SAN/hostname), the `net.connect_tls` builtin + `net.read_tls`/`net.write_tls` VM plumbing, gated live against `openssl s_server` | jarvis's path; the reason the story exists | +| F — record + handshake (client) | 🔄 **F1–F3b LANDED 2026-09-08** — new `tls.c`/`tls.h`. **F1 record layer** (`wo_tls_record_seal`/`open`, RFC 8446 §5.2, per-record nonce = iv XOR seq, both suites) KAT'd byte-for-byte vs python. **F2 key schedule** (`wo_tls_derive_handshake`/`_application`/`_traffic_keys`/`_finished_verify`, §7.1) KAT'd byte-for-byte vs **RFC 8448 §3**. **F3a message layer** (`wo_tls_parse_server_hello` — attacker input, bounded, rejects HRR/bad suite/truncation; `wo_tls_build_client_hello` — SNI, x25519, sig-algs) KAT'd vs RFC 8448 SH + validated by an independent parser. **F3b offline handshake verification** (`wo_tls_verify_cert_verify` over phase E+D; server + client Finished) — the whole handshake **crypto** proven end-to-end offline vs RFC 8448. **F3c-core sans-io driver** (`wo_tls_client` — pure FSM, caller frames records: CH→SH→flight→Finished, message reassembly, per-message transcript timing, constant-time Finished, application encrypt/decrypt) KAT'd against the **full RFC 8448 record trace** — client Finished + first app record byte-for-byte, NewSessionTicket + server app data decrypt, tampered flight refused. **SAN/hostname** (`wo_x509_check_host`, RFC 6125) + driver enforcement landed. **Remaining F3c-net**: random ephemeral for production start, the multi-cert chain walk to a **system CA trust anchor**, and the `net.connect_tls` builtin + `net.read_tls`/`net.write_tls` VM plumbing (record framing over a real fd), gated live against `openssl s_server` | jarvis's path; the reason the story exists | | G — server (inbound) | the server handshake half, cert+key loading, signing CertificateVerify; porch terminates TLS | retires the inbound proxy requirement, and the doctrine docs | ## Consumers