A Certificate Authority (CA) can be used to create:
self-signed, server-side certs for use on servers on a home network
self-signed, client-side certs for devices allowed to connect to your home servers, such as smartphones, tablets and laptops connecting from within or outside the home network
A certificate has a public key and a private key. The two keys are used to verify the identity of a web site, server or client device.
For a more complete explanation of why a Certificate Authority is required, please see the page Self-Signed Certificates. In summary, creating a Certificate Authority (CA), is the pre-requisite step to creating self-signed certs.
Required Parts:
Any model of Raspberry Pi running the latest version of Raspberry Pi OS with ssh enabled
Step 2. Download Script
Creating a certificate authority's key and certificate is not that difficult. It can be done in one-line.
However, I started scripting the self-signed certs and thought I should continue that here.
Get the script by running the commands:
$ cd ~/.
$ pwd
/home/pi
$ mkdir certs # the directory should match value for MYCERTS in private-data.sh
$ cd certs
$ wget https://raw.githubusercontent.com/dumbo25/garage-door/main/home/pi/certs/ca-certs.sh
$ wget https://raw.githubusercontent.com/dumbo25/garage-door/main/home/pi/certs/private-data.sh
Step 3. Edit the Private Date and the Script
There are several UPPERCASE variables you should or may want to change for your project.
Notes:
The Common Name (aka prompt for FQDN) cannot be the same for the Certificate Authority, server or client. Using the same name will cause a later check to fail (error 18 at 0 depth).
openssl verify isn't used to validate the CA cert
$ nano private-data.sh
Create and enter your CA PEM Key password = ♣pem-pass-phrase♣
Step 4. Execute the Script
Once private-data.sh has been edited to use your values, execute the script:
$ sudo bash ca-certs.sh
You should have the following, which are output at the end of the script:
♣cacert♣ path and filename
♣cakey♣
Step 5. Add cron to check when CA Cert is expiring
Get the script:
$ cd ~/certs
$ wget https://raw.githubusercontent.com/dumbo25/garage-door/main/home/pi/certs/cert-check.py
Edit cron to run at every day:
$ sudo crontab -e
# check if cert is expiring at 12:05pm every day and send email if within 14 days of expiring
5 12 * * * python3 /home/pi/certs/cert-check.py -c "♣cacert♣" -d 14
Step 6. Apache Config File
Edit the apache2 configuration file:
$ sudo nano /etc/apache2/sites-available/default-ssl.conf
change the following lines to:
#SSLCACertificatePath /etc/ssl/certs/
#SSLVerifyClient require
#SSLVerifyDepth 10
to:
SSLCACertificatePath /home/pi/certs/
# the following line enables client verification - this must be done !
SSLVerifyClient require
SSLVerifyDepth 2
The path to ♣cacert♣ is defined in private-data.sh and is /etc/ssl/certs/
Step 7. You're Done!
Setting up a Certificate Authority doesn't do anything of value, unless it is combined with other guides to generate self-signed certs.
As an example, go to Restrict access to Web Server, or return to whatever guide sent you here.
Path, Key and Certificate Naming Conventions:
The CA files stay on the server. So, there is no real need to uniquely identify the certs.
CA Cert File
/home/pi/certs/ca-cert.pem
/etc/ssl/certs/ca-cert.pem
CA Cert Key
/home/pi/certs/ca-key.pem
/etc/ssl/private/ca-key.pem
Configuration File
/etc/ssl/openssl.cnf
Background [you can skip]:
Work:
In my day job, I manage a team of developers. I started doing Raspberry Pi projects as a way to understand some of the complexities my team faces.
At work, certs are an on-going, constantly evolving topic.
My work systems have a relatively complex hierarchy of root, intermediate and leaf or node certs. There are hundreds of thousands of devices deployed, which work with millions of customer devices on a daily basis. The systems are deployed in layers of trust (e.g., red, orange, yellow, green). For example, the red zone is accessible via the internet. Orange is the DMZ. And then there are multiple types of users with different privileges and access. Servers are treated similarly to users.
Many of my work systems have multiple certs, because each has a well-defined and limited role in a particular type of authentication. And, to add to the madness, many of the certs are updated at very short intervals. Of course all of the cert creation is scripted, the checks are all automated, and so are the updates. However, a device may go offline for a variety of reasons, and miss its cert update. The team is alerted when a cert is approaching its expiration date. Significant issues occur when the certs fail or expire. Of course, there is always someone who creates a cert and isn't aware of everything in place to handle certs.
In addition, browsers and smart phones are improving their security and may change how certificates need to be generated (.e., certificate transparency)
At work, my team uses a recognize certificate authority.
Home:
On my home network, I don't have a recognized certificate authority and my servers do not have Fully Qualified Domain Names (FQDNs).
My home LAN use Port Address Translation (PAT), which means the public IP of my ISP's gateway can forward a port to a server on my home network.
Since my home servers do not have FQDNs, they do not use DNS. An FQDN is required to setup a Certificate Authority. Instead of using a recognized Certificate Authority (CA), I create my own CA.
With linux, I can get things done, and not even be close to doing it the "right way", but, "Hey, it works for me!"
This seems to be why I am always rewriting or updating these guides. I learn new things. I find different ways to do things. I find something that is closer to being the correct way.
I guess my point is Linux is very flexible, which is great.
Notes:
A Certificate Authority (CA) only needs to be setup one time. After the CA is set up, it can be used to generate multiple certs. So, only do this once.
The script checks if the CA has already been setup and will prompt if you want to continue.
I create a CA on each server that requires one. However, one CA could be created for your home LAN.
If the cert expires, then this script can be run again to replace the expiring cert
Browsers will not trust certs generated from this CA
In general, trusted CA certificates are added to a main trust store at etc/ssl/certs/ca-certificates.crt.
The main trust store is updated through either through:
$ update-ca-certificates
or reconfiguring the ca-certificates package using:
$ dpkg-reconfigure ca-certificates
However, the CA generated in this guide should not be added to the trust store because the trust store is for CAs from other servers
If the server becomes compromised, then a CA for Revocation List or crl should be created to revoke the cert. If this happens, I would reflash the microSD Card and start over. So, I am not going to create a crl. There are some good guides for crls in References at the end of this guide.
Troubleshooting:
Find path to openssl files:
$ openssl version -d
OPENSSLDIR: "/usr/lib/ssl"
$ ls -l /usr/lib/ssl
total 4
lrwxrwxrwx 1 root root 14 Apr 27 2020 certs -> /etc/ssl/certs
drwxr-xr-x 2 root root 4096 Aug 20 05:32 misc
lrwxrwxrwx 1 root root 20 Apr 27 2020 openssl.cnf -> /etc/ssl/openssl.cnf
lrwxrwxrwx 1 root root 16 Apr 27 2020 private -> /etc/ssl/private
Show symlinks:
$ ls -l /usr/lib/ssl
Check expiration date on cert:
$ sudo openssl x509 -enddate -noout -in /home/pi/certs/ca-crt.pem
References:
Notes on references:
Browsers and phones are constantly updating their security. Steps that may have worked in the past may fail because of enhanced security. When googling a solution always use Tools, and set Anytime to Past Year.
Semurity, How to Setup your Own Certificate Authority (CA) using OpenSSL, best explanation for how to setup a Certificate Authority
SuperUser: JW0914's answer, OpenSSL CA keyUsage extension, great explanation of what is required by CA
OpenSSL.org, OpenSSL Release Strategy, The current version of openssl is 1.1.1 ($ openssl version). 3.0.0 is the next release. Alpha7 of 3.0.0 (pre-release version) came out in October, 2020. Version 1.1.1 will be supported until 2023-09-11. The 3.0 version is expected in early 4Q2020.
OpenSSL.org, openssl command, man page
OpenSSL.org, openssl ca, sample, minimal certificate authority
StackExchange, Bryan Field, How to make secure communication between servers, There are several solutions, pick only one: 1) Shared Secret, 2) Client certificate as part of the TLS connection, 3) Time-of-day with encryption, or 4) Challenge response. Note: my systems use a self-signed, client-side cert, or 2).
OpenSSL.org, X509 V3 certificate extension configuration format, explains the format and options in an .ext or configuration file
StackOverflow, best description of how to setup a CA, see the answers
StackOverflow: JellicleCat's bash script, Getting Chrome to accept self-signed localhost certificate, simple bash script to create a CA
curl.se, SSL Certificate Verification, shows how to verify CA cert
JamieLinux, Certificate Revocation Lists, excellent description of how to setup and use CRLs
StackExchange, answer from RubberStamp, Entrusted Certificates installation, How to add certs to the trust store
github, Matty9191, SSL Certification Expiration Checker, cron script to check if cert expired and send email
Non-OpenSSL approaches:
ubunutu.com, GnuTLS, Guide for installing and using Gnu tools to create certificate authority and self-signed certs
Linux Babe, Set Certificate Authority using GnuUtils, openssl isn't the only way to set up a certificate authority
Apache Infrastructure, uses gpg to create self-signed certs, alternate to openssl
Linux Babe, Practical Guide to GPG, step-by-step guide