Minimum Gemini Survival Kit

For those times when all you have is a Unixy shell. I'll use the words prep, prepper, and prepping so it can be found via GUS when you need it most! Below are some seed URLs to might want to use to start exploring.

The following sections will cover 1) a minimal client, 2) creating a client certificate, 3) creating a server certificate. A client certificate is only used if you need to authenticate yourself, and a server certificate is only needed if you're running your own server.

Simplest Client

Here are some examples, each using a different TLS client utility.

echo -ne "gemini://g.susa.net/\r\n" | ncat --ssl g.susa.net 1965

echo -ne "gemini://g.susa.net/\r\n" | gnutls-cli --no-ca-verification --port=1965 g.susa.net

echo -ne "gemini://g.susa.net/\r\n" | openssl s_client -connect "g.susa.net:1965" -quiet

Create Client Certificate

You won't need this for general browsing, but if the server has protected resources, or if it needs to identify you between sessions, then client certificates are Gemini's neat way of doing this.

The subject's CN value would typically be your user-name.

# openssl allows us to do everything in a single line
openssl req -x509 -newkey rsa:2048 -nodes -keyout my.key -out my.crt -subj '/CN=kevinsan'

# certtool requires separate steps - key, template, then certificate
certtool -p --rsa --bits=2048 --outfile my.key
echo "cn = kevinsan" >/tmp/template
certtool -s --load-privkey my.key --outfile my.crt --template /tmp/template

The Simplest Client with Client Certificate

Just give your client certificate to whatever command you're using, and it will supply it to the server when it's requested.

echo -ne 'gemini://g.susa.net/private\r\n' | \
    ncat --ssl --ssl-cert ./my.crt --ssl-key ./my.key g.susa.net 1965

echo -ne 'gemini://g.susa.net/private\r\n' | \
    openssl s_client -connect g.susa.net:1965 -key my.key -cert my.crt -ign_eof -quiet

Create Server Certificate

This is almost identical to a self-signed client certificate.

The subject's CN value should be your server's hostname, or a wildcard domain. The client may check this and reject the session if your server's CN value is different from the hostname you're asking it to fetch from.

# The openssl approach
openssl req -x509 -newkey rsa:2048 -nodes -keyout serv.key -out serv.crt -subj '/CN=*.susa.net'

# The certtool approach
certtool -p --rsa --bits=2048 --outfile serv.key
echo "cn = *.susa.net" >/tmp/template
certtool -s --load-privkey serv.key --outfile serv.crt --template /tmp/template

Elliptic Curve Keys

If you prefer elliptic curves over big primes, then use the following examples (I link to the original source).

# Simple server key, corresponding to the RSA example above
openssl req -new -subj "/CN=g.susa.net" -x509 -newkey ec -days 36500 \
    -pkeyopt ec_paramgen_curve:prime256v1 -nodes -out serv.crt -keyout serv.key

# makeworld's example below supports multiple hosts/domains
openssl req -new -subj "/CN=example.com" \
    -addext "subjectAltName = DNS:example.com, DNS:example2.com" \
    -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
    -nodes -out cert.pem -keyout key.pem

The following, for reference only, generates key using the curve 25519 (which as I understand it is not widely supported yet, despite being computationally much simpler than other curves.

# Generate a private key
openssl genpkey -algorithm X25519 -out private.pem

# Generate a public key
openssl pkey -in private.pem -pubout -out public.pem

I intend to generate a certificate from a 25519 key to see what clients/servers work well with it, but my current Debian version doesn't seem to have a recent enough version to do this. On the back burner I suppose...

Some further reading