docs(rv2-tls): rv2 9 COMPLETE (both directions); retire proxy doctrine; jarvis-after-porch

- rv2 9 story -> status: done. §G G3 landed; ladder A–G complete, live-gated
  both directions (just tls 5/0, just tls-server 4/0). review_pending +
  phase rows + G sub-phases updated
- doctrine retired where the story named it: language 34 ("TLS permanently
  the proxy's job"), language 38 ("proxy-terminated ... no HTTPS clients"),
  porch 00-story ("TLS ... proxy-terminated") — each corrected to point at
  in-process TLS (net.connect_tls / net.accept_tls)
- status board: rv2 9 row DONE + a top summary; NEXT PLAN = porch then
  jarvis (sequencing set: jarvis follows porch)
- jarvis 00-story: sequencing note (no longer runtime-blocked; porch first)
- CODE-LOGIC: the inbound-server section (net.accept_tls, signing, slot
  refactor, RST-drain, gate)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit f3a3c962e5f288c25e505851edef4e0a5df9a85f)
This commit is contained in:
shoney.arickathil 2026-09-09 05:03:30 +02:00
parent e1d29d63e4
commit 8992dbd589
7 changed files with 76 additions and 22 deletions

View file

@ -76,7 +76,23 @@ behind this board; live Obsidian Dataview views:
## ▶ NEXT PLAN ## ▶ NEXT PLAN
### Landed 2026-09-09 — the outbound TLS 1.3 client is COMPLETE (rv2 9 A–F3c), live-gated; jarvis unblocked ### Landed 2026-09-09 — rv2 9 in-process TLS 1.3 is COMPLETE, both directions, live-gated
**rv2 9 DONE.** In-process TLS 1.3 both directions, hand-rolled, RFC-8448/real-cert
gated, retiring the proxy-termination doctrine (34/38/porch corrected). **Outbound**
`net.connect_tls`/`read_tls`/`write_tls` (ids 115–117) — `just tls` 5/0.
**Inbound** `net.accept_tls` (id 118) — `just tls-server` 4/0 (openssl s_client,
EC + RSA). Signing is the runtime's first private-key crypto: constant-time
RSA-PSS + ECDSA-P256 with an RFC 6979 nonce, plus `wo_pkey_parse`
(PKCS#8/PKCS#1/SEC1). `test_tls` 123/0, `test_crypto` 130/0, full suite 0 fail.
Deferred (named follow-ups, none blocking): park-based handshake, `TlsConn`
language object, connection pooling, close_notify on shutdown, complete-formula
EC ladder. **Next: porch** (then jarvis — the developer set jarvis to follow
porch completion). Separately open: language 41's marshal fix (unblocks porch 9).
<details><summary>outbound client detail (F-phases)</summary>
### Landed 2026-09-09 — the outbound TLS 1.3 client (rv2 9 A–F3c), live-gated; jarvis unblocked
**What happened (code + docs):** a whole hand-rolled TLS 1.3 client, in **What happened (code + docs):** a whole hand-rolled TLS 1.3 client, in
`runtime/src/crypto.c` + new `tls.c`/`tls.h` + the `net.*_tls` builtins, gated `runtime/src/crypto.c` + new `tls.c`/`tls.h` + the `net.*_tls` builtins, gated
@ -100,12 +116,19 @@ trap `WO_T_IO`; per-shard lazy read-only CA bundle `WO_CA_BUNDLE`; handshake
deadline `WO_TLS_HANDSHAKE_MS`; basicConstraints+EKU hardening). Forks deadline `WO_TLS_HANDSHAKE_MS`; basicConstraints+EKU hardening). Forks
auto-approved 2026-09-08/09, `review_pending` for a developer second review. auto-approved 2026-09-08/09, `review_pending` for a developer second review.
**Next step — jarvis 1 (the chat loop) is now buildable** (its outbound seam is (This F-phase detail is superseded by the rv2-9-DONE summary above.)
open); or rv2 9 **G** (inbound TLS server) for porch, which also lets the
proxy-termination doctrine docs (34/38/porch) be corrected. Deferred rv2 9 </details>
follow-ups: a park-based handshake, a first-class `TlsConn` object, connection
pooling. (Separately still open: language 41's marshal fix — below — unblocking ### Sequencing set 2026-09-09 — jarvis follows porch
porch 9.)
The developer set the order: **jarvis is implemented once porch is complete and
ready for all future jarvis iterations**. So with rv2 9 (the outbound seam) done,
the path is **porch first** — the framework the jarvis chat loop is written on —
then jarvis 1–3. porch's own blocker is language 41's marshal fix (unblocks
[porch 9](porch/09-idempotent-replay.md)); the porch track (2–8) is brainstormed
to `ready`, its language bill three small builtins (`random_bytes`,
`deflate`/`crc32`, `time.utc`).
### Brainstormed 2026-09-06 — the porch track (2–8) and language 41's fix, both to `ready` ### Brainstormed 2026-09-06 — the porch track (2–8) and language 41's fix, both to `ready`
@ -1574,7 +1597,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 | | 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 | | 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 | | 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** — **outbound client COMPLETE 2026-09-09**, **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 (KAT'd vs **RFC 8448** / real certs, ASan/UBSan clean): **A AEAD ✅ → B HKDF ✅ → C X25519 ✅ → D signatures ✅ → E X.509 + SAN/hostname + basicConstraints/EKU ✅ → F1 record ✅ → F2 key schedule ✅ → F3a messages ✅ → F3b offline verify ✅ → F3c-core sans-io driver ✅ → F3c-net `net.connect_tls`/`read_tls`/`write_tls` ✅** (ids 115–117; deadline-bounded blocking handshake then parked data plane; per-shard fd-keyed no-lock slots; CA bundle via `WO_CA_BUNDLE`). **Live-gated** `just tls` (5/0) from `.wo` incl. untrusted-chain + hostname-mismatch negatives. `tls.c`/`tls.h`; test_tls 107/0, test_crypto 104/0, full suite 0 fail. **Remaining: G inbound server** (porch) + deferred park-handshake/`TlsConn`/pooling. Forks auto-approved 2026-09-08/09, `review_pending`. The project's **highest-risk** work; mandatory reference-tested/constant-time/negative-test gates | | 9 | [in-process TLS](runtime-v2/09-in-process-tls.md) | ✅ **DONE 2026-09-09** — in-process TLS 1.3 **both directions**, **retired the "TLS is the proxy's job" doctrine** (34/38/porch corrected). Hand-rolled, 1.3-only, RSA+ECDSA+full X.509; KAT'd vs **RFC 8448** / real certs, ASan/UBSan clean. **A–E crypto** (AEAD, HKDF, X25519, sign/verify, X.509 + SAN + basicConstraints/EKU) → **F client** (`net.connect_tls`/`read_tls`/`write_tls`, ids 115–117) → **G server** (constant-time RSA-PSS + ECDSA-P256 signing w/ RFC 6979, server FSM, `net.accept_tls` id 118, `wo_pkey_parse`). Live-gated: `just tls` 5/0 (outbound) + `just tls-server` 4/0 (inbound, openssl s_client EC+RSA). test_tls 123/0, test_crypto 130/0, full suite 0 fail. Deferred follow-ups (non-blocking): park-based handshake, `TlsConn` object, connection pooling, close_notify, complete-formula EC ladder. Forks auto-approved 2026-09-08/09, `review_pending`. The project's **highest-risk** work — done |
### ▸ wmux — the terminal multiplexer track ### ▸ wmux — the terminal multiplexer track

View file

@ -76,6 +76,12 @@ Only iteration 1's scope is settled by this overview; every iteration file is
written and refined to `ready` before its code lands, per the repo's story written and refined to `ready` before its code lands, per the repo's story
discipline. discipline.
**Sequencing (set 2026-09-09):** the outbound TLS seam is done (runtime-v2 9),
so jarvis is no longer blocked on the runtime. The developer set the build order:
**jarvis is implemented once [porch](../porch/00-story.md) is complete and ready
for all future jarvis iterations** — jarvis's chat loop is a porch app, so porch
lands first, then jarvis 1–3.
## Dependencies ## Dependencies
Consumed, and already `ready` or shipped: Consumed, and already `ready` or shipped:

View file

@ -80,7 +80,11 @@ only the digests are missing.
- Asymmetric crypto (ed25519 signatures/keypairs) — held iteration 21's - Asymmetric crypto (ed25519 signatures/keypairs) — held iteration 21's
spec decides what it needs when it unholds; this iteration lays the spec decides what it needs when it unholds; this iteration lays the
digest floor it will stand on. digest floor it will stand on.
- TLS — permanently the proxy's job (framework doctrine). - TLS — ~~permanently the proxy's job (framework doctrine)~~ **RETIRED
2026-09-09.** The runtime now speaks TLS 1.3 in-process, both directions
(hand-rolled, RFC-8448-gated) — see [runtime-v2 9](../runtime-v2/09-in-process-tls.md).
This iteration's digests are a rung of that ladder, not a floor beneath a
proxy boundary.
- CRC32 — the ledger lists it, but no consumer is blocked on it; it - CRC32 — the ledger lists it, but no consumer is blocked on it; it
joins only if 24's spec finds a real need (rejecting speculative joins only if 24's spec finds a real need (rejecting speculative
surface). surface).

View file

@ -111,9 +111,12 @@ readiness: refine
- **Full-text search.** The engine indexes equality probes on declared - **Full-text search.** The engine indexes equality probes on declared
columns; there is no prefix scan or FTS. Query-grammar growth is columns; there is no prefix scan or FTS. Query-grammar growth is
[databasev2 8](../databasev2/08-query-grammar-corpus.md)'s. [databasev2 8](../databasev2/08-query-grammar-corpus.md)'s.
- **TLS** — proxy-terminated, by doctrine, unchanged. The outbound half - **TLS** — ~~proxy-terminated, by doctrine~~ **RETIRED 2026-09-09.** The
therefore speaks plaintext to a local sidecar or a trusted-network peer, runtime now speaks TLS 1.3 in-process both directions — this iteration's
and the story says so out loud rather than implying HTTPS clients. `net.connect` gained an HTTPS sibling `net.connect_tls`, and porch can
terminate inbound TLS with `net.accept_tls`, all in
[runtime-v2 9](../runtime-v2/09-in-process-tls.md). The plaintext-to-a-sidecar
framing above no longer holds.
- **A plugin/app ecosystem.** In-runtime recompile is - **A plugin/app ecosystem.** In-runtime recompile is
[iteration 26](26-blue-green-deploy.md)'s; nothing here loads [iteration 26](26-blue-green-deploy.md)'s; nothing here loads
code at run time. code at run time.

View file

@ -74,7 +74,8 @@ risky work starts.
| TTL cache, `transaction { }`, durable job queue | language: [iteration 18](../language-runtime-database/18-memory-db-features.md) | | TTL cache, `transaction { }`, durable job queue | language: [iteration 18](../language-runtime-database/18-memory-db-features.md) |
| a `proxy` middleware | language: [iteration 38](../language-runtime-database/38-content-platform-capabilities.md) — needs `net.connect`, which does not exist | | a `proxy` middleware | language: [iteration 38](../language-runtime-database/38-content-platform-capabilities.md) — needs `net.connect`, which does not exist |
| metrics, profiling, per-change CI, fuzzing | [runtime-v2 7](../runtime-v2/07-observability.md) — observability (was language iteration 30; metrics/profiling/trace-on-trap; CI + fuzz are tooling, split out) | | metrics, profiling, per-change CI, fuzzing | [runtime-v2 7](../runtime-v2/07-observability.md) — observability (was language iteration 30; metrics/profiling/trace-on-trap; CI + fuzz are tooling, split out) |
| TLS, HTTP/2 | nobody — proxy-terminated by doctrine | | TLS | ✅ [runtime-v2 9](../runtime-v2/09-in-process-tls.md) — in-process TLS 1.3 both directions (2026-09-09); porch can terminate inbound TLS with `net.accept_tls`, no front proxy required. The proxy-termination doctrine is retired |
| HTTP/2 | nobody yet — a separate protocol slice; TLS is its prerequisite, now met |
| a runtime template engine | nobody — rejected; markup is a compile-time literal (`writeonce-view`) | | a runtime template engine | nobody — rejected; markup is a compile-time literal (`writeonce-view`) |
| a radix-tree router | nobody yet — waiting on a *measurement*, not a decision | | a radix-tree router | nobody yet — waiting on a *measurement*, not a decision |

View file

@ -1,9 +1,9 @@
--- ---
track: runtime-v2 track: runtime-v2
iteration: "9" iteration: "9"
status: in-progress status: done
readiness: ready readiness: ready
review_pending: "forks auto-approved 2026-09-08/09 for autonomous execution — developer second review before this ships. OUTBOUND CLIENT COMPLETE + live-gated (just tls, 5/0): A–E crypto, F1 record, F2 key schedule, F3a messages, F3b offline verify, F3c-core sans-io driver, SAN/hostname, F3c-net chain validation + basicConstraints/EKU, and the net.connect_tls/read_tls/write_tls builtins (ids 115-117). Six integration forks implemented as locked. REMAINING: G inbound server (porch); deferred park-based handshake + TlsConn object + connection pooling; correcting the doctrine docs (34/38/porch)" review_pending: "forks auto-approved 2026-09-08/09 for autonomous execution — developer second review before this ships. COMPLETE BOTH DIRECTIONS, live-gated (just tls 5/0 outbound, just tls-server 4/0 inbound EC+RSA). Outbound: A–E crypto, F1–F3c client (net.connect_tls/read_tls/write_tls, ids 115-117). Inbound: G1 constant-time RSA-PSS + ECDSA-P256 signing (RFC 6979), G2 server FSM, G3 net.accept_tls (id 118) + private-key parse. Deferred (named follow-ups, not blockers): park-based handshake, TlsConn language object, connection pooling, TLS close_notify on shutdown, complete-formula EC ladder. Doctrine docs (34/38/porch) corrected as part of this landing"
--- ---
# runtime-v2 9 — in-process TLS: retiring the proxy-termination doctrine # runtime-v2 9 — in-process TLS: retiring the proxy-termination doctrine
@ -80,7 +80,7 @@ they may split into their own runtime-v2 iterations as they are picked up.
| 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 | | 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 | | 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) | ✅ **COMPLETE 2026-09-08/09** (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. **F3c-net chain validation** (`wo_tls_verify_chain`) + **basicConstraints/EKU** hardening KAT'd offline. **F3c-net socket/VM ✅ LANDED 2026-09-09**: `getrandom` ephemeral, per-shard lazy CA-bundle loader (`WO_CA_BUNDLE`), and the `net.connect_tls` / `net.read_tls` / `net.write_tls` builtins (ids 115–117; blocking deadline-bounded connect+handshake then a parked data plane; per-shard fd-keyed slot table, no locks). **Live-gated** (`just tls`, 5/0) from `.wo` against a local TLS 1.3 stub incl. untrusted-chain + hostname-mismatch negatives. Client side complete | jarvis's path; the reason the story exists | | F — record + handshake (client) | ✅ **COMPLETE 2026-09-08/09** (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. **F3c-net chain validation** (`wo_tls_verify_chain`) + **basicConstraints/EKU** hardening KAT'd offline. **F3c-net socket/VM ✅ LANDED 2026-09-09**: `getrandom` ephemeral, per-shard lazy CA-bundle loader (`WO_CA_BUNDLE`), and the `net.connect_tls` / `net.read_tls` / `net.write_tls` builtins (ids 115–117; blocking deadline-bounded connect+handshake then a parked data plane; per-shard fd-keyed slot table, no locks). **Live-gated** (`just tls`, 5/0) from `.wo` against a local TLS 1.3 stub incl. untrusted-chain + hostname-mismatch negatives. Client side complete | jarvis's path; the reason the story exists |
| G — server (inbound) | 📋 **READY 2026-09-09** (see §G below) — the server handshake FSM, constant-time RSA-PSS + ECDSA-P256 **signing** (the first private-key ops), private-key parsing, `net.accept_tls`; porch terminates TLS | retires the inbound proxy requirement, and the doctrine docs; may become its own iteration | | G — server (inbound) | ✅ **COMPLETE 2026-09-09** — the server handshake FSM (loopback-KAT'd), constant-time RSA-PSS + ECDSA-P256 **signing** (RFC 6979), private-key parse, `net.accept_tls` (id 118); live-gated by `openssl s_client` (EC + RSA), `just tls-server` 4/0 | retires the inbound proxy requirement; doctrine docs corrected |
## F3c-net — the socket/VM slice (✅ **LANDED 2026-09-09**; decisions locked, forks auto-approved, `review_pending`) ## F3c-net — the socket/VM slice (✅ **LANDED 2026-09-09**; decisions locked, forks auto-approved, `review_pending`)
@ -292,10 +292,15 @@ when picked up.
the G1 primitives (RSA-PSS or ECDSA + a DER SEQ{r,s} encoder). **KAT by the G1 primitives (RSA-PSS or ECDSA + a DER SEQ{r,s} encoder). **KAT by
loopback** — our client driver against our server driver, EC then RSA server loopback** — our client driver against our server driver, EC then RSA server
identity, ESTABLISHED with an app round-trip both ways. test_tls 123, ASan clean. identity, ESTABLISHED with an app round-trip both ways. test_tls 123, ASan clean.
- **G3 — `net.accept_tls` + the live gate.** The VM builtin (id 118, - **G3 — `net.accept_tls` + the live gate.** ✅ **LANDED 2026-09-09** — the VM
`WO_B_MAX`→118) + the shard identity cache, gated live by **`openssl s_client`** builtin (id 118, `WO_B_MAX`→118), private-key PEM/DER parse (`wo_pkey_parse`,
completing a handshake against our server and exchanging data — real-world PKCS#8/PKCS#1/SEC1), the per-shard identity cache, and the `wo_tls_conn`
interop, the mirror of §F3c-net's `openssl s_server` gate. refactor (negotiated app keys, not an embedded driver — read/write serve both
directions). **Live-gated** `just tls-server` (`docs/examples/tls-server`):
**`openssl s_client` validates our hand-rolled server (EC + RSA certs) and gets
the reply — 4/0**, and the outbound `just tls` stays 5/0. Interop fix: the
server loops past the client's change_cipher_spec, and `net.close` drains a TLS
conn before FIN so the reply is never lost to an RST.
### Acceptance criteria ### Acceptance criteria

View file

@ -470,5 +470,17 @@ Any failure — DNS, connect, handshake, chain, or hostname — **traps `WO_T_IO
loudly**, never a silent downgrade. The live gate is `just tls` loudly**, never a silent downgrade. The live gate is `just tls`
(`scripts/tls-accept.sh`, `docs/examples/tls-client`): a `.wo` client against a (`scripts/tls-accept.sh`, `docs/examples/tls-client`): a `.wo` client against a
local TLS 1.3 stub, happy path plus untrusted-chain and hostname-mismatch local TLS 1.3 stub, happy path plus untrusted-chain and hostname-mismatch
negatives. The inbound server (phase G) and a park-based handshake are not built negatives.
yet.
The **inbound server** (phase G) mirrors the client: `wo_tls_server` (the
server FSM in `tls.c`), the runtime's first **private-key** ops in `crypto.c`
(constant-time RSA-PSS + ECDSA-P256 signing with an RFC 6979 nonce, and
`wo_pkey_parse` for PKCS#8/PKCS#1/SEC1 keys), and `net.accept_tls` (id 118) in
`sysio.c`. A connection slot (`wo_tls_conn`) stores the negotiated application
keys — not a driver — so `net.read_tls`/`net.write_tls` serve both directions
over the record layer; the handshake drivers are transient. `net.close` drains a
TLS conn before closing so the reply is never lost to an RST. Gate: `just
tls-server` (`docs/examples/tls-server`) — `openssl s_client` validates the
hand-rolled server (EC + RSA certs). Named follow-ups (not built): a park-based
handshake, a `TlsConn` language object, connection pooling, and sending a TLS
close_notify on shutdown.