shithub: tlssrv.sni

Clone

clone: git://shithub.us/igor/tlssrv.sni gits://shithub.us/igor/tlssrv.sni
push: hjgit://shithub.us/igor/tlssrv.sni
patches to: igor@9lab.org

Last commit

6fbda982 – igor <igor@mux> authored on 2024/01/25 05:59
Fix typos and install in /bin instead of $user/bin.

About

# Tlssrv(8) with Server Name Indication (SNI) support

A variant of tlssrv(8) supporting the [Server Name Indication
(SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication)
extension.  With this extension it is possible to use *multiple* SSL
certificates with a *single* IP address.

# Installation

```
% git/clone git://shithub.us/igor/tlssrv.sni
% cd tlssrv.sni
% mk install
```

# Example Setup

The easiest way to fetch and renew a **TLS** certificate on
[9front](http://9front.org) is via
[acmed(8)](http://man.9front.org/8/acmed). We are going to
request 4 SSL certificates, that is `9lab.org`, `mux.9lab.org`,
`bytelabs.org`, and `mux.bytelabs.org`, backed by the same IP address.

Initially an account key must be generated (see
[acmed(8)](http://man.9front.org/8/acmed):

```
% ramfs -p ; cd /tmp
% auth/rsagen -t \
    'service=acme role=sign hash=sha256 acct=igor@9lab.org' \
    >account.key
% auth/rsa2jwk account.key \
    >/sys/lib/tls/acmed/igor@9lab.org.pub
```

The `account.key` must be loaded into
[factotum(4)](http://man.9front.org/4/factotum); however, it is best
to store it in [secstore(1)](http://man.9front.org/1/secstore) instead
of storing it unencrypted on the file system:

```
% auth/secstore -g factotum
secstore password:
% cat account.key >> factotum
% auth/secstore -p factotum
secstore password:
% read -m factotum > /mnt/factotum/ctl
```

Please consult [secstore(1)](http://man.9front.org/1/secstore) as well
as the excellent [9front FQA secstore
documentation](http://fqa.9front.org/fqa8.html#8.4.7) if the above
doesn't make sense or doesn't work for you.

Next, generate a [rsa(8)](http://man.9front.org/8/rsa) key (i.e.
`certificate.key`) and store it in
[secstore(1)](http://man.9front.org/1/secstore):

```
% auth/rsagen -t 'service=tls role=client owner=*' \
    >certificate.key
% auth/secstore -g factotum
secstore password:
% cat certificate.key >> factotum
% auth/secstore -p factotum
secstore password:
% read -m factotum > /mnt/factotum/ctl
```

See [rsa(8)](http://man.9front.org/8/rsa) and
[tlssrv(8)](http://man.9front.org/8/tlssrv) for more examples on how
to use RSA keys.

Now it is time to create certificate signing requests (i.e.
`mux.9lab.org.csr`):

```
% auth/rsa2csr 'CN=9lab.org' certificate.key \
    >/sys/lib/tls/acmed/9lab.org.csr
% auth/rsa2csr 'CN=mux.9lab.org' certificate.key \
    >/sys/lib/tls/acmed/mux.9lab.org.csr
% auth/rsa2csr 'CN=bytelabs.org' certificate.key \
    >/sys/lib/tls/acmed/bytelabs.org.csr
% auth/rsa2csr 'CN=mux.bytelabs.org' certificate.key \
    >/sys/lib/tls/acmed/mux.bytelabs.org.csr
```

Finally, the certificates for your domains can be fetched.  This
requires [webfs(4)](http://man.9front.org/4/webfs) to be mounted as
the [ACME
protocol](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment)
uses HTTP to talk to the provider.

```
% webfs
% auth/acmed igor@9lab.org /sys/lib/tls/acmed/9lab.org.csr \
    >/sys/lib/tls/acmed/9lab.org.crt
% auth/acmed igor@9lab.org /sys/lib/tls/acmed/mux.9lab.org.csr \
    >/sys/lib/tls/acmed/mux.9lab.org.crt
% auth/acmed igor@9lab.org /sys/lib/tls/acmed/bytelabs.org.csr \
    >/sys/lib/tls/acmed/bytelabs.org.crt
% auth/acmed igor@9lab.org /sys/lib/tls/acmed/mux.bytelabs.org.csr \
    >/sys/lib/tls/acmed/mux.bytelabs.org.crt
```

The above incantation is also used to *renew* certificates. The
following is handy to display a certificate:

```
% auth/pemdecode 'CERTIFICATE' /sys/lib/tls/acmed/mux.9lab.org.crt | auth/x5092pub
key proto=rsa size=2048 ek=… n=… subject=mux.9lab.org
```

At last, to [listen(8)](http://man.9front.org/8/listen) on https port
443 for requests modify the file `/bin/service/tcp443` as follows:

```
% cat /bin/service/tcp443
#!/bin/rc
exec tlssrv -c/sys/lib/tls/acmed/9lab.org.crt -ltcp80 -r`{cat $3/remote} /bin/tcp80 `{cat $3/remote}>>[2]/sys/log/tcp80
```

If you already have `/bin/service/tcp443` with a certificate setup you
do not need any additional steps to enable SNI to work other than
ensuring your certificates are in the appropriate folder
`/sys/lib/tls/acmed/` using the right suffix (see Caveats section).

# Caveats

A main or fallback certificate can be specified to tlssrv(8) via the
`-c` option.  If a Server Name Identifier SNI is provided, we attempt
to load its certificate from:

```
  snprint(path, sizeof(path), "/sys/lib/tls/acmed/%s.crt", c->serverName);
```

That means the certificate has to be present in `/sys/lib/tls/acmed/`
with the name `SNI.crt`, where SNI is the the server name indicator
provided by the client.