While building WebThemis, we've encountered the need to build LibreSSL for PNaCl as a source of cryptographic primitives.
The problem? LibreSSL has huge codebase with a lot of complicated code, that won't build on new platform out of the box. Solution? Strip all we can and make the rest work.
Having gone “let’s do a quick hack to build Libre” barbaric way for PoC version of WebThemis, we would like to share our experience for the aspiring PNaCl developers to benefit.
We are interested only in a limited LibreSSL functionality, used as a part of Themis, so we can remove some of parts without damaging Themis itself. Moreover, our target architecture enables us to skip some platform-specific stuff.
We weren't able to find any configuration tools to exclude LibreSSL components from the build - and we doubt there are any such tools, as LibreSSL architecture comes from OpenSSL origins. In OpenSSL code structure, things are so complicated that removing one unnecessary (for you) part can result in malfunctions in parts you need. Sometimes such interactions and dependencies are awkward, to say the least. However, this article is not about OpenSSL being cumbersome, but about making it's better little brother,- LibreSSL,- work on PNaCl. So let's get going.
As our sole need was libcrypto, we removed all other targets in config.ac and we had to remove all subdirectories except for include and crypto in the Makefile.am file.
We've used autoconf and automake to make the build.
LibreSSL build involves two stages:
During the first stage you should generate Makefile with fully-written paths to a compiler, composer, headers, etc. Just adding right PNaCl-SDK path settings to Makefile will not help. Thus said, we will begin with configuration. Let’s show correct paths to a configure script:
CC=$PNACL_ROOT$PNACL_TOOLCHAIN/bin/pnacl-clang CXX=$PNACL_ROOT$PNACL_TOOLCHAIN/bin/pnacl-clang++ LD=$PNACL_ROOT$PNACL_TOOLCHAIN/bin/pnacl-ld AR=$PNACL_ROOT$PNACL_TOOLCHAIN/bin/pnacl-ar CFLAGS="-I$PNACL_ROOT/include/pnacl -I$PNACL_ROOT/usr/include/pnacl" ./configure --disable-shared --without-pic
This is what we get:
checking whether we are cross compiling... configure: error: in `/home/andrey/research/pnacl_libs/libressl-2.2.5': configure: error: cannot run C compiled programs. If you meant to cross compile, use `--host'.
Ok, let’s add --host=x86-32 target.
Makefile is ready, it’s time to go to make.
This is the first output we received:
pnacl-clang: Unrecognized option: -Qunused-arguments
Let’s open m4/disable-compiler-warnings.m4 file, find the CLANG_FLAGS=-Qunused-arguments line and comment it.
The next attempt of building LibreSSL leads to the following:
bio/bss_bio.c:302:13: error: use of undeclared identifier 'SSIZE_MAX' if (num_ > SSIZE_MAX)
We found that SSIZE_MAX macros is defined at include/compt/sys/types.h and for MinGW & MSVS only.
We added the following into CFLAGS - -DSSIZE_MAX=LONG_MAX.
New error log contained the following:
bio/bss_log.c:68:10: fatal error: 'syslog.h' file not found #include <syslog.h>
We can disable syslog by adding -DNO_SYSLOG into CFLAGS and, interestingly enough, by adding #include <syslog.h> into the block surrounding NO_SYSLOD in bio/bss_log.c file.
This time our build missed the uio.h file:
In file included from x509/by_mem.c:59: ../include/compat/sys/uio.h:7:15: fatal error: 'sys/uio.h' file not found #include_next <sys/uio.h>
From /include/compat/sys/uio.h we can see that in WIN32 systems iovec structure is defined automatically.
We forced this to happen by commenting conditional macros.
#ifndef _WIN32 #include_next <sys/uio.h> #else ... #endif
We then did the same for the next error we encountered:
In file included from compat/inet_pton.c:23: ../include/compat/arpa/nameser.h:7:15: fatal error: 'arpa/nameser.h' file not found #include_next <arpa/nameser.h>
We commented the conditional directives then:
//#ifndef _WIN32 //#include_next <arpa/nameser.h> //#else //#include <win32netcompat.h> #ifndef INADDRSZ #define INADDRSZ 4 #endif #ifndef IN6ADDRSZ #define IN6ADDRSZ 16 #endif #ifndef INT16SZ #define INT16SZ 2 #endif //#endif
The next time we ran it, our build returned the following:
In file included from compat/arc4random.c:68: compat/arc4random.h:31:2: error: "No arc4random hooks defined for this platform." #error "No arc4random hooks defined for this platform." ^ compat/arc4random.c:93:3: warning: implicit declaration of function '_getentropy_fail' is invalid in C99 [-Wimplicit-function-declaration] _getentropy_fail(); ^ compat/arc4random.c:186:2: warning: implicit declaration of function '_ARC4_LOCK' is invalid in C99 [-Wimplicit-function-declaration] _ARC4_LOCK(); ^ compat/arc4random.c:188:2: warning: implicit declaration of function '_ARC4_UNLOCK' is invalid in C99 [-Wimplicit-function-declaration] _ARC4_UNLOCK();
We edited compat/arc4random.h in the following way:
#ifndef LIBCRYPTOCOMPAT_ARC4RANDOM_H #define LIBCRYPTOCOMPAT_ARC4RANDOM_H #include <sys/param.h> #include "arc4random_linux.h" #endif
Another make showed the library was built and ready to be used in PNaСl project. Yay!
This is not the best way to port libraries from one platform to another, certainly. However, when you need some quick and dirty fix (in our case to get good old libcrypto to work), sometimes even make-fix-repeat path is sufficient to port things to PNaCl.