Modern TLS 1.3 for classic Mac OS 9.
The Postman example app, running on Mac OS 9 in SheepShaver. The connection worked BTW, I'm not screenshotting my API key :)
Certainly is a static C library that bridges BearSSL to Open Transport and exposes a non-blocking, pump-loop API designed for the cooperative Mac OS 9 Toolbox event model. It ships with a hand-picked set of modern root CAs (ISRG, Google, DigiCert, Amazon, Starfield), validates certificates against them, and negotiates TLS 1.3 (X25519, AES-GCM / ChaCha20-Poly1305) with a TLS 1.2 fallback for servers that don't yet speak 1.3. Built with Retro68 (GCC 12, C99).
This is a hobby and research project. I have decades of coding experience but I am not a security expert, and this has not been audited by anyone who is. It exists because writing a TLS 1.3 stack for a 27-year-old operating system is genuinely interesting — not because the world needs another way to put Mac OS 9 on the internet.
Mac OS 9.2.2 predates most of the security hardening modern operating systems take for granted — no enforced memory protection between applications, no address space layout randomization, no privilege separation, and a network stack written long before the modern threat landscape existed. Even with TLS 1.3 working correctly at the library level, the broader environment is almost certainly soft in ways nobody has catalogued. Please don't use this for anything you'd regret losing.
Research software, no warranty. Certainly is provided "as is," without warranty of any kind — no guarantee that it works, that it's secure, or that it's fit for any particular purpose. The authors are not liable for any claims or damages arising from its use. This is the standard MIT bargain, spelled out here so it isn't a surprise. The full legal text:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
See LICENSE for the full MIT terms.
#include <certainly.h>
MacTLS_Init();
MacTLS_Context *ctx = MacTLS_Create("api.example.com", 443);
while (running) {
EventRecord ev;
WaitNextEvent(everyEvent, &ev, 1, NULL);
/* ... handle ev ... */
switch (MacTLS_Pump(ctx)) {
case kMacTLS_Connected:
MacTLS_Write(ctx, request, strlen(request));
n = MacTLS_Read(ctx, buf, sizeof(buf));
break;
case kMacTLS_Closed:
case kMacTLS_Error:
running = 0;
break;
default: break;
}
}
MacTLS_Close(ctx);
MacTLS_Shutdown();The contract is the pump loop: call MacTLS_Pump from your WaitNextEvent
loop, react to the state it returns. The library never blocks and never spins;
every operation yields before the next one begins.
After kMacTLS_Connected, MacTLS_GetVersion returns kMacTLS_Version12 or
kMacTLS_Version13 so you can show users which protocol was negotiated.
TLS 1.3 first, BearSSL as fallback.
MacTLS_Create starts with a handwritten TLS 1.3 ClientHello that also
advertises TLS 1.2 cipher suites. If the server responds with TLS 1.3, the
custom handshake in tls13_handshake.c drives the connection — HKDF key
schedule, X25519 key exchange, and AEAD-only record layer
(tls13_keysched.c, tls13_record.c). If the server selects TLS 1.2, the
connection is reset and BearSSL's T0 engine takes over for the full handshake.
SHA-384 cipher suites are explicitly rejected. Keeping a single 256-bit transcript hash (SHA-256) lets the key schedule fit in the memory budget of a cooperative Mac OS 9 app without resorting to dynamic allocation tricks.
Open Transport async TCP, no threads.
ot_transport.c drives Open Transport's async notifier model. Every OT call
that can yield does so; completion is polled from MacTLS_Pump without
requiring the Thread Manager or any blocking calls. This is the only way to do
non-blocking network I/O on Mac OS 9 without breaking the cooperative
scheduler.
Trust anchors baked in at build time.
ca_roots.c is generated by tools/generate_ca_roots.sh, which downloads
ten root CA certificates directly from their issuers (Let's Encrypt / ISRG,
Google Trust Services, DigiCert, Amazon Trust Services, and Starfield) and
feeds them through brssl ta to produce the C trust anchor structures.
Certificate chain validation runs through BearSSL's X.509 engine in both the
TLS 1.2 and TLS 1.3 paths.
simple_get — Sweeps a list of public HTTPS endpoints, prints the HTTP
status and negotiated TLS version ([1.2] / [1.3]) for each, and writes a
log to certainly.log on the host filesystem. Useful for regression testing
after transport or handshake changes.
postman — A full-featured HTTPS request builder with a platinum-theme
Toolbox UI: method picker, editable URL / headers / body fields, a Send
button, status line (shows the negotiated TLS version), and a scrollable
response pane. Handles chunked transfer encoding. Defaults to the Anthropic
Messages API. See the screenshot above.
- Retro68 on
PATH - CMake 3.12 or newer
- BearSSL sources under
bearssl/
mkdir -p build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE=$RETRO68/cmake/retro68.toolchain.cmake ..
makeProduces libcertainly.a and a .dsk disk image for each example. Mount the
images in SheepShaver, QEMU, or a real PowerMac.
cd tests/host && make testRuns the TLS 1.3 key schedule tests against RFC 8448 vectors and the HTTP request/response unit tests on the developer machine — no emulator needed. Run these before committing any change to the key schedule or HTTP parser.
See docs/EMULATORS.md for step-by-step setup of
SheepShaver (recommended) and QEMU, including ROM and disk image sources,
networking configuration, and the launch scripts (run-sheepshaver.sh,
run-macos9.sh).
include/certainly.h Public API — source of truth for callers
src/
certainly.c Public-API entry points + BearSSL/OT glue
ot_transport.c Open Transport async TCP
tls13_handshake.c TLS 1.3 handshake state machine
tls13_keysched.c TLS 1.3 HKDF key schedule
tls13_record.c TLS 1.3 record layer (AEAD)
ca_roots.c Mozilla trust anchors (generated — do not edit)
entropy.c Entropy collection for PRNG seeding
bearssl/ Vendored BearSSL
examples/
simple_get/ HTTPS GET sweep across many endpoints
postman/ Interactive HTTPS request builder (UI app)
tests/host/ Host-side unit tests (native cc, not Retro68)
docs/ Design notes and emulator setup
tools/ CA bundle regeneration script
- AEAD-only cipher suites. No RSA key exchange, no static DH, no CBC, no SHA-1.
- ChaCha20-Poly1305 is preferred over AES-GCM on PowerPC hardware, where AES has no hardware acceleration.
- Trust anchors are baked in at build time. The regeneration script is in
tools/. - Client-only. Not a general-purpose TLS toolkit, not security-audited. Use it to connect to well-known HTTPS endpoints — not to build a server.
- No session resumption; every connection performs a full handshake.
Certainly is built on the shoulders of a lot of generous open-source work. The interesting parts of this project are all downstream of these people and projects.
Cryptography
- BearSSL by Thomas Pornin — the underlying TLS engine. Certainly's TLS 1.2 path runs BearSSL's T0 engine end-to-end, and the TLS 1.3 path borrows BearSSL's X.509 validator, AEAD primitives (AES-GCM, ChaCha20-Poly1305), HKDF/HMAC/SHA-256, and the X25519 implementation. The entire library is essentially a thin Mac OS 9 transport wrapper around BearSSL. (MIT)
Toolchain
- Retro68 by Wolfgang Thaller and contributors — the GCC 12 cross-compiler, linker, and resource tooling that makes it possible to build classic Mac OS PPC binaries on a modern host. Without Retro68 this project simply does not exist. (Various OSS licenses; see Retro68 for details.)
- Apple Universal Interfaces 3.4 — the canonical Mac OS Toolbox headers (Quickdraw, Open Transport, Files, Events, etc.), redistributed via Retro68.
Trust anchors
Root certificates downloaded directly from each CA, then converted to
BearSSL br_x509_trust_anchor structs via brssl ta:
- Let's Encrypt / ISRG — ISRG Root X1, ISRG Root X2
- Google Trust Services — GTS Root R1, R2, R3, R4
- DigiCert — Global Root G2, Global Root G3
- Amazon Trust Services — Amazon Root CA 1
- Starfield Technologies — Starfield Services Root G2
Standards
- RFC 8446 — TLS 1.3 protocol specification
- RFC 8448 — Example handshake
traces, used as test vectors in
tests/host/test_keysched.c - RFC 7748 — X25519 key exchange
- RFC 5869 — HKDF
Emulation and disk images
For developing without real hardware:
- SheepShaver — PowerPC
Mac emulator, originally by Christian Bauer and Gwenolé Beauchesne, now
maintained as part of the
macemurepo by kanjitalk755 and contributors. (GPL) - QEMU — system emulator, used here in
qemu-system-ppc/ mac99 mode. (GPL) Mac OS 9, the Mac Toolbox, Open Transport, and the Old World ROM are trademarks and copyrights of Apple Inc. Nothing in this repo is distributed by Apple or endorsed by Apple, and this project intentionally does not mirror, link to, or otherwise redistribute any Apple-owned binaries. You'll need to bring your own legally obtained Mac OS 9 install media and ROM file to actually run anything — ideally from a real Mac or a CD you own.
Certainly itself is MIT — see LICENSE.
Vendored and referenced components keep their own licenses; BearSSL is MIT, Retro68 is a mix of GPL/BSD/MIT (component-by-component, see its repository), and the emulators (SheepShaver, QEMU) are GPL. None of those licenses are inherited by Certainly because Certainly does not vendor or statically link those projects — BearSSL is the only third-party code included in this repository's build output, and it is MIT-compatible.

