Tuesday, April 4, 2023

Crypto Ancienne 2.2: now supported on AmigaOS and classic MacOS/MPW

As threatened we're up to the next checkpoint with Crypto Ancienne, the TLS 1.2/1.3 library we maintain for pre-C99 vintage compilers and architectures, so here's version 2.2, or "Crypto Ancienne Meets the Hooded Fang" (read about previous releases).

New checkpoints are always an opportunity for new ports. Why am I showing you a picture of my Amiga Technologies A4000T? Because AmigaOS 3.9 is one of them!

This A4000T (the second generation after the original Commodore A4000T) has a QuikPak 68060 at 50MHz and 128MB of fast RAM, and it can ably run carl, the Crypto Ancienne-based mini-curl clone and demonstration application. I compiled it with ADE from Aminet, which includes gcc 2.95.2 and ixemul.library, essentially a mini-BSD kernel lurking in an AmigaOS library. The Amigaheads in the audience might cry foul and say that programs using ixemul aren't truly a native port, and I get that point of view, but it was the easiest means to get the port mounted and it pretty much "just worked." The only trick with this port is stack usage, which we keep down by reducing the buffer size as we also do for the same reason with BeOS R5. There are other TLS options for classic 68K Amigas, but this one is another.

Our other new port is an even weirder one, and a bit more bumpy: classic Mac OS through the MPW Shell.

MPW, the Macintosh Programmer's Workshop, is notionally "just" a development environment for writing Mac applications, but the MPW Shell can be much more than that as it provides an entire command shell language running tools on a scrolling worksheet. These tools naturally include the compilers and linkers MPW comes with, but you can also get things like Perl that runs as an MPW tool, and now you can run carl as one too.

In fact, not too long ago I had an early prototype running using the MPW tool version of gcc. MPW gcc existed back when there was still support in libiberty for the classic Mac, and this support was also used in contemporary gcc derivatives such as the General Magic MIPS cross-compiler. This very rough conversion was cantankerous and crashed or stalled a lot but basically worked. While I was fiddling with that, Matej Horvat sent me a different patch of his own to compile with MrC, the PowerPC C compiler that ships with MPW. I still have my initial draft and the MPW gcc spin (maybe one for CodeWarrior and SIOUX?) might get resurrected as an alternative, but Matej's version is more convenient and my moderately revised form of it is what's shipping here.

The classic MacOS port does require a free third-party library called the Grand Unified Socket Interface, or GUSI. GUSI is used in lots of ported software, including Classilla as part of NSPR, to provide more POSIX-like interfaces for threads and networking on top of the Mac OS. An MPW Makefile and GUSI configuration code are included in a .sit.hqx that you can just unstuff and use. The MPW Makefile we're using is in the screenshot. Most of it worked unmodified except that we do need a special version of connect(): if a host doesn't answer, the whole system will hang up waiting, so we make the socket non-blocking, connect() to that, make the socket blocking again to preserve semantics, and then use GUSI's select() to wait for the socket to become writeable which will properly cooperately multitask with the rest of the system.

MrC is a fast compiler and generates fast code, even unoptimized. That's good because it (at least 4.1.0f1c1, the version in the MPW I had on my 9.2.2 dev G4) makes a total hash of the code base trying to optimize it, so we compile with optimizations off (like the poor BeOS R5 port), and then spot-optimize in a couple places I believe to be safe with the relatively limited test coverage available. We might be able to juice this better later.

The other change required was to reduce the stack usage here also. MacOS doesn't have a fork() and MPW tools run within the MPW Shell as dependent processes (they also can't run sub-tools). While carl would appear to work normally, the entire system would crash hard when quitting MPW and there was other odd behaviour even beforehand. Analysis in MacsBug showed carl was overrunning available stack and stomping on the rest of the system courtesy of classic Mac OS's minimal memory protection. It's possible to tell the MPW Shell to give the running tool more stack (change the HEXA 128 resource; the number there is in bytes), and the GNU tools even recommend this, but also cutting down buffer size like we do for the Amiga and BeOS ports allows the code to run hopefully stably on stock MPW at the cost of a bit of efficiency. That said, because of this and the issues with MrC, as well as minor differences with how the MPW Shell handles standard i/o, this port is officially "partially working." The screenshot shows carl fetching How's My SSL as a good test site, which it emits to the Worksheet, or you can redirect the output to a file to use it for downloading.

The last frontier with the classic Mac OS port would be to use it as a self-hosted on-board TLS/HTTPS proxy for Classilla and MacLynx, like we've done with other browsers. Currently to bolt it onto those browsers you need to run carl in proxy mode in a sidecar Un*x environment, like running OS X or Rhapsody with Classic, or running A/UX, or Power MachTen. carl doesn't listen on any ports of its own in proxy mode and relies on an inetd-like environment, and where I furnish binaries I usually ship Jef Poskanzer's micro_inetd for this purpose.

Unfortunately, there isn't a classic Mac OS inetd tool I could find. The GUSI docs make reference to an inetd written by "David Peterson" but I can't seem to find that anywhere in the usual places (do you have it? update: looks like it's part of MacHack 1995, but may not be suitable for this exact application; thanks easrng@lobsters!). A similar concept was ToolDaemon, which furnished a way to remotely log into a Mac over Telnet and run MPW tools. Originally shareware, its author made it open source, but it will need modification to work as a stripped-down inetd. I actually do have this mostly building with CodeWarrior 7 but it needs more changes and it's not yet ready for primetime. Additionally, while MacLynx will run on 68K Macs and GUSI has a 68K version, this port hasn't been tested with the 68K SC compiler (the Symantec C compiler Apple licensed) and only the fastest 68040-based Macs will likely be fast enough to avoid sites timing out. For now you'll still have to run carl on a sidecar Un*x or on another host, but at least the (PowerPC) port is real, and it's (partially) spectacular.

We also have two additional contributed ports: Lorenzo Gatti sent in patches for SCO UNIX 4.2/SCO ODT — could Xenix be next? — and I earlier missed that Larkin got it into the SerenityOS ports!

Under the hood are a few other changes of note. TLSe, the upstream Cryanc derives from, uses unaligned memory access in multiple places as a shortcut for handling network-ordered data in an endian-independent fashion. This is obviously fine on x86 and current ARM, and PowerPC and Power ISA have hardware for handling that at a small or negligible performance cost. Other RISC chips like MIPS or SPARC, however, will crash, or take an exception which requires the kernel to fix it up in software. We've had a snarky pre-processor define NO_FUNNY_ALIGNMENT which will break up those accesses where we've found them, and now that this has been tweaked to work properly on little-endian (tested on mipsel and sh), it's now the default for MIPS, SPARC, SuperH and PA-RISC regardless of operating system. In particular this sped up the PA-RISC port a bit because while it didn't crash before (at least on Linux or NeXTSTEP), the kernel exception it hits is slow, and now we avoid it completely. If you're dealing with a chip in these families that can handle unaligned access, which probably would be a later MIPS architecture, you can define FUNNY_ALIGNMENT_OK to override it. Unfortunately this is still not enough for DEC Alpha, which (at least with the Compaq C compiler in Tru64) still requires -misalign, even if you compile with NO_FUNNY_ALIGNMENT. Oh well.

(A funny story about NeXTSTEP. While upgrading the test suite on NeXTSTEP 3.3 on our PA-RISC SAIC Galaxy 1100, it turns out its grep has an odd bug: when examining output from carl, the NeXTSTEP 3.3 grep will fail to find the requested string in a line that doesn't have a newline at the end even if it's present. My initial workaround was to use awk to preprocess the output and feed that to grep, but NeXTSTEP awk also has a string size limit, and some pages even made it crash. Eventually I settled on isolating the sections of interest with head and tail, feeding the output of that to awk, and feeding the output of that to grep. Maybe I should just compile a better grep!)

For all supported platforms, there are also various bugfixes including for sites that send data without a change cipher request, upstream patches, and automatic fallback in carl to a TLS 1.2 context for those sites that support TLS 1.2 but offer no TLS 1.3-supported ciphers (except for BeOS R5, which remains limited to TLS 1.2 due to system limitations). Yes, there are some of these out there. An option has been added to defeat this fallback and will likely become the default as fewer and fewer of these sites remain. Also, new for BeOS on PowerPC, we now support the Fred Fish/Geek Gadgets gcc as an alternative to Metrowerks C, though unfortunately it doesn't mitigate those system limitations either.

At any rate that's good for a minor checkpoint release. The next release, either 2.5 or 3.0 depending on the scope, hopefully will address ECDSA support and allow carl to finally validate certificates (right now the encryption is strictly opportunistic). I would also like to rework carl's timeout handling since more systems are requiring the -t option to disable timeouts entirely. Likely we'll make the new default timeout only while waiting for data rather than being a hard cap on the entire transaction, and the hard cap can be a new, non-default option along with the -t option to not timeout at all.

We need some new ports for 2.5/3.0 too. I've threatened to do an OpenVMS port for the longest time and this might be that time, but we should also do one for Windows or DOS. I don't have a DOS compiler toolchain set up right now and my 486 tower system has an iffy NIC, but the Windows port could be doable with mxe or mingw and judicious use of Winsock. Seems like Windows 95 could really do with TLS 1.3, couldn't it? With that we would have some of the widest support of any TLS library on older systems that could really use it.

Crypto Ancienne is available on Github under the 2-clause BSD license. Updated binaries are available over Gopher for Rhapsody/PowerPC Mac OS X, MachTen, and PowerPC BeOS R5, and for Dreamcast Linux coming soon.

No comments:

Post a Comment

Comments are subject to moderation. Be nice.

See more of my general vintage computing projects,
mostly microcomputers, 6502, PalmOS, 68K/Power Mac
and Unix workstations, but that's not all. Be kind, REWIND and PLAY.

Buy Me a Coffee at ko-fi.com

Old VCR is advertisement- and donation-funded, and what I get
goes to maintaining the hardware here at Floodgap.
I don't drink coffee, but the Mr Pibb doesn't buy itself. :-)
Thanks for reading. -- Cameron Kaiser