---
title: x509 certificat managment
date: 2022-02-06
slug: manage-x509-certs
authors:
- lunik
description: Presentation and managment of a Root Certificate Authority
tags:
- certificate
- openssl
- x509
- private_key
- public_key
- rsa
- pem
- cert
related_posts:
  - ssh-ca-authentication
  - install-custom-ca-on-ios
  - understanding-totp
---

<!--
# CHANGELOG

14/01/2024 - Fix options in my-app.cnf

-->

![cover](/blog/img/posts/2022-02-06-manage-x509-certs/cover.png)

## What are x509 certificates ?

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

<!-- truncate -->

## 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][lets-encrypt-website].

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`][openssl-tool-website].

### Generating the secret

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

```shell
openssl genrsa -out root-CA.key 4096
```

Ouput :

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

I now have a nice looking private key :

```shell
-----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][x509-rfc]. Using the [default OpenSSL configuration][openssl-default-conf]:

```toml
[ 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 :

```shell
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 :
```shell
openssl x509 -in root-CA.crt -noout -text
```

Output :

```shell
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** :

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

Do the same for the private key :

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

You should get exactly the same output with both commands :

```shell
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 :

```shell
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][openssl-default-conf] :

```toml
[ 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 :

```shell
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 :

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

Output :

```shell
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 :

```shell
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 :

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

Output :

```shell
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 :

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

Ouput :

```shell
my-app.crt: OK
```

Also with an intermediate certificate :

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


<!-- links -->

[x509-wikipedia]: https://en.wikipedia.org/wiki/X.509
[x509-rfc]: https://datatracker.ietf.org/doc/html/rfc5280
[tls-rfc]: https://datatracker.ietf.org/doc/html/rfc8446
[https-rfc]: https://datatracker.ietf.org/doc/html/rfc2818
[lets-encrypt-website]: https://letsencrypt.org
[openssl-tool-website]: https://www.openssl.org
[openssl-default-conf]: https://github.com/openssl/openssl/blob/master/apps/openssl.cnf
