Building OpenSSL and TLS on Windows

Published , updated

This post may be partially, or even completely, out of date. Both OpenSSL and the TLS extension have had major updates since it was written.

Building the Tcl TLS extension on Unix/Linux is straightforward because OpenSSL libraries are already present and installed. It's a different matter on Windows where you need to build OpenSSL yourself. This short article describes the process.

The actual steps required to build OpenSSL and Tcl TLS are very few as you will see below; that is, once you know what to do and more important, what not to do. To get there though took me the better part of an evening, so I'm writing it down. No, not for you, dear reader, but for myself for when I next need to do a build.

Prerequisites

These instructions are for building using the Microsoft toolchain, not Cygwin or MinGW. I use Visual C++ 6.0 for my 32-bit builds and the compiler from the February 2003 platform SDK for 64-bit builds. Why such ancient compilers? Well, because I'm kind of ancient myself. Also using older compilers has a major advantage - you do not need to redistribute the C runtime libraries with your extension because the runtimes for those compilers are already present on all Windows systems.

In addition to the compiler, you need to have two additional tools installed:

  • A suitable Perl interpreter where suitable means an interpreter that will not barf on the Windows OpenSSL build scripts. In particular, do not assume, as I did, that I already have Msys installed so I can just use the Perl that comes with that. I landed up using the ActiveState Perl distribution. And try not to be a bonehead, as I was, and stick the installation directory later in the PATH than the Msys Perl if you have one.

  • The NASM open source assembler. This is actually optional but you will need it if you are following my steps. Using the assembler allows OpenSSL to be built with some performance optimized x86 assembler crypto routines.

Building OpenSSL

Download the OpenSSL source distribution. The latest version at the time of writing was 1.0.2 which is what I used for my build.

Every time you do an OpenSSL build, do it by extracting the distribution into a new empty directory and working there. Do not rebuild from an existing source directory unless you are absolutely sure that target platform options are exactly the same.

First start a new DOS shell configured for the 32-bit Visual C++ compiler, either from the Windows Program Menu or running the appropriate vcvars32.bat.

Then cd to the OpenSSL source directory and start off by configuring OpenSSL for a 32-bit Windows build using Visual C++. Note all steps below are done from the toplevel OpenSSL source directory. In our demonstration, we have extracted to the openssl-src directory.

cd openssl-src
perl Configure VC-WIN32 --prefix=c:\temp\openssl\x86

The --prefix option specifies where OpenSSL will be installed. Any directory will do as long as you do not specify the same directory for the 64-bit build later.

Next we have to build the Visual C++ makefiles based on the build configuration in the ms directory.

ms\do_nasm

Once the makefile are built, invoke nmake to compile and link

nmake -f ms\nt.mak

In the above nmake commands, we have chosen to run the ms\nt.mak makefile because we wanted static libraries to link to our Tcl TLS extension. We could have run ms\ntdll.mak instead to build shared DLL versions of the library. However, I built the static version because I prefer the Tcl TLS extension to be one single binary for easy of distribution, inclusion in a TclKit or StarPack.

Once the build is completed, verify it by running the test suite. Change to the out32 subdirectory before running the test suite ( or out32dll subdirectory if you did the shared DLL build).

cd out32
..\ms\test

You should see a passed all tests message at the end of the run.

The final step is to package and install the OpenSSL binaries.

cd ..
nmake -f ms\nt.mak install

Again, specify ntdll.mak if you build the shared DLL version. If all goes well, you should now have a complete OpenSSL distribution in the directory you specified through the --prefix option.

The lazy reader might, as lazy people are wont to do, look to avoid all that work by downloading existing Windows binaries instead. There are good reasons I prefer to build from source. First, I prefer using the static OpenSSL libraries for reasons I mentioned above. Second, pre-built binaries do not allow control of build options such as ciphers. Third, and perhaps most important, when you need to update OpenSSL to fix newly discovered vulnerabilities, you are at the mercy of someone else to build an updated binary.

Building the TLS extension

Now that OpenSSL is built, we can move on to building the TLS extension. The Tcl TLS extension sources can be downloaded from SourceForge. Extract it into its own directory and change to the win subdirectory beneath it.

You may need to edit makefile.vc to change the OpenSSL library names from ssleay32s.lib and libeay32s.lib to ssleay32.lib and libeay32.lib respectively. Then run nmake to build and install the extension as follows:

nmake -f makefile.vc OPENSSL=c:\temp\openssl\x86 TCLDIR=c:\src\twapi\tcl-tk\85 INSTALLDIR=c:\tcl\863\x86
nmake -f makefile.vc install OPENSSL=c:\temp\openssl\x86 TCLDIR=c:\src\twapi\tcl-tk\85 INSTALLDIR=c:\tcl\863\x86

The TLS extension makefile follows the standard format for Tcl extensions so the above command should need no explaining. The only unusual thing is the need to set OPENSSL to point to the location of the OpenSSL distribution we just built (matching the --prefix option passed to the OpenSSL build).

Building 64-bit versions

Building the 64 bit versions follows the same pattern except for slightly different commands so we only summarize here.

To repeat a previous warning, do not build the 64-bit OpenSSL version from the same directory that the 32-bit version was built from. Not even if you do a make clean.

Start a new DOS command shell to make sure no environment settings are left over from the 32-bit build. Run the appropriate vcvars32.bat for your 64-bit Visual C++ compiler to set up its environment. Then change to the newly extracted directory and run the following commands:

perl Configure VC-WIN64A --prefix=c:\temp\openssl\x64
ms\do_win64a

Note the platform is now VC-WIN64A and we are using ms\do_win64a instead of ms\do_nasm. Also ensure the directory passed to --prefix is different from that for the 32-bit builds.

The remaining commands are identical to those for the 32-bit builds.

nmake -f ms\nt.mak
cd out32
..\ms\test
cd ..
nmake -f ms\nt.mak install

The steps for building the 64-bit TLS extension is the same as before except that you need to make sure you pass the paths appropriate for 64-bits. For example, OPENSSL should point to c:\temp\openssl\x64.

Testing

To verify the built TLS extension, cd to the tests diectory in the TLS source distribution and run the following command:

tclsh all.tcl

You may see two test failures related to ciphers. This is because the test depends on enumerating the number of ciphers built into OpenSSL and can change depending on both the OpenSSL version and build options.

Non-default build options

You may notice the built extension is fairly large, around 1 MB. This is at least in part because the default OpenSSL build probably includes a whole bunch of ciphers that are not required for the TLS extension. You can exclude these by specifying options to the perl Configure command. However, I have not looked into which ciphers are actually required.

And so where are the binaries?

I am unsure what export restrictions there are on distributing crypto software, both in the US and my country of residence. And I can't be bothered to find out. Thus I have not made binaries available. Also, what's that saying about teaching a man to fish... :-)

Happy Tcl'ing!