Title: Add a TLS layer to your Gopher server Author: Solène Date: 07 March 2019 Tags: gopher openbsd Description: Hi, In this article I will explain how to setup a gopher server supporting TLS. Gopher TLS support is not "official" as there is currently no RFC to define it. It has been recently chose by the community how to make it work, while keeping compatibility with old servers / clients. The way to do it is really simple. Client A tries to connects to Server B, Client A tries TLS handshake, if Server B answers correctly to the TLS handshakes, then Client A sends the gopher request and Server B answers the gopher requests. If Server B doesn't understand the TLS handshakes, then it will probably output a regular gopher page, then this is throwed and Client A retries the connection using plaintext gopher and Server B answers the gopher request. This is easy to achieve because gopher protocol doesn't require the server to send anything to the client before the client sends its request. The way to add the TLS layer and the dispatching can be achieved using **sslh** and **relayd**. You could use haproxy instead of relayd, but the latter is in OpenBSD base system so I will use it. Thanks parazyd for sharing about sslh for this use case. **sslh** is a protocol demultiplexer, it listens on a port, and depending on what it receives, it will try to guess the protocol used by the client and send it to the according backend. It's first purpose was to make ssh available on port 443 while still having https daemon working on that server. Here is a schema of the setup +→ relayd for TLS + forwarding ↑ ↓ ↑ tls? ↓ client -> sslh TCP 70 → + ↓ ↓ not tls ↓ ↓ ↓ +→ → → → → → → gopher daemon on localhost This method allows to wrap any server to make it TLS compatible. The best case would be to have TLS compatibles servers which do all the work without requiring sslh and something to add the TLS. But it's currently a way to show TLS for gopher is real. ## Relayd The relayd(1) part is easy, you first need a x509 certificate for the TLS part, I will not explain here how to get one, there are already plenty of how-to and one can use let's encrypt with acme-client(1) to get one on OpenBSD. We will write our configuration in **/etc/relayd.conf** log connection relay "gopher" { listen on 127.0.0.1 port 7000 tls forward to 127.0.0.1 port 7070 } In this example, relayd listens on port 7000 and our gopher daemon listens on port 7070. According to relayd.conf(5), relayd will look for the certificate at the following places: `/etc/ssl/private/$LISTEN_ADDRESS:$PORT.key` and `/etc/ssl/$LISTEN_ADDRESS:$PORT.crt`, with the current example you will need the files: /etc/ssl/private/127.0.0.1:7000.key and /etc/ssl/127.0.0.1:7000.crt relayd can be enabled and started using rcctl: # rcctl enable relayd # rcctl start relayd ## Gopher daemon Choose your favorite gopher daemon, I recommend geomyidae but any other valid daemon will work, just make it listening on the correct address and port combination. # pkg_add geomyidae # rcctl enable geomyidae # rcctl set geomyidae flags -p 7070 # rcctl start geomyidae ## SSLH We will use sslh_fork (but sslh_select would be valid too, they have differents pros/cons). The `--tls` parameters tells where to forward a TLS connection while `--ssh` will forward to the gopher daemon. This is so because the protocol ssh is already configured within sslh and acts exactly like a gopher daemon: the client doesn't expect the server to be the first sending data. # pkg_add sslh # rcctl enable sslh_fork # rcctl set sslh_fork flags --tls 127.0.0.1:7000 --ssh 127.0.0.1:7070 -p 0.0.0.0:70 # rcctl start sslh_fork ## Client You can easily test if this works using openssl to connect by hand to the port 70 $ openssl s_client -connect 127.0.0.1:7000 can send a gopher request like "/" and you should get a result. Using telnet on the same address and port should give the same result. My gopher client **clic** already supports gopher TLS and is available at git://bitreich.org/clic and only requires the ecl common lisp interpreter to compile. |