Table of Contents

OpenSSL CA on Ubuntu server 20.04

OpenSSL is a free, open-source library that you can use for digital certificates. One of the things you can do is build your own CA (Certificate Authority).

A CA is an entity that signs digital certificates. An example of a well-known CA is Verisign. Many websites on the Internet use certificates for their HTTPS connections that were signed by Verisign.

Besides websites and HTTPS, there are some other applications/services that can use digital certificates. For example:

Instead of paying companies like Verisign for all your digital certificates. It can be useful to build your own CA for some of your applications. In this lesson, you will learn how to create your own CA.

Configuration

In this example, I will use an Ubuntu server. The OpenSSL configuration will be similar as on other distributions like CentOS.

Prerequisites

Before we configure OpenSSL, Set the correct hostname/FQDN correctly and make sure that time, date and timezone are correct.

$ hostname
ca

The hostname is “ca”. Let's check the FQDN:

$ hostname -f
ca

It’s also “ca”. Let's change the FQDN; you need to edit the following file for this:

$ sudo vim /etc/hosts 
#Change the following line:
127.0.1.1       ca
#To:
127.0.1.1       ca.example.local ca

Let’s verify the hostname and FQDN again:

$ hostname
ca
 
$ hostname -f
ca.example.local

The hostname and FQDN is looking good.

Change timezone

$ sudo timedatectl
               Local time: Wed 2022-02-02 09:36:44 UTC
           Universal time: Wed 2022-02-02 09:36:44 UTC
                 RTC time: Wed 2022-02-02 09:36:44
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
$ sudo timedatectl set-timezone Europe/Zagreb
$ sudo timedatectl
               Local time: Wed 2022-02-02 10:38:30 CET
           Universal time: Wed 2022-02-02 09:38:30 UTC
                 RTC time: Wed 2022-02-02 09:38:30
                Time zone: Europe/Zagreb (CET, +0100)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
$

Time and date could be configured manually, but it is a better idea to use NTP. You can synchronize the time/date with this command:

$ sudo vim /etc/systemd/timesyncd.conf
# uncomment and modify line: #NTP=
[Time]
NTP=hr.pool.ntp.org
#save the file
$ sudo timedatectl set-ntp off
$ sudo timedatectl set-ntp on
$ sudo systemctl status systemd-timesyncd
● systemd-timesyncd.service - Network Time Synchronization
     Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2022-02-02 10:42:04 CET; 15s ago
       Docs: man:systemd-timesyncd.service(8)
   Main PID: 15260 (systemd-timesyn)
     Status: "Initial synchronization to time server 162.159.200.1:123 (hr.pool.ntp.org)."
      Tasks: 2 (limit: 918)
     Memory: 1.4M
     CGroup: /system.slice/systemd-timesyncd.service
             └─15260 /lib/systemd/systemd-timesyncd
 
Feb 02 10:42:04 ca systemd[1]: Starting Network Time Synchronization...
Feb 02 10:42:04 ca systemd[1]: Started Network Time Synchronization.
Feb 02 10:42:04 ca systemd-timesyncd[15260]: Initial synchronization to time server 162.159.200.1:123 (hr.pool.ntp.org).
$

OpenSSL Configuration

OpenSSL uses a configuration file that is easy to read. There are a couple of things that we will change in it:

# vim /usr/lib/ssl/openssl.cnf

Look for the following section:

[ CA_default ]
 
dir		= ./demoCA
 
#And change it, so it looks like this:
 
[ CA_default ]                                                                                 
 
dir             = /root/ca
 
#Also, find and uncomment:
copy_extensions = copy
#Be careful with the copy_extensions

The “/root/ca” folder is where we will store our private keys and certificates.

You might also want to take a look at the default policy:

[ policy_match ]
countryName		= match
stateOrProvinceName	= match
organizationName	= match
organizationalUnitName	= optional
commonName		= supplied
emailAddress		= optional

Some fields like country, state/province, and organization have to match. If you are building your CA for a lab environment like I am then you might want to change some of these values:

[ policy_match ]
countryName             = match
stateOrProvinceName     = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

I’ve changed it so that only the country name has to match.

Root CA

The first thing we have to do is to create a root CA. This consists of a private key and root certificate. These two items are the “identity” of our CA.

Let’s switch to the root user:

$ sudo su

We will create a new folder which stores all keys and certificates:

$ mkdir /root/ca

In this new folder we have to create some additional sub-folders:

$ cd /root/ca
$ mkdir newcerts certs crl private requests

We also require two files. The first one is called “index.txt”. This is where OpenSSL keeps track of all signed certificates:

$ touch index.txt

The second file is called “serial”. Each signed certificate will have a serial number. I will start with number 1234:

$ echo '1234' > serial

All folders and files are in place. Let’s generate the root private key:

$ openssl genrsa -aes256 -out private/cakey.pem 4096
Generating RSA private key, 4096 bit long modulus
..++
..................++
e is 65537 (0x10001)
Enter pass phrase for private/cakey.pem:
Verifying - Enter pass phrase for private/cakey.pem:

The root private key that I generated is 4096 bit and uses AES 256 bit encryption. It is stored in the private folder using the “cakey.pem” filename.

Anyone that has the root private key will be able to create trusted certificates. Keep this file secure!

We can now use the root private key to create the root certificate:

# openssl req -new -x509 -key /root/ca/private/cakey.pem -out cacert.pem -days 3650 -set_serial 0
Enter pass phrase for /root/ca/private/cakey.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:HR
State or Province Name (full name) [Some-State]:Croatia
Locality Name (eg, city) []:Zagreb
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:CA.example.local
Email Address []:admin@example.local

The root certificate will be saved as the “cacert.pem” filename and is valid for 10 years. If “cacert.pem” is renamed to “cacert.crt”, you can import it to windows trusted root store

Create a certificate - short and with conf and DNS alt names

config.txt
[req]
default_bits = 4096
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
 
[ dn ]
countryName=HR
stateOrProvinceName=Croatia
localityName=Zagreb
organizationName=Company
emailAddress=person@example.com
commonName=fqdn
 
[ req_ext ]
subjectAltName=@alt_names
 
[ alt_names ]
DNS.1=fqdn1
DNS.2=fqdn2
// generate key
openssl genrsa -aes256 -out pwd.key 4096
// apache will ask for key password on each service restart, so you can remove the password
openssl rsa -in pwd.key -out pwdPASSWORDLESS.key
// generate CSR using the config file
openssl req -new -key pwd.key -out pwd.csr -sha256 -config <( cat config.txt )
// check id DNS entry is present
openssl req -noout -text -in pwd.csr | grep DNS:
// sign the CSR
openssl ca -in pwd.csr -out pwd.pem
// check if DNS entry is present in signed certificate
openssl x509 -noout -text -in pwd.pem | grep DNS:
// Combine the full chain (if you can't specify each file separately)
cat {pwd.pem,cacert.pem,pwdPASSWORDLESS.key} > starCOMBINED.pem

Create a certificate

Our root CA is now up and running. Normally when you want to install a certificate on a device (a web server for example), then the device will generate a CSR (Certificate Signing Request). This CSR is created by using the private key of the device.

On our CA, we can then sign the CSR and create a digital certificate for the device.

Another option is that we can do everything on our CA. We can generate a private key, CSR and then sign the certificate…everything “on behalf” of the device.

That’s what I am going to do in this example; it’s a good way to test if your CA is working as expected.

I’ll generate a private key, CSR and certificate for an imaginary “web server”.

Let’s use the requests folder for this:

$ cd /root/ca/requests/

First, we have to generate a private key:

$ openssl genrsa -aes256 -out some_serverkey.pem 2048
Generating RSA private key, 2048 bit long modulus
..............................+++
....+++
e is 65537 (0x10001)
Enter pass phrase for some_server.pem:
Verifying - Enter pass phrase for some_server.pem:

The private key will be 2048 bit and uses AES 256 bit encryption. With the private key, we can create a CSR:

root@ca:~/ca/requests# openssl req -new -key some_serverkey.pem -out some_server.csr
Enter pass phrase for some_serverkey.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country