summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/index.html16
-rw-r--r--doc/libsbearssl/index.html548
-rw-r--r--doc/libstls/index.html127
-rw-r--r--doc/s6-tlsc.html268
-rw-r--r--doc/s6-tlsclient.html168
-rw-r--r--doc/s6-tlsd.html280
-rw-r--r--doc/s6-tlsserver.html216
-rw-r--r--doc/upgrade.html2
8 files changed, 1619 insertions, 6 deletions
diff --git a/doc/index.html b/doc/index.html
index 8ad4264..9ba1daf 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -24,6 +24,8 @@
It includes command-line client and server management, TCP access
control, privilege escalation across UNIX domain sockets, IDENT
protocol management and clock synchronization.
+Optionally, it also includes command-line TLS/SSL tools for
+secure communications.
</p>
<p>
@@ -53,9 +55,9 @@ library. </li>
2.1.0.0 or later. It's a build-time requirement. It's also a run-time
requirement if you link against the shared version of the s6-dns
libraries. </li>
- <li> If you want to build the TLS tools:
+ <li> If you want to build the TLS/SSL tools:
<ul>
- <li> Either <a href="http://libressl.org/">LibreSSL</a> version 2.5.0
+ <li> Either <a href="http://libressl.org/">LibreSSL</a> version 2.4.4
or later </li>
<li> Or <a href="http://bearssl.org/">BearSSL</a> version 0.1
or later. <strong>THIS IS EXPERIMENTAL.</strong> </li>
@@ -134,7 +136,7 @@ relevant page.
<li><a href="s6-tcpserver6d.html">The <tt>s6-tcpserver6d</tt> program</a></li>
</ul>
-<h4> UCSPI tools for TLS 1.2 over TCP </h4>
+<h4> UCSPI tools for SSL/TLS over TCP </h4>
<ul>
<li><a href="s6-tlsclient.html">The <tt>s6-tlsclient</tt> program</a></li>
@@ -165,8 +167,12 @@ relevant page.
<h3> Libraries </h3>
<ul>
-<li> The <a href="libs6net/">s6net</a> library, containing: </li>
-<li> <a href="libs6net/ident.html">The <tt>ident</tt> library interface</a> </li>
+<li> The <a href="libstls/">stls</a> library </li>
+<li> The <a href="libsbearssl/">sbearssl</a> library </li>
+<li> The <a href="libs6net/">s6net</a> library, containing:
+ <ul>
+ <li> <a href="libs6net/ident.html">The <tt>ident</tt> library interface</a> </li>
+ </ul> </li>
</ul>
<hr />
diff --git a/doc/libsbearssl/index.html b/doc/libsbearssl/index.html
new file mode 100644
index 0000000..1c797c7
--- /dev/null
+++ b/doc/libsbearssl/index.html
@@ -0,0 +1,548 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-networking: the sbearssl library interface</title>
+ <meta name="Description" content="s6-networking: the sbearssl interface" />
+ <meta name="Keywords" content="s6-networking net sbearssl library TLS SSL BearSSL libbearssl" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="../">s6-networking</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>sbearssl</tt> library interface </h1>
+
+<h2> General information </h2>
+
+<p>
+ <tt>libsbearssl</tt> is a support library for the
+<a href="../s6-tlsc.html">s6-tlsc</a> and
+<a href="../s6-tlsd.html">s6-tlsd</a> executables when they're built
+against the <a href="https://bearssl.org/">BearSSL</a>
+backend. Among other things, it offers interfaces to read private
+keys and certificates from a Unix filesystem, which BearSSL does
+not provide on its own.
+</p>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Make sure the s6-networking headers, as well as the skalibs headers,
+and the <tt>bearssl.h</tt> header, are visible in your header search path. </li>
+ <li> Use <tt>#include &lt;s6-networking/sbearssl.h&gt;</tt> </li>
+</ul>
+
+<h2> Linking </h2>
+
+<ul>
+ <li> Make sure the s6-networking libraries, as well as the skalibs
+libraries, and the BearSSL libraries, are visible in your library search path. </li>
+ <li> Link against <tt>-lsbearssl</tt>, <tt>-lskarnet</tt>, <tt>-lbearssl</tt>,
+<tt>`cat $sysdeps/socket.lib`</tt>, <tt>`cat $sysdeps/spawn.lib`</tt>, and
+<tt>`cat $sysdeps/tainnow.lib`</tt>, where <tt>$sysdeps</tt> is your skalibs
+sysdeps directory. </li>
+</ul>
+
+<h2> Programming </h2>
+
+<h3> General concepts </h3>
+
+<p>
+ <a href="https://bearssl.org/">BearSSL</a> provides engines
+to decode PEM objects and X.509 certificates, and to run a
+TLS/SSL connection. However, it does not store such objects:
+it never allocates memory, and does not interact with the
+filesystem. <tt>sbearssl</tt> provides functions to
+address this.
+</p>
+
+<p>
+ When reading an object into memory, <tt>sbearssl</tt> stores all
+the bytes of the object in a
+<a href="http://skarnet.org/software/skalibs/libstddjb/stralloc.html">stralloc</a>,
+and the <tt>sbearssl_*</tt> structures contain indices of bytes in that
+stralloc. That allows the structures to remain valid even when the stralloc
+contents get reallocated and move to some other place in the heap. After
+you have finished adding data to the stralloc and are sure its contents
+will not move again, you can use the
+<tt>sbearssl_*_to</tt> functions to convert <tt>sbearssl_*</tt> structures
+to the corresponding <tt>br_*</tt> structures (native BearSSL), which
+contain pointers to memory.
+</p>
+
+<h3> Private keys (typically for servers) </h3>
+
+<p>
+ BearSSL handles two types of private keys: RSA keys and
+EC keys (i.e. points on an elliptic curve). <tt>sbearssl</tt>
+adds some generic functions to handle keys no matter their
+type.
+</p>
+
+<h4> <code> int sbearssl_rsa_skey_from (sbearssl_rsa_skey *l, br_rsa_private_key const *k, stralloc *sa) </code> </h4>
+
+<p>
+ Converts the RSA private key from BearSSL format (reading from a structure pointed to by <em>k</em>)
+to <tt>sbearssl</tt> format (writing to a structure pointed to by <em>l</em>).
+The data from *<em>k</em>'s contents are copied into the stralloc in *<em>sa</em>.
+The function returns 1 on success and 0 (and sets errno) on failure.
+</p>
+
+<h4> <code> void sbearssl_rsa_skey_to (sbearssl_rsa_skey const *l, br_rsa_private_key *k, char *s) </code> </h4>
+
+<p>
+ Converts the RSA private key from <tt>sbearssl</tt> format (reading from a structure pointed to by <em>l</em>)
+to BearSSL format (writing to a structure pointed to by <em>k</em>).
+The indices in <em>l</em> must refer to data stored in the string <em>s</em>.
+</p>
+
+<h4> <code> int sbearssl_ec_skey_from (sbearssl_ec_skey *l, br_ec_private_key const *k, stralloc *sa) </code> </h4>
+
+<p>
+ Converts the EC private key from BearSSL format (reading from a structure pointed to by <em>k</em>)
+to <tt>sbearssl</tt> format (writing to a structure pointed to by <em>l</em>).
+The data from *<em>k</em>'s contents are copied into the stralloc in *<em>sa</em>.
+The function returns 1 on success and 0 (and sets errno) on failure.
+</p>
+
+<h4> <code> void sbearssl_ec_skey_to (sbearssl_ec_skey const *l, br_ec_private_key *k, char *s) </code> </h4>
+
+<p>
+ Converts the EC private key from <tt>sbearssl</tt> format (reading from a structure pointed to by <em>l</em>)
+to BearSSL format (writing to a structure pointed to by <em>k</em>).
+The indices in <em>l</em> must refer to data stored in the string <em>s</em>.
+</p>
+
+<h4> <code> int sbearssl_skey_from (sbearssl_skey *l, br_skey const *k, stralloc *sa) </code> </h4>
+
+<p>
+ Converts the private key from BearSSL format (reading from a structure pointed to by <em>k</em>)
+to <tt>sbearssl</tt> format (writing to a structure pointed to by <em>l</em>).
+The data from *<em>k</em>'s contents are copied into the stralloc in *<em>sa</em>.
+The function returns 1 on success and 0 (and sets errno) on failure.
+</p>
+
+<h4> <code> void sbearssl_skey_to (sbearssl_skey const *l, br_skey *k, char *s) </code> </h4>
+
+<p>
+ Converts the private key from <tt>sbearssl</tt> format (reading from a structure pointed to by <em>l</em>)
+to BearSSL format (writing to a structure pointed to by <em>k</em>).
+The indices in <em>l</em> must refer to data stored in the string <em>s</em>.
+</p>
+
+<h4> <code> int sbearssl_skey_readfile (char const *fn, sbearssl_skey *key, stralloc *sa) </code> </h4>
+
+<p>
+ Reads a private key from the file named <em>fn</em> and stores it
+in <tt>sbearssl</tt> format into the structure in *<em>key</em>,
+the bytes of the key being added to the stralloc in *<em>sa</em>.
+</p>
+
+<p>
+The private key in <em>fn</em> can be either DER-encoded (binary format)
+or PEM-encoded (text format).
+</p>
+
+<p>
+ The function returns 0 on success. It returns a negative value in
+case of a system error, in which case <tt>errno</tt> identifies the
+error. It returns a positive value in case of an error returned by
+a BearSSL decoder, in which case an appropriate message can be
+obtained with the <tt>sbearssl_error_str()</tt> function.
+</p>
+
+<h3> Public keys </h3>
+
+<p>
+ BearSSL handles two types of public keys: RSA keys and
+EC keys (i.e. points on an elliptic curve). <tt>sbearssl</tt>
+adds some generic functions to handle keys no matter their
+type.
+</p>
+
+<p>
+ You normally should not handle public keys directly;
+you should handle x509 certificate chains instead.
+</p>
+
+<h4> <code> int sbearssl_rsa_pkey_from (sbearssl_rsa_pkey *l, br_rsa_public_key const *k, stralloc *sa) </code> </h4>
+
+<p>
+ Converts the RSA public key from BearSSL format (reading from a structure pointed to by <em>k</em>)
+to <tt>sbearssl</tt> format (writing to a structure pointed to by <em>l</em>).
+The data from *<em>k</em>'s contents are copied into the stralloc in *<em>sa</em>.
+The function returns 1 on success and 0 (and sets errno) on failure.
+</p>
+
+<h4> <code> void sbearssl_rsa_pkey_to (sbearssl_rsa_pkey const *l, br_rsa_public_key *k, char *s) </code> </h4>
+
+<p>
+ Converts the RSA public key from <tt>sbearssl</tt> format (reading from a structure pointed to by <em>l</em>)
+to BearSSL format (writing to a structure pointed to by <em>k</em>).
+The indices in <em>l</em> must refer to data stored in the string <em>s</em>.
+</p>
+
+<h4> <code> int sbearssl_ec_pkey_from (sbearssl_ec_skey *l, br_ec_public_key const *k, stralloc *sa) </code> </h4>
+
+<p>
+ Converts the EC public key from BearSSL format (reading from a structure pointed to by <em>k</em>)
+to <tt>sbearssl</tt> format (writing to a structure pointed to by <em>l</em>).
+The data from *<em>k</em>'s contents are copied into the stralloc in *<em>sa</em>.
+The function returns 1 on success and 0 (and sets errno) on failure.
+</p>
+
+<h4> <code> void sbearssl_ec_pkey_to (sbearssl_ec_pkey const *l, br_ec_public_key *k, char *s) </code> </h4>
+
+<p>
+ Converts the EC public key from <tt>sbearssl</tt> format (reading from a structure pointed to by <em>l</em>)
+to BearSSL format (writing to a structure pointed to by <em>k</em>).
+The indices in <em>l</em> must refer to data stored in the string <em>s</em>.
+</p>
+
+<h4> <code> int sbearssl_pkey_from (sbearssl_pkey *l, br_x509_pkey const *k, stralloc *sa) </code> </h4>
+
+<p>
+ Converts the public key from BearSSL format (reading from a structure pointed to by <em>k</em>)
+to <tt>sbearssl</tt> format (writing to a structure pointed to by <em>l</em>).
+The data from *<em>k</em>'s contents are copied into the stralloc in *<em>sa</em>.
+The function returns 1 on success and 0 (and sets errno) on failure.
+</p>
+
+<h4> <code> void sbearssl_pkey_to (sbearssl_pkey const *l, br_x509_pkey *k, char *s) </code> </h4>
+
+<p>
+ Converts the public key from <tt>sbearssl</tt> format (reading from a structure pointed to by <em>l</em>)
+to BearSSL format (writing to a structure pointed to by <em>k</em>).
+The indices in <em>l</em> must refer to data stored in the string <em>s</em>.
+</p>
+
+<h3> Generic PEM objects </h3>
+
+<p>
+ You normally should not have to call these functions
+directly. Instead, you should use the higher-level functions for
+private keys, X509 certificate chains and trust anchors, which
+will perform the PEM decoding for you.
+</p>
+
+<h4> <code> int sbearssl_pem_decode_from_buffer (buffer *b, genalloc *list, stralloc *sa) </code> </h4>
+
+<p>
+ Decodes a PEM object, reading from the
+<a href="http://skarnet.org/software/skalibs/libstddjb/buffer.html">buffer</a>
+in *<em>b</em>. The decoded bytes are appended to *<em>sa</em>.
+<em>list</em> points to a
+<a href="http://skarnet.org/software/skalibs/libstddjb/genalloc.html">genalloc</a>
+containing objects of type <tt>sbearssl_pemobject</tt>.
+One <tt>sbearssl_pemobject</tt> is appended to the genalloc per PEM entity
+decoded from the byte stream read from the buffer.
+</p>
+
+<p>
+ The function returns 0 on success. It returns a negative value in
+case of a system error, in which case <tt>errno</tt> identifies the
+error. It returns a positive value in case of an error returned by
+a BearSSL decoder, in which case an appropriate message can be
+obtained with the <tt>sbearssl_error_str()</tt> function.
+</p>
+
+<h4> <code> int sbearssl_pem_decode_from_string (char const *s, size_t len, genalloc *list, stralloc *sa) </code> </h4>
+
+<p>
+ Decodes a PEM object from the <em>len</em> bytes pointed to by <em>s</em>.
+The decoded bytes are appended to *<em>sa</em>.
+<em>list</em> points to a
+<a href="http://skarnet.org/software/skalibs/libstddjb/genalloc.html">genalloc</a>
+containing objects of type <tt>sbearssl_pemobject</tt>.
+One <tt>sbearssl_pemobject</tt> is appended to the genalloc per PEM entity
+found in the bytes in <em>s</em>.
+</p>
+
+<p>
+ The function returns 0 on success. It returns a negative value in
+case of a system error, in which case <tt>errno</tt> identifies the
+error. It returns a positive value in case of an error returned by
+a BearSSL decoder, in which case an appropriate message can be
+obtained with the <tt>sbearssl_error_str()</tt> function.
+</p>
+
+<h3> X.509 certificates (typically for servers) </h3>
+
+<h4> <code> int sbearssl_cert_from (sbearssl_cert *l, br_x509_certificate const *k, stralloc *sa) </code> </h4>
+
+<p>
+ Converts a certificate from BearSSL format (reading from a structure pointed to by <em>k</em>)
+to <tt>sbearssl</tt> format (writing to a structure pointed to by <em>l</em>).
+The data from *<em>k</em>'s contents are copied into the stralloc in *<em>sa</em>.
+The function returns 1 on success and 0 (and sets errno) on failure.
+</p>
+
+<h4> <code> void sbearssl_cert_to (sbearssl_cert const *l, br_x509_certificate *k, char *s) </code> </h4>
+
+<p>
+ Converts a certificate from <tt>sbearssl</tt> format (reading from a structure pointed to by <em>l</em>)
+to BearSSL format (writing to a structure pointed to by <em>k</em>).
+The indices in <em>l</em> must refer to data stored in the string <em>s</em>.
+</p>
+
+<h4> <code> int sbearssl_cert_readfile (char const *fn, genalloc *list, stralloc *sa) </code> </h4>
+
+<p>
+ Reads one or more certificates from the file named <em>fn</em> and appends
+them to the <a href="http://skarnet.org/software/skalibs/libstddjb/genalloc.html">genalloc</a>
+in *<em>list</em>, which is a dynamically growing list of
+<tt>sbearssl_cert</tt> structures. The bytes of the
+(maybe PEM-decoded, but still DER-encoded) certificate are
+appended to the stralloc in *<em>sa</em>.
+</p>
+
+<p>
+ The <em>fn</em> file can be either DER-encoded (binary format)
+or PEM-encoded (text format). If it is DER-encoded, it must
+contain exactly one X.509 certificate. If it is PEM-encoded,
+it may contain a chain of certificates as long as the PEM
+file fits within the size limits.
+</p>
+
+<p>
+ <em>fn</em> must not be bigger than SBEARSSL_MAXCERTFILESIZE,
+which is 8 kB. This function is meant to read individual
+certificates, not files containing large certificate chains or
+sets of trust anchors. To do that, use
+<tt>sbearssl_cert_readbigpem()</tt> instead.
+</p>
+
+<p>
+ The function returns 0 on success. It returns a negative value in
+case of a system error, in which case <tt>errno</tt> identifies the
+error. It returns a positive value in case of an error returned by
+a BearSSL decoder, in which case an appropriate message can be
+obtained with the <tt>sbearssl_error_str()</tt> function.
+</p>
+
+<h4> <code> int sbearssl_cert_readbigpem (char const *fn, genalloc *, stralloc *sa) </code> </h4>
+
+<p>
+ Reads one or more PEM-encoded certificates from the file named
+<em>fn</em> and appends them to the
+<a href="http://skarnet.org/software/skalibs/libstddjb/genalloc.html">genalloc</a>
+in *<em>list</em>, which is a dynamically growing list of
+<tt>sbearssl_cert</tt> structures. The bytes of the PEM-decoded (but
+still DER-encoded) certificates are appended to the stralloc
+in *<em>sa</em>.
+</p>
+
+<p>
+ The function will refuse to read a file that is not valid PEM.
+Inside the file, It will ignore PEM objects that are
+not X.509 certificates.
+</p>
+
+<p>
+ The function returns 0 on success. It returns a negative value in
+case of a system error, in which case <tt>errno</tt> identifies the
+error. It returns a positive value in case of an error returned by
+a BearSSL decoder, in which case an appropriate message can be
+obtained with the <tt>sbearssl_error_str()</tt> function.
+</p>
+
+<h3> Trust anchors (typically for clients) </h3>
+
+<p>
+ BearSSL clients do not use X.509-encoded certificates,
+they use sets of <em>trust anchors</em>, i.e. structures
+decoded from certificates representing (intermediate or)
+root CAs.
+</p>
+
+<h4> <code> int sbearssl_ta_from (sbearssl_ta *l, br_x509_trust_anchor const *k, stralloc *sa) </code> </h4>
+
+<p>
+ Converts a trust anchor from BearSSL format (reading from a structure pointed to by <em>k</em>)
+to <tt>sbearssl</tt> format (writing to a structure pointed to by <em>l</em>).
+The data from *<em>k</em>'s contents are copied into the stralloc in *<em>sa</em>.
+The function returns 1 on success and 0 (and sets errno) on failure.
+</p>
+
+<h4> <code> void sbearssl_ta_to (sbearssl_ta const *l, br_x509_trust_anchor *k, char *s) </code> </h4>
+
+<p>
+ Converts a trust anchor from <tt>sbearssl</tt> format (reading from a structure pointed to by <em>l</em>)
+to BearSSL format (writing to a structure pointed to by <em>k</em>).
+The indices in <em>l</em> must refer to data stored in the string <em>s</em>.
+</p>
+
+<h4> <code> int sbearssl_ta_readfile (char const *fn, genalloc *list, stralloc *sa) </code> </h4>
+
+<p>
+ Reads a set of trust anchors from a PEM file named <em>fn</em>
+which must contain a list of (intermediate or) root CA certificates.
+The trust anchors are appended to the
+<a href="http://skarnet.org/software/skalibs/libstddjb/genalloc.html">genalloc</a>
+in *<em>list</em>, which is a dynamically growing list of
+<tt>sbearssl_ta</tt> structures. The contents of the trust anchors
+are appended to *<em>sa</em>, which is a
+<a href="http://skarnet.org/software/skalibs/libstddjb/stralloc.html">stralloc</a>
+used for storage.
+</p>
+
+<p>
+ The function returns 0 on success. It returns a negative value in
+case of a system error, in which case <tt>errno</tt> identifies the
+error. It returns a positive value in case of an error returned by
+a BearSSL decoder, in which case an appropriate message can be
+obtained with the <tt>sbearssl_error_str()</tt> function.
+</p>
+
+<h4> <code> int sbearssl_ta_readdir (char const *dir, genalloc *list, stralloc *sa) </code> </h4>
+
+<p>
+ Reads a set of trust anchors from a directory named <em>dir</em>,
+which must contain a list of (intermediate or) root CA certificates
+stored as individual DER- or PEM-encoded files.
+The trust anchors are appended to the
+<a href="http://skarnet.org/software/skalibs/libstddjb/genalloc.html">genalloc</a>
+in *<em>list</em>, which is a dynamically growing list of
+<tt>sbearssl_ta</tt> structures. The contents of the trust anchors
+are appended to *<em>sa</em>, which is a
+<a href="http://skarnet.org/software/skalibs/libstddjb/stralloc.html">stralloc</a>
+used for storage.
+</p>
+
+<p>
+ The function ignores files that do not contain valid DER
+or PEM objects containing X.509 certificates representing
+certification authorities.
+</p>
+
+<p>
+ The function returns 0 on success. It returns a negative value in
+case of a system error, in which case <tt>errno</tt> identifies the
+error. It returns a positive value in case of an error returned by
+a BearSSL decoder, in which case an appropriate message can be
+obtained with the <tt>sbearssl_error_str()</tt> function.
+</p>
+
+<h3> Miscellaneous utilities </h3>
+
+<p>
+ You probably shouldn't need to call any of these functions
+directly, except for the first one.
+</p>
+
+<h4> <code> char const *sbearssl_error_str (int err) </code> </h4>
+
+<p>
+ Returns a fixed string containing an error message corresponding
+to the <em>err</em> code, which must be non-negative. The return
+value from a few <tt>sbearssl</tt> functions, if positive, can be
+interpreted via this function.
+</p>
+
+<h4> <code> int sbearssl_isder (unsigned char const *s, size_t len) </code> </h4>
+
+<p>
+ Tests whether the array of <em>len</em> bytes pointed to by <em>s</em>
+looks like a DER-encoded object. Returns 1 if it does and 0 otherwise.
+</p>
+
+<h4> <code> int sbearssl_x509_minimal_set_tai (br_x509_minimal_context *ctx, tai_t t) </code> </h4>
+
+<p>
+ Sets the validation time for the X.509 context in *<em>ctx</em> to
+the absolute time contained in *<em>t</em>, which is a
+<a href="http://skarnet.org/software/skalibs/libstddjb/tai.html">tai_t</a>.
+Returns 1 if it succeeds, or 0 if it fails - probably
+because *<em>t</em> does not represent a valid time.
+</p>
+
+<h4> <code> int sbearssl_x509_minimal_set_tain (br_x509_minimal_context *ctx, tain_t a) </code> </h4>
+
+<p>
+ Same as the above function, except the time is given as a
+<a href="http://skarnet.org/software/skalibs/libstddjb/tai.html">tain_t</a>,
+i.e. a <tt>tai_t</tt> plus nanoseconds (which are simply ignored).
+</p>
+
+
+<h3> Running the TLS/SSL engine (both clients and servers) </h3>
+
+<h4> <code> int sbearssl_run (br_ssl_engine_context *ctx, int *fds, unsigned int verbosity, uint32_t options, tain_t const *tto) </code> </h4>
+
+<p>
+ This function runs a full-duplex TLS/SSL engine, reading/writing
+clear text from/to two file descriptors, and writing/reading
+ciphertext to/from two other file descriptors, until the
+connection is closed both ways (either with a SSL close, or
+with EOF).
+</p>
+
+<ul>
+ <li> <em>ctx</em> is a pointer to a fully initialized context,
+connected to <em>fds</em>[2] and <em>fds</em>[3]. The
+TLS/SSL handshake does not have to be completed. </li>
+ <li> <em>fds</em> is an array of 4 file descriptors, in this
+order: fd reading clear text, fd writing clear text, fd reading
+ciphertext, fd writing ciphertext. </li>
+ <li> <em>verbosity</em> defines the engine's verbosity: the
+higher the more verbose. This parameter is currently ignored. </li>
+ <li> <em>options</em> is a bitfield.
+ <ul>
+ <li> bit 0 tells the engine how to behave when
+the local application closes the connection (i.e. when the engine
+reads EOF on <em>fds</em>[0]). If the bit is clear, then the
+engine will perform as SSL close: it will send a SSL close_notify,
+and stop processing incoming records, waiting for a peer
+acknowledgement of the close_notify. If the bit is set, then the
+engine will not send a close_notify but simply transmit EOF to
+the peer, while continuing to process incoming records until it
+gets EOF back. close_notify is secure when handling protocols that
+are not auto-terminated (such as HTTP 0.9), but it does not permit
+separate closing of both ways. EOF allows full-duplex until the
+very end, but is insecure if the application protocol does not
+know in advance how many bytes it should get. Modern application
+protocols should all work with EOF. </li>
+ </ul> </li>
+ <li> <em>tto</em> is a pointer to a
+ <a href="http://skarnet.org/software/skalibs/libstddjb/tai.html">tain_t</a>
+containing a relative time (i.e. a timeout) If *<em>tto</em> time elapses
+with no application data being exchanged, the engine will forcibly close the
+connection (with the method defined by <tt><em>options</em> &amp; 1</tt>).
+ You can use <tt>&amp;tain_infinite_relative</tt> as a value for <em>tto</em>
+if you don't want the engine to ever timeout. </li>
+</ul>
+
+<p>
+ <tt>sbearssl_run</tt> will make the process die with an appropriate error
+message if it encounters an unrecoverable error. If there were no problems
+and the SSL/TLS connection closed cleanly, it returns 0. If a SSL/TLS-level
+error occurred, it returns nonzero; a corresponding error message for the
+return value can be obtained via <tt>sbearssl_error_str()</tt>.
+All four descriptors in <em>fds</em> are closed when
+<tt>sbearssl_run</tt> returns.
+</p>
+
+<h4> <code> int sbearssl_s6tlsc (char const *const *argv, char const *const *envp, tain_t const *tto, uint32_t preoptions, uint32_t options, uid_t uid, gid_t gid, unsigned int verbosity, char const *servername, int *sfd) </code> </h4>
+
+<p>
+ This function implements <a href="../s6-tlsc.html">s6-tlsc</a> on top of BearSSL.
+It has no other practical purpose; you're better off directly invoking
+<a href="../s6-tlsc.html">s6-tlsc</a>.
+</p>
+
+<h4> <code> int sbearssl_s6tlsd (char const *const *argv, char const *const *envp, tain_t const *tto, uint32_t preoptions, uint32_t options, uid_t uid, gid_t gid, unsigned int verbosity) </code> </h4>
+
+<p>
+ This function implements <a href="../s6-tlsd.html">s6-tlsd</a> on top of BearSSL.
+It has no other practical purpose; you're better off directly invoking
+<a href="../s6-tlsd.html">s6-tlsd</a>.
+</p>
+
+</body>
+</html>
diff --git a/doc/libstls/index.html b/doc/libstls/index.html
new file mode 100644
index 0000000..4c6819b
--- /dev/null
+++ b/doc/libstls/index.html
@@ -0,0 +1,127 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-networking: the stls library interface</title>
+ <meta name="Description" content="s6-networking: the stls library interface" />
+ <meta name="Keywords" content="s6-networking net stls library TLS SSL LibreSSL OpenSSL libtls" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="../">s6-networking</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>stls</tt> library interface </h1>
+
+<h2> General information </h2>
+
+<p>
+ <tt>libstls</tt> is a small support library for the
+<a href="../s6-tlsc.html">s6-tlsc</a> and
+<a href="../s6-tlsd.html">s6-tlsd</a> executables when they're built
+against the <a href="https://www.libressl.org/">LibreSSL</a>
+backend. You can use it in your own programs, but since
+<a href="http://man.openbsd.org/OpenBSD-current/man3/tls_init.3">libtls</a>
+is already relatively high-level, it's probably not very useful.
+</p>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Make sure the s6-networking headers, as well as the skalibs headers,
+and the <tt>tls.h</tt> header, are visible in your header search path. </li>
+ <li> Use <tt>#include &lt;s6-networking/stls.h&gt;</tt> </li>
+</ul>
+
+<h2> Linking </h2>
+
+<ul>
+ <li> Make sure the s6-networking libraries, as well as the skalibs
+libraries, and the LibreSSL libraries, are visible in your library search path. </li>
+ <li> Link against <tt>-lstls</tt>, <tt>-lskarnet</tt>, <tt>-ltls</tt>,
+<tt>-lssl</tt>, <tt>-lcrypto</tt>,
+<tt>`cat $sysdeps/socket.lib`</tt>, <tt>`cat $sysdeps/spawn.lib`</tt>, and
+<tt>`cat $sysdeps/tainnow.lib`</tt>, where <tt>$sysdeps</tt> is your skalibs
+sysdeps directory. </li>
+</ul>
+
+<h2> Programming </h2>
+
+<h3> Running the TLS/SSL engine </h3>
+
+<h4> <code> int stls_run (struct tls *ctx, int *fds, unsigned int verbosity, uint32_t options, tain_t const *tto) </code> </h4>
+
+<p>
+ This function runs a full-duplex TLS/SSL engine, reading/writing
+clear text from/to two file descriptors, and writing/reading
+ciphertext to/from two other file descriptors, until the
+connection is closed both ways (either with a SSL close, or
+with EOF).
+</p>
+
+<ul>
+ <li> <em>ctx</em> is a pointer to a fully initialized context,
+connected to <em>fds</em>[2] and <em>fds</em>[3]. The TLS
+handshake must already be completed. </li>
+ <li> <em>fds</em> is an array of 4 file descriptors, in this
+order: fd reading clear text, fd writing clear text, fd reading
+ciphertext, fd writing ciphertext. </li>
+ <li> <em>verbosity</em> defines the engine's verbosity: the
+higher the more verbose. This parameter is currently ignored. </li>
+ <li> <em>options</em> is a bitfield.
+ <ul>
+ <li> bit 0 tells the engine how to behave when
+the local application closes the connection (i.e. when the engine
+reads EOF on <em>fds</em>[0]). If the bit is clear, then the
+engine will perform as SSL close: it will send a SSL close_notify,
+and stop processing incoming records, waiting for a peer
+acknowledgement of the close_notify. If the bit is set, then the
+engine will not send a close_notify but simply transmit EOF to
+the peer, while continuing to process incoming records until it
+gets EOF back. close_notify is secure when handling protocols that
+are not auto-terminated (such as HTTP 0.9), but it does not permit
+separate closing of both ways. EOF allows full-duplex until the
+very end, but is insecure if the application protocol does not
+know in advance how many bytes it should get. Modern application
+protocols should all work with EOF. </li>
+ </ul> </li>
+ <li> <em>tto</em> is a pointer to a
+ <a href="http://skarnet.org/software/skalibs/libstddjb/tai.html">tain_t</a>
+containing a relative time (i.e. a timeout). If *<em>tto</em> time elapses
+with no application data being exchanged, the engine will forcibly close the
+connection (with the method defined by <tt><em>options</em> &amp; 1</tt>).
+ You can use <tt>&amp;tain_infinite_relative</tt> as a value for <em>tto</em>
+if you don't want the engine to ever timeout. </li>
+</ul>
+
+<p>
+ <tt>stls_run</tt> will make the process die with an appropriate error
+message if it encounters an error. If there were no problems and the
+SSL/TLS connection closed cleanly, it returns 0. All four descriptors
+in <em>fds</em> are closed when <tt>stls_run</tt> returns, but the
+caller should still free <em>ctx</em> itself.
+</p>
+
+<h4> <code> int stls_s6tlsc (char const *const *argv, char const *const *envp, tain_t const *tto, uint32_t preoptions, uint32_t options, uid_t uid, gid_t gid, unsigned int verbosity, char const *servername, int *sfd) </code> </h4>
+
+<p>
+ This function implements <a href="../s6-tlsc.html">s6-tlsc</a> on top of LibreSSL.
+It has no other practical purpose; you're better off directly invoking
+<a href="../s6-tlsc.html">s6-tlsc</a>.
+</p>
+
+<h4> <code> int stls_s6tlsd (char const *const *argv, char const *const *envp, tain_t const *tto, uint32_t preoptions, uint32_t options, uid_t uid, gid_t gid, unsigned int verbosity) </code> </h4>
+
+<p>
+ This function implements <a href="../s6-tlsd.html">s6-tlsd</a> on top of LibreSSL.
+It has no other practical purpose; you're better off directly invoking
+<a href="../s6-tlsd.html">s6-tlsd</a>.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-tlsc.html b/doc/s6-tlsc.html
new file mode 100644
index 0000000..b44caf5
--- /dev/null
+++ b/doc/s6-tlsc.html
@@ -0,0 +1,268 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-networking: the s6-tlsc program</title>
+ <meta name="Description" content="s6-networking: the s6-tlsc program" />
+ <meta name="Keywords" content="s6-networking s6-tlsc tlsc tls ssl ucspi tcp inet network tcp/ip client" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6-networking</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6-tlsc</tt> program </h1>
+
+<p>
+<tt>s6-tlsc</tt> is a program that establishes a TLS or SSL
+client connection over an existing TCP connection, then spawns
+an application. It is meant to make network communications
+secure even for applications that do not natively support
+TLS/SSL.
+</p>
+
+<p>
+ <a href="index.html">s6-networking</a> does not include
+cryptographic software. All the crypto used in <tt>s6-tlsc</tt>
+is provided by the chosen SSL backend:
+<a href="https://bearssl.org/">BearSSL</a> or
+<a href="https://www.libressl.org/">LibreSSL</a>, depending on
+the options given when configuring <tt>s6-networking</tt>.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-tlsc [ -S | -s ] [ -Y | -y ] [ -Z | -z ] [ -v <em>verbosity</em> ] [ -K kimeout ] [ -k <em>servername</em> ] [ -6 <em>rfd</em> ] [ -7 <em>wfd</em> ] [ -- ] <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-tlsc expects to have an open TCP connection it
+can talk to on its (by default) descriptors 6 (for reading)
+and 7 (for writing). </li>
+ <li> It spawns <em>prog...</em> as a child process,
+interposing itself between it and the network. </li>
+ <li> It initiates a TLS/SSL handshake over the
+network connection, expecting a TLS/SSL server on the other
+side. </li>
+ <li> It manages the encryption/decryption of all the
+messages between <em>prog</em> and the server.
+<em>prog</em> speaks plaintext, but only ciphertext is sent
+on the network. </li>
+ <li> When <em>prog</em> exits, <tt>s6-tlsc</tt> exits.
+</ul>
+
+<h2> Exit codes </h2>
+
+<ul>
+ <li> 96: error while configuring the TLS/SSL context - for instance, invalid trust anchor set. </li>
+ <li> 97: error while setting up the TLS/SSL client engine. </li>
+ <li> 98: TLS/SSL error while running the engine. </li>
+ <li> 100: wrong usage. </li>
+ <li> 111: system call failed. </li>
+</ul>
+
+<p>
+ If the TLS/SSL connection closes cleanly, <tt>s6-tlsc</tt>
+waits for <em>prog</em> to exit, then exits with an
+<a href="http://skarnet.org/software/execline/exitcodes.html">approximation</a>
+of <em>prog</em>'s exit code.
+</p>
+
+<h2> Protocol version and parameters </h2>
+
+<p>
+ During the TLS/SSL handshake, <tt>s6-tlsc</tt> tries
+every version of the protocol that is supported by the
+backend, with all supported algorithms and cipher suites;
+the backend normally ensures that the most secure combination
+is tried first, with slow degradation until the client and
+the server agree.
+</p>
+
+<ul>
+ <li> For BearSSL, this means use of the
+<a href="https://bearssl.org/apidoc/bearssl__ssl_8h.html#aa386dd0b03a0123760bf63df5a41c1e0">br_ssl_client_init_full()</a>
+function. The supported protocol versions are described
+<a href="https://bearssl.org/support.html#supported-versions">here</a>. </li>
+ <li> For LibreSSL, this means use of the
+<a href="http://man.openbsd.org/OpenBSD-current/man3/tls_config_set_protocols.3">tls_config_set_protocols(TLS_PROTOCOLS_ALL)</a>
+call. </li>
+</ul>
+
+<p>
+ As a client, it is better for <tt>s6-tlsc</tt> to adapt to as many servers
+as possible, that's why it adopts a liberal approach to protocol
+versions.
+</p>
+
+<h2> Environment variables </h2>
+
+<h3> Read </h3>
+
+<p>
+ <tt>s6-tlsc</tt> expects to have one of the
+<tt>CADIR</tt> or <tt>CAFILE</tt> environment variables set.
+It will refuse to run if both are unset. If both are set,
+<tt>CADIR</tt> has priority. The value of that variable is:
+</p>
+
+<ul>
+ <li> for <tt>CADIR</tt>: a directory where trust anchors
+(i.e. root or intermediate CA certificates) can be found,
+one per file, DER- or PEM-encoded. </li>
+ <li> for <tt>CAFILE</tt>: a file containing the whole set
+of trust anchors, PEM-encoded. </li>
+</ul>
+
+<p>
+ If you are using client certificates, s6-tlsc also reads
+two more environment variables: <tt>KEYFILE</tt> contains
+the path to a file containing the private key, DER- or
+PEM-encoded; and <tt>CERTFILE</tt> contains the path to
+a file containing the client certificate, DER- or
+PEM-encoded. Please note that for now, support for client
+certificates is experimental, and only works
+with the <a href="https://www.libressl.org/">LibreSSL</a>
+backend (BearSSL does not support client certificates yet).
+</p>
+
+<p>
+ If <tt>s6-tlsc</tt> is run as root, it can also read two
+other environment variables, <tt>TLS_UID</tt> and <tt>TLS_GID</tt>,
+which contain a numeric uid and a numeric gid; <tt>s6-tlsc</tt>
+then drops its root privileges to this uid/gid after spawning
+<em>prog...</em>. This ensures that the TLS/engine and the
+application run with different privileges. Note that <em>prog...</em>
+should drop its own root privileges by its own means: the
+<a href="http://skarnet.org/software/s6/s6-applyuidgid.html">s6-applyuidgid</a>
+program is a way of doing it.
+</p>
+
+<h3> Written </h3>
+
+<p>
+ Unless the <tt>-Z</tt> option has been given to
+<tt>s6-tlsc</tt>, <em>prog...</em> is run with all the
+TLS/SSL variables <em>unset</em>: CADIR, CAFILE,
+KEYFILE, CERTFILE, TLS_UID and TLS_GID. The goal is
+for <tt>s6-tlsc</tt> to be, by default, as invisible
+as possible.
+</p>
+
+<h2> Server name determination for SNI </h2>
+
+<p>
+ The <tt>-k <em>servername</em></tt> option is important to
+<tt>s6-tlsc</tt>: it tells it to send <em>servername</em>
+as the name to require a certificate for.
+Not setting this option allows <tt>s6-tlsc</tt> to
+proceed without SNI,
+<strong>which may be a security risk.</strong>
+</p>
+
+<p>
+ The <a href="s6-tlsclient.html">s6-tlsclient</a> program can
+automatically craft a <tt>-k</tt> option for <tt>s6-tlsc</tt>
+if the <em>host</em> argument that is given to it is a
+host name. But if you're invoking <tt>s6-tlsc</tt> directly,
+do not forget to give it this option.
+</p>
+
+<h2> SSL close handling </h2>
+
+<p>
+ If <em>prog</em> initiates the end of the session by sending
+EOF, there are two ways for the TLS/SSL layer to handle it.
+</p>
+
+<ul>
+ <li> It can send a <tt>close_notify</tt> alert, and wait for
+an acknowledgement from the peer, at which point the connection
+is closed. The advantage of this setup is that it is secure
+even when the application protocol is not auto-terminated, i.e.
+when it does not know when its data stops. Old protocols such
+as HTTP-0.9 are in this case. The drawback of this setup is
+that it breaks full-duplex: once a peer has sent the
+<tt>close_notify</tt>, it must discard all the incoming
+records that are not a <tt>close_notify</tt> from the
+other peer. So if a client sends EOF while it is still
+receiving data from the server, the connection closes
+immediately and the data can be truncated. </li>
+ <li> It can simply transmit the EOF, shutting down
+half the TCP connection, and wait for the EOF back.
+The advantage of this setup is that it maintains
+full-duplex: a client can send EOF after its initial
+request, and still receive a complete answer from the
+server. The drawback is that it is insecure when the application
+protocol is not auto-terminated. </li>
+</ul>
+
+<p>
+ Nowadays (2016), most protocols are auto-terminated, so
+it is not dangerous anymore to use EOF tranmission, and that
+is the default fo <tt>s6-tlsc</tt>. Nevertheless, by
+using the <tt>-S</tt> option, you can
+force it to use the <tt>close_notify</tt> method if your
+application requires it to be secure.
+</p>
+
+<h2> <tt>s6-tlsc</tt> options </h2>
+
+<ul>
+ <li> <tt>-v&nbsp;<em>verbosity</em></tt>&nbsp: Be more or less
+verbose. Default for <em>verbosity</em> is 1. 0 is quiet, 2 is
+verbose, more than 2 is debug output. This option currently has
+no effect. </li>
+ <li> <tt>-Z</tt>&nbsp;: do not clean the environment of
+<tt>s6-tlsc</tt>-related variables before spawning <em>prog...</em>. </li>
+ <li> <tt>-z</tt>&nbsp;: clean the environment of
+<tt>s6-tlsc</tt>-related variables before spawning <em>prog...</em>.
+This is the default. </li>
+ <li> <tt>-S</tt>&nbsp;: send a <tt>close_notify</tt> alert
+and break the connection when <em>prog</em> sends EOF. </li>
+ <li> <tt>-s</tt>&nbsp;: transmit EOF by half-closing the TCP
+connection without using <tt>close_notify</tt>. This is the default. </li>
+ <li> <tt>-Y</tt>&nbsp;: Do not send a client certificate. This is the default. </li>
+ <li> <tt>-y</tt>&nbsp;: Send a client certificate. This is experimental and
+for now unsupported by BearSSL. </li>
+ <li> <tt>-k&nbsp;<em>servername</em></tt>&nbsp: use Server Name
+Indication, and send <em>servername</em>. The default is not to
+use SNI, which may be a security risk. </li>
+ <li> <tt>-K&nbsp;<em>kimeout</em></tt>&nbsp;: close the connection
+if <em>kimeout</em> milliseconds elapse without any data being
+received from either side. The default is 0, which means
+infinite timeout (never kill the connection). </li>
+ <li> <tt>-6&nbsp;<em>rfd</em></tt>&nbsp;: expect an open file
+descriptor numbered <em>rfd</em> to read network (ciphertext)
+data from. Make sure <em>prog</em> also reads its data
+from its own fd <em>rfd</em>. Default is 6. </li>
+ <li> <tt>-7&nbsp;<em>wfd</em></tt>&nbsp;: expect an open file
+descriptor numbered <em>wfd</em> to write network (ciphertext)
+data to. Make sure <em>prog</em> also writes its data to
+its own fd <em>wfd</em>. Default is 7. </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> The goal of the <tt>s6-tlsc</tt> interface (and its
+server-side companion <a href="s6-tlsd.html">s6-tlsd</a> is to
+make it so that if you have a client, run by the command line
+<tt>client...</tt> that speaks a cleartext protocol to a server
+run by the command line <tt>server...</tt>, then if the server
+has the proper private key and certificate, and the client has
+the proper list of trust anchors, you can just change the
+client command line to <tt>s6-tlsc client...</tt> and the
+server command line to <tt>s6-tlsd server...</tt>
+without changing the client or the server themselves, and the
+communication between them will be secure. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-tlsclient.html b/doc/s6-tlsclient.html
new file mode 100644
index 0000000..aea1c33
--- /dev/null
+++ b/doc/s6-tlsclient.html
@@ -0,0 +1,168 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-networking: the s6-tlsclient program</title>
+ <meta name="Description" content="s6-networking: the s6-tlsclient program" />
+ <meta name="Keywords" content="s6-networking s6-tlsclient tlsclient tls ssl ucspi tcp inet network tcp/ip client" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6-networking</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6-tlsclient</tt> program </h1>
+
+<p>
+<tt>s6-tlsclient</tt> is an
+<a href="http://cr.yp.to/proto/ucspi.txt">UCSPI client tool</a> for
+TLS/SSL connections over INET domain sockets. It establishes a TCP
+connection to a server and a TLS transport over it,
+then executes into a program.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-tlsclient [ <em>options</em> ] [ -- ] <em>host</em> <em>port</em> <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-tlsclient rewrites itself into a command line
+involving:
+ <ul>
+ <li> <a href="s6-tcpclient.html">s6-tcpclient</a>, which
+establishes a TCP connection to host <em>host</em> port <em>port</em>. </li>
+ <li> <a href="s6-tlsc.html">s6-tlsc</a>, which establishes
+a TLS transport (client-side) over that connection. </li>
+ <li> <em>prog...</em>, your client program, which is run as a
+child of <a href="s6-tlsc.html">s6-tlsc</a>. </li>
+ </ul> </li>
+ <li> It runs until the connection closes. </li>
+ <li> It exits either with a <a href="s6-tlsc.html">s6-tlsc</a>
+error code (and error message), or with an
+<a href="https://skarnet.org/software/execline/exitcodes.html">approximation</a>
+of <em>prog</em>'s exit code. </li>
+</ul>
+
+<p>
+ <em>prog</em> is expected to read from its peer on
+descriptor 6 and write to its peer on descriptor 7.
+Since there will be a <a href="s6-tlsc.html">s6-tlsc</a>
+program between <em>prog</em> and the network to perform
+the SSL encryption/decryption, those descriptors will not
+be a network socket - they will be pipes.
+</p>
+
+<h2> Server name determination for SNI </h2>
+
+<p>
+
+ If the <tt>-H</tt> option is not given to <tt>s6-tlsclient</tt>,
+then <em>host</em> will be used as the server name to verify.
+You can use the <tt>-k</tt> option to override this default.
+Please note that if you use the <tt>-H</tt> option and do not
+provide a server name via <tt>-k</tt>, <strong>SNI will not be
+used, which may be a security risk.</strong>
+</p>
+
+
+<h2> Environment variables </h2>
+
+<h3> Read </h3>
+
+<p>
+ The following variables should be set before invoking
+<tt>s6-tlsclient</tt>, because they will be used by
+<a href="s6-tlsc.html">s6-tlsc</a>:
+</p>
+
+<ul>
+ <li> CADIR </li>
+ <li> CAFILE (alternative to CADIR) </li>
+ <li> KEYFILE (if you're using a client certificate) </li>
+ <li> CERTFILE (if you're using a client certificate) </li>
+ <li> TLS_UID and TLS_GID (if you run <tt>s6-tlsclient</tt> as root) </li>
+</ul>
+
+<p>
+ Setting either CADIR or CAFILE is mandatory.
+</p>
+
+<h3> Written </h3>
+
+<p>
+ <em>prog...</em> is run with the following variables added to,
+or removed from, its environment by <a href="s6-tcpclient.html">s6-tcpclient</a>:
+</p>
+
+<ul>
+ <li> PROTO </li>
+ <li> TCPREMOTEIP </li>
+ <li> TCPREMOTEPORT </li>
+ <li> TCPREMOTEHOST </li>
+ <li> TCPLOCALHOST </li>
+ <li> TCPREMOTEINFO </li>
+</ul>
+
+<p>
+ Unless the <tt>-Z</tt> option is given to <tt>s6-tlsclient</tt>,
+the CADIR, CAFILE, KEYFILE, CERTFILE, TLS_UID and TLS_GID
+variables will not appear in <em>prog</em>'s environment.
+</p>
+
+
+<h2> Options </h2>
+
+<p>
+ <tt>s6-tlsclient</tt> accepts a myriad of options, most of which are
+passed as is to the correct executable. Not giving any options will
+generally work: the defaults are sensible.
+</p>
+
+<h3> Options passed as is to s6-tcpclient </h3>
+
+<ul>
+ <li> <tt>-q</tt>, <tt>-Q</tt>, <tt>-v</tt> </li>
+ <li> <tt>-4</tt>, <tt>-6</tt> </li>
+ <li> <tt>-d</tt>, <tt>-D</tt> </li>
+ <li> <tt>-r</tt>, <tt>-R</tt> </li>
+ <li> <tt>-h</tt>, <tt>-H</tt>, <tt>-l <em>localname</em></tt> </li>
+ <li> <tt>-n</tt>, <tt>-N</tt> </li>
+ <li> <tt>-t <em>timeout</em></tt> </li>
+ <li> <tt>-i <em>localip</em></tt>, <tt>-p <em>localport</em></tt> </li>
+ <li> <tt>-T <em>timeoutconn</em></tt> </li>
+</ul>
+
+<h3> Options passed as is to s6-tlsc </h3>
+
+<ul>
+ <li> <tt>-Z</tt>, <tt>-z</tt> </li>
+ <li> <tt>-S</tt>, <tt>-s</tt> </li>
+ <li> <tt>-Y</tt>, <tt>-y</tt> </li>
+ <li> <tt>-k <em>servername</em></tt> </li>
+ <li> <tt>-K <em>kimeout</em></tt> </li>
+</ul>
+
+<h2> Example </h2>
+
+<p>
+ <code> CADIR=/etc/ssl/certs s6-tlsclient skarnet.org 443 s6-ioconnect </code>
+</p>
+
+<p>
+ This will open a connection to
+<a href="https://skarnet.org/">the skarnet.org web server
+over TLS</a> and verify its certificate via the trust anchors
+listed in the <tt>/etc/ssl/certs</tt> directory. It will then
+branch your terminal to it: try typing
+<tt>GET / HTTP/1.0</tt> then hitting return twice.
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-tlsd.html b/doc/s6-tlsd.html
new file mode 100644
index 0000000..ab3243a
--- /dev/null
+++ b/doc/s6-tlsd.html
@@ -0,0 +1,280 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-networking: the s6-tlsd program</title>
+ <meta name="Description" content="s6-networking: the s6-tlsd program" />
+ <meta name="Keywords" content="s6-networking s6-tlsd tlsd tls ssl ucspi tcp inet network tcp/ip server" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6-networking</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6-tlsd</tt> program </h1>
+
+<p>
+<tt>s6-tlsd</tt> is a program that performs the server side of
+a TLS or SSL connection over an existing TCP connection, then spawns
+an application. It is meant to make network communications
+secure even for applications that do not natively support
+TLS/SSL.
+</p>
+
+<p>
+ <a href="index.html">s6-networking</a> does not include
+cryptographic software. All the crypto used in <tt>s6-tlsc</tt>
+is provided by the chosen SSL backend:
+<a href="https://bearssl.org/">BearSSL</a> or
+<a href="https://www.libressl.org/">LibreSSL</a>, depending on
+the options given when configuring <tt>s6-networking</tt>.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-tlsd [ -S | -s ] [ -Y | -y ] [ -Z | -z ] [ -v <em>verbosity</em> ] [ -K kimeout ] [ -- ] <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-tlsd expects to have an open TCP connection it
+can talk to on its stdin (for reading) and stdout
+(for writing). </li>
+ <li> It spawns <em>prog...</em> as a child process,
+interposing itself between it and the network.
+In other words: <em>prog</em> still reads cleartext
+on its stdin and writes cleartext on its stdout, but
+those will actually be pipes to <tt>s6-tlsd</tt>, which
+will read ciphertext from its own stdin (the network)
+and write ciphertext to its own stdout (the network). </li>
+ <li> It initiates the server side of a TLS/SSL handshake
+over the network connection, expecting a TLS/SSL client on
+the other side. </li>
+ <li> It manages the encryption/decryption of all the
+messages between <em>prog</em> and the client.
+<em>prog</em> speaks plaintext, but only ciphertext is sent
+on the network. </li>
+ <li> When <em>prog</em> exits, <tt>s6-tlsd</tt> exits.
+</ul>
+
+<h2> Exit codes </h2>
+
+<ul>
+ <li> 96: error while configuring the TLS/SSL context - for instance, invalid
+private key or server certificate files. </li>
+ <li> 97: error while setting up the TLS/SSL client engine. </li>
+ <li> 98: TLS/SSL error while running the engine. </li>
+ <li> 100: wrong usage. </li>
+ <li> 111: system call failed. </li>
+</ul>
+
+<p>
+ If the TLS/SSL connection closes cleanly, <tt>s6-tlsd</tt>
+waits for <em>prog</em> to exit, then exits with an
+<a href="http://skarnet.org/software/execline/exitcodes.html">approximation</a>
+of <em>prog</em>'s exit code.
+</p>
+
+<h2> Protocol version and parameters </h2>
+
+<p>
+ During the TLS/SSL handshake, <tt>s6-tlsd</tt> tries the
+versions of the protocol that is supported by default by the
+backend, with the default algorithms and cipher suites;
+the backend normally ensures that the most secure combination
+is tried first, with slow degradation until the client and
+the server agree.
+</p>
+
+<ul>
+ <li> For BearSSL, this means use of the
+<a href="https://bearssl.org/apidoc/bearssl__ssl_8h.html#a76293c81c4624c58254a62be7b2d5e79">br_ssl_server_init_full_rsa()</a> or
+<a href="https://bearssl.org/apidoc/bearssl__ssl_8h.html#a592b2af27b2f6b9389aac854fb0b783a">br_ssl_server_init_full_ec()</a>
+function. The supported protocol versions are described
+<a href="https://bearssl.org/support.html#supported-versions">here</a>. </li>
+ <li> For LibreSSL, this means use of the
+<a href="http://man.openbsd.org/OpenBSD-current/man3/tls_config_set_protocols.3">tls_config_set_protocols(TLS_PROTOCOLS_DEFAULT)</a>
+call. </li>
+</ul>
+
+<p>
+ As a server, <tt>s6-tlsd</tt> can be conservative in its
+choice of protocols. It is currently not very conservative
+when using the BearSSL backend; it could become more so in
+the future, by defining a custom server profile that supports
+only TLS-1.2 but with several algorithms and cipher suites.
+</p>
+
+<h2> Environment variables </h2>
+
+<h3> Read </h3>
+
+<p>
+ <tt>s6-tlsd</tt> expects to have the following
+environment variables set:
+</p>
+
+<ul>
+ <li> <tt>KEYFILE</tt>: a path to the file
+containing the server's private key, DER- or PEM-encoded. </li>
+ <li> <tt>CERTFILE</tt>: a path to the file
+containing the server's certificate, DER- or PEM-encoded.
+If PEM-encoded, the file can actually contain a chain
+of certificates. </li>
+</ul>
+
+<p>
+ If one of those variables is unset, <tt>s6-tlsd</tt>
+will refuse to run.
+</p>
+
+<p>
+ If you are using client certificats, <tt>s6-tlsd</tt>
+also requires either one of the following variables to be set:
+</p>
+
+<ul>
+ <li> <tt>CADIR</tt>: a directory where trust anchors
+(i.e. root or intermediate CA certificates) can be found,
+one per file, DER- or PEM-encoded. </li>
+ <li> <tt>CAFILE</tt>: a file containing the whole set
+of trust anchors, PEM-encoded. </li>
+</ul>
+
+<p>
+Please note that for now, support for client
+certificates is experimental, and only works
+with the <a href="https://www.libressl.org/">LibreSSL</a>
+backend (BearSSL does not support client certificates yet).
+</p>
+
+<p>
+ If <tt>s6-tlsd</tt> is run as root, it can also read two
+more environment variables, <tt>TLS_UID</tt> and <tt>TLS_GID</tt>,
+which contain a numeric uid and a numeric gid; <tt>s6-tlsd</tt>
+then drops its root privileges to this uid/gid after spawning
+<em>prog...</em>. This ensures that the TLS/engine and the
+application run with different privileges.
+</p>
+
+<p>
+ Note that <em>prog...</em>
+should drop its own root privileges by its own means: the
+<a href="http://skarnet.org/software/s6/s6-applyuidgid.html">s6-applyuidgid</a>
+program is a way of doing it. If the <tt>s6-tlsd</tt>
+invocation actually comes from a
+<a href="s6-tlsserver.html">s6-tlsserver</a> command line,
+and privilege-dropping options (<tt>-G</tt>, <tt>-g</tt>,
+<tt>-u</tt> or <tt>-U</tt>) have been given to
+<a href="s6-tlsserver.html">s6-tlsserver</a>, then
+<a href="http://skarnet.org/software/s6/s6-applyuidgid.html">s6-applyuidgid</a>
+directly follows <tt>s6-tlsd</tt> on the command line, in order
+to also drop the child's privileges before executing the application.
+The point of that setup is:
+</p>
+
+<ul>
+ <li> To read the private key file as root </li>
+ <li> To run the application as a non-root user </li>
+ <li> To run <tt>s6-tlsd</tt> as a <em>different</em> non-root user </li>
+ <li> That way, even if <tt>s6-tlsd</tt>, the application, or both,
+get compromised, the private key is still secure. </li>
+</ul>
+
+<h3> Written </h3>
+
+<p>
+ Unless the <tt>-Z</tt> option has been given to
+<tt>s6-tlsd</tt>, <em>prog...</em> is run with all the
+TLS/SSL variables <em>unset</em>: CADIR, CAFILE,
+KEYFILE, CERTFILE, TLS_UID and TLS_GID. The goal is
+for <tt>s6-tlsd</tt> to be, by default, as invisible
+as possible.
+</p>
+
+<h2> SSL close handling </h2>
+
+<p>
+ If <em>prog</em> initiates the end of the session by sending
+EOF, there are two ways for the TLS/SSL layer to handle it.
+</p>
+
+<ul>
+ <li> It can send a <tt>close_notify</tt> alert, and wait for
+an acknowledgement from the peer, at which point the connection
+is closed. The advantage of this setup is that it is secure
+even when the application protocol is not auto-terminated, i.e.
+when it does not know when its data stops. Old protocols such
+as HTTP-0.9 are in this case. The drawback of this setup is
+that it breaks full-duplex: once a peer has sent the
+<tt>close_notify</tt>, it must discard all the incoming
+records that are not a <tt>close_notify</tt> from the
+other peer. So if a client sends EOF while it is still
+receiving data from the server, the connection closes
+immediately and the data can be truncated. </li>
+ <li> It can simply transmit the EOF, shutting down
+half the TCP connection, and wait for the EOF back.
+The advantage of this setup is that it maintains
+full-duplex: a client can send EOF after its initial
+request, and still receive a complete answer from the
+server. The drawback is that it is insecure when the application
+protocol is not auto-terminated. </li>
+</ul>
+
+<p>
+ Nowadays (2016), most protocols are auto-terminated, so
+it is not dangerous anymore to use EOF tranmission, and that
+is the default fo <tt>s6-tlsd</tt>. Nevertheless, by
+using the <tt>-S</tt> option, you can
+force it to use the <tt>close_notify</tt> method if your
+application requires it to be secure.
+</p>
+
+<h2> <tt>s6-tlsd</tt> options </h2>
+
+<ul>
+ <li> <tt>-v&nbsp;<em>verbosity</em></tt>&nbsp: Be more or less
+verbose. Default for <em>verbosity</em> is 1. 0 is quiet, 2 is
+verbose, more than 2 is debug output. This option currently has
+no effect. </li>
+ <li> <tt>-Z</tt>&nbsp;: do not clean the environment of
+<tt>s6-tlsd</tt>-related variables before spawning <em>prog...</em>. </li>
+ <li> <tt>-z</tt>&nbsp;: clean the environment of
+<tt>s6-tlsd</tt>-related variables before spawning <em>prog...</em>.
+This is the default. </li>
+ <li> <tt>-S</tt>&nbsp;: send a <tt>close_notify</tt> alert
+and break the connection when <em>prog</em> sends EOF. </li>
+ <li> <tt>-s</tt>&nbsp;: transmit EOF by half-closing the TCP
+connection without using <tt>close_notify</tt>. This is the default. </li>
+ <li> <tt>-Y</tt>&nbsp;: Do not require a client certificate. This is the default. </li>
+ <li> <tt>-y</tt>&nbsp;: Require a client certificate. This is experimental and
+for now unsupported by BearSSL. </li>
+ <li> <tt>-K&nbsp;<em>kimeout</em></tt>&nbsp;: close the connection
+if <em>kimeout</em> milliseconds elapse without any data being
+received from either side. The default is 0, which means
+infinite timeout (never kill the connection). </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> The goal of the <tt>s6-tlsd</tt> interface (and its
+client-side companion <a href="s6-tlsc.html">s6-tlsc</a> is to
+make it so that if you have a client, run by the command line
+<tt>client...</tt> that speaks a cleartext protocol to a server
+run by the command line <tt>server...</tt>, then if the server
+has the proper private key and certificate, and the client has
+the proper list of trust anchors, you can just change the
+client command line to <tt>s6-tlsc client...</tt> and the
+server command line to <tt>s6-tlsd server...</tt>
+without changing the client or the server themselves, and the
+communication between them will be secure. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-tlsserver.html b/doc/s6-tlsserver.html
new file mode 100644
index 0000000..e50f817
--- /dev/null
+++ b/doc/s6-tlsserver.html
@@ -0,0 +1,216 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-networking: the s6-tlsserver program</title>
+ <meta name="Description" content="s6-networking: the s6-tlsserver program" />
+ <meta name="Keywords" content="s6-networking s6-tlsclient tlsserver tls ssl ucspi tcp inet network tcp/ip server superserver" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6-networking</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6-tlsserver</tt> program </h1>
+
+<p>
+<tt>s6-tlsserver</tt> is an
+<a href="http://cr.yp.to/proto/ucspi.txt">UCSPI server tool</a> for
+TLS/SSL connections over INET domain sockets. It acts as a TCP superserver
+that listens to connections, accepts them, and for each connection,
+establishes a TLS transport over it, then executes into a program.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-tlsserver [ <em>options</em> ] [ -- ] <em>ip</em> <em>port</em> <em>prog...</em>
+</pre>
+
+<ul>
+ <li> s6-tlsserver rewrites itself into a command line
+involving:
+ <ul>
+ <li> <a href="s6-tcpserver.html">s6-tcpserver</a>, which
+listens to TCP connections on IP address <em>ip</em> port <em>port</em>
+and forks a command line for every connection. Note that
+<a href="s6-tcpserver.html">s6-tcpserver</a> also rewrites
+itself into a more complex commnd line (the final long-lived
+process being <a href="s6-tcpserver4d.html">s6-tcpserver4d</a>
+or <a href="s6-tcpserver4d.html">s6-tcpserver6d</a>),
+so your end command line may look a lot longer in <tt>ps</tt>
+than what you originally wrote. This is normal and healthy. </li>
+ <li> (if applicable) <a href="s6-tcpserver-access.html">s6-tcpserver-access</a>,
+which performs TCP access control and various operations on the
+TCP connection. </li>
+ <li> <a href="s6-tlsd.html">s6-tlsd</a>, which establishes
+a TLS transport (server-side) over a connection. </li>
+ <li> (if applicable)
+<a href="http://skarnet.org/software/s6/s6-applyuidgid.html">s6-applyuidgid</a>,
+which drops root privileges. </li>
+ <li> <em>prog...</em>, your client program, which is run as a
+child of <a href="s6-tlsd.html">s6-tlsd</a>. </li>
+ </ul> </li>
+ <li> It runs until it is killed by a signal. </li>
+</ul>
+
+<p>
+ <em>prog</em> is expected to read from its peer on its
+standard input and write to its peer on its standard output.
+Since there will be a <a href="s6-tlsd.html">s6-tlsd</a>
+program between <em>prog</em> and the network to perform
+the SSL encryption/decryption, those descriptors will not
+be a network socket - they will be pipes.
+</p>
+
+<h2> Signals </h2>
+
+<p>
+ <tt>s6-tlsserver</tt> reacts to the same signals as
+<a href="s6-tcpserver4d.html">s6-tcpserver4d</a> or
+<a href="s6-tcpserver6d.html">s6-tcpserver6d</a>,
+one of which is the long-lived process hanging around.
+</p>
+
+<h2> Environment variables </h2>
+
+<h3> Read </h3>
+
+<p>
+ The following variables should be set before invoking
+<tt>s6-tlsserver</tt>, because they will be used by
+every <a href="s6-tlsd.html">s6-tlsd</a> invocation:
+</p>
+
+<ul>
+ <li> KEYFILE </li>
+ <li> CERTFILE </li>
+ <li> TLS_UID and TLS_GID (if you run <tt>s6-tlsserver</tt> as root) </li>
+ <li> CADIR (if you want client certificates) </li>
+ <li> CAFILE (if you want client certificates, alternative to CADIR) </li>
+</ul>
+
+<p>
+ Setting both KEYFILE and CERTFILE is mandatory.
+</p>
+
+<h3> Written </h3>
+
+<p>
+ <em>prog...</em> is run with the following variables added to,
+or removed from, its environment by <a href="s6-tcpserver4d.html">s6-tcpserver4d</a>
+or <a href="s6-tcpserver6d.html">s6-tcpserver6d</a>, and possibly
+by <a href="s6-tcpserver-access.html">s6-tcpserver-access</a>:
+</p>
+
+<ul>
+ <li> PROTO </li>
+ <li> TCPREMOTEIP </li>
+ <li> TCPREMOTEPORT </li>
+ <li> TCPCONNNUM </li>
+ <li> TCPLOCALIP </li>
+ <li> TCPLOCALPORT </li>
+ <li> TCPREMOTEHOST </li>
+ <li> TCPLOCALHOST </li>
+ <li> TCPREMOTEINFO </li>
+</ul>
+
+<p>
+ Depending on TCP access rules (if the <tt>-i</tt> or <tt>-x</tt>
+option has been given), it is possible that <em>prog</em>'s
+environment undergoes more modifications. Also, since
+<a href="s6-tlsd.html">s6-tlsd</a> is always run
+after <a href="s6-tcpserver-access.html">s6-tcpserver-access</a>,
+it is possible to set different TLS/SSL parameters (typically
+a different KEYFILE and CERTFILE) depending on the client
+connection, by writing the correct set of TCP access rules.
+</p>
+
+<p>
+ Unless the <tt>-Z</tt> option is given to <tt>s6-tlsserver</tt>,
+the CADIR, CAFILE, KEYFILE, CERTFILE, TLS_UID and TLS_GID
+variables will not appear in <em>prog</em>'s environment.
+</p>
+
+
+<h2> Options </h2>
+
+<p>
+ <tt>s6-tlsserver</tt> accepts a myriad of options, most of which are
+passed as is to the correct executable. Not giving any options will
+generally work, but unless you're running a very public server
+(such as a Web server) or base your access control on client
+certificates, you probably still want TCP access rules.
+</p>
+
+<h3> Options passed as is to s6-tcpserver </h3>
+
+<ul>
+ <li> <tt>-q</tt>, <tt>-Q</tt>, <tt>-v</tt> </li>
+ <li> <tt>-4</tt>, <tt>-6</tt> </li>
+ <li> <tt>-1</tt> </li>
+ <li> <tt>-c <em>maxconn</em></tt> </li>
+ <li> <tt>-C <em>localmaxconn</em></tt> </li>
+ <li> <tt>-b <em>backlog</em></tt> </li>
+</ul>
+
+<h3> Options passed as is to s6-tcpserver-access </h3>
+
+<ul>
+ <li> The verbosity level, if not default, as <tt>-v0</tt> or <tt>-v2</tt> </li>
+ <li> <tt>-w</tt>, <tt>-W</tt> </li>
+ <li> <tt>-d</tt>, <tt>-D</tt> </li>
+ <li> <tt>-r</tt>, <tt>-R</tt> </li>
+ <li> <tt>-p</tt>, <tt>-P</tt> </li>
+ <li> <tt>-h</tt>, <tt>-H</tt>, <tt>-l <em>localname</em></tt> </li>
+ <li> <tt>-B <em>banner</em></tt> </li>
+ <li> <tt>-t <em>timeout</em></tt> </li>
+ <li> <tt>-i <em>rulesdir</em></tt>, <tt>-x <em>rulesfile</em></tt> </li>
+</ul>
+
+<h3> Options passed as is to s6-tlsd </h3>
+
+<ul>
+ <li> <tt>-Z</tt>, <tt>-z</tt> </li>
+ <li> <tt>-S</tt>, <tt>-s</tt> </li>
+ <li> <tt>-Y</tt>, <tt>-y</tt> </li>
+ <li> <tt>-k <em>servername</em></tt> </li>
+ <li> <tt>-K <em>kimeout</em></tt> </li>
+</ul>
+
+<h3> Options passed to s6-applyuidgid </h3>
+
+<ul>
+ <li> <tt>-u <em>uid</em></tt>, <tt>-g <em>gid</em></tt>, <tt>-G <em>gidlist</em></tt> </li>
+ <li> <tt>-U</tt> (passed as <tt>-Uz</tt>) </li>
+</ul>
+
+<h2> Example </h2>
+
+
+<p>
+ As root:
+ <code> KEYFILE=/etc/ssl/private/mykey.der CERTFILE=/etc/ssl/public/mycert.pem \
+ TLS_UID=65534 TLS_UID=65536 \
+ s6-envuidgid www
+ s6-tlsserver -U -- 1.2.3.4 443 httpd </code>
+</p>
+
+<p>
+This will start a server listening to 1.2.3.4 on TCP port 443,
+ and for every connection, spawn the <tt>httpd</tt> program
+reading queries on stdin and replying on stdout, as user <tt>www</tt>,
+with a TLS layer protecting the connection, the TLS engine running
+as user <tt>nobody</tt> (<tt>65534:65534</tt>). The server is
+authentified by the certificate in <tt>/etc/ssl/public/mycert.pem</tt>
+that it sends to the client, and the private key in
+<tt>/etc/ssl/private/mykey.der</tt> that it keeps to itself.
+</p>
+
+</body>
+</html>
diff --git a/doc/upgrade.html b/doc/upgrade.html
index 4b20888..b2cfe21 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -22,7 +22,7 @@
<ul>
<li> skalibs dependency bumped to 2.4.0.1. </li>
- <li> TLS 1.2 support added:
+ <li> SSL/TLS support added:
<ul>
<li> <a href="s6-tlsclient.html">s6-tlsclient</a> </li>
<li> <a href="s6-tlsserver.html">s6-tlsserver</a> </li>