The Zerofox Syndicate

Create a Self Signed Certificate

2019-11-08

So how should you create a self-signed certificate?

The Common Way

This is the top voted and accepted answer on Stack Overflow.

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365

I prefer not getting prompted for options so I prefer to add the -subj flag.

openssl req -x509 -newkey rsa:4096 -nodes -days 365 -utf8 \
    -subj "/C=US/ST=MyState/L=MyCity/O=MyCompany/OU=Org/CN=mydomain.com" \
    -keyout key.key -out cert.pem

Using this is relatively straightforward, just replace your own options with everything after -subj.

Why isn’t this perfect?

The issue here is that it is still using CN, the Common Name field, and no Subject Alternative Name (SAN). This has been deprecated since the year 2000 when RFC 2818 was published. Browsers have also started to block certificates that do not provide a SAN and only a CN. CN-only certificates are no longer supported in Firefox 48 and Chrome 58.

This means even if you decide to add this certificate to your certificate store, this certificate will still give you error messages that you cannot get rid of.

The Alt Way

To add the Subject Alternative Name to a certificate, it used to be necessary to edit some configuration files. This is no longer necessary. Since openssl version 1.1.1 you can do everything with one command (taken from this stackoverflow answer).

openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
    -keyout example.key -out example.crt -subj /CN=example.com \
    -addext subjectAltName=DNS:example.com,DNS:example.net,IP:10.0.0.1

Note that you can specify multiple DNS names and also IP addresses. This is how https://1.1.1.1/ manages to have a working certificate.

Below is a pre-1.1.1 version of this command. (I didn’t test this.)

openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
    -keyout example.key -out example.crt -extensions san -config \
    <(echo "[req]"; 
        echo distinguished_name=req; 
        echo "[san]"; 
        echo subjectAltName=DNS:example.com,DNS:example.net,IP:10.0.0.1
        ) \
    -subj /CN=example.com

openssl req

This is the utility to request and generate PKCS#10 requests. See man 1 req.

-x509   # used to create a self-signed test or rootCa cert.
-nodes  # don't encrytp it (with DES).
-newkey # create a new certificate request and private key.
-utf8   # field values should be interpreted as UTF-8. (ASCII is the default)
-days   # by default this is 30 days.

Configuring TLS/SSL

Now that you have your certificates. How are you going to deploy them?

Generate a strong Diffie-Hellman group

A self-signed certificate and key file are usually not enough for a good SSL config. That’s why I’m also including the instructions on how to generate a Diffie-Hellman group. Here’s how to generate a dhparams.pem file.

openssl dhparam -out dhparams.pem 2048

See also: weakdh.org

Ngircd example config

A lot of software supports SSL/TLS. Here is just an example config for ngircd I tested. From etc/ngircd.conf:

[SSL]
    # SSL Server Key Certificate
    CertFile = /opt/ngircd/etc/example.crt

    # Diffie-Hellman parameters
    DHFile = /opt/ngircd/etc/dhparams.pem

    # SSL Server Key
    KeyFile = /opt/ngircd/etc/example.key
    Ports = 6697

Test by connecing with IRSSI.

/connect -tls localhost 6697

The above command does not verify the TLS certificate. The following command does.

/connect -tls -ssl_verify localhost 6697

IRSSI won’t connect because it is not possible to verify the self-signed certificate. I suggest using -ssl-verify on networks that do not have self-signed certificates to prevent MitM attacks.

Tags: cryptography