warp-s2n-tls
TLS support for the Warp web server using s2n-tls.
Overview
This library provides an alternative to warp-tls by using AWS's s2n-tls
library for TLS termination instead of the Haskell tls package.
Usage
import Network.Wai.Handler.WarpS2N
import Network.Wai.Handler.Warp (defaultSettings, setPort)
import Network.Wai (Application)
main :: IO ()
main = do
let tlsSet = tlsSettings "cert.pem" "key.pem"
runTLS tlsSet defaultSettings myApp
myApp :: Application
myApp = ...
Dynamic library loading
To load libs2n.so at runtime instead of linking:
main :: IO ()
main = withS2nTls (Dynamic "/usr/local/lib/libs2n.so") $ \tls -> do
runTLSLib tls tlsSet warpSet myApp
Memory Locking (mlock)
What is mlock?
s2n-tls uses the Linux mlock() system call to lock memory pages containing
cryptographic secrets (private keys, session keys, etc.) into RAM. This prevents
the operating system from swapping these pages to disk, where they could
potentially be recovered by an attacker after your application terminates.
The RLIMIT_MEMLOCK limit
Linux enforces a per-process limit on how much memory can be locked, controlled
by RLIMIT_MEMLOCK. On many systems, this defaults to just 64 KB (or even
32 KB on some Debian versions). Since s2n-tls locks memory for all TLS
connections and cryptographic operations, this limit can be exhausted quickly
in applications handling multiple connections.
When the limit is exceeded, you'll see errors like:
Error Message: 'error calling mlock'
Debug String: 'Error encountered in s2n_mem.c line 106'
Solutions
Option 1: Increase the mlock limit (recommended for production)
Raise the limit for your shell session:
ulimit -l unlimited
Or set it to a specific value (in KB):
ulimit -l 65536 # 64 MB
For systemd services, add to your unit file:
[Service]
LimitMEMLOCK=infinity
Option 2: Disable mlock (acceptable for development/testing)
Set the environment variable to disable memory locking entirely:
S2N_DONT_MLOCK=1 ./your-application
Security considerations
-
With mlock enabled: Secrets are protected from being written to swap,
reducing the risk of recovery from disk. This is the recommended setting
for production deployments handling sensitive data.
-
With mlock disabled: Secrets may be swapped to disk under memory
pressure. This is generally acceptable for development, testing, and
applications where the threat model doesn't include disk forensics.
-
Note: Even with mlock enabled, laptop suspend/hibernate modes may
save RAM contents to disk regardless of memory locks.
Development
Running tests
Tests require S2N_DONT_MLOCK=1 to avoid exhausting the default mlock limit:
S2N_DONT_MLOCK=1 cabal test
See the Memory Locking section above for details.
- s2n-tls - High-level Haskell bindings (used internally by this package)
- s2n-tls-ffi - Low-level FFI bindings for direct s2n-tls access
License
Apache-2.0