Replacing Openssl, Part 1: wolfSSL
Jan 6, 2021
8 minute read

This post highlight my experiment of replacing OpenSSL cryptographic library with its embedded competitor: wolfssl.

Prerequites: Basic knowledge about C/C++ programming.

A bit of background about OpenSSL

OpenSSL is one of the most crucial libraries on a Unix system: it performs cryptographic functions and it provides Transport Layer Security (TLS) and Secure Sockets Layer (SSL) protocols to applications.

According to the Arch Linux OpenSSL package, 355 packages, out of the 11523 available, depend on it. You can find it installed on any Unix system (and on Windows too!).

It started in 1998 as a fork of SSLeay and it has been in development since. Two full-time developers work on it, as well as many volunteers.

Fast forward to 2014: a CVE had been issued regarding a high risk vulnerability found in OpenSSL. It has been given the name Heartbleed, because it has been found in the TLS/DTLS heartbeat extension (RFC6520). This vulnerability allowed attackers to steal sensitive data, such as secret keys, user names and passwords.

All the community turned to the OpenSSL project, weighting its implementation and security policy. Heartbleed have been promptly fixed, but there could be new vulnerabilities in the future, if security was not properly prioritized during development.

At this point, OpenBSD’s folks forked OpenSSL and started a new project: LibreSSL. It primary goals were to modernize the codebase and to improve its security. This new project hasn’t been adopted by big distributions such Ubuntu and Arch Linux; instead smaller distributions (at that time) replaced OpenSSL with LibreSSL on their default configuration, such as Alpine and Void.

In the last years, LibreSSL have seen a decline in its usage. Alpine switched back to OpenSSL (link to the thread). Many people and distributions are considering doing the same, since OpenSSL got the improvement that LibreSSL aimed for. And it’s still the de facto standard cryptographic library on Unix.

Why replacing OpenSSL now?

OpenSSL works fine, there is no denying that. Every software has out of the box support for it so it costs no effort in term of additional mainteinance. However, there are newer and lighter TLS and SSL implementations, which many folks might prefer over the heavy OpenSSL’s one. I, too, prefer lightweight libraries.

I am uninstalling LibreSSL on my systems, therefore this might be the perfect time to experiment with something different. I have found an interesting (and well done!) library called wolfSSL that claims to have an OpenSSL compatibility layer. It also claims to be 20 times smaller than OpenSSL.

Installation

wolfSSL is a small C library; It uses autotools to build and CMake support is being added (sigh!). Upon running configure, I am overwhelmed by the quantity of compile options available.

some of the wolfSSL configure options

Fortunately, there is one comfy option which I’ve used when compiling wolfSSL: --enable-all. It enables all options, including the OpenSSL compatibility layer and leaves out the SSL 3 protocol.

Upon completing the build and installation (which takes a couple of minutes), a library libwolfssl.so will be installed into /usr/lib, as well as a pkgconfig file (wolfssl.pc) and all the headers.

Out of the box support

Key applications provide support for different SSL implementations other than OpenSSL. For example curl supports mbedTLS, BearSSL and our wolfSSL. To compile curl using wolfSSL, we just need to add --with-ssl=wolfssl and we’re done. I am aware of only two packages that have out of the box support for wolfSSL and they are curl and wget2 (not the legacy version!).

OpenSSL compatibility

--enable-all configure option enabled the OpenSSL compatibility layer. To use this layer, according to the documentation, we need to link the wolfssl library manually by adding -lwolfssl as link argument. We also need to include the path /usr/include/wolfssl so that the OpenSSL headers in /usr/include/wolfssl/openssl will be picked up.

This way both wolfSSL and OpenSSL can coexist on the same system and the latter can be replaced on a per project basis. However, that’s not what we want since want to replace OpenSSL at a system level.

Adding the link flag to each package on the system or patching one by one is not an option as it would take too much time. Let’s instead apply some workarounds.

First, we create a symlink for the headers:

$ sudo ln -sf /usr/include/wolfssl/openssl /usr/include/openssl

Then we create a symlink for each library. OpenSSL provides the following libraries:

  • libssl.so
  • libcrypto.so

So we can run:

$ sudo ln -sf /usr/lib/libwolfssl.so /usr/lib/libssl.so
$ sudo ln -sf /usr/lib/libwolfssl.so /usr/lib/libcrypto.so

Fixing pkg-config

Some software rely on pkg-config for checking OpenSSL dependency since it provides the following pkg-config files:

  • libssl.pc
  • libcrypto.pc
  • openssl.pc

My system doesn’t currently have either OpenSSL or LibreSSL installed, so any attempt to include OpenSSL by using pkg-config will fail. We can fix this by adding a pkg-config file in /usr/lib/pkgconfig/openssl.pc:

prefix=/usr/x86_64-pc-linux-musl
includedir=${prefix}/include/wolfssl

Name: openssl
Description: wolfssl C library.
Version: 4.6.0
Requires: wolfssl
Cflags: -I${includedir}

Our pkg-config file will include the correct directory containing the OpenSSL headers. It will also import cflags and link flags from the wolfssl pkg-config. Let’s try if it works as intended:

$ pkg-config --cflags --libs openssl
-I/usr/x86_64-pc-linux-musl/include/wolfssl -lwolfssl

Yes! Now we just need create symlinks the other two pkg-config files:

$ sudo ln -sf /usr/lib/pkgconfig/openssl.pc /usr/lib/pkgconfig/libssl.pc
$ sudo ln -sf /usr/lib/pkgconfig/openssl.pc /usr/lib/pkgconfig/libcrypto.pc

Now we’re ready to compile system packages.

Compiling system packages

Before actually going further into the various compile results, there are few general changes that I’ve done:

  1. Include the default /usr/include/wolfssl/option.h provided in /usr/include/wolfssl/wolfcrypt/setting.h. This way we will have a bunch of defines already included that enable many wolfSSL features.
  2. Remove some defines from option.h that disable old OpenSSL features, like old SSL names. While I understand that these features are plainly old (or even deprecated), projects will still use them as long as they haven’t been removed upstream.
  3. Define OPENSSL_NO_WHIRPOOL in the same header as above, since this feature ins’t implemented in wolfSSL. There are other OPENSSL_NO_* defines there for unimplemented features, but this one was missing.

wget

wget, which comes installed on any Unix system, is the first software we’ll try building with wolfSSL and its OpenSSL compatibility layer.

wget compile error

wget complains about two undeclared identifiers:

  • CONF_MFLAGS_DEFAULT_SECTION
  • CONF_MFLAGS_IGNORE_MISSING_FILE

We can fix this by adding the defines from the OpenSSL file openssl/conf.h to /usr/include/wolfssl/option.h:

# define CONF_MFLAGS_IGNORE_MISSING_FILE 0x10
# define CONF_MFLAGS_DEFAULT_SECTION     0x20

wget link-time errors about missing symbols

We arrived at link-time, that’s huge! However, there are 8 undefined symbols: 6 symbols about unimplemented features in wolfSSL, such as i2d_x509_PUBKEY and a2i_IPADDRESS; 2 symbols regarding wolfSSL functions. The latter could probably be fixed by adding the proper compile time option to wolfSSL, like --enable-sslv3.

rhash

rhash is an utility that calculates and verifies message digests, such as SHA256 and MD5. It is required by CMake, so we can consider it an essential package. Compiling rhash led to many errors. Let’s look in depth at some of them.

rhash compile error about RIPEMD160_CTX

rhash uses RIPEMD160_CTX which is not implemented by wolfSSL.

rhash compile error about WOLFSSL_MD5_CTX

This time, rhash access a member of MD5_CTX (which wolfSSL has replaced by WOLFSSL_MD5_CTX) using offsetof. The original MD5_CTX struct looks like this:

typedef struct MD5state_st {
    MD5_LONG A, B, C, D;
    MD5_LONG Nl, Nh;
    MD5_LONG data[MD5_LBLOCK];
    unsigned int num;
} MD5_CTX;

WOLFSSL_MD5_CTX instead looks like this:

typedef struct WOLFSSL_MD5_CTX {
    /* big enough to hold wolfcrypt md5, but check on init */
#ifdef STM32_HASH
    void* holder[(112 + WC_ASYNC_DEV_SIZE + sizeof(STM32_HASH_Context)) / sizeof(void*)];
#else
    void* holder[(112 + WC_ASYNC_DEV_SIZE) / sizeof(void*)];
#endif
} WOLFSSL_MD5_CTX;

I think that this incosistency between OpenSSL and wolfSSL structs will happen again with different data types.

libssh2

From the official libssh2 site:

libssh2 a client-side C library implementing the SSH2 protocol

curl has a hard dependency on libssh2, so we can consider it another essential package.

libssh2 build errors

This time there are only 2 errors, both about unimplemented features: EVP_bf_cbc and EVP_cast5_cbc. The man pages are the best source of information about OpenSSL functions; we can browse them by running:

$ man EVP
$ man EVP_bf_cbc
$ man EVP_cast5_cbc

Let’s split the names and study each part:

  • EVP is a high-level interface to cryptographic functions
  • bf and cast5 are the name of the algorithms, blowfish and CAST respectively.
  • cbc, Cipher Block Chaining, is a mode of operation that tells OpenSSL to operate on each block seperately from the others.

Operating cryptographic functions in CBC mode isn’t really safe nor the two algorithms above are really popular, so I understand why wolfSSL developers might have prioritized other things over implementing the two functions above.

ffmpeg

ffmpeg is a powerful library and a collection of utilities for handling images, audio and videos. It is required by Firefox, Chromium, mpv and another hundred and a half software (at least). We surely don’t want a system without this library.

ffmpeg build error

This time there is only one error (but others may still pop up later while building!). The function BN_sub_word is missing. According to the man pages, it is the arithmetic function that perform subtractions on big integers. This seems pretty straightforward to add in wolfSSL.

Conclusion

I’ve tried building different essential software and none of them succeeded using wolfSSL and its OpenSSL compatibility layer. However, most of them had small errors that can probably be fixed in a day or two. That’s a shame because wolfSSL is really close to replace OpenSSL at a distro level, and yet so distant since it’s not its priority. Basing on what I’ve seen and the documentation, the OpenSSL compatibility layer is best used on a per-project basis, where you can fix your code or replace missing features with modern ones (or even better, you can pay them to implement the features you need).




Comments