No description
  • C 39.7%
  • Shell 26.8%
  • Scheme 25.1%
  • Makefile 8.1%
  • Common Lisp 0.3%
Find a file
2026-07-30 15:47:33 -06:00
.builds ci: set umask 022 in package/verify tasks too (jerbuild creates group-writable cache dirs during pkg operations) 2026-07-22 13:10:59 -06:00
.jerboa Security hardening and release readiness 2026-06-23 10:51:42 -06:00
docs fix: close security audit findings 2026-07-11 17:25:43 -06:00
scripts fix: close security audit findings 2026-07-11 17:25:43 -06:00
src ssl: add conn-write-sub for zero-copy sub-range writes 2026-07-22 15:57:38 -06:00
support Security hardening and release readiness 2026-06-23 10:51:42 -06:00
tests ssl: add conn-write-sub for zero-copy sub-range writes 2026-07-22 15:57:38 -06:00
.gitignore build: remove tracked generated .sls files and ignore them 2026-07-24 11:44:05 -06:00
AGENTS.md docs: remove jerboa-emacs restriction 2026-07-30 15:47:33 -06:00
jerboa_ssl_shim.c ssl: add conn-write-sub for zero-copy sub-range writes 2026-07-22 15:57:38 -06:00
jpkg.sexp Add jpkg packaging 2026-07-21 15:09:27 -06:00
LICENSE Switch to MIT license 2026-07-21 13:42:20 -06:00
Makefile build: add lint target 2026-07-21 11:50:41 -06:00
README.md fix: close security audit findings 2026-07-11 17:25:43 -06:00
SECURITY.md Security hardening and release readiness 2026-06-23 10:51:42 -06:00

jerboa-ssl

TLS-encrypted TCP socket connections for Jerboa via FFI to OpenSSL.

This library provides the raw TLS transport layer — connect, read, write, close. It does not implement HTTP. It is intended as a building block for higher-level libraries like jerboa-https.

Why

Jerboa currently delegates TLS to native libraries. Without this shim, talking to HTTPS services requires shelling out to a tool such as curl for every request, which spawns a subprocess each time. This library gives Jerboa clients native TLS sockets with no subprocess overhead.

Requirements

  • Jerboa and jerbuild
  • A supported, patched OpenSSL development package. Release evidence currently accepts OpenSSL 4.0.1+, 3.6.3+, 3.5.7+, 3.4.6+, or 3.0.21+.
  • Linux x86_64
  • GCC

On Debian/Ubuntu:

sudo apt install build-essential libssl-dev

Build

make

This compiles jerboa_ssl_shim.c into jerboa_ssl_shim.so or jerboa_ssl_shim.dylib.

Test

make security
make test
make audit
make sbom
make openssl-advisory-check
make reproducibility-report
make target-evidence
make release-evidence

Connects to example.com:443 over TLS, sends an HTTP GET, and verifies the response. The release-evidence target archives OpenSSL advisory status, native linkage, SBOM/platform support notes, source/artifact hashes, target-deployment proof status, and hash-only reproducibility output. Target proof markers are supplied with JSSL_TARGET_PROOF_FILE; set JSSL_REQUIRE_TARGET_PROOF=1 to fail a release when the proof is missing.

Usage

(import (jerboa-ssl))

(ssl-init!)

(let ([conn (ssl-connect "example.com" 443)])
  (ssl-write-string conn
    "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n")
  ;; Refuse responses larger than 1 MiB or slower than 15 seconds total.
  (let ([response (utf8->string (ssl-read-all conn 1048576 15))])
    (display response))
  (ssl-close conn))

(ssl-cleanup!)

To use the library from another project, add the generated lib/ directory to the Jerboa library path:

jerbuild exec --libdirs /path/to/jerboa-ssl/lib your-program.ss

Production executables must statically link and register the SSL shim; the library never searches the current directory or a bare platform-loader name. Interpreter development may set JERBOA_SSL_ALLOW_DYNAMIC_NATIVE=1 together with an absolute, canonical JERBOA_SSL_LIB directory. The library and every ancestor must have an expected root/current-user owner and safe mode; privileged processes ignore both variables. Dynamic loading is rejected for root or real/effective-ID-mismatched processes and is not a production deployment mechanism.

API Reference

(ssl-init!)

Initialize OpenSSL. Call once at program start. Safe to call multiple times (idempotent).

(ssl-cleanup!)

Release OpenSSL global resources. Call at program shutdown.

(ssl-connect hostname port) -> connection

Connect to hostname (string) on port (integer) over TLS.

  • Resolves DNS via getaddrinfo (IPv4 and IPv6)
  • Creates a TCP socket and connects
  • Sets up TLS with SNI (SSL_set_tlsext_host_name) and OpenSSL certificate name verification
  • Verifies the server certificate against system CA roots
  • Returns an opaque connection handle

Raises an exception with a descriptive error message on failure (DNS resolution, connection refused, TLS handshake error, certificate verification failure).

(ssl-write conn bytevector) -> void

Write the entire bytevector to the connection. Handles partial writes internally (loops until all bytes are sent). Raises on error.

(ssl-write-string conn string) -> void

Convenience wrapper — converts the string to UTF-8 and calls ssl-write.

(ssl-read conn bytevector length) -> integer

Low-level read. Reads up to length bytes into bytevector. Returns the number of bytes actually read, or 0 on EOF.

(let ([buf (make-bytevector 4096)])
  (let ([n (ssl-read conn buf 4096)])
    (display (format "Read ~a bytes\n" n))))

(ssl-read-all conn max-bytes timeout-seconds) -> bytevector

High-level bounded read. Reads until the peer closes the connection and returns a single bytevector. max-bytes is a hard body limit and timeout-seconds is a total deadline, not a per-read timeout. Limit and deadline violations raise distinct errors. Callers that need larger or longer transfers should stream them through ssl-read with protocol-specific limits.

(ssl-close conn) -> void

Shut down the TLS session and close the underlying TCP socket. Frees all associated resources. Safe to call multiple times.

(ssl-connection? obj) -> boolean

Returns #t if obj is an active (not yet closed) SSL connection.

Architecture

jerboa-ssl/
├── jerboa_ssl_shim.c     C shim (OpenSSL FFI wrapper)
├── src/
│   └── jerboa-ssl.ss     Jerboa source library
├── tests/
│   └── ssl-test.ss       Integration test
├── Makefile
└── README.md

The C shim (jerboa_ssl_shim.c) wraps OpenSSL into simple C functions that Jerboa's FFI can call. It manages a jerboa_ssl_conn struct that bundles the SSL*, SSL_CTX*, and socket file descriptor together. The Scheme side passes this around as an opaque void* integer.

Why a C shim?

The FFI can call C functions directly, but OpenSSL's API involves:

  • Structs that must be allocated and threaded through multiple calls
  • Macros (SSL_set_tlsext_host_name) that can't be called from FFI
  • Multi-step workflows (DNS lookup, socket connect, TLS handshake) that are simpler in C

The shim collapses each workflow into a single callable function.

Notes for AWS

  • SNI is mandatory. AWS rejects TLS connections without Server Name Indication. This library sets SNI automatically via SSL_set_tlsext_host_name.
  • Certificate verification is enabled. The library loads system CA certificates and verifies the server's certificate chain, including hostname or IP-address matching.
  • Connection reuse. This library provides raw TLS transport. For high-throughput use (thousands of requests), implement HTTP/1.1 keep-alive and connection pooling at the HTTP layer above this.

License

See LICENSE.