PKI CA
A PKI (Public Key Infrastructure) Certificate Authority (CA) is an entity that issues digital certificates. These certificates verify the identity of individuals, organizations, or devices. The CA signs the certificates using its private key, ensuring their authenticity.
When should you create one?
I am creating one to secure connections between some IoT devices that I am working on. Instead of sharing custom symmetric secrets, that can leak from the deployed devices, I will create a root certificate that will be installed on every server and device. This way I have one single publicly accessible and not critical information (public certificate) that can be used to validate other certificates. Each device can have its own certificate that can be revoked at any time.
How did I configure it using OpenSSL?
My requirements for a CA are as follows:
- simple,
- allows further automation inside a CI/CD,
- not for nuclear launch codes.
So I decided on a single Root CA certificate stored on a server without any extra hardware security that will be used to issue further encryption certs.
OpenSSL provides a utility ideal for this scenario, that implements a crude CA: openssl-ca - sample minimal CA application
.
To use it first we need to create:
./CA/private
folder for storing the Root CA key./CA/newcerts
folder for storing issued certificates./CA/serial
file with a number (in hex) from which the new certificates should be numbered (for example01
)./CA/index.txt
file for the issued certificates database./openssl-ca.conf
file with theopenssl ca
configuration
./openssl-ca.conf
The content of the file is taken straight from the man pages of openssl-ca
(with slight modifications done for my use case)
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
dir = ./CA # top dir
database = $dir/index.txt # index file.
new_certs_dir = $dir/newcerts # new certs dir
certificate = $dir/cacert.pem # The CA cert
serial = $dir/serial # serial no file
#rand_serial = yes # for random serial#'s
private_key = $dir/private/cakey.pem # CA private key
default_days = 730 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = sha256 # SHA256 to use
policy = policy_any # default policy
email_in_dn = no # Don't add the email into cert DN
unique_subject = no # Entries may have the exact same subject
name_opt = ca_default # Subject name display option
cert_opt = ca_default # Certificate display option
copy_extensions = none # Don't copy extensions from request
[ policy_any ]
countryName = supplied
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
Root Certificate
First I created the private key for the Root CA certificate:
openssl genpkey -algorithm Ed25519 -out private/cakey.pem
Where:
- I used Ed25519 as the cryptography algo for the key. Why this one? Because the keys are smaller then RSA. Why not other ECC algorithms? Because cryptography algorithms are like milk. There are many variants: full-fat, chocolate, etc. Just make sure you’re not using an expired one!
Then I created a signing request:
openssl req -new -key private/cakey.pem -out private/cacert.csr
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]:PL
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Halidelabs
Organizational Unit Name (eg, section) []:Halidelabs Root CA
Common Name (e.g. server FQDN or YOUR name) []:Halidelabs Root CA
Email Address []:contact@halidelabs.eu
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Then I self-signed the request using my previous generated private key:
openssl req -x509 -days 7300 -key private/cakey.pem -in private/cacert.csr -out cacert.pem
Where:
- I specified to generate a x.509 type certificate
- I issued the certificate for 7300 days (20 years)
Issuing further certificates
Now, to create certificates for a service (for example, an Nginx server), we need to:
- Generate a private key
openssl genpkey -algorithm Ed25519 -out nginx-key.pem
- Generate a certificate signing request
openssl req -new -key nginx-key.pem -out nginx.csr -subj "/C=PL/CN=example.com"
- Sign the certificate
openssl ca -config openssl-ca.conf -in nginx.csr
The newly created certificate will be configured according to the openssl-ca.conf
file and stored in ./CA/newcerts/01.pem
.
Number in the ./CA/serial
file will be incremented.
The issued certificate number and other information will be stored in the ./CA/index.txt
file.