Certificate Authority (CA)
Transport Layer Security (TLS) secures internet communication by encrypting traffic between client and server. Server identity is verified using a certificate issued by a trusted Certificate Authority (CA).
A Certificate Authority (CA) is a trusted organization (e.g. ISRG ROOT, Let's Encrypt) that issues digital certificates to verify the owner of a domain. When a client accesses a server, the server provides its certificate. The client then validates the certificate by checking if the certificate is:
- signed by a trusted root CA or an intermediate CA that chains up to a trusted root CA
- not expired based on its
NotBefore
andNotAfter
fields - issued for the domain the client is trying to access by verifying the Subject Alternative Name (SAN) or, if absent, the Common Name (CN)
- not revoked, using CRL (Certificate Revocation List) or OCSP (Online Certificate Status Protocol)
Most modern operating systems and browsers maintain a set of trusted root CAs.
Example of a certificate chain:
Root CA (e.g. ISRG Root X1)
├─── Intermediate CA (e.g. Let's Encrypt R3)
│ ├─── Server Certificate (e.g. hello-world-1.com)
│ └─── Server Certificate (e.g. hello-world-2.com)
└─── Intermediate CA (e.g. Let's Encrypt E1)
├─── Server Certificate (e.g. hello-world-3.com)
└─── Server Certificate (e.g. hello-world-4.com)
Tinkering with Certificates using OpenSSL
DANGER
Never expose a private key! The private keys and certs below are just some examples on how they look like.
Below a short tinkering with OpenSSL to generate a Root CA, an Intermediate CA, and a Server Certificate which will work together. Note that the Root CA is self-signed and browsers will not trust it unless it is added to the browser's trust store.
Generating a Root CA Certificate
CA certificate must have CA:TRUE
to be able to sign other certificates. keyCertSign
and cRLSign
are required for signing other certificates.
openssl genpkey -algorithm RSA -out rootCA.key
openssl req -x509 -new -nodes -key rootCA.key \
-sha256 -days 3650 -out rootCA.crt -subj "/CN=My Root CA" \
-extensions v3_ca -config <(echo "[ v3_ca ]"; echo "basicConstraints = critical,CA:TRUE"; echo "keyUsage = critical, keyCertSign, cRLSign")
Generating an Intermediate CA Certificate
Intermediate CA is signed by the Root CA. The CA:TRUE
and pathlen:0
constraints are set to prevent the Intermediate CA from signing other CA certificates.
openssl genpkey -algorithm RSA -out intermediateCA.key
openssl req -new -key intermediateCA.key -out intermediateCA.csr -subj "/CN=My Intermediate CA"
openssl x509 -req -in intermediateCA.csr -CA rootCA.crt -CAkey rootCA.key \
-CAcreateserial -out intermediateCA.crt -days 1825 -sha256 \
-extensions v3_ca -extfile <(echo "[ v3_ca ]"; echo "basicConstraints = critical,CA:TRUE,pathlen:0"; echo "keyUsage = critical, keyCertSign, cRLSign")
# Certificate request self-signature ok
# subject=CN=My Intermediate CA
Generating a Server Certificate
CA:FALSE
ensures that certificate can not act as CA. serverAuth
ensures that the certificate is a valid server certificate.
openssl genpkey -algorithm RSA -out server.key
openssl req -new -key server.key -out server.csr -subj "/CN=example.com"
openssl x509 -req -in server.csr -CA intermediateCA.crt -CAkey intermediateCA.key \
-CAcreateserial -out server.crt -days 365 -sha256 \
-extensions v3_end -extfile <(echo "[ v3_end ]"; echo "basicConstraints = critical,CA:FALSE"; echo "keyUsage = critical, digitalSignature, keyEncipherment"; echo "extendedKeyUsage = serverAuth")
# Certificate request self-signature ok
# subject=CN=example.com
Playing with the Certificates
Validating the intermediate CA certificate:
openssl verify -CAfile rootCA.crt intermediateCA.crt
# intermediateCA.crt: OK
Verify if server certificate is valid and gets chained up to the Root CA:
openssl verify -CAfile rootCA.crt -untrusted intermediateCA.crt server.crt
# server.crt: OK
Get expiration date of server certificate:
openssl x509 -enddate -noout -in server.crt
# notAfter=Feb 19 15:41:31 2026 GMT
Bundling Certificates
To properly provide necessary certificates during the TLS handshake, the certificate chain must be bundled into one file. The .pem
ending is often used for chains where multiple certificates are bundled together.
cat server.crt intermediateCA.crt > server-chain.pem
This then can be used for example for a nginx web server:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/server-chain.pem;
ssl_certificate_key /path/to/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
}