# warp-s2n-tls
TLS support for the Warp web server using [s2n-tls](https://github.com/aws/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
```haskell
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:
```haskell
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:
```bash
ulimit -l unlimited
```
Or set it to a specific value (in KB):
```bash
ulimit -l 65536 # 64 MB
```
For systemd services, add to your unit file:
```ini
[Service]
LimitMEMLOCK=infinity
```
**Option 2: Disable mlock (acceptable for development/testing)**
Set the environment variable to disable memory locking entirely:
```bash
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:
```bash
S2N_DONT_MLOCK=1 cabal test
```
See the [Memory Locking](#memory-locking-mlock) section above for details.
## Related Packages
- [s2n-tls](https://github.com/goertzenator/s2n-tls) - High-level Haskell bindings (used internally by this package)
- [s2n-tls-ffi](https://github.com/goertzenator/s2n-tls-ffi) - Low-level FFI bindings for direct s2n-tls access
## License
Apache-2.0