W# 0.1.1

TLS and certificates

std/curve25519, std/nistec, std/rsa, std/der, std/x509 and std/tls.

TLS 1.3, client and server, written in W#. The whole client and server are replayed against RFC 8448’s published traces byte for byte in the compiler’s test suite.

You do not normally reach for these directly. http.get("https://…") is what they are for.

std/curve25519

const curve25519 = @import("std/curve25519");

x25519 and x25519_base for key agreement, and Ed25519 signing and verification.

The small-order check is on the output rather than on a list of bad encodings, which is the check a list of bad encodings misses.

std/nistec

const nistec = @import("std/nistec");

p256 p384 derive ecdh valid ecdsa_verify: the NIST prime curves, one implementation over std/bignum, with the key-share validation RFC 8446 requires.

std/rsa

const rsa = @import("std/rsa");

public_key, verify_pkcs1, verify_pss. Verification only, since TLS 1.3 does no RSA key exchange. The encoded message is built and compared rather than parsed, which is the shape that does not have a padding oracle in it.

std/der

const der = @import("std/der");

A strict DER reader: read_value read_seq read_uint read_oid read_bitstring read_time. Strict means a non-minimal length or a non-canonical encoding is rejected rather than accepted and normalised.

std/x509

const x509 = @import("std/x509");
SigKey and its three subtypesRSA, an ECDSA curve, or Ed25519
parse_spki, verify_signature
matches_host(cert, host) bool
verify_chain(chain, roots, host) !void
pem_certificates(text) []Certificate
system_roots() []Certificatethe trust anchors the machine already has

SigKey having three subtypes is dispatch again: which verification runs is chosen by the key’s type rather than by a tag the parser wrote down.

std/tls

const tls = @import("std/tls");
client(...), server(...)a handshake state machine
feed(s, bytes), pending(s)drive it with bytes, take bytes out
Sessionthe blocking version, over a std/net socket

The state machine is separate from the socket on purpose: feed and pending are what let the RFC 8448 traces be replayed as bytes, with no network in the test.

What works and what does not

example.com, github.com, nixos.org, www.cloudflare.com and crates.io all work, which between them cover RSA, P-256 and P-384 chains.

What does not is a chain through a P-521 key. There is one such root in a typical store, and it is the last item still open on the roadmap.

Last changed 8 September 2026. Improve this page

On this page