Now that the Internet Engineering Task Force has approved the new TLS v1.3 cryptographic protocol, we’ll surely see implementation based on the final specification rather soon, given how far work has progressed in OpenSSL and probably other libraries. In the second to last article I have [shown] how to upgrade servers running on Windows 2000 with modern cryptography and Let’s Encrypt certificates. That software was based on OpenSSL 1.0.2 and stunnel 5.44, which both fully support Windows 2000. However, when looking at the [current state] of the stunnel project in its latest 5.45 beta 6 version, it seems there isn’t even a 32-bit Windows version of it anymore.
Since compiling OpenSSL with some old Microsoft compiler is especially tricky, I tried to cross-compile the latest beta version with mingw 4.9.2 on CentOS 6.9 Linux instead, to get my 32-bit version. The same goes for stunnel. When tried that, I ran into several parts of code that simply can’t work on Windows 2000 any longer as-is.
For my ancient server, TLS v1.3 would be helpful though, as it would lower the CPU load due to its more efficient way of doing TLS handshakes. So there is a pretty good reason for trying this for real.
2.) Required software
Naturally, you need a Linux machine with the 32-bit x86 version of mingw installed for this. It might very well be easy to do on BSDs and other UNIX systems as well. You’ll also need the usual essentials for building programs under Linux like GNU autoconf, make, etc. Then, fetch the latest versions of OpenSSL and stunnel. At the time of writing, that’d be OpenSSL 1.1.1-pre3 and stunnel 5.45b6.
Unpack those, and get your favorite text editor ready, as we’ll need to modify parts of the source code before attempting a build.
3.) OpenSSL with TLS v1.3
First we need OpenSSL, as stunnel will be linking against it. Enter its source directory, then open the header file crypto/bio/bio_lcl.h. After the initial include lines, you’ll need to switch off the
AI_PASSIVE macro. This results in OpenSSL using it’s own implementation for name resolutions. If you don’t do this, it would call the Winsock API functions
freeaddrinfo(), as well as use the
struct addrinfo, none of which exist on Windows 2000, but only on Windows XP and newer. So add the following as described, just after the first
/* XIN.at mod: Disable AI_PASSIVE so we don't call freeaddrinfo() * and getaddrinfo() etc. on Windows 2000 */ # undef AI_PASSIVE
Save the file, then compile (here, for 16 CPU threads in parallel with
make -j16) and install with the following options set:
$ ./Configure enable-tls1_3 no-asm no-async no-dso no-engine --cross-compile-prefix=i686-w64-mingw32- --prefix=/opt/openssl-mingw mingw shared $ make -j16 # make install
Just a little explanation for the
./Configure options, why they need to be there, and what the implications are:
Like the name says, this enables TLS v1.3. Currently, as it’s still only a draft and not the final version, TLS v1.3 won’t be enabled by default, hence this option.
This is optional depending on your hardware. If you remove it, OpenSSL will be built including SSE2 code, so you’d need to run Windows on a machine with a new enough processor, meaning either Intels’ Pentium 4 or AMDs’ Athlon 64 CPU. With that option gone, it won’t work on older chips. As my Pentium Pro CPUs don’t have any SSE, I have to fall back to pure C code without assembly optimizations by setting this parameter.
This disables asynchronous sockets in WinSock. This is required as those need light-weight co-operatively multitasking threads called “Fibres”, which don’t exist on Windows 2000. This disables the otherwise failing calls
Disables the shared object abstraction layer, and with it the call to
GetModuleHandeEx(), which is used to communicate with kernel drivers for cryptographic hardware acceleration engines. This also means that we have to switch off support for things like VIA Padlock unfortunately. So no more hardware acceleration, as
no-dso. This disables all cryptographic hardware acceleration engines. As a side-effect, this also disables the native Windows CryptAPI/schannel support of stunnel, so you can no longer store certificates in Windows’ own certificate store either. For us, the CryptAPI is useless anyway, as it’s far too old on Windows 2000, no matter how you look at it (SSL v3, TLS v1.0,
Here: A mingw running on a 64-bit host operating system targeting a 32-bit Windows system. You can determine this string by the names of your mingw programs. Usually that string triplet should be correct as-is for what we’re doing.
Don’t change it! This is the installation directory for our cross-compiled Windows version of OpenSSL, and this location is exactly where the stunnel build system will look for it!
Allright, that settles it with OpenSSL. Next: stunnel!
4.) stunnel ≥5.45
Enter stunnels’ source directory, and open str/str.c in a text editor. Then, look for the following code block:expand/collapse source code
/* reportedly, malloc does not always return 16-byte aligned addresses * for 64-bit targets as specified by * https://msdn.microsoft.com/en-us/library/6ewkz86d.aspx */ #ifdef USE_WIN32 #define system_malloc(n) _aligned_malloc((n),16) #define system_realloc(p,n) _aligned_realloc((p),(n),16) #define system_free(p) _aligned_free(p) #else #define system_malloc(n) malloc(n) #define system_realloc(p,n) realloc((p),(n)) #define system_free(p) free(p) #endif
This shows that a fix of some memory allocation functions has been implemented to correct the old functions’ behavior for 64-bit code. However, this also replaces the functions for 32-bit versions of Windows with aligning ones. Problem: Those don’t exist on Windows 2000 either. We’re talking about
_aligned_free() replacing the good old
Mind you, the x86 architecture isn’t as strict as not to allow for unaligned memory access, but the CPU fixing things transparently in the background does reduce performance when misaligning your accesses to RAM (You can compare this to filesystem misalignments on solid state drives). So forcing the use of memory alignment is a good thing. But it’s not something Windows 2000 needs, as for 32-bit, the old functions should align properly anyway. Replace the above code with the following:expand/collapse source code
/* XIN.at mod: Removed aligning memory functions required for x86_64 * to restore Windows 2000 compatibility. Will be using the regular calls * instead, as they should work fine for x86_32 */ #define system_malloc(n) malloc(n) #define system_realloc(p,n) realloc((p),(n)) #define system_free(p) free(p)
Now run the following commands for a cross-compiled build of stunnel linked against the modern OpenSSL you’ve built before. In my case, I’m doing a parallel build across 16 CPU threads again. What
./configure does might look wrong to you in terms of cross-compiling, but just ignore that. It’s going to work just fine (Hopefully at least, heh)!
$ ./configure $ cd src/ $ make -j16 mingw $ cd ../doc/ $ make $ cd ..
And we’re set! All you have to do now is copy off the required files to replace your original stunnel installation. The following files are required; On the left side: The location of the file on a typical Windows installation of stunnel. On the right side: Where to find the corresponding new file on your Linux machine. You might need to adjust the paths a little depending on where you have extracted the source code and where exactly mingw is installed. Also, your current installation might not yet have libssp-0.dll, but you’ll need that one too:
- %PROGRAMFILES%\stunnel\bin\libssp-0.dll -> /usr/i686-w64-mingw32/sys-root/mingw/bin/libssp-0.dll
- %PROGRAMFILES%\stunnel\bin\openssl.exe -> /opt/openssl-mingw/bin/openssl.exe
- %PROGRAMFILES%\stunnel\bin\libssl-1_1.dll -> /opt/openssl-mingw/bin/libssl-1_1.dll
- %PROGRAMFILES%\stunnel\bin\libcrypto-1_1.dll -> /opt/openssl-mingw/bin/libcrypto-1_1.dll
- %PROGRAMFILES%\stunnel\config\openssl.cnf -> /opt/openssl-mingw/ssl/openssl.cnf
- %PROGRAMFILES%\stunnel\bin\stunnel.exe -> ~/yourbuilddir/stunnel/bin/mingw/stunnel.exe
- %PROGRAMFILES%\stunnel\bin\tstunnel.exe -> ~/yourbuilddir/stunnel/bin/mingw/tstunnel.exe
- %PROGRAMFILES%\stunnel\doc\stunnel.html -> ~/yourbuilddir/stunnel/doc/stunnel.html
5.) Using it
stunnel with the modern OpenSSL can be used as-is. Just copy the files over your existing installation of stunnel 5.44 or older, then restart the program or service.
Other applications which do not work in tandem with stunnel might need to be recompiled though. There is some software where OpenSSL DLLs can just be swapped out all the way from version 0.9.6 to 1.0.2, but for those, it failed with 1.1.1 for me. The DLLs just wouldn’t load even if a full [dependency walk] checks out ok. Could also be because they’ve been built with mingw instead of Microsoft Visual C though, who knows. For closed source software or open source software that is too hard to recompile, using stunnel is usually a good alternative, as has been shown [here].
6.) The truly final TLS v1.3
As soon as OpenSSL 1.1.1 gets released with official TLS v1.3 support, I will update this article in case the process shown here will require any changes to work with the final versions.
Anyway, I’m looking forward to how much speed can be gained using TLS v1.3 over TLS v1.2 on CPUs from 1997!
7.) Hey, I just want the binary programs to use on Windows 2000!
Oh my… Well, here you go:
- [OpenSSL 1.1.1-pre3 and stunnel 5.45b6] (TLS v1.3 enabled and Windows 2000 compatible)
As for the source code, you can find the original sources of OpenSSL [here] and the stunnel sources [here]. The patches shown by me here shall be released under the [OpenSSL license] for the code added to OpenSSL and under the [GPL v3] for the code added to stunnel.