Certificates
A certificate is a key with a signature attached. The signature comes from a Certificate Authority (CA), and it asserts that the public key inside the certificate genuinely belongs to the person or device named in it. Without that signature, a key is just a number. With it, other systems have a basis for trusting it.
In the public internet, that trust chain runs back to a handful of root CAs whose certificates are baked into your operating system and browser. In this network, it runs back to a CA you control, built later in this series. The mechanics are identical. The difference is that you are the one doing the signing.
This page covers generating Certificate Signing Requests (CSRs), which is what you send to a CA when you want a certificate issued. There are two types covered here: personal user certificates, which identify a person and are used for things like encrypted mail and website logins, and client device certificates, which identify a specific machine and are used for things like VPN authentication.
Preparations
Create a directory structure to keep keys, CSRs, and certificates organised:
mkdir -p ~/.ssl/{certs,private}
chmod 700 ~/.ssl/private
Set a couple of environment variables that the OpenSSL configs below will use. Replace these with your actual hostname and email address:
export CN=$HOSTNAME.yourdomain.net
export emailAddress=you@yourdomain.net
Personal user certificate
A personal certificate identifies you as a person. It can be used to authenticate to websites that support certificate-based login, and to sign and encrypt email via S/MIME. It includes your name and email address in the certificate metadata.
OpenSSL configuration
Create the file ~/.ssl/openssl-user.cnf with the following content, updating the distinguished name fields to match your details:
#
# OpenSSL configuration for personal user certificate requests.
#
# Requires the following environment variables to be set:
# export emailAddress=you@yourdomain.net
#
emailAddress = $ENV::emailAddress
HOME = $ENV::HOME/.ssl
RANDFILE = $HOME/private/.rnd
oid_section = new_oids
[ new_oids ]
xmppAddr = 1.3.6.1.5.5.7.8.5
[ req ]
default_bits = 4096
default_keyfile = $HOME/private/$emailAddress.key.pem
encrypt_key = yes
default_md = sha256
req_extensions = user_req_ext
prompt = no
distinguished_name = req_distinguished_name
string_mask = utf8only
utf8 = yes
[ user_req_ext ]
keyUsage = digitalSignature
extendedKeyUsage = clientAuth, emailProtection
subjectKeyIdentifier = hash
subjectAltName = @subj_alt_names
[ req_distinguished_name ]
countryName = GB
stateOrProvinceName = England
localityName = Manchester
organizationName = yourdomain.net
Name = Your Name
emailAddress = $emailAddress
[ subj_alt_names ]
email = $emailAddress
otherName = xmppAddr;UTF8:$emailAddress
Set it as the active OpenSSL config:
export OPENSSL_CONF=~/.ssl/openssl-user.cnf
Certificate signing request
Generate the key and CSR together:
openssl req -new -out ~/.ssl/$emailAddress.req.pem
OpenSSL will prompt you for a passphrase to protect the private key. Use a six-word Diceware passphrase as covered in the passphrases section.
Lock down the private key file:
chmod 400 ~/.ssl/private/$emailAddress.key.pem
Verify the CSR looks correct before sending it anywhere:
openssl req -verify -in ~/.ssl/$emailAddress.req.pem \
-noout -text -nameopt multiline \
-reqopt no_version,no_pubkey,no_sigdump
Send ~/.ssl/you@yourdomain.net.req.pem to your CA for signing. The CA section of this series covers what happens on the other end of that process.
Client device certificate
A device certificate identifies a specific machine rather than a person. This is used primarily for VPN authentication, but can also be used for other services that support mutual TLS. The key distinction from a personal certificate is scope: if a device is lost or stolen, its certificate can be revoked without affecting any other device or user.
This is a meaningfully better approach than using the same credential across multiple devices. One compromised device, one revocation, done.
OpenSSL configuration
Create ~/.ssl/openssl-client.cnf, again updating the distinguished name fields:
#
# OpenSSL configuration for client device certificate requests.
#
# Requires the following environment variables to be set:
# export CN=${HOSTNAME}.yourdomain.net
# export emailAddress=you@yourdomain.net
#
emailAddress = $ENV::emailAddress
CN = $ENV::CN
HOME = $ENV::HOME/.ssl
RANDFILE = $HOME/private/.rnd
oid_section = new_oids
[ new_oids ]
id-on-xmppAddr = 1.3.6.1.5.5.7.8.5
[ req ]
default_bits = 4096
default_keyfile = $HOME/private/$CN.key.pem
encrypt_key = yes
default_md = sha256
req_extensions = device_req_ext
prompt = no
distinguished_name = req_distinguished_name
string_mask = utf8only
utf8 = yes
[ device_req_ext ]
keyUsage = digitalSignature
extendedKeyUsage = clientAuth
subjectKeyIdentifier = hash
subjectAltName = @subj_alt_names
[ req_distinguished_name ]
countryName = GB
stateOrProvinceName = England
localityName = Manchester
commonName = $CN
name = Your Name
emailAddress = $emailAddress
[ subj_alt_names ]
DNS.1 = $CN
email = $emailAddress
otherName = xmppAddr;UTF8:$emailAddress
Set it as active:
export OPENSSL_CONF=~/.ssl/openssl-client.cnf
Certificate signing request
Generate the key and CSR:
openssl req -new -out ~/.ssl/$CN.req.pem
Lock down the private key:
chmod 400 ~/.ssl/private/$CN.key.pem
Verify the request:
openssl req -verify -in ~/.ssl/$CN.req.pem \
-noout -text \
-reqopt no_version,no_pubkey,no_sigdump \
-nameopt multiline
Send ~/.ssl/hostname.yourdomain.net.req.pem to your CA for signing.
Using the signed certificate
Once the CA returns a signed certificate, you will have a file ending in .cert.pem. To inspect it:
openssl x509 -in $CN.cert.pem \
-noout -text \
-certopt no_version,no_pubkey,no_sigdump \
-nameopt multiline
To verify it against your CA chain:
openssl verify -issuer_checks -policy_print -verbose \
-untrusted intermed-ca.cert.pem \
-CAfile root-ca.cert.pem \
certs/$CN.cert.pem
A clean verification confirms the certificate chains correctly back to your root CA. If it does not, check that you are using the correct intermediate and root CA files, and that the certificate was actually signed by your CA rather than an old test certificate.
Keep the private key and the signed certificate together but separately from anything you distribute. The
.cert.pemfile is safe to share. The.key.pemfile is not.