Stage 3 · Build
TLS & Certificate Management
X.509 Certificates
Certificate structure, SANs, CA chains, intermediate certs, and trust stores.
Certificate Structure
An X.509 certificate is a signed statement binding a public key to an identity. It contains the subject (who), the issuer (who signed it), validity dates, the public key, and extensions that define how the certificate can be used.
# View certificate details
openssl x509 -in cert.pem -text -noout
# Key fields you will see:
# Subject: CN=example.com, O=Example Inc
# Issuer: CN=R3, O=Let's Encrypt
# Not Before: Jan 1 00:00:00 2024 GMT
# Not After : Apr 1 00:00:00 2024 GMT
# Subject Alternative Name: DNS:example.com, DNS:*.example.com
# Public Key Algorithm: rsaEncryption (2048 bit)
# Signature Algorithm: sha256WithRSAEncryptionThe Subject was historically the primary identifier, but modern certificates use the Subject Alternative Name (SAN) extension. Browsers check SAN, not CN, for hostname matching.
Subject Alternative Names
SANs define which hostnames the certificate is valid for. A single certificate can cover multiple domains and wildcards. This is how one certificate protects both example.com and www.example.com.
# DNS name
DNS:example.com
DNS:www.example.com
DNS:*.example.com # wildcard (single level)
# IP address
IP:192.168.1.1
IP:10.0.0.1
# Email
email:admin@example.com
# URI
URI:https://example.com/.well-known/...The wildcard *.example.com matches api.example.com, www.example.com, etc. but not example.com itself or sub.api.example.com. You need a separate SAN for the bare domain.
TLS clients match the hostname from the URL against the SANs in the certificate. If no SAN is present, some clients fall back to CN. Always include SANs — do not rely on CN alone.
CA Hierarchy and Chain of Trust
Certificate Authorities (CAs) form a hierarchy. Root CAs are trusted by operating systems and browsers. Intermediate CAs issue end-entity certificates. The chain of trust goes: Root CA -> Intermediate CA -> Your Certificate.
ISRG Root X1 (Root CA - in trust store)
|
+-- R3 (Intermediate CA)
|
+-- example.com (End-entity certificate)
+-- api.example.com
+-- www.example.com
The certificate chain:
1. Your certificate (issued to example.com)
2. Intermediate cert (R3, signed by ISRG Root X1)
3. Root cert (ISRG Root X1, self-signed)Your server sends the full chain (your cert + intermediates) during the TLS handshake. The client verifies each link up to a root CA in its trust store. Missing intermediate certificates cause chain validation failures.
# Check the full chain
openssl s_client -connect example.com:443 -showcerts
# Verify the chain against the system trust store
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt chain.pem
# Check which intermediate certificates are present
openssl x509 -in cert.pem -noout -issuer
openssl x509 -in intermediate.pem -noout -issuerThe -showcerts flag shows every certificate in the chain. If you see only one certificate, the server is not sending the intermediate — this is a common misconfiguration.
Trust Stores
Trust stores are collections of root CA certificates that the operating system or application trusts. Each platform maintains its own trust store — browsers often have their own too (Firefox uses NSS, not the OS store).
# Linux (Ubuntu/Debian)
/etc/ssl/certs/ca-certificates.crt
# Linux (RHEL/CentOS)
/etc/pki/tls/certs/ca-bundle.crt
# macOS
security find-certificate -a /System/Library/Keychains/SystemRootCertificates.keychain
# Java
$JAVA_HOME/lib/security/cacerts
# Firefox (NSS)
cert9.db in Firefox profile directoryWhen you add a custom CA (for internal services or corporate proxies), you need to add it to the trust store of every application that will encounter it. Some applications (like curl with --cacert) use their own trust store.
A certificate trusted by curl may not be trusted by your browser. Java applications use their own cacerts file. Docker containers have their own trust store. When debugging trust issues, check which trust store the specific application uses.
Certificate Lifecycle
| Stage | What Happens | Tool |
|---|---|---|
| Generate key | Create private key | openssl genrsa, ec |
| Create CSR | Certificate Signing Request | openssl req |
| Sign certificate | CA validates and signs | Let's Encrypt, internal CA |
| Deploy | Install cert + chain on server | Copy to server, configure TLS |
| Monitor | Check expiry dates | certbot certificates, openssl |
| Renew | Get new cert before expiry | certbot renew, cert-manager |
| Revoke | Invalidate compromised cert | CA revocation API |
# Check expiry for a remote server
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -dates
# Check all certificates in a chain
echo | openssl s_client -connect example.com:443 -showcerts 2>/dev/null | \
grep -E "Not (Before|After)"
# Check local certificate file
openssl x509 -in cert.pem -noout -datesSet up monitoring for certificate expiry. Expired certificates cause browser warnings and connection failures. Let's Encrypt certificates expire after 90 days — automate renewal.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.