Skip to content

Client certificates

oakkitten edited this page Oct 3, 2020 · 4 revisions

As your device can authenticate a server by having a look at its TLS certificate, the server can authenticate you in a similar way. Using a client certificate is one of the most secure ways for the web server to make sure that you are who you say you are and not someone else.

Upon importing your certificate and private key pair, Weechat-Android will attempt to put it into a secure key store. On modern devices, it will likely be stored inside security hardware, out of which it cannot be retreived. You can use RSA keys on API 18+, and EC keys on API 23+, and DSA keys on API 19 to 22.

A client certificate can be used with WeeChat SSL and WebSocket SSL connections.

Creating a client certificate

You can find plenty of tutorials online on how to make and deploy client certificates. Here's a short version:

# generate the key and the certificate of your certificate authority
openssl genrsa -des3 -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt

# generate user key and certifiacate signing request
openssl genrsa -des3 -out user.key 2048
openssl req -new -key user.key -out user.csr

# generate and sign user certificate using things above
openssl x509 -req -days 365 -in user.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out user.crt

# combine user key and user certificate chain into a bundle
openssl pkcs12 -export -out user.pfx -inkey user.key -in user.crt -certfile ca.crt

The last command will ask you to enter an “Export Password”, and this is the one that you will need to enter when importing the resulting user.pfx into the app. Note that this will create a CA certificate valid for 10 years and a user certificate valid for a year, which is is often too long for user certificates. Adjust to your taste.

Configuring client

Tap on Connection → SSL settngs → Client certificate, enter the above mentioned Export Password, if any, and open or paste the file. If you see “Certificate stored inside security hardware”, you're good to go.

Configuring server: nginx

As WeeChat doesn't support client certificates by itself, you will have to tunnel the connection through something that does. One of the option is to use a web server such as nginx.

It might be not very wise and too complicated for a web server to only ask for a client certificate if you access certain locations. Therefore servers usually ask for the client certificate globally. On a desktop, the browser in this case usually won't actually send the certificate unless it gets an error. On Android, however, browsers will often offer you to submit a certificate from the get-go, which can be annoying. For this reason it might be wise to dedicate a whole subdomain that always requires a client certificate.

For nginx, the additional configuration might looks like this:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name secure.your.website;
    ssl_certificate         /etc/letsencrypt/live/your.website/fullchain.pem;
    ssl_certificate_key     /etc/letsencrypt/live/your.website/privkey.pem;
    ...

    # require a valid client certificate
    ssl_verify_client on;

    # signed by this certificate authority generated by the above code
    ssl_client_certificate /etc/nginx/client-certs/ca.crt;

    location /weechat {
        proxy_pass http://127.0.0.1:9000/weechat;
        ...
    }

Configuring server: stunnel

An easier option perhaps would be to use stunnel to wrap an unencrypted weechat relay connection. The configuration for a relay that is using an unix socket created with /relay add unix.weechat %h/relay_socket might look like this:

[weechat]
accept = 9007
connect = /home/user/.weechat/relay_socket
cert = /etc/letsencrypt/live/your.website/fullchain.pem
key = /etc/letsencrypt/live/your.website/privkey.pem

; our generated certificate authority, same as in the above example
CAfile = /etc/nginx/client-certs/ca.crt

; verify the peer certificate chain starting from the root CA
verifyChain = yes

; limiting SSL version to 1.3 requires Android 10
sslVersion = TLSv1.3
Clone this wiki locally