iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

PKI & Certificates

Public Key Infrastructure binds identities to public keys via a chain of trust. Certificates, certificate authorities (CAs), and the chain rules underpin HTTPS, code signing, mTLS, and SSH certificates — understanding the pieces means you can debug and ship modern trust systems.

CA chains, X.509, mTLS, key rotation

EXAMPLE
# 1) Generate a self-signed cert (dev only)
openssl req -x509 -newkey rsa:3072 -sha256 -days 365 \\
    -keyout key.pem -out cert.pem -nodes \\
    -subj '/CN=localhost' \\
    -addext 'subjectAltName=DNS:localhost,IP:127.0.0.1'

# 2) Real production = Let's Encrypt / your cloud's managed certs
# Manual via certbot:
sudo certbot certonly --webroot -w /var/www/html -d example.com -d www.example.com
# Or via DNS-01 challenge for wildcard:
sudo certbot certonly --dns-cloudflare -d '*.example.com' -d example.com
# Renewal: certbot renew --quiet  (run via cron / systemd timer; renews in last 30 days of validity)

# 3) Anatomy of an X.509 certificate
openssl x509 -in cert.pem -text -noout
# Key fields:
#   Subject:           who the cert identifies (CN=example.com, often legacy)
#   Subject Alternative Name (SAN):  the actual hostnames it covers — CN is ignored by modern browsers
#   Issuer:            who signed it (the CA)
#   Not Before / Not After: validity window
#   Public Key:        the public part of a key pair
#   Signature Algorithm: SHA256-RSA, ECDSA, Ed25519, etc.
#   Extensions:        keyUsage, extendedKeyUsage, basicConstraints, AIA, CRL distribution points
#
# Browsers and OS root stores trust a small set of CAs; CAs sign intermediate CAs; intermediates sign
# leaf (server) certs. The CHAIN is what's served, not just the leaf.

# 4) Chain of trust
# Browser ← leaf cert (yours)
#                 ↑ signed by
#         intermediate CA (e.g. Let's Encrypt R3)
#                 ↑ signed by
#         root CA (e.g. ISRG Root X1)  ← preinstalled in browser/OS
#
# Server must send leaf + intermediate(s). Root is in the client.
# Missing intermediate → 'unable to get local issuer certificate' errors.

# 5) Check a server's chain
openssl s_client -connect example.com:443 -servername example.com -showcerts < /dev/null
# Look for multiple BEGIN CERTIFICATE blocks; intermediates should be present.
# Online: ssllabs.com/ssltest grades the entire setup.

# 6) Modern web TLS — recommended defaults
# Cert: ECDSA P-256 with RSA fallback for old clients (rare in 2025)
# Protocols: TLS 1.3 (preferred), TLS 1.2 (fallback)
# Ciphers (TLS 1.2): ECDHE-ECDSA / ECDHE-RSA with AES-GCM or ChaCha20-Poly1305
# HSTS: max-age=31536000; includeSubDomains; preload
# OCSP stapling: enabled

# Generate ECDSA key + CSR
openssl ecparam -name prime256v1 -genkey -noout -out key.pem
openssl req -new -key key.pem -out csr.pem -subj '/CN=example.com' \\
    -addext 'subjectAltName=DNS:example.com,DNS:www.example.com'

# 7) mTLS — client certificates (machine identity)
# Server config (nginx):
# server {
#     ssl_client_certificate /etc/nginx/client-ca.pem;
#     ssl_verify_client on;                            # require + verify
#     ssl_verify_depth 2;
#     ...
# }
#
# Client connects with its own cert + private key. Server verifies the chain back to client-ca.pem.
# Used for internal service-to-service auth, partner APIs, IoT.

# 8) Build a tiny internal CA (for dev / mTLS)
openssl genrsa -aes256 -out ca-key.pem 4096
openssl req -x509 -new -nodes -key ca-key.pem -sha256 -days 3650 \\
    -out ca-cert.pem -subj '/CN=Internal CA'

# Issue a client cert
openssl genrsa -out client-key.pem 3072
openssl req -new -key client-key.pem -out client.csr -subj '/CN=service-a'
openssl x509 -req -in client.csr -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial \\
    -out client-cert.pem -days 365 -sha256
# Distribute ca-cert.pem to verifiers; keep ca-key.pem in a vault.
# Production: use smallstep CA or HashiCorp Vault PKI engine — they handle CRL/OCSP, rotation, audit.

# 9) Revocation
# • CRL — Certificate Revocation List — periodically published, lookup is slow
# • OCSP — Online Certificate Status Protocol — query 'is this cert still valid?'
# • OCSP stapling — server attaches OCSP response to TLS handshake (no extra client round trip)
# • CRLite — modern compressed format; major browsers ship it client-side

# Configure OCSP stapling (nginx):
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 valid=60s;
resolver_timeout 2s;

# 10) Code signing
# • Same primitives as TLS, different X.509 EKU (extendedKeyUsage = codeSigning)
# • Authenticode (Windows), Apple Developer ID, Google Play signing, sigstore/Cosign for containers
# • Time-stamping: include a trusted timestamp so the signature stays valid after the cert expires

# 11) SSH certificates — like X.509 but for SSH
# Replace per-user authorized_keys with a CA-signed model:
ssh-keygen -f ssh-ca               # generate the CA
ssh-keygen -s ssh-ca -I user@host -n alice -V +1d -z 1 user-pub.pem  # short-lived user cert
# Server trusts the CA's public key; rotated user certs expire in hours, not years.
# Tools: Vault SSH secrets engine, smallstep, Teleport.

# 12) Certificate transparency
# Every public CA logs issued certs to public append-only logs.
# • You can monitor crt.sh / Google's CT logs for unexpected certs on your domains
# • Browsers refuse certs not logged in CT (SCT requirement)
# • Use this as an alarm — surprise cert issuance can mean DNS hijack or CA compromise

# 13) Key rotation + hygiene
# • Rotate TLS certs annually (or every 90 days with Let's Encrypt — automated)
# • Rotate internal CA every 2-5 years; keep ROOTS in offline HSMs
# • Never check private keys into version control
# • Limit private keys to a single use (no sharing TLS key with code-signing)
# • Use HSMs / cloud KMS for any cert that protects a real workload

# 14) Common bugs
# • Missing intermediates → 'unable to get local issuer certificate'; serve full chain
# • Wildcard cert in DNS but request hits a sub-subdomain not covered — wildcard is one level only
# • Self-signed cert in production → 'NET::ERR_CERT_AUTHORITY_INVALID'
# • Cert expired silently because renewal cron failed → monitoring with --keep-until-expiring + alerts on cert age
# • System time skew → 'cert not valid yet' or 'expired'; chrony / ntpd is part of TLS
# • Wrong key/cert pairing — 'private key does not match cert' from nginx/Apache
# • Pinned cert in mobile app breaks after rotation — pin a CA, not a leaf
# • Reused private key across services → one compromise affects everything; per-service keys

# 15) Mental model
# PKI = a tree of trust:
#   roots (preinstalled, very rare changes)
#       intermediates (often rotated annually)
#           leaves (rotated daily / monthly / yearly)
# The browser / OS trusts roots; servers send leaf + intermediates; clients walk the chain.
# Lose the leaf key → rotate. Lose an intermediate's key → CA emergency. Lose the root's key → disaster.

Why it matters

PKI works because there’s a tree of trust: roots in the browser/OS, intermediates rotated regularly, leaves rotated more often still. Use Let’s Encrypt or your cloud’s managed certs for public TLS, run smallstep/Vault for internal CAs, and rotate leaf keys aggressively — short-lived certs make most PKI incidents survivable.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// PKI = the trust chain. Root → Intermediate → Leaf.
// Browsers trust roots in the root store. Devs trust public CAs (Let's Encrypt, ZeroSSL).
// For internal services, run a private CA via step-ca, smallstep, AWS Private CA.
Try it Yourself »

Discussion

Loading…