The outbound TLS 1.3 client wired into the VM (ids 115-117, WO_B_MAX->117):
- net.connect_tls(host,port)->Int: DNS + non-blocking connect+poll bounded
by WO_TLS_HANDSHAKE_MS (decision 5), then a blocking, SO_*TIMEO-bounded
hand-rolled handshake over the sans-io driver, then wo_tls_verify_chain
(chain + host + validity + basicConstraints/EKU) against the shard's
lazily-loaded read-only CA bundle (decision 4). Any failure traps WO_T_IO
loudly (decision 3). Returns the fd.
- net.read_tls / net.write_tls: application data over the parked data plane
(decision 1) — O_NONBLOCK + park on POLLIN/POLLOUT like net.read/write,
with record reassembly + leftover-plaintext + in-flight-record buffers in
the per-fd slot so a park/retry never re-seals or loses progress.
- per-shard wo_tls_conn slot table keyed by fd, no locks (one thread per
shard, the wo_child pattern; decision 2); net.close frees the slot;
wo_vm_destroy reaps all slots + the CA bundle. getrandom ephemeral.
- driver keeps the whole Certificate message + wo_tls_client_chain() so the
trust walk sees the full chain, not just the leaf.
- wiring: wob.h, loader.c arities, builtin.c dispatch (second net range),
types.ml (net.connect_tls/read_tls/write_tls), sysio.c impl.
Builds; full runtime suite 0 fail; woc builds. Live behaviour is the
Phase-4 gate (next commit).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 9a922b3245eaa9134efb60bfd46521952ed12a39)