Library
TLS and cryptography
Secure connections wrap the existing socket in place, so TcpStream, HttpClient and HttpServer gain TLS without any API change.
since 0.1.0-alpha.1linux
Description
TLS in Leviathan is wrap-in-place. After a session is armed over a connected (client) or
accepted (server) socket, the descriptor stays the same descriptor: sends, receives and closes
are routed through the TLS session transparently, and the event loop keeps watching the same
descriptor. A TcpStream, an HttpClient or an HttpServer therefore works over TLS with no
change to the code that uses it.
TLS is provided by the system OpenSSL library (1.1.1 or newer) behind a narrow internal seam. A
runtime built without OpenSSL ships a provider that reports TLS support not built into this runtime from any TLS call; programs that never use TLS are unaffected.
Client. std::tlsConnect(fd, host, alpn, caFile, verifyMode, callback) secures a connected
descriptor. It performs the handshake without blocking, and on success calls callback with the
descriptor, which you then wrap in a TcpStream. On failure, including a certificate that does not
verify, it throws a RuntimeException whose message starts with TLS handshake: and names the
reason, host and descriptor. Verification happens before the first byte of protocol is sent.
hostis the name the certificate must match and the name sent for server selection. An IP-literal host sends no server name and is verified against the certificate's IP addresses.alpnis the application protocol list ("h2,http/1.1"), or""for none.caFileadds one extra trusted certificate authority file to the system's roots;""uses only the system roots (and the standardSSL_CERT_FILEandSSL_CERT_DIRenvironment variables).verifyModeis0for full verification (certificate chain and host name),1for the chain only, or2for encryption without any verification. Mode2exists for testing; it is never the default and is easy to find by searching for it.
Server. std::tlsAccept(fd, certPath, keyPath, alpn, deadlineMs, callback) secures an
accepted descriptor with a certificate and a private key. A client that fails the handshake or
takes longer than deadlineMs is dropped and callback receives -1; the call never throws, so
one bad client cannot disturb the accept loop.
Driving an armed descriptor. std::tlsDrive(fd, callback) runs the handshake for a descriptor
that is already armed; callback receives the descriptor on success or -1 on failure. The
event loop copes with the awkward cases of TLS on its own: a read that has to wait for the
descriptor to become writable (and the reverse), and data that the TLS layer has already buffered
while the descriptor looks idle.
HTTPS. HttpServer(port, certPath, keyPath) serves HTTPS, and HttpClient has
requestTls, getTls, postTls and fetchTls. The client always uses full verification.
The cryptography floor. Two more natives support secure protocols:
std::sysRandom(n)returnsnrandom bytes, carried in a string. It is cryptographic-grade (the operating system's secure random source).n <= 0gives"", and more than one megabyte throws aRuntimeException.std::sysRsaEncrypt(publicKeyPem, bytes, padding)encrypts bytes with an RSA public key, for key transport in authentication handshakes.paddingis"oaep"(the default) or"pkcs1". It returnsstring?and givesNonewhen the key cannot be parsed, the data does not fit the key, or the encryption fails.
Both are part of the native floor (see lang.system-floor), so they are not available in
comptime code.
Rules
- Secure by default. TLS 1.2 is the minimum and TLS 1.3 is enabled; renegotiation and
compression are off; certificate verification is on unless
verifyModesays otherwise. tlsConnectthrows on a failed handshake;tlsAcceptdrops the connection and reports-1.- The descriptor stays the same, so keep using the same
TcpStreamplumbing. HttpClientcannot turn verification off.- The environment variable
SSLKEYLOGFILE, when set, makes the runtime write key-log lines for debugging tools. It is off by default. - A runtime without OpenSSL reports
TLS support not built into this runtime.
Examples
Opening a secure connection with full verification, then speaking plain text over it:
std::connectTimeout("example.com", 443, 3000, (fd) => {
if (fd < 0) {
console.writeln("could not connect");
return;
}
std::tlsConnect(fd, "example.com", "", "", 0, (secured) => {
TcpStream conn = TcpStream(secured);
conn.onData((chunk) => console.writeln("received ${chunk.length()} bytes"));
conn << "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n";
});
});
Notes
Not implemented: client certificates (mutual TLS), session resumption, certificate reloading without a restart, a cipher policy setting, OCSP, native TLS providers for Windows and macOS, HTTP/2, and authenticated-encryption APIs over byte blocks.
See also
- TcpStream — A connected network socket that reads and writes text.
- HttpClient — A simple HTTP client that sends one request per connection and delivers the response to a callback.
- HttpServer — A web server that listens on a port and answers each request with a handler function.