Tls
stdlib/tls.march — TLS (Transport Layer Security) support for March.
Wraps OpenSSL 3 via C builtins to provide TLS client and server functionality over existing TCP file descriptors.
Architecture: TlsCtx — an SSL_CTX (configuration + CA store), long-lived, shareable TlsConn — a single SSL * connection wrapping one TCP fd
Typical client usage: let config = Tls.default_client_config() match Tls.client_ctx(config) do Ok(ctx) -> match tcp_connect("example.com", 443) do Ok(fd) -> -- Bound reads against a peer that accepts and then goes silent. -- Must be set BEFORE the handshake to bound the handshake too. Socket.set_recv_timeout(fd, 30000) match Tls.connect(fd, ctx, "example.com") do Ok(conn) -> Tls.write(conn, "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") Tls.read(conn, 4096) Tls.close(conn) Err(e) -> Err(e) end Err(e) -> Err(TlsHandshakeFailed(e)) end Err(e) -> Err(e) end
Types
Functions
Perform a TLS server handshake on an accepted TCP fd. Returns Ok(TlsConn) or Err(TlsError).
Create a client-side TLS context from a TlsConfig. Returns Ok(TlsCtx) or Err(TlsError). The ctx can be shared across many connections (thread-safe).
Perform TLS shutdown and free the connection object. Does NOT close the underlying TCP fd — caller must call tcp_close(fd).
Perform a TLS client handshake on an already-connected TCP fd. hostname is used for SNI and certificate hostname verification. Returns Ok(TlsConn) or Err(TlsError).
Free a TLS context. Call after all connections using this ctx have been closed.
Default client configuration: verify server cert, TLS 1.2+, HTTP/1.1 ALPN.
>>> Tls.verify_peer(Tls.default_client_config())
TrueConvert a TlsError to a human-readable string.
>>> Tls.error_to_string(TlsHandshakeFailed("timeout"))
"TLS handshake failed: timeout"
>>> Tls.error_to_string(TlsCertError("invalid CN"))
"TLS certificate error: invalid CN"
>>> Tls.error_to_string(TlsReadError("EOF"))
"TLS read error: EOF"
>>> Tls.error_to_string(TlsReadTimeout)
"TLS read timed out"
>>> Tls.error_to_string(TlsWriteError("broken pipe"))
"TLS write error: broken pipe"
>>> Tls.error_to_string(TlsContextError("bad cert"))
"TLS context error: bad cert"Client config for HTTPS with H2+HTTP1.1 ALPN negotiation.
Full HTTPS GET convenience function. Connects to host:port, performs TLS handshake, sends a minimal HTTP/1.1 GET request, reads the response, tears down TLS, closes the TCP fd. Returns Ok(response_string) or Err(TlsError).
Return the negotiated ALPN protocol, or None if none was selected.
Return the peer's certificate Common Name, or None if unavailable.
Read up to max_bytes from a TLS connection. Returns Ok(String) or Err(TlsError). Ok("") signals a clean shutdown.
This read has no deadline of its own and will wait indefinitely for a peer
that has gone silent. To bound it, call Socket.set_recv_timeout(fd, ms) on
the underlying fd BEFORE Tls.connect -- SO_RCVTIMEO is the only mechanism
that reaches a read made through OpenSSL, and setting it before the
handshake bounds the handshake too. A deadline that fires part-way through
a TLS record leaves the session unusable, so treat an expired read as
"close the connection", not as something to retry.
When that deadline expires this returns Err(TlsReadTimeout), which is a
different fact from Err(TlsReadError(...)) -- the peer was silent, rather
than the connection failing. Both still mean close it.Read up to max_bytes from a TLS connection, waiting at most timeout_ms.
`Ok(None)` is the cap expiring with nothing readable — the absence of an
event, not a broken connection. `Ok(Some(""))` signals a clean shutdown,
exactly as `read` does.Server configuration with a PEM cert+key and no client-cert verification.
Create a server-side TLS context from a TlsConfig. cert_file and key_file must be non-empty PEM paths. Returns Ok(TlsCtx) or Err(TlsError).
Convert a TlsVersion to a human-readable string.
>>> Tls.version_to_string(Tls12)
"TLS 1.2"
>>> Tls.version_to_string(Tls13)
"TLS 1.3"Write data to a TLS connection. Returns Ok(Int) — bytes written — or Err(TlsError).