From 23915536587fb2900308ab81ce3eedcbf4cdb918 Mon Sep 17 00:00:00 2001 From: "shoney.arickathil" Date: Tue, 8 Sep 2026 18:28:14 +0200 Subject: [PATCH] docs(rv2-tls,status): F3c-net plan + net.connect_tls object-model default; session NEXT PLAN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rv2 9 §F3c-net: the remaining live-gated slice with auto-approved defaults — getrandom ephemeral, system CA-bundle loader, net.connect_tls builtin returning the TCP fd (fd-keyed side table, blocking model like net.connect) driving the sans-io driver, then wo_tls_verify_chain; plus net.read_tls/write_tls and a live gate - status board NEXT PLAN: the TLS client security engine landed this session (E-F3c minus socket glue), F3c-net is the next rung, then jarvis Co-Authored-By: Claude Opus 4.8 (cherry picked from commit ad87974fc722268e278f957f1f3d607f5dafa50d) --- docs/stories/00-status.md | 28 +++++++++++++++ docs/stories/runtime-v2/09-in-process-tls.md | 36 ++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/docs/stories/00-status.md b/docs/stories/00-status.md index 3bddb99..cddf423 100644 --- a/docs/stories/00-status.md +++ b/docs/stories/00-status.md @@ -76,6 +76,34 @@ behind this board; live Obsidian Dataview views: ## ▶ NEXT PLAN +### Landed 2026-09-08 — the TLS 1.3 client security engine (rv2 9, A–F3c minus the socket glue) + +**What happened this session (code + docs):** the entire security-critical logic +of a hand-rolled TLS 1.3 client is implemented and gold-KAT'd, in `runtime/src/` +`crypto.c` + new `tls.c`/`tls.h`. Landed and vector-gated (ASan/UBSan clean): +**E** X.509 chain-link verify + SPKI + validity + **SAN/hostname** (RFC 6125); +**F1** record layer (RFC 8446 §5.2, both suites, byte-for-byte vs python); +**F2** key schedule (§7.1, byte-for-byte vs **RFC 8448**); **F3a** ClientHello +builder + ServerHello parser; **F3b** offline CertificateVerify + Finished +verify; **F3c-core** the **sans-io handshake driver** (`wo_tls_client`, whole +handshake driven offline against the RFC 8448 record trace — client Finished + +app records byte-for-byte, tampered flight refused); **F3c-net security core** +`wo_tls_verify_chain` (chain-link + anchor + host + validity, no partial trust). +Tests: `test_tls` 100/0, `test_crypto` 95/0, full runtime suite 0 fail. Forks +auto-approved 2026-09-08, marked `review_pending` in the story frontmatter for a +developer second review before this drives a live connection. + +**Next step — F3c-net (the only remaining rung before jarvis unblocks):** the I/O +integration that must be gated **live** (a local `openssl s_server` / python TLS +server), specified with auto-approved defaults in +[rv2 9 §F3c-net](runtime-v2/09-in-process-tls.md): a `getrandom` ephemeral, the +system CA-bundle PEM loader, and the **`net.connect_tls`** builtin (default: +returns the TCP fd as an Int with `wo_tls_client` state in an fd-keyed side +table, blocking model like `net.connect`) driving the sans-io driver over a real +socket, then `wo_tls_verify_chain` against the loaded anchors. Then **G** (inbound +server) for porch. After that, jarvis 1 is buildable. (Separately still open: +language 41's marshal fix — below — unblocking porch 9.) + ### Brainstormed 2026-09-06 — the porch track (2–8) and language 41's fix, both to `ready` **What happened this session (docs only, no code):** the whole diff --git a/docs/stories/runtime-v2/09-in-process-tls.md b/docs/stories/runtime-v2/09-in-process-tls.md index ba00c92..f0f7cc1 100644 --- a/docs/stories/runtime-v2/09-in-process-tls.md +++ b/docs/stories/runtime-v2/09-in-process-tls.md @@ -82,6 +82,42 @@ they may split into their own runtime-v2 iterations as they are picked up. | 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 | +## F3c-net — the remaining slice (decisions auto-approved 2026-09-08, review pending) + +Everything security-critical is landed and offline-KAT'd. What is left is I/O +integration that can only be gated **live** (against a local `openssl s_server` +/ python TLS server), so it is a single cohesive slice, not further split: + +1. **Random ephemeral.** A `getrandom(2)`-backed source for the per-connection + X25519 private key (and the ClientHello random / session id). No `.wo` + randomness builtin is assumed; this is internal to the connect path. +2. **CA-bundle loader.** Parse the system PEM bundle + (`/etc/ssl/certs/ca-certificates.crt`, confirmed present on the dev box) into + DER trust anchors for `wo_tls_verify_chain`. Built **with** its consumer, not + ahead of it (its memory model is the connect path's to own). +3. **`net.connect_tls(host, port)` builtin.** TCP-connects (reusing the + `net.connect` path), generates the ephemeral, runs the sans-io driver — + framing records off the socket (read the 5-byte header, then the body) and + flushing `take_output` — until ESTABLISHED, then validates the chain + (`wo_tls_verify_chain` with the loaded anchors + the host). Plus + `net.read_tls` / `net.write_tls` for application data. + - **Handle representation (default, auto-approved):** mirror `net.connect` — + the builtin returns the **TCP fd as an Int**, and the runtime keeps the + `wo_tls_client` state in a side table keyed by fd; `net.read_tls` / + `net.write_tls` / `net.close` look it up and free it on close. This is the + smallest change to the language surface (no new class) and matches the + existing fd-based net verbs. The alternative — a first-class `TlsConn` + language object — is heavier and deferred unless the developer prefers it. + - **Blocking model (default, auto-approved):** the handshake and app I/O + block, exactly as today's `net.connect` does; the park-plane async refit is + a later refinement, not a v1 requirement. + - VM wiring: new `WO_B_NET_CONNECT_TLS` / `_READ_TLS` / `_WRITE_TLS` ids in + `wob.h`, `emit.ml` / `types.ml` registration, `loader.c` arities, + `builtin.c` dispatch, `sysio.c` implementation. +4. **Live gate.** A `just` recipe dialing a local TLS server: full handshake, + chain+host validation, a request/response round-trip, and the negative cases + (wrong host, untrusted chain, expired cert) each refused. + ## Consumers Named, so this is not a capability shipped as decoration: