Provides TLS transport for Modula-2+ networking, wrapping OpenSSL/LibreSSL behind a stable interface with both synchronous (try-once) and asynchronous (Future-returning) operation modes.
- TLSContext -- Opaque handle wrapping an
SSL_CTX*. One per trust configuration. - TLSSession -- Opaque handle for a single TLS connection over a socket fd.
- Status -- Result code:
OK,WantRead,WantWrite,Closed,SysError,Invalid,OutOfMemory,VerifyFailed. - VerifyMode --
VerifyPeer(default) orNoVerify(debugging only). - TLSVersion --
TLS10,TLS11,TLS12,TLS13. Default minimum is TLS12.
MaxSummaryLen = 512-- Maximum length for peer certificate summary strings.MaxALPNLen = 64-- Maximum length for ALPN wire-format protocol lists.
-
PROCEDURE ContextCreate(VAR out: TLSContext): StatusCreate a TLS client context. Defaults to VerifyPeer, TLS 1.2 minimum. -
PROCEDURE ContextCreateServer(VAR out: TLSContext): StatusCreate a TLS server context. Defaults to NoVerify (clients not verified), TLS 1.2 minimum. -
PROCEDURE ContextDestroy(VAR ctx: TLSContext): StatusDestroy a context and set the handle to NIL.
-
PROCEDURE SetVerifyMode(ctx: TLSContext; mode: VerifyMode): StatusSet peer certificate verification mode. Never use NoVerify in production. -
PROCEDURE SetMinVersion(ctx: TLSContext; v: TLSVersion): StatusSet the minimum acceptable TLS protocol version. -
PROCEDURE LoadSystemRoots(ctx: TLSContext): StatusLoad the system default CA root store. -
PROCEDURE LoadCAFile(ctx: TLSContext; VAR path: ARRAY OF CHAR): StatusLoad a CA bundle from a PEM file. -
PROCEDURE SetClientCert(ctx: TLSContext; VAR certPath, keyPath: ARRAY OF CHAR): StatusLoad a client certificate and private key from PEM files. -
PROCEDURE SetServerCert(ctx: TLSContext; VAR certPath, keyPath: ARRAY OF CHAR): StatusLoad a server certificate and private key from PEM files.
-
PROCEDURE SetClientCA(ctx: TLSContext; VAR caPath: ARRAY OF CHAR): StatusLoad a CA file for verifying client certificates (typically on a server context). -
PROCEDURE RequireClientCert(ctx: TLSContext; require: BOOLEAN): StatusRequire or stop requiring that clients present a certificate. Must be called before creating sessions. -
PROCEDURE GetPeerCertDN(s: TLSSession; VAR buf: ARRAY OF CHAR): BOOLEANCopy the peer certificate's distinguished name into buf. Returns TRUE if a peer certificate is present.
-
PROCEDURE SetALPN(ctx: TLSContext; protos: ADDRESS; protosLen: INTEGER): StatusSet client-side ALPN protocol list in wire format (length-prefixed strings). -
PROCEDURE SetALPNServer(ctx: TLSContext; protos: ADDRESS; protosLen: INTEGER): StatusSet server-side ALPN preferred protocol list in wire format.
-
PROCEDURE SessionCreate(lp: Loop; sched: Scheduler; ctx: TLSContext; fd: INTEGER; VAR out: TLSSession): StatusCreate a client session over a connected non-blocking socket. -
PROCEDURE SessionCreateServer(lp: Loop; sched: Scheduler; ctx: TLSContext; fd: INTEGER; VAR out: TLSSession): StatusCreate a server session over an accepted non-blocking socket. -
PROCEDURE SessionDestroy(VAR s: TLSSession): StatusDestroy a session. Does NOT close the underlying fd. -
PROCEDURE SetSNI(s: TLSSession; VAR host: ARRAY OF CHAR): StatusSet SNI hostname. Must be called before Handshake.
-
PROCEDURE Handshake(s: TLSSession): StatusAttempt one step of the TLS handshake. Returns OK when complete, WantRead/WantWrite to retry later. -
PROCEDURE Read(s: TLSSession; buf: ADDRESS; max: INTEGER; VAR got: INTEGER): StatusAttempt to read up to max bytes. On OK, got contains bytes read. -
PROCEDURE Write(s: TLSSession; buf: ADDRESS; len: INTEGER; VAR sent: INTEGER): StatusAttempt to write up to len bytes. On OK, sent contains bytes written. -
PROCEDURE Shutdown(s: TLSSession): StatusInitiate TLS shutdown (send close_notify).
-
PROCEDURE HandshakeAsync(s: TLSSession; VAR out: Future): StatusComplete the TLS handshake asynchronously. Future resolves on success or rejects with error code. -
PROCEDURE ReadAsync(s: TLSSession; buf: ADDRESS; max: INTEGER; VAR out: Future): StatusRead up to max bytes asynchronously. Future resolves with Value.tag = bytes read. -
PROCEDURE WriteAsync(s: TLSSession; buf: ADDRESS; len: INTEGER; VAR out: Future): StatusWrite up to len bytes asynchronously. Future resolves with Value.tag = bytes written. -
PROCEDURE WriteAllAsync(s: TLSSession; buf: ADDRESS; len: INTEGER; VAR out: Future): StatusWrite all len bytes asynchronously (loops until complete).
-
PROCEDURE GetPeerSummary(s: TLSSession; VAR out: ARRAY OF CHAR): StatusCopy the peer certificate subject (one-line format) into out. -
PROCEDURE GetALPN(s: TLSSession; VAR out: ARRAY OF CHAR; VAR got: INTEGER): StatusQuery the negotiated ALPN protocol string after handshake. -
PROCEDURE GetVerifyResult(s: TLSSession): INTEGERReturn the X509 verification result code (0 = success). -
PROCEDURE GetLastError(VAR out: ARRAY OF CHAR)Copy the last TLS engine error string into out.
MODULE TLSExample;
FROM TLS IMPORT TLSContext, TLSSession, Status,
ContextCreate, ContextDestroy, LoadSystemRoots,
SessionCreate, SessionDestroy, SetSNI,
Handshake, Read, Write, Shutdown;
FROM SYSTEM IMPORT ADR;
VAR
ctx: TLSContext;
sess: TLSSession;
st: Status;
buf: ARRAY [0..4095] OF CHAR;
got, sent: INTEGER;
BEGIN
st := ContextCreate(ctx);
st := LoadSystemRoots(ctx);
(* assume fd is a connected TCP socket *)
st := SessionCreate(loop, sched, ctx, fd, sess);
st := SetSNI(sess, "example.com");
(* drive handshake to completion *)
REPEAT
st := Handshake(sess);
UNTIL st = OK;
(* send a request *)
st := Write(sess, ADR(request), reqLen, sent);
(* read response *)
st := Read(sess, ADR(buf), 4096, got);
st := Shutdown(sess);
st := SessionDestroy(sess);
st := ContextDestroy(ctx);
END TLSExample.
(* Server that requires client certificates *)
st := ContextCreateServer(ctx);
st := SetServerCert(ctx, "server.pem", "server-key.pem");
st := SetClientCA(ctx, "client-ca.pem");
st := RequireClientCert(ctx, TRUE);
(* After handshake, inspect client identity *)
IF GetPeerCertDN(sess, dnBuf) THEN
(* dnBuf contains the client certificate subject *)
END;