Hi, and thanks for macTLS — running a real TLS 1.3 handshake natively on Classic Mac OS is a genuinely impressive piece of work.
I've been porting it to a different toolchain and would like to ask about licensing, but let me lead with what I found, since some of it may be useful to you.
What I did
I ported macTLS from CodeWarrior 8 / Carbon CFM to Retro68 (GCC 16.1.0), targeting Classic PPC against InterfaceLib. It's verified end to end on a PowerBook G4 Titanium running Mac OS 9: TLS 1.3 with 0x1303 (ChaCha20-Poly1305), session resumption, chain validation against the embedded anchors, decrypted responses from example.com, google.com, apple.com and wikipedia.org.
The porting surface turned out to be very small — 51 inserted and 9 changed lines across 6 files. Two things made it that small:
- The
InContext family is not Carbon-only. Apple's Universal Interfaces declare OTOpenEndpointInContext / OTAsyncOpenEndpointInContext with identical signatures for Classic too; the Classic link libraries just don't export them. So no call sites needed changing — two thin forwarders that drop the (meaningless under Classic) client context were enough.
- The
#ifdef __MWERKS__ guards only needed widening to also take the real-Toolbox branch under GCC.
Two spots did need real fixes, both cases where CW8's C89 was lenient and GCC 16 is not: ostls_async.c calls OSTLS_LogLine/OSTLS_LogLinef and YieldToAnyThread() without including ostls_log.h or <Threads.h>.
A bug in the blocking path
OSTLS_Fetch() fails against servers that close promptly — I hit it on google.com with OTRcv FAIL (err=-3158), i.e. kOTLookErr. The blocking path has no handling for it (no OTLook, T_ORDREL or T_DISCONNECT anywhere in ostls_fetch.c), while ostls_async.c handles it in three places. I fixed it by copying your async pattern: on T_ORDREL/T_DISCONNECT, consume the event and, if plaintext was already collected, fall through to the success path — with HTTP/1.0 and Connection: close, the close is the end-of-body marker, the same rule your BR_SSL_CLOSED branch already applies. Happy to send that as a PR.
Measurements on a G4, in case they're useful
|
|
| X25519 scalar multiplication |
3.3 ms |
P-256 mulgen |
6.6 ms |
| ChaCha20 |
51 MB/s |
| SHA-256 |
27 MB/s |
| AES-128-CTR |
6.1 MB/s |
| Full TLS 1.3 handshake |
71–305 ms, depending on the chain |
| Resumed |
15–19 ms |
ChaCha20 is 8.3× faster than AES here, so your preference for TLS_CHACHA20_POLY1305_SHA256 measures out as correct on this hardware, not just plausible.
One note on the README: it says each OSTLS_Pump "does a bounded amount of work and returns, so the host stays responsive". That holds on average (3–21 µs per call), but not at the maximum — I measured exactly one call per full handshake blocking for 61–305 ms, always in the Handshaking state; in Open it stays under 0.5 ms, and a resumed session never exceeds 20 ms. max_steps bounds the number of steps, but one step advances BearSSL's engine and performs key exchange plus chain verification indivisibly. Not a defect — but worth a sentence, since a UI has to draw its "connecting…" state before that call rather than after.
The actual question
The repository has no LICENSE file and GitHub reports no license, which means all rights reserved by default. I'm therefore treating the code as not licensed for reuse and keeping my port in a private repository, and I haven't redistributed any of your source — my repo carries only a patch and a script that clones this repo at a pinned commit.
Would you consider adding a license? Something permissive would match the vendored BearSSL (MIT, Thomas Pornin) and would let people build on this. If you'd rather not, that's completely fine — I'd just like to know where I stand, and I'll keep it private either way.
Thanks again for the work.
Hi, and thanks for macTLS — running a real TLS 1.3 handshake natively on Classic Mac OS is a genuinely impressive piece of work.
I've been porting it to a different toolchain and would like to ask about licensing, but let me lead with what I found, since some of it may be useful to you.
What I did
I ported macTLS from CodeWarrior 8 / Carbon CFM to Retro68 (GCC 16.1.0), targeting Classic PPC against InterfaceLib. It's verified end to end on a PowerBook G4 Titanium running Mac OS 9: TLS 1.3 with
0x1303(ChaCha20-Poly1305), session resumption, chain validation against the embedded anchors, decrypted responses from example.com, google.com, apple.com and wikipedia.org.The porting surface turned out to be very small — 51 inserted and 9 changed lines across 6 files. Two things made it that small:
InContextfamily is not Carbon-only. Apple's Universal Interfaces declareOTOpenEndpointInContext/OTAsyncOpenEndpointInContextwith identical signatures for Classic too; the Classic link libraries just don't export them. So no call sites needed changing — two thin forwarders that drop the (meaningless under Classic) client context were enough.#ifdef __MWERKS__guards only needed widening to also take the real-Toolbox branch under GCC.Two spots did need real fixes, both cases where CW8's C89 was lenient and GCC 16 is not:
ostls_async.ccallsOSTLS_LogLine/OSTLS_LogLinefandYieldToAnyThread()without includingostls_log.hor<Threads.h>.A bug in the blocking path
OSTLS_Fetch()fails against servers that close promptly — I hit it on google.com withOTRcv FAIL (err=-3158), i.e.kOTLookErr. The blocking path has no handling for it (noOTLook,T_ORDRELorT_DISCONNECTanywhere inostls_fetch.c), whileostls_async.chandles it in three places. I fixed it by copying your async pattern: onT_ORDREL/T_DISCONNECT, consume the event and, if plaintext was already collected, fall through to the success path — with HTTP/1.0 andConnection: close, the close is the end-of-body marker, the same rule yourBR_SSL_CLOSEDbranch already applies. Happy to send that as a PR.Measurements on a G4, in case they're useful
mulgenChaCha20 is 8.3× faster than AES here, so your preference for
TLS_CHACHA20_POLY1305_SHA256measures out as correct on this hardware, not just plausible.One note on the README: it says each
OSTLS_Pump"does a bounded amount of work and returns, so the host stays responsive". That holds on average (3–21 µs per call), but not at the maximum — I measured exactly one call per full handshake blocking for 61–305 ms, always in theHandshakingstate; inOpenit stays under 0.5 ms, and a resumed session never exceeds 20 ms.max_stepsbounds the number of steps, but one step advances BearSSL's engine and performs key exchange plus chain verification indivisibly. Not a defect — but worth a sentence, since a UI has to draw its "connecting…" state before that call rather than after.The actual question
The repository has no LICENSE file and GitHub reports no license, which means all rights reserved by default. I'm therefore treating the code as not licensed for reuse and keeping my port in a private repository, and I haven't redistributed any of your source — my repo carries only a patch and a script that clones this repo at a pinned commit.
Would you consider adding a license? Something permissive would match the vendored BearSSL (MIT, Thomas Pornin) and would let people build on this. If you'd rather not, that's completely fine — I'd just like to know where I stand, and I'll keep it private either way.
Thanks again for the work.