- docs/examples/tls-client/main.wo: an outbound HTTPS client in .wo — net.connect_tls, write_tls a request, read_tls to EOF, print; connect failure caught with try/catch and reported (never a silent downgrade) - scripts/tls-accept.sh + `just tls`: dials a local TLS 1.3 stub (python ssl, TLS1.3-only) with a generated test CA — proves the hand-rolled handshake + chain/host validation + an app round-trip end to end from .wo through the compiler, and refuses the untrusted-chain and hostname-mismatch negatives. No live network; log /tmp/tls.log - gate: 5 checks, 0 failures Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> (cherry picked from commit 3d8bb140ec478167a4e660adf2caa964ff410ff1)
50 lines
1.7 KiB
Text
50 lines
1.7 KiB
Text
-- tls-client — runtime-v2 9 F3c-net's acceptance workload. An outbound HTTPS
|
|
-- client, written end to end in .wo: it dials a TLS 1.3 server with
|
|
-- `net.connect_tls`, which runs the hand-rolled handshake (X25519 + AES-GCM /
|
|
-- ChaCha20-Poly1305 + the RFC 8446 key schedule), validates the certificate
|
|
-- chain to a trust anchor and matches the hostname (SAN), then carries
|
|
-- application bytes over `net.write_tls` / `net.read_tls`.
|
|
--
|
|
-- woc --emit main.wo -o tls-client.wob
|
|
-- WO_CA_BUNDLE=ca.pem wovm tls-client.wob localhost 18443
|
|
--
|
|
-- A connection whose chain does not chain to a trusted anchor, whose SAN does
|
|
-- not match the host, or that is expired, is refused loudly (the connect traps,
|
|
-- caught here). The gate (scripts/tls-accept.sh, `just tls`) proves the happy
|
|
-- path and those negatives against a local stub — no live network.
|
|
use net
|
|
|
|
fn main(args: multi Text) -> Int {
|
|
if len(args) < 2 {
|
|
print_err("usage: tls-client <host> <port>");
|
|
return 2;
|
|
}
|
|
let host = args[0];
|
|
let port = parse_int(args[1]);
|
|
if port == nil {
|
|
print_err("tls-client: <port> must be a number");
|
|
return 2;
|
|
}
|
|
|
|
-- connect_tls traps on DNS/connect/handshake/chain/hostname failure — a
|
|
-- secure connection is never silently downgraded, so we catch and report.
|
|
let fd = try net.connect_tls(host, port) catch (e) -1;
|
|
if fd < 0 {
|
|
print("tls: refused (handshake, chain, or hostname)");
|
|
return 1;
|
|
}
|
|
|
|
net.write_tls(fd, "GET / HTTP/1.0\r\nHost: ${host}\r\n\r\n");
|
|
|
|
let acc = "";
|
|
while true {
|
|
let chunk = try net.read_tls(fd, 4096) catch (e) "";
|
|
if len(chunk) == 0 { break; }
|
|
acc = acc .. chunk;
|
|
}
|
|
net.close(fd);
|
|
|
|
print("recv ${len(acc)} bytes");
|
|
print(acc);
|
|
return 0;
|
|
}
|