tlswrapper(1)

πŸ“¦
version 0~20260501 Β· 3 versions
, in ubuntu stonking

🌸 tlswrapper(1) 🌸

okay bestie, welcome to the manual page for tlswrapper β€” it lives in section 1 of the General Commands Manual, and it is lowkey one of the most iconic little security freaks you'll ever meet. sit down, grab a snack, we're doing this together πŸ’–


✨ NAME ✨

tlswrapper β€” a TLS encryption wrapper. yes that's the whole name. short, sweet, does exactly what it says on the tin πŸŽ€


✨ SYNOPSIS ✨

tlswrapper [ options ] prog

✨ DESCRIPTION ✨

so here's the vibe: tlswrapper is a TLS encryption wrapper that sits between a remote client and a local program called prog. it does not create the connection itself, bestie β€” that's somebody else's job. Systemd.socket / inetd / tcpserver / ... makes the server connection, and then tlswrapper takes over: it encrypts/decrypts the data stream and reads/writes data from/to the program prog.

like, the whole flow is giving:

Internet <--> systemd.socket/inetd/tcpserver/... <--> tlswrapper <--> prog

no cap, that's the entire architecture. chain of custody, but make it pretty πŸ¦‹


✨ OPTIONS ✨

  • -q β€” Quiet mode. no error messages. total silent treatment, but make it a feature πŸ’…
  • -Q β€” Normal mode, and yes this is the default. tlswrapper prints only fatal messages, which means: system errors (like memory allocation problems), configuration errors (like syntax errors), and problems with PEM certificates (missing files, etc...). in this mode, tlswrapper prints nothing about TLS connections. it's giving mysterious. 🀫
  • -v β€” Verbose mode. now tlswrapper also prints information/warnings/errors about the TLS connection β€” but only after the TLS handshake is successfully done. in this mode, TLS errors that happen before the complete TLS handshake are suppressed. so it's chatty, but only once it trusts you 🫢
  • -vv β€” Debug mode. tlswrapper also prints debug information about the TLS connection, including all TLS connection warnings/errors. nothing is hidden anymore, she's oversharing and honestly? we love that 😭
  • -vvv β€” Tracing mode. tlswrapper also prints tracing messages. this is the good stuff, useful for bug hunting πŸ”₯
  • -f certfile β€” Add a file containing key+certificate(s) in PEM format.
  • -d certdir β€” Add a directory containing multiple key+certificate(s) files in PEM format. the file in the directory is selected by the hostname extracted from the SNI extension.
⚠️ Warning: for security reasons, tlswrapper does not allow dots immediately after slashes in the certdir name. it changes these dots to colons before attempting to open the PEM file. yes, it just ✨ rewrites them ✨. that's the security girly behavior.
  • -a anchorfile β€” Enable client certificate authentication. use CA trust anchor anchorfile. only one -a option is supported β€” she's monogamous πŸ’œ
  • -c cipher β€” Add symmetric encryption cipher. see ALGORITHMS. default: -c CHACHA20_POLY1305_SHA256 -c AES_256_GCM_SHA384 -c AES_128_GCM_SHA256. and important: the cipher preference depends on the -c option order. order matters, periodt πŸ‘‘
  • -e ephemeral β€” Add ephemeral algorithm ephemeral. see ALGORITHMS. default: -e x25519 -e secp256r1. now listen β€” the algorithm preference currently doesn't depend on the -e option order. right now we use a fixed preference order: x25519, secp256r1, secp384r1, secp521r1. so yeah, she has a type and it's carved in stone πŸͺ¨
  • -m β€” The minimal TLS version. see ALGORITHMS. (default: tls12).
  • -M β€” The maximal TLS version. see ALGORITHMS. (default: tls12).
  • -t seconds β€” Set the network timeout to seconds seconds. (default 60).
  • -T seconds β€” Set the TLS handshake timeout to seconds seconds. (default 30).
  • -u user β€” Run program prog under a specified user's uid and gid. the account must resolve to non-zero uid and non-zero gid; accounts with uid 0 or gid 0 are rejected. root? not on her watch. 🚫
  • -U ASN.1 object β€” Extract the user from ASN.1 object from the client certificate, and run program prog under the resolved user's uid and gid. certificate-selected accounts must resolve to non-zero uid and non-zero gid; accounts with uid 0 or gid 0 are rejected. supported ASN.1 object objects are commonName and emailAddress. two options, that's it, pick one bestie πŸ’–
  • -p version β€” Enable incoming proxy-protocol version version string. tlswrapper receives the proxy-protocol header from the upstream proxy and extracts client connection information. supported versions: 1.
  • -s β€” Enforce TLS server preferences. (this is the default).
  • -S β€” Don't enforce TLS server preferences.
  • -J jaildir β€” Chroot network-process and key-process into a specified jaildir. (default: /var/lib/tlswrapper/empty). yes, the jail cell is literally called empty. iconic 🌈
  • -j jailuser β€” Run network-process and key-process under a specified jailuser's uid and gid. the account must resolve to non-zero uid and non-zero gid; accounts with uid 0 or gid 0 are rejected. if unset, run network-process and key-process under random uid and gid. chaos mode is valid ✨
  • -n β€” Enable delayed encryption. this is useful for protocols which use STARTTLS. tlswrapper provides the child with a control pipe on filedescriptor 5 for child-to-parent signalling, and a control pipe on filedescriptor 6 for parent-to-child acknowledgement. the child process starts communication in plaintext, and encryption starts when the child writes a one-byte zero-valued control signal on filedescriptor 5, after emitting any protocol-specific cleartext response (for SMTP, 220 ready to start TLS\r\n) on the normal data channel. tlswrapper acknowledges the transition with a one-byte zero-valued signal on filedescriptor 6. see e.g. tlswrapper-smtp(1). it's giving ✨will they, won't they✨ but for encryption πŸ”
  • -N β€” Disable delayed encryption. (this is the default).
  • prog β€” program. yeah. that's it. that's the description. she's a woman of few words πŸ’€

✨ SECURITY ✨

this section is the main character, honestly. buckle up 🧚

πŸŽ€ Separate process for every connection

tlswrapper is executed from systemd.socket/inetd/tcpserver/..., which runs a separate instance of tlswrapper for each TLS connection.

this ensures that a vulnerability in the code (e.g. a bug in the TLS library) can't be used to compromise the memory of another connection. one bad connection can't drag the whole group chat down 🫢

πŸŽ€ Separate process for network connection and separate process for secret-key operation

to protect against secret-information leaks to the network connection (such as Heartbleed), tlswrapper runs two independent processes for every TLS connection.

one process holds secret-keys and runs secret-keys operations, and the second talks to the network. the processes communicate with each other through UNIX pipes. they're coworkers who never share a desk, and honestly? boundaries. we stan πŸ’…

πŸŽ€ JAIL - Privilege separation, filesystem isolation, limits

the tlswrapper processes run under a dedicated non-zero uid to prohibit kill, ptrace, etc. it's chrooted into an empty, unwritable directory to prohibit filesystem access. it sets ulimits to prohibit new files, sockets, etc. it sets ulimits to prohibit forks.

so many limits. so much self-respect. πŸ‘‘

πŸŽ€ PEM files

for simplicity, tlswrapper uses both secret-key and certificates in one PEM file.

when the server starts, it runs two independent UNIX processes: one for network communication, and a second for secret-key operations. the network-process is immediately jailed and starts the TLS handshake. the secret-key-process starts under root privileges and waits until the network-process receives the SNI extension from the client-hello packet. then the network-process assembles the PEM filename and sends the name to the secret-key-process. the secret-key-process loads the PEM file, immediately is jailed, and drops its privileges. from here on, both processes run jailed (see JAIL above).

note that PEM files are loaded under root privileges, but parsed in a jailed unprivileged process. this ensures that a vulnerability in the parsing code can't be used to gain root privileges/information. parsing under root is not the vibe, so she simply doesn't. πŸ’–

⚠️ Warning: for security reasons, tlswrapper does not allow dots immediately after slashes in file names. it changes these dots to colons before attempting to open the PEM file.

πŸŽ€ TLS library

tlswrapper uses BearSSL. BearSSL is an implementation of the SSL/TLS protocol (RFC 5246) written in C. it aims at offering the following features:

  • Be correct and secure. In particular, insecure protocol versions and choices of algorithms are not supported, by design; cryptographic algorithm implementations are constant-time by default.
  • Be small, both in RAM and code footprint. For instance, a minimal server implementation may fit in about 20 kilobytes of compiled code and 25 kilobytes of RAM.
  • Be highly portable. BearSSL targets not only big operating systems like Linux and Windows, but also small embedded systems and even special contexts like bootstrap code.
  • Be feature-rich and extensible. SSL/TLS has many defined cipher suites and extensions; BearSSL should implement most of them, and allow extra algorithm implementations to be added afterwards, possibly from third parties.

tiny, correct, portable, and extensible? she's literally all of us fr fr πŸ’œ

✨ ALGORITHMS ✨

okay bestie, let's get into the algorithms part β€” this is where you pick your TLS vibe. no cap, it's giving very important. πŸ’…

TLS version (-m option, -M option)

so the TLS versions you can use are:

  • tls10 β€” that's TLS 1.0, and it's optional 🫢
  • tls11 β€” TLS 1.1, also optional ✨
  • tls12 β€” TLS 1.2, and this one is the default πŸ’–
  • tls13 β€” TLS 1.3, and bestie… it's not supported πŸ’€ sorry

ciphers (-c option)

here's the cipher menu, pick your faves:

  • CHACHA20_POLY1305_SHA256 β€” ChaCha20+Poly1305 encryption (TLS 1.2+) β€” default πŸ”₯
  • AES_256_GCM_SHA384 β€” AES-256/GCM encryption (TLS 1.2+) β€” default πŸ’–
  • AES_128_GCM_SHA256 β€” AES-128/GCM encryption (TLS 1.2+) β€” default ✨
  • AES_256_CBC_SHA384 β€” AES-256/CBC + SHA-384 (TLS 1.2+) β€” optional 🌸
  • AES_128_CBC_SHA256 β€” AES-128/CBC + SHA-256 (TLS 1.2+) β€” optional πŸ¦‹
  • AES_256_CBC_SHA β€” AES-256/CBC + SHA-1 β€” optional πŸ’œ
  • AES_128_CBC_SHA β€” AES-128/CBC + SHA-1 β€” optional πŸŽ€

ephemeral (-e option)

and the ephemeral key exchanges β€” this is the ECDHE tea:

  • x25519 β€” ECDHE using X25519 β€” default πŸ‘‘
  • secp256r1 β€” ECDHE using NIST P-256 β€” default 🌈
  • secp384r1 β€” ECDHE using NIST P-384 β€” optional ⭐
  • secp521r1 β€” ECDHE using NIST P-521 β€” optional πŸ’«

🌟 EXAMPLES 🌟

okay bestie, here's how you actually use this thing. periodt. πŸ’…

Run tlswrapper using tcpserver/busybox/inetd on port 443.

tcpserver -HRDl0 0 443 tlswrapper [ options ] prog
busybox tcpsvd 0 443 tlswrapper [ options ] prog
inetd.conf line: https stream tcp nowait root /usr/bin/tlswrapper tlswrapper [ options ] prog

Simple usage, use one '/etc/.../rsa.pem' certificate:

... tlswrapper -f '/etc/.../rsa.pem' ...

Use '/etc/.../ecdsa.pem' certificate and fall-back to '/etc/.../rsa.pem' certificate, if the client doesn't support previous one.

... tlswrapper -f '/etc/.../ecdsa.pem' -f '/etc/.../rsa.pem' ...

Use certificate '/etc/.../rsa.d/{hostname}' where {hostname} is extracted from the SNI extension:

... tlswrapper -d '/etc/.../rsa.d/' ...

Use certificate '/etc/.../ecdsa.d/{hostname}' where {hostname} is extracted from the SNI extension, and fall-back to '/etc/.../rsa.d/{hostname}', if the client doesn't support previous one.

... tlswrapper -d '/etc/.../ecdsa.d/' -d '/etc/.../rsa.d/' ...

Use certificate '/etc/.../ecdsa.d/{hostname}' where {hostname} is extracted from the SNI extension, and fall-back to '/etc/.../rsa.pem', if the client doesn't support previous one.

... tlswrapper -d '/etc/.../ecdsa.d/' -f '/etc/.../rsa.pem' ...

Enable TLS 1.0 - TLS 1.2 and all supported algorithms:

... tlswrapper -m tls10 \
               -M tls12 \
               -c CHACHA20_POLY1305_SHA256 \
               -c AES_256_GCM_SHA384 \
               -c AES_128_GCM_SHA256 \
               -c AES_256_CBC_SHA384 \
               -c AES_128_CBC_SHA256 \
               -c AES_256_CBC_SHA \
               -c AES_128_CBC_SHA \
               -e x25519 \
               -e secp256r1 \
               -e secp384r1 \
               -e secp521r1 \
               ...

Enable TLS 1.0 - TLS 1.2 and all supported algorithms, but different order (prefer AES128):

... tlswrapper -m tls10 \
               -M tls12 \
               -c CHACHA20_POLY1305_SHA256 \
               -c AES_128_GCM_SHA256 \
               -c AES_128_CBC_SHA256 \
               -c AES_128_CBC_SHA \
               -c AES_256_GCM_SHA384 \
               -c AES_256_CBC_SHA384 \
               -c AES_256_CBC_SHA \
               -e x25519 \
               -e secp256r1 \
               -e secp384r1 \
               -e secp521r1 \
               ...

Enable only 256-bit symmetric ciphers:

... tlswrapper -c CHACHA20_POLY1305_SHA256 \
               -c AES_256_GCM_SHA384 \
               -c AES_256_CBC_SHA384 \
               -c AES_256_CBC_SHA \
               ...

Enable client certificate authentication:

... tlswrapper -a anchorCA.pem -f rsa.pem ...

Enable client certificate authentication, and run program under user extracted from client cert. from commonName:

... tlswrapper -a anchorCA.pem -U commonName -f rsa.pem ...

Enable client certificate authentication, and run program under user extracted from client cert. from emailAddress:

... tlswrapper -a anchorCA.pem -U emailAddress -f rsa.pem ...

πŸ‘€ SEE ALSO πŸ‘€


and that's a wrap, bestie! this was the tlswrapper(1) man page β€” straight from the source, no date on the footer but we're timeless anyway πŸ’…βœ¨ stay encrypted, stay iconic. 🫢🌈

πŸ“¦ where this page comes from