Skip to content

x509 certificat managment

cover

What are x509 certificates ?

According to Wikipedia, x509 is a standard defining the format of public key certificates. They are used in many Internet protocols, including TLS/SSL, which is the basis for HTTPS (the secure protocol for browsing the web).

Purpose

The purpose of having my own Certification Authority (CA) allow me to generate self signed certificates for non public uses. Hosted services on my own private network prevent me from getting free certificates from well known Let's Encrypt authority.

Since I host more than one service and I want that all my devices (laptop, phone, ...) can have access to them without having to install certificate every 3 weeks (when I'm updating hostnames for exemple). I have decided to create my own CA and generate signed certificates validated by it. That way, I only have to install the root CA on all my device to make it work.

Making my own certification authority

All I need is a linux environment and openssl.

Generating the secret

First let's generate the private key with the following command :

openssl genrsa -out root-CA.key 4096

Ouput :

Generating RSA private key, 4096 bit long modulus
.................................................................++
......................................................................................................................................................................++
e is 65537 (0x10001)

I now have a nice looking private key :

-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEA2IxiR6U/B6Ypd1/3KG5Pxk/BY47HzHpBAHnEFsMHdcpCNNXO
GxqhUsIHBGMc0I2xa0WiyNJB4k5qGwL58J1TK/kKaW8yOOGajawvhjL/6bYXgN1I
[...]
rcL3YJyl/m0mlYl80syPPViHM9TD7uwQi/M9DPeOGLwVuCYzpl3qAkQRaTwQc2Ev
5hffBNz+evhf2Q7iUCmWQFizIFlFpOCq1f/jvpleqf8ChG6EhNRgvAFIUMc=
-----END RSA PRIVATE KEY-----

This file should be kept secret and securelly stored offline.

Generating the certificate configuration

Now that I have the secret part, I need to generate the public part : the x509 certificate. Using the default OpenSSL configuration:

[ req ]
default_bits       = 4096
default_keyfile    = root-CA.key
encrypt_key        = no
utf8               = yes
distinguished_name = req_distinguished_name
prompt             = no
x509_extensions    = v3_ca

[ req_distinguished_name ]
countryName         = FR
stateOrProvinceName = France
localityName        = Paris
organizationName    = Example
commonName          = example.org

[ v3_ca ]
subjectKeyIdentifier = hash
basicConstraints     = critical,CA:true,pathlen:1
keyUsage             = critical,keyCertSign

This configuration should be kept for the next time I need to regenerate the root certificate. Keep in mind that this cert shouldn't be changed too often otherwise it make the main purpose useless.

You can adjust this configuration based on your need.

Generating the root certificate

Using the previous configuration, I have generated the self signed root CA :

openssl req -x509 -new -nodes \
  -config root-CA-openssl.cnf \
  -key root-CA.key \
  -sha256 -days 1024 \
  -out root-CA.crt

Checking the content of the certificate :

openssl x509 -in root-CA.crt -noout -text

Output :

Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 11676879669831540892 (0xa20c9c31654a209c)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=FR, ST=France, L=Paris, O=Example, CN=example.org
        Validity
            Not Before: Feb  6 15:53:58 2022 GMT
            Not After : Nov 26 15:53:58 2024 GMT
        Subject: C=FR, ST=France, L=Paris, O=Example, CN=example.org
[...]
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                F1:FA:C4:50:A4:7F:53:D3:6C:D5:EF:48:72:24:B8:CE:08:10:3F:94
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:1
            X509v3 Key Usage: critical
                Certificate Sign
[...]

This command generate the certificate file and sign its content with the private key.

I now have a Authority Certificate, I can generate all my apps certificates and sign them with it.

Verifying that the certificate and the private key match

Get the checkum of the certificat modulus :

openssl x509 -in root-CA.crt -noout -modulus | sha256sum

Do the same for the private key :

openssl rsa -in root-CA.key -noout -modulus| sha256sum

You should get exactly the same output with both commands :

dc51b8c96c2d745df3bd5590d990230a482fd247123599548e0632fdbf97fc22  -

Creating certificates for my apps

Generating the secret

Same as for the root CA, I need to generate a secret key.

I can use an identical command as earlier :

openssl genrsa -out my-app.key 2048

Generating the openssl config

I now need to create the OpenSSL configuration for my certificate using the default OpenSSL configuration :

[ req ]
default_bits       = 2048
default_keyfile    = my-app.key
encrypt_key        = no
utf8               = yes
distinguished_name = req_distinguished_name
req_extensions     = v3_req
prompt             = no

[ req_distinguished_name ]
countryName         = FR
stateOrProvinceName = France
localityName        = Paris
organizationName    = Example
commonName          = my-app.example.org

[v3_req]
subjectKeyIdentifier = hash
subjectAltName       = @alt_names

[ alt_names ]

DNS.1 = my-app.example.org
DNS.2 = extra.my-app.example.org

Note here that the subjectAltName parameter and the alt_names are very important. Now every browser or phone application require that the hostname exposed by the web application should be specified in this section.

You can still add more than one alternative name to the certificate. This allow you to use the same certificate for multiple application. Make sure to use different certificate based on the security level you need for your apps.

Generating the certificate request

In order to generate a certificate that is signed by my root CA, I need to generate a certificate request. Using the following command, I can generate the request and sign it with the app private key :

openssl req -sha256 -new \
  -key my-app.key \
  -config my-app.cnf \
  -out my-app.csr

I can review the content of my request with :

openssl req -in my-app.csr -noout -text

Output :

Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=FR, ST=France, L=Paris, O=Example, CN=my-app.example.org
[...]

Signing my app certificate with the root CA

Lastly I need to use my root CA to generate my application certificate based on the request and ensure its authenticity.

I only need to use the following command :

openssl x509 -req \
  -CA root-CA.crt \
  -CAkey root-CA.key \
  -CAcreateserial \
  -in my-app.csr \
  -days 500 -sha256 \
  -out my-app.crt

To verify the content of the newly generated certificate, I can run the following conmmand :

openssl x509 -in my-app.crt -noout -text

Output :

Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 15807445207358136962 (0xdb5f53aa27086282)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=FR, ST=France, L=Paris, O=Example, CN=example.org
        Validity
            Not Before: Feb  6 16:22:38 2022 GMT
            Not After : Jun 21 16:22:38 2023 GMT
        Subject: C=FR, ST=France, L=Paris, O=Example, CN=my-app.example.org

Verifiying the full trust chain

Now that I have the certificate for my application, I need to make sure that the root CA validate the authenticity of it.

Using one last openssl command :

openssl verify \
  -CAfile root-CA.crt \
  my-app.crt

Ouput :

my-app.crt: OK

Also with an intermediate certificate :

openssl verify \
  -CAfile root-CA.crt \
  -untrusted intermediate.pem \
  my-app.crt