Memory safe TLS with Apache on FreeBSD 06 jul 2024

A memory safe alternative to the OpenSSL based Apache module providing https capability.

Memory safe TLS with Apache on FreeBSD

The new, and expirimental, Rust-based Apache httpd module mod_tls has existed since Apache 2.4.52 (December 2021). The module was commissioned by the Prossimo Memory Safety initiative, which in turn is an Internet Security Research Group project. Prossimo contracted Stefan Eissing, an Apache httpd maintainer and creator of the HTTP/2 and ACME modules.

It was about time that this was made available for FreeBSD, the not ABI-stable Rustls and Rustls-ffi libraries were blocking earlier, but have been updated in the Apache httpd 2.4.60 release.

Let's try this again!

So we have a new port to create, and the Apache httpd port to modify to allow mod_tls to be built as a module.

Rustls-ffi

So there I was, overcomplicating things. It's not that building Rust doesn't take forever-and-a-day, but I'm no Rust veteran either. I need to wrap my head around the "Rust way" of doing things every time.

No need to build aws-lc-rs, then Rustls to get to Rustls-ffi, just build the thing, everything's self-contained.

Ultimately, the port does need cargo, but Rust has no concept of installing libraries in any way. The Rustls-ffi package ships with a regular gmake file for building and installing the static library. So I've had to override the build and install make targets to make this work. The port still depends on Rust via USES= rust but this is merely for creation of the dependent crates and running the extract/patch.

So now there's the security/rustls-ffi port. All it produces is the static library lib/librustls.a and the header file include/rustls.h.

Modifying the Apache port

Wiring things into the port for mod_tls to build was quite trivial. Other than adding the option, the option description, a dependency on the freshly created rustls-ffi port, and passing this on to apache httpd's configure. Add the mod_tls.so to the pkg-plist conditionally and "Bob's your uncle".

And it WORKS!

NOTE: To enable mod_tls, you need to enable the option for the port. It is not enabled by default since the Apache httpd project labels it as "experimental".

Adapting your Apache config for testing

As it says on the tin: you can have either mod_tls or mod_ssl enabled on an IP:port combination.

If you make your config conditional, you should be able to switch between your mod_ssl and mod_tls config.

<IfModule !tls_module>
    SSLEngine on
    SSLCertificateFile    /etc/ssl/certs/example.org.pem
    SSLCertificateKeyFile /etc/ssl/priv/example.org.pem
</IfModule>
<IfModule tls_module>
    TLSEngine 443
    TLSCertificate /etc/ssl/certs/example.org.pem /etc/ssl/priv/example.org.pem
</IfModule>

Do read the mod_tls module documentation for caveats and hints. I've settled on creating files in ${PREFIX}/etc/apache24/modules.d to enable/disable modules and the server level configuration for the module. So I have a file ${PREFIX}/etc/apache24/modules.d/002_mod_tls.conf containing

# TLS v1.2 and v1.3 implemented in memory-safe Rust via the rustls library
#
# https://httpd.apache.org/docs/2.4/mod/mod_tls.html

<IfModule !ssl_module>

LoadModule tls_module libexec/apache24/mod_tls.so

<IfModule tls_module>
    TLSEngine 443
    TLSStrictSNI on
    TLSCiphersSuppress TLS_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
</IfModule>

</IfModule>

and I control which module's used by commenting out the LoadModule line in the modules.d/001_mod_ssl.conf file that has a similar structure.

Using @icing's mod_md module makes this even simpler, expect a follow-up blog-post!