An overview of the TLS-related programs
The s6-*tls* programs are organized in a way that minimizes
the amount of code, and in particular that keeps the crypto code as
encapsulated as possible.
They are divided in two sets: client programs, which have client
or c in their name, and server programs, which have server
or d in their name. The sets are symmetrical: the same
functionality is available whether you're interested in using a
client or a server.
Of course, they do not have to be used together. You can run a
TLS-enabled super-server via s6-tlsserver
and it will work with any client speaking the correct TLS-enabled
protocol, not only s6-tlsclient.
The core TLS engine: s6-tlsc-io and s6-tlsd-io
- s6-tlsc-io and
s6-tlsd-io are the only programs
that actually perform TLS operations; the only ones that are linked
against the BearSSL or LibreSSL libraries.
- They read TLS-related
information (where to find my trust anchor list? where to find my
server certificate and private key?) from their environment.
- They assume that their stdin/stdout is talking to the network; they
also take two other fds on the command line that they assume are
open and talking to the local application - one for reading, one for
- They establish a TLS tunnel over the network.
- They maintain full-duplex communication: what they read
from the local application is sent to stdout as ciphertext; what
they read from stdin is sent to the local application as cleartext.
- They exit when they cannot transmit any more data.
Other programs in the s6-tls set perform various operations such as
Unix file descriptor plumbing in order to provide a specific interface,
but they always end up spawning a
s6-tlsd-io child that will handle the
actual TLS management for them.
Regular TLSification of a service: s6-tlsc and s6-tlsd
- The s6-tlsc and
s6-tlsd programs are "immediate encryption"-type
programs. They assume that the rest of their command line is a
UCSPI client or server application, i.e. reads from the network on
fd (6 for clients, 0 for servers) and writes to the network on fd
(7 for clients, 1 for servers); their goal is to provide this
application with transparent encryption.
- They first spawn a s6-tlsc-io or
s6-tlsd-io child to initialize the TLS
- When the TLS handshake has completed, they exec into the
rest of their command line, interposing the s6-tls[cd]-io program
in between this application and the network.
- The application still communicates via cleartext, but the
data is transparently encrypted before it goes to the network.
- The application is only started after the handshake
succeeds; the TLS tunnel stays up for the whole lifetime of the
application, or until the application closes the fds it uses to
communicate with (what it thinks is) the network.
Opportunistic TLS: s6-ucspitlsc and s6-ucspitlsd
- The s6-ucspitlsc and
s6-ucspitlsd programs are
"delayed encryption"-type programs. They assume that the rest
of their command line is an application that follows the
protocol. This is a bit of a misnomer: the aim of this protocol is
just to provide an application with a means to ask for TLS
encryption at any time.
- They prepare the necessary communication channels, then
fork. The parent execs into the rest of its command line, with
the appropriate ucspi-tls environment variables set. The child
stays and waits for a command.
- When the application sends a command to start TLS, the
child execs into s6-tlsc-io or
s6-tlsd-io, which initializes
a TLS connection and performs a handshake.
- The application then communicates via the fds that have
been provided to it via the ucspi-tls protocol. Those fds go
through the TLS engine.
High-level client connections and super-servers: s6-tlsclient and s6-tlsserver