writeonce/docs/examples/tls-server/main.wo
shoney.arickathil e1d29d63e4 feat(tls): net.accept_tls — inbound TLS 1.3 termination (rv2 9 phase G3)
- net.accept_tls(listener, certfile, keyfile) -> Int (id 118, WO_B_MAX->118):
  accept (parks like net.accept), load+cache the server identity per path in
  the shard, run the blocking deadline-bounded server handshake, return a TLS
  conn fd. Real clients terminate against the runtime — no front proxy
- wo_tls_conn refactored: holds the negotiated application keys (not an
  embedded driver), so read_tls/write_tls serve both client and server
  connections via the record layer; the handshake drivers are transient
  (heap, ~100KB, freed after). net.close drains a TLS conn's inbound before
  close() so it sends FIN not RST (clients send close_notify)
- server handshake loops past the client's change_cipher_spec (TLS 1.3
  middlebox-compat) before its Finished — the openssl-interop fix
- private-key file loading: wo_tls_pem_one (any-label PEM block) +
  wo_pkey_parse; per-shard identity cache (vm->tls_id), freed in reap
- docs/examples/tls-server + `just tls-server`: openssl s_client validates
  our hand-rolled server (EC + RSA certs) and gets the reply — 4/0; the
  outbound `just tls` gate stays 5/0 through the refactor
- wiring: wob.h, loader.c, builtin.c dispatch, types.ml, vm.h

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 2d4c30033c36c88de5b7ab7cc1042c9537238297)
2026-09-15 01:16:13 +02:00

40 lines
1.5 KiB
Text

-- tls-server — runtime-v2 9 phase G's acceptance workload. An inbound HTTPS
-- server written end to end in .wo: it terminates TLS 1.3 itself with
-- `net.accept_tls` (the hand-rolled server handshake — X25519 + AES-GCM /
-- ChaCha20-Poly1305 + a server-signed CertificateVerify), then serves a fixed
-- reply over `net.read_tls` / `net.write_tls`. No front proxy — the runtime is
-- the TLS endpoint.
--
-- woc --emit main.wo -o tls-server.wob
-- wovm tls-server.wob 18443 leaf.pem leaf.key
--
-- The gate (scripts/tls-server-accept.sh, `just tls-server`) points
-- `openssl s_client` at it (RSA and EC identities) and checks the handshake
-- validates and the reply arrives.
use net
use env
fn main(args: multi Text) -> Int {
if len(args) < 3 {
print_err("usage: tls-server <port> <certfile> <keyfile>");
return 2;
}
let port = parse_int(args[0]);
if port == nil { print_err("tls-server: <port> must be a number"); return 2; }
let cert = args[1];
let key = args[2];
let srv = net.listen("127.0.0.1", port);
print("listening on 127.0.0.1:${port}");
while true {
if env.stopping() { net.close(srv); return 0; }
-- accept + terminate TLS; a failed handshake is caught and skipped, never
-- fatal to the server.
let c = try net.accept_tls(srv, cert, key) catch (e) -1;
if c < 0 { continue; }
let req = try net.read_tls(c, 2048) catch (e) "";
let body = "hello-wo-tls";
net.write_tls(c, "HTTP/1.0 200 OK\r\nContent-Length: ${len(body)}\r\nConnection: close\r\n\r\n${body}");
net.close(c);
}
}