SSL/TLS & OpenSSL Cheatsheet
Quick reference for OpenSSL, certificate operations, PKI setup, TLS debugging, format conversions, and cert-manager on Kubernetes.
Quick Reference
Certificate Inspection
# View full certificate
openssl x509 -in cert.pem -text -noout
# View specific fields
openssl x509 -in cert.pem -subject -noout
openssl x509 -in cert.pem -issuer -noout
openssl x509 -in cert.pem -dates -noout
openssl x509 -in cert.pem -fingerprint -sha256 -noout
openssl x509 -in cert.pem -modulus -noout | md5sum
# View SANs (Subject Alternative Names)
openssl x509 -in cert.pem -text -noout \
| grep -A1 "Subject Alternative Name"
# Check expiry
openssl x509 -in cert.pem -noout -enddate
# Script: check if expires within 30 days
openssl x509 -checkend 2592000 -noout -in cert.pem
echo $? # 0=valid, 1=expires soon
Generate Keys & CSR
# Generate RSA private key
openssl genrsa -out server.key 4096
openssl genrsa -aes256 -out server.key 4096 # With passphrase
# Generate ECDSA private key
openssl ecparam -name prime256v1 -genkey -noout -out ec.key
openssl ecparam -name secp384r1 -genkey -noout -out ec.key
# Generate CSR from existing key
openssl req -new -key server.key -out server.csr
# Generate key + CSR in one command
openssl req -newkey rsa:4096 -keyout server.key \
-out server.csr -nodes \
-subj "/C=VN/ST=Hanoi/L=Hanoi/O=MyCompany/CN=example.com"
# View CSR contents
openssl req -in server.csr -text -noout
openssl req -in server.csr -verify
# Self-signed certificate (for testing)
openssl req -x509 -newkey rsa:4096 -keyout key.pem \
-out cert.pem -days 365 -nodes \
-subj "/CN=localhost"
Certificate Operations
# Sign CSR with your CA
openssl x509 -req -in server.csr \
-CA ca.crt -CAkey ca.key \
-CAcreateserial -out server.crt \
-days 365 -sha256 \
-extfile v3.ext # Include extensions
# Convert PEM to DER
openssl x509 -in cert.pem -outform DER -out cert.der
# Convert DER to PEM
openssl x509 -in cert.der -inform DER -out cert.pem
# Convert PEM to PFX/PKCS12
openssl pkcs12 -export \
-out certificate.pfx \
-inkey server.key \
-in server.crt \
-certfile ca-chain.crt
# Extract cert from PFX
openssl pkcs12 -in certificate.pfx -nokeys -out cert.pem
openssl pkcs12 -in certificate.pfx -nocerts -nodes -out key.pem
# Bundle full chain
cat server.crt intermediate.crt root.crt > fullchain.pem
Verify & Test
# Verify cert is signed by CA
openssl verify -CAfile ca.crt server.crt
openssl verify -CAfile ca-chain.pem server.crt
# Verify cert matches private key (same modulus)
openssl x509 -noout -modulus -in server.crt | md5sum
openssl rsa -noout -modulus -in server.key | md5sum
# Both must produce same MD5 hash
# Test TLS connection
openssl s_client -connect example.com:443
# With SNI (Server Name Indication — required for vhosts)
openssl s_client -connect example.com:443 \
-servername example.com
# Show full chain
openssl s_client -connect example.com:443 \
-servername example.com -showcerts
# Test specific TLS version
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3
Remote Certificate Checks
# Check expiry of remote cert (one-liner)
echo | openssl s_client -connect example.com:443 \
-servername example.com 2>/dev/null \
| openssl x509 -noout -dates
# Get cert chain from server
openssl s_client -connect example.com:443 \
-servername example.com \
-showcerts 2>/dev/null | grep -E "BEGIN|END CERT"
# Download remote cert to file
echo | openssl s_client \
-connect example.com:443 \
-servername example.com 2>/dev/null \
| openssl x509 > remote.crt
# Test cipher support
nmap --script ssl-enum-ciphers -p 443 example.com
# Check OCSP stapling
openssl s_client -connect example.com:443 \
-servername example.com -status 2>/dev/null \
| grep -A 10 "OCSP response:"
STARTTLS & Other Protocols
# SMTP STARTTLS
openssl s_client -connect smtp.gmail.com:587 \
-starttls smtp
# IMAP STARTTLS
openssl s_client -connect mail.example.com:143 \
-starttls imap
# LDAP STARTTLS
openssl s_client -connect ldap.example.com:389 \
-starttls ldap
# Test specific cipher
openssl s_client -connect example.com:443 \
-cipher ECDHE-RSA-AES256-GCM-SHA384
# Check if TLS 1.0/1.1 is disabled (should fail)
openssl s_client -connect example.com:443 -tls1
openssl s_client -connect example.com:443 -tls1_1
# curl TLS debug
curl -v --tls-max 1.2 https://example.com
curl -v --tlsv1.3 https://example.com
Complete PKI Setup: Root CA → Intermediate CA → Leaf Cert
Best Practice: Keep the Root CA offline (air-gapped). Use the Intermediate CA for day-to-day signing. If the Intermediate CA is compromised, revoke it and create a new one — the Root CA remains trusted.
Step 1 — Create Root CA
# Create directory structure
mkdir -p pki/{root-ca,intermediate-ca,certs}/{certs,crl,newcerts,private}
chmod 700 pki/root-ca/private pki/intermediate-ca/private
touch pki/root-ca/index.txt pki/intermediate-ca/index.txt
echo 1000 > pki/root-ca/serial
echo 1000 > pki/intermediate-ca/serial
# Generate Root CA key (4096-bit RSA, passphrase protected)
openssl genrsa -aes256 -out pki/root-ca/private/ca.key.pem 4096
chmod 400 pki/root-ca/private/ca.key.pem
# Create Root CA certificate
openssl req -config pki/openssl-root.cnf \
-key pki/root-ca/private/ca.key.pem \
-new -x509 -days 7300 -sha256 \
-extensions v3_ca \
-out pki/root-ca/certs/ca.cert.pem
# openssl-root.cnf [v3_ca] section:
# subjectKeyIdentifier = hash
# authorityKeyIdentifier = keyid:always,issuer
# basicConstraints = critical, CA:true
# keyUsage = critical, digitalSignature, cRLSign, keyCertSign
Step 2 — Create Intermediate CA
# Generate Intermediate CA key
openssl genrsa -aes256 \
-out pki/intermediate-ca/private/intermediate.key.pem 4096
chmod 400 pki/intermediate-ca/private/intermediate.key.pem
# Create Intermediate CA CSR
openssl req -config pki/openssl-intermediate.cnf \
-new -sha256 \
-key pki/intermediate-ca/private/intermediate.key.pem \
-out pki/intermediate-ca/csr/intermediate.csr.pem
# Sign with Root CA
openssl ca -config pki/openssl-root.cnf \
-extensions v3_intermediate_ca \
-days 3650 -notext -md sha256 \
-in pki/intermediate-ca/csr/intermediate.csr.pem \
-out pki/intermediate-ca/certs/intermediate.cert.pem
# Create certificate chain bundle
cat pki/intermediate-ca/certs/intermediate.cert.pem \
pki/root-ca/certs/ca.cert.pem \
> pki/intermediate-ca/certs/ca-chain.cert.pem
# [v3_intermediate_ca] section in openssl-root.cnf:
# subjectKeyIdentifier = hash
# authorityKeyIdentifier = keyid:always,issuer
# basicConstraints = critical, CA:true, pathlen:0
# keyUsage = critical, digitalSignature, cRLSign, keyCertSign
Step 3 — Issue Leaf (Server) Certificate
# Generate server key
openssl genrsa \
-out pki/certs/example.com.key.pem 2048
# Create v3.ext for SAN (REQUIRED — CN alone is deprecated)
cat > /tmp/v3.ext <<EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = api.example.com
IP.1 = 192.168.1.100
EOF
# Create CSR
openssl req -new -sha256 \
-key pki/certs/example.com.key.pem \
-subj "/C=VN/ST=Hanoi/O=MyCompany/CN=example.com" \
-out pki/certs/example.com.csr.pem
# Sign with Intermediate CA
openssl x509 -req \
-in pki/certs/example.com.csr.pem \
-CA pki/intermediate-ca/certs/intermediate.cert.pem \
-CAkey pki/intermediate-ca/private/intermediate.key.pem \
-CAcreateserial \
-out pki/certs/example.com.cert.pem \
-days 365 -sha256 \
-extfile /tmp/v3.ext
# Verify the issued cert
openssl verify \
-CAfile pki/intermediate-ca/certs/ca-chain.cert.pem \
pki/certs/example.com.cert.pem
Subject Alternative Names (SAN)
Important: Modern browsers and clients ignore the Common Name (CN) field and require Subject Alternative Names. Always include SANs — a cert with only CN will fail validation in Chrome, Firefox, and most TLS clients since 2017.
# openssl.cnf with SAN section
[req]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[dn]
C = VN
ST = Hanoi
L = Hanoi
O = MyCompany
OU = IT
CN = example.com
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = *.example.com # Wildcard
IP.1 = 10.0.0.1
email.1 = [email protected]
# Generate with SAN config
openssl req -newkey rsa:2048 -nodes \
-keyout server.key \
-out server.csr \
-config openssl.cnf
# Verify SANs in CSR
openssl req -text -noout -in server.csr | grep -A 5 "Subject Alternative"
Certificate Format Conversions
# Format summary:
# PEM — Base64 encoded, -----BEGIN CERTIFICATE----- header, most common on Linux
# DER — Binary format, used in Java and Windows environments
# PFX/PKCS12 — Binary, bundles cert + key + chain, used in Windows/IIS
# PKCS7/P7B — Bundle of certs (no private key), used in Windows cert import
# JKS — Java KeyStore, used in Java applications (Tomcat, etc.)
# PEM <-> DER
openssl x509 -in cert.pem -outform DER -out cert.der
openssl x509 -in cert.der -inform DER -outform PEM -out cert.pem
# PEM -> PFX/PKCS12
openssl pkcs12 -export \
-out bundle.pfx \
-inkey server.key \
-in server.crt \
-certfile ca-chain.crt \
-name "My Certificate"
# PFX/PKCS12 -> PEM
openssl pkcs12 -in bundle.pfx -nodes -out all.pem # All in one file
openssl pkcs12 -in bundle.pfx -nokeys -out cert.pem # Cert only
openssl pkcs12 -in bundle.pfx -nocerts -nodes -out key.pem # Key only
openssl pkcs12 -in bundle.pfx -nokeys -cacerts -out chain.pem # CA chain only
# PEM -> PKCS7/P7B
openssl crl2pkcs7 -nocrl \
-certfile server.crt \
-certfile ca-chain.crt \
-out bundle.p7b
# PKCS7 -> PEM
openssl pkcs7 -in bundle.p7b -print_certs -out certs.pem
# JKS -> PFX (requires Java keytool)
keytool -importkeystore \
-srckeystore keystore.jks \
-destkeystore keystore.pfx \
-deststoretype pkcs12
# PFX -> JKS
keytool -importkeystore \
-srckeystore bundle.pfx -srcstoretype pkcs12 \
-destkeystore keystore.jks -deststoretype jks
Cipher Suites
# List all available ciphers in OpenSSL
openssl ciphers -v 'ALL'
# List strong ciphers only (TLS 1.2+)
openssl ciphers -v 'ECDHE+AESGCM:ECDHE+CHACHA20:!aNULL:!MD5:!DSS'
# List TLS 1.3 ciphersuites
openssl ciphers -v -tls1_3
# Test what ciphers a server supports
nmap --script ssl-enum-ciphers -p 443 example.com
# Nginx: restrict to strong ciphers only
# ssl_protocols TLSv1.2 TLSv1.3;
# ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
# ssl_prefer_server_ciphers off;
# Apache: restrict ciphers
# SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
# SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:...
cert-manager on Kubernetes
# List all certificates
kubectl get certificates -A
kubectl get cert -A
# Describe a certificate (check conditions, last renewal)
kubectl describe certificate myapp-tls -n production
# Check certificate secret
kubectl get secret myapp-tls -n production -o yaml
kubectl get secret myapp-tls -n production \
-o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout
# Check CertificateRequests
kubectl get certificaterequests -A
kubectl describe certificaterequest -n production
# Trigger manual renewal
kubectl annotate certificate myapp-tls \
cert-manager.io/issuer-name- \
-n production
# Or use cmctl (cert-manager CLI)
cmctl renew myapp-tls -n production
cmctl status certificate myapp-tls -n production
# Check ClusterIssuers and Issuers
kubectl get clusterissuer
kubectl get issuer -A
kubectl describe clusterissuer letsencrypt-prod
# Example Certificate resource
# apiVersion: cert-manager.io/v1
# kind: Certificate
# metadata:
# name: myapp-tls
# namespace: production
# spec:
# secretName: myapp-tls
# issuerRef:
# name: letsencrypt-prod
# kind: ClusterIssuer
# dnsNames:
# - example.com
# - www.example.com
# duration: 2160h # 90 days
# renewBefore: 360h # Renew 15 days before expiry