1.) Introduction
There has been an issue with my [stoneage server] (which is also hosting this weblog) that has been bugging me for quite a while now: I’ve been scared of the time when other server operators and software developers would start to seriously disable ancient SSL/TLS ciphers such as
SSL_RSA_WITH_3DES_EDE_CBC_SHA, or in other words: SHA1, RC4 and 3DES. The XIN.at services are actually made of both non-free as well as free services that are using several different cryptographic libraries such as different OpenSSL versions but also WinSSL CryptAPI / schannel. Naturally it’s the latter which is presenting the biggest issue: The CryptAPI of Windows 2000 Server is ancient. And while it can do at least TLS v1.0, the ciphers have been becoming the true burden. Unfortunately (?!), some services on XIN.at do require some form of widely accepted encryption.
Some of the servers do have interchangeable OpenSSL libraries – so you can just swap those .dll files for an upgrade – while others do not. Some from the latter category can be backported to / recompiled for Windows 2000 to upgrade OpenSSL, like I’ve been [able to do] for the UnrealIRCd IRC server. Some however can not.
And then there are services which are using Windows SSL or in other words the CryptAPI / schannel. Those are the most inflexible of the pack.
Another problem is that self-signed certificates such as the ones I’ve been using have also become increasingly problematic. Most client software like web browsers in particular, but also email clients, IRC clients and others keep pestering their users quite a bit when being presented with such an “untrustworthy” SSL certificate. They really want one signed by a fully trusted certificate authority (CA) or an intermediate CA. The best solution for that problem right now is to get a Let’s Encrypt certificate, as it’s free and well-trusted. Only reason I haven’t done that so far is that it needs automatisms (=ACME client software) in place to remain manageable.
I wanted to solve both issues in one fell swoop.
2.) The trigger
Then again, you know how people are – they tend to act only when something bad has already happened. In the tradition of that (bad) behavior I’ve chosen to act only where the problem at hand was truly easy to solve. After I’ve managed to compile a modern enough OpenSSL library, I’ve just swapped it on the spot where possible, but I haven’t touched the more problematic services, where such a thing is not doable.
However, there has been a serious issue recently when mail server operators started to beef up their cryptography across the board. It seems there are some updates being rolled out about now which block the ancient ciphers and/or protocols I mentioned in the introduction.
The truly serious part is that seemingly, all mail servers who encounter another that does feature
STARTTLS on SMTP port 25, but has no secure ciphers to offer just drop the connection on the spot without generating any error. The mail will not be delivered, but no delivery error will be returned to the sender either! It’s truly a case where the eMails just “disappear” without anyone ever noticing a problem at first. To make matters worse, there was no way to disable just
STARTTLS for SMTP with my server software. It’s either no SSL/TLS at all or fully enabled
STARTTLS on all plain eMail ports.
See this log to get an idea (remote host names have been replaced with “remote.mailtransfer.com” and IP addresses as well as security-relevant data have been masked here):expand/collapse log file
---------- Session 74281; child 1; thread 11616 Accepting SMTP connection from [♡.♡.♡.♡:4286] Performing PTR lookup (♡.♡.♡.♡.IN-ADDR.ARPA) * D=♡.♡.♡.♡.IN-ADDR.ARPA TTL=(1093) PTR=[remote.mailtransfer.com] * Gathering A records... * D=remote.mailtransfer.com TTL=(735) A=[♡.♡.♡.♡] ---- End PTR results --> 220 xin.at ESMTP ♡; Mon, 05 Feb 2018 11:38:17 +0100 250-xin.at Hello remote.mailtransfer.com, pleased to meet you --> 250-ETRN --> 250-AUTH=LOGIN --> 250-AUTH LOGIN CRAM-MD5 --> 250-8BITMIME --> 250-STARTTLS --> 250 SIZE 0 220 Begin TLS negotiation SSL negotiation successful (TLS 1.0, 2048 bit key exchange, 168 bit 3DES encryption) Connection closed SMTP session terminated (Bytes in/out: 694/1248) ----------
The most interesting part is clearly at the bottom, where it says “SSL negotiation successful (TLS 1.0, 2048 bit key exchange, 168 bit 3DES encryption)”. 3DES is the best Windows 2000 can do by itself, and it looks as if the remote server would accept the implementation just fine. But what happens next is that the remote machine just drops the connection, and that’s it!
The remote side who sent the eMail (that was myself from my account at work actually) never got any delivery failure notification, and after asking other people about it, it was just the same. As said, the mails just vanish!
I also talked to the operator of the mail gateway at work, and he said he didn’t see anything in the logs either, other than that the connection was just being dropped. Pretty stupid to not generate a proper error here, if you ask me.
Well, that was enough of a reason to act! eMails just disappearing is completely unacceptable after all!
3.) What can you do?
I thought about this issue in the past already, and one of my ideas was to use something like [BlackWingCats’] kernel API extensions for Windows 2000 (“KernelEx”). The issue with that is though, that it’s modifying large parts of the operating system, and it’s very incompatible to my German version, wrecking half of the system upon installation during my tests in a VM. So that idea went down the drain pretty fast.
Very recently however, I got the idea that maybe I could use [stunnel] to solve the cipher problem. It’s basically a port mapper wrapping plain text protocols up in SSL/TLS. It’s a program coming from the Linux/UNIX world, but it also works on Windows. On top of that, it miraculously runs on Windows 2000 as well, even in its newest version bundling modern OpenSSL 1.0.2.
Additionally, I thought I’d once again try to get some Let’s Encrypt ACME client to work on Windows 2000 for certificate issuing and renewal, even though I failed to get any of them working before.
3a.) Let’s Encrypt configuration via ZeroSSL
Since we need an SSL certificate for stunnel anyway, let’s cover this part first. For ease of use, I chose ZeroSSLs’ [Crypt::LE] Perl tool. I didn’t like their [web-based configuration] too much, as they’ll be issuing your private key for you on their servers.
Generally, when dealing with cryptography and trust concepts, I wouldn’t recommend anyone other than yourself generate and use your private key, so that’s one reason why I chose their Perl tool instead. Plus, you can’t automate the certificate renewal process with some web tool, but you can with Perl.
If you don’t have Strawberry Perl installed on your machine, you can still rely on their [Windows binaries] as well. Those are basically just le.pl and the necessary Perl parts wrapped in an le32.exe file. Crypt::LE also supports ActiveState Perl, but the free Strawberry Perl should be preferable, if you’re choosing that path.
Unfortunately, if you choose to use the .exe version, it won’t run on Windows 2000 out of the box, as it calls the WinSock 2.0 function
freeaddrinfo(), which is only available on Windows XP and newer. For an easy fix, you can use a modified WS2_32.dll WinSock library found in the dllfiles\ subfolder of this [winsock2_getaddrinfo.rar] archive by [Martin Brenner], if you choose to trust the DLL.
If you do, just put it next to le32.exe, and make sure you launch the program only while sitting within the installation folder of le32.exe itself. Do not overwrite your system-wide %WINDIR%\system32\WS2_32.dll, you don’t need to do that, and you shouldn’t either!
As said, if you don’t trust the hack for the binary, you need to install Strawberry Perl and follow the instructions for the compilation & installation of Crypt::LE from their website.
3a1.) Ok, I have the tools, now what?
I won’t cover the process of using Crypt::LE, as there is an excellent manual [right here at ZeroSSL]! There is one thing that needs to be said though: You need an openssl.exe for the initial certificate request and key generation part. There is one bundled with stunnel in the subdirectory bin\ of its installation folder, you can just use that.
But before you start with it on a cmd terminal, you’ll need to tell OpenSSL where to look for its configuration file. Say you’ve installed stunnel in %PROGRAMFILES%\stunnel\, then run the following command before starting to work with OpenSSL:
%OPENSSL_CONF% to the file name of the OpenSSL configuration, and OpenSSL will automatically parse that environment variable. Adjust paths as necessary, then follow ZeroSSLs’ manual to get your first Let’s Encrypt certificate(s)!
If you’ve been following this article, you’ll already have stunnel installed by now. On Linux & UNIX, stunnel is just a command line tool and/or xinetd service, but on Windows, you also get a bit of a GUI and a tray icon with it. You’ll still have to configure it by editing its config\stunnel.conf configuration file with your favorite text editor however.
Say you wanted to protect a web server on port 80 by adding HTTPS on port 443 for it. The corresponding configuration entry in that configuration file would look like that (here: with separate key file not stored directly within the certificate):
[https] accept = 443 connect = 80 cert = mydomain.pem key = mydomain.key
stunnel will listen on port 443 with implicit TLS for you, and then redirect the traffic to port 80 on the same machine. To a web browser connecting to https://yourdomain.com:443/, it’ll look like just another TLS-enabled web server.
The same goes for other implicit SSL/TLS services such as SMTPS, IMAPS, POP3S, etc.
The exception of course are explicit SSL/TLS implementations using the
STARTTLS command. One classic example for that would be SMTP on port 587, which is typically
STARTTLS-enabled. To make that work, stunnel has to emulate parts of the specific protocol to secure, so support for this is rather limited. Currently, stunnel supports the following network protocols for explicit
- CIFS (SMB, Samba, older implementation)
- CONNECT (Client only)
- IMAP (as per RFC 2595)
- NNTP (as per RFC 4642)
- POP3 (as per RFC 2449)
- SMTP (as per RFC 2487)
- SOCKS (versions 4, 4a and 5)
To use it, you’d need to configure the service as follows, this example is for SMTP with
STARTTLS on port 587, mapping it to your local, unencrypted SMTP server:
[smtp-es] accept = 587 connect = 25 cert = mydomain.pem key = mydomain.key protocol = smtp
Now if present, switch off your existing SSL/TLS services first (like make your web server stop listening to port 443), and then fire up the stunnel program and everything should work. You can also install it as a system service on Windows by the way, it’s very easy:
Together with a properly requested and signed Let’s Encrypt certificate this will give any ancient server things like TLS v1.2 with AES256-GCM-SHA384 and any modern client will trust your certificate implicitly, as most vendors have by now added the ISRG CA certificates to their CACert bundles. Even Microsoft trusts them by now.
4.) Really putting it all together
Even if you’ve managed to do all of this manually, it won’t solve the problem forever. Let’s Encrypt certificates have a lifetime of just 90 days, so you will have to renew them pretty often. That can be done with just a batch script launching Crypt::LE as well as doing the rollout of the certificates and relaunch of the servers, so that they can re-read the certificates and key files.
Here’s an example script for stunnel and some other hypothetical servers that accept certificate files in different configurations. It assumes that you’re using Crypt::LE together with Strawberry Perl. As you can see, aside from Perl and Crypt::LE you won’t need anything else, as the rest can be done with regular Windows cmd builtins and the NetShell:expand/collapse certificate-renewal.bat
:: Renew our certificate if it expires within the next 30 days, put HTTP
:: challenge files in C:\MyHTTProot\.well-known\acme-challenge\ and return
:: code 42 if there was a renewal
"%PERLBIN%" "%LE%" -renew 30 -generate-missing -unlink -live -legacy ^
-key "C:\MyCerts\my-account-key.key" -csr "C:\MyCerts\my-cert-request.csr" ^
-csr-key "C:\MyCerts\mydomain-key.key" -crt "C:\MyCerts\mydomain-cert.cert" ^
-domains "www.mydomain.com,mydomain.com" -issue-code 42 ^
:: Check whether there was a renewal, and roll out certs + restart servers
:: if so, otherwise just terminate
IF %ERRORLEVEL% EQU 42 (
:: stunnel for servers with old cryptographic implementations, this requires
:: a domain+intermediate certificate bundle with a separate private key file
TYPE "C:\MyCerts\mydomain.cert" > "%PROGRAMFILES%\stunnel\config\mydomain.pem"
ECHO. >> "%PROGRAMFILES%\stunnel\config\mydomain.pem"
TYPE "C:\MyCerts\mydomain.ca" >> "%PROGRAMFILES%\stunnel\config\mydomain.pem"
:: They key needs copying only once
:: COPY /V /Y "C:\MyCerts\mydomain.key" "C:\Server\stunnel\mydomain.key"
:: A server that needs domain certificate, intermediate CA cert and key all
COPY /V /Y "C:\MyCerts\mydomain.cert" "C:\Server1\sslconf\"
:: They key and intermediate certificate need copying only once
:: COPY /V /Y "C:\MyCerts\mydomain.ca" "C:\Server1\sslconf\"
:: COPY /V /Y "C:\MyCerts\mydomain.key" "C:\Server1\sslconf\"
:: A server that needs domain and intermediate certificates in one bundle, but
:: the private key as a separate file, like stunnel
TYPE "C:\MyCerts\mydomain.cert" > "C:\Server2\sslconf\mydomain.pem"
ECHO. >> "C:\Server2\sslconf\mydomain.pem"
TYPE "C:\MyCerts\mydomain.ca" >> "C:\Server2\sslconf\mydomain.pem"
:: They key needs copying only once
:: COPY /V /Y "C:\MyCerts\mydomain.key" "C:\Server2\sslconf\"
:: Yet another server, that needs both certificates and your private key all
:: in one bundled file
TYPE "C:\MyCerts\mydomain.key" > "C:\Server3\sslconf\mydomain.pem"
ECHO. >> "C:\Server3\sslconf\mydomain.pem"
TYPE "C:\MyCerts\mydomain.cert" >> "C:\Server3\sslconf\mydomain.pem"
ECHO. >> "C:\Server3\sslconf\mydomain.pem"
TYPE "C:\MyCerts\mydomain.ca" >> "C:\Server3\sslconf\mydomain.pem"
:: Restart all services to reload the certificate and key
:: Restart stunnel
net stop "stunnel"
net start "stunnel"
:: Restart Server 1
net stop "Server 1 system service name"
net start "Server 1 system service name"
:: Restart Server 2
net stop "Server 2 system service name"
net start "Server 2 system service name"
:: Restart Server 3
net stop "Server 3 system service name"
net start "Server 3 system service name"
:: All done!
Now you can automate the process by creating a job in Windows task scheduler to launch that certificate-renewal.bat like every 20 days or so. The script will of course vary quite a bit depending on your environment and your services, so take it only as a rough guide.
And that’s how you get Let’s Encrypt certificates and modern cryptography up and running on an 18 years old Windows operating system, for what it’s worth.
5.) Bonus information
You can actually use stunnel in client mode as well. Say you’re using Windows 2000 Pro as your client operating system (*cough*) and your software is so old and insecure, that some remote server at say https://www.verysecureserver.com:443 won’t talk to you anymore. Just run stunnel on your client on demand, with a per-host configuration such as this:
[thatverysecureserver] client = yes accept = localhost:9999 connect = www.verysecureserver.com:443 CAfile = ca-certs.pem
Open up your web browser, surf to https://localhost:9999, and stunnel’ll redirect you to that server, which will now see a secure clientside SSL implementation. Only thing is that you might need to create an exception in your browser, because the host names don’t match between what you entered in the address field and what’s in the remote servers’ certificate, but no way around that.
And now, time for some cold beer!
 The “Let’s Encrypt®” word mark is a trademark of the Internet Security Research group. All rights reserved.