OpenSSL Commands Cheat Sheet: CSR, Certificates, Keys & Debugging
OpenSSL is the Swiss Army knife of SSL/TLS work. Whether you're generating a CSR, inspecting a certificate's expiry date, converting between PEM and PFX, or debugging a TLS handshake, OpenSSL has a command for it. The challenge is remembering which command does what.
This cheat sheet covers the OpenSSL commands you'll actually use — organized by task, with copy-paste examples and explanations of the important flags.
OpenSSL Essentials
OpenSSL is an open-source cryptographic library and command-line toolkit. It implements TLS/SSL protocols and a wide range of cryptographic operations.
Check your version
openssl version -a
The version matters — some commands and cipher suites differ between OpenSSL 1.x and 3.x. Most modern Linux distributions ship with OpenSSL 3.x. macOS ships with LibreSSL (a compatible fork) but you can install OpenSSL via Homebrew.
Install OpenSSL
Ubuntu/Debian:
sudo apt-get update && sudo apt-get install openssl
RHEL/CentOS/Amazon Linux:
sudo yum install openssl
# or on RHEL 8+
sudo dnf install openssl
macOS (via Homebrew — replaces LibreSSL):
brew install openssl
echo 'export PATH="/opt/homebrew/opt/openssl@3/bin:$PATH"' >> ~/.zshrc
Windows: Download a pre-built binary from slproweb.com or use it via WSL, Git Bash, or the openssl command included with Git for Windows.
Certificate Inspection Commands
View a PEM certificate
openssl x509 -in certificate.pem -text -noout
This dumps the full certificate contents: subject, issuer, validity dates, public key, SANs (Subject Alternative Names), key usage, and extensions. The -noout flag suppresses the raw PEM output so you only see the human-readable version.
View just the important fields
# Subject and issuer only
openssl x509 -in certificate.pem -subject -issuer -noout
# Validity dates only
openssl x509 -in certificate.pem -dates -noout
# SHA-256 fingerprint
openssl x509 -in certificate.pem -fingerprint -sha256 -noout
# Subject Alternative Names (SANs)
openssl x509 -in certificate.pem -ext subjectAltName -noout
Check certificate expiry
# Show not-before and not-after dates
openssl x509 -in certificate.pem -dates -noout
# Check how many days until expiry (Linux)
echo "Certificate expires in: $(( ($(date -d "$(openssl x509 -enddate -noout -in certificate.pem | cut -d= -f2)" +%s) - $(date +%s)) / 86400 )) days"
View a DER-encoded certificate
DER is the binary format. Add the -inform DER flag:
openssl x509 -in certificate.der -inform DER -text -noout
View a CSR (Certificate Signing Request)
openssl req -in request.csr -text -noout
This shows the distinguished name, public key, and any SANs or extensions included in the CSR.
View a private key
# RSA key
openssl rsa -in private.key -text -noout
# EC key
openssl ec -in private.key -text -noout
# View key type without knowing it
openssl pkey -in private.key -text -noout
Never share the output of these commands — they contain your private key material.
View a PKCS#12 / PFX file
openssl pkcs12 -in certificate.pfx -info -noout
# You'll be prompted for the PFX password
CSR Generation
A CSR (Certificate Signing Request) is what you submit to a Certificate Authority to get a certificate issued. It contains your public key and identity information.
Generate a new private key and CSR in one command
openssl req -new -newkey rsa:2048 -keyout private.key -out request.csr \
-subj "/C=US/ST=California/L=San Francisco/O=Acme Corp/CN=example.com"
Flag breakdown:
-new— generate a new CSR-newkey rsa:2048— generate a new 2048-bit RSA key at the same time-keyout private.key— save the private key to this file-out request.csr— save the CSR to this file-subj— provide the subject fields without an interactive prompt
For a 4096-bit key (more secure, but slower TLS handshakes):
openssl req -new -newkey rsa:4096 -keyout private.key -out request.csr \
-subj "/C=US/ST=California/L=San Francisco/O=Acme Corp/CN=example.com"
Generate a CSR with Subject Alternative Names (SANs)
Modern certificates require SANs for every hostname they should be valid for. Create a config file:
# Create san.cnf
cat > san.cnf << EOF
[req]
default_bits = 2048
prompt = no
distinguished_name = dn
req_extensions = req_ext
[dn]
C = US
ST = California
L = San Francisco
O = Acme Corp
CN = example.com
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = api.example.com
EOF
# Generate the CSR using the config
openssl req -new -newkey rsa:2048 -keyout private.key -out request.csr -config san.cnf
Generate a CSR from an existing private key
If you already have a private key and just need a new certificate (renewal):
openssl req -new -key existing_private.key -out request.csr \
-subj "/C=US/ST=California/L=San Francisco/O=Acme Corp/CN=example.com"
Verify a CSR
openssl req -verify -in request.csr -noout
# Should output: verify OK
Certificate Format Conversions
PEM to DER
openssl x509 -in certificate.pem -outform DER -out certificate.der
DER to PEM
openssl x509 -in certificate.der -inform DER -outform PEM -out certificate.pem
PEM to PFX/PKCS#12 (combines cert + key + chain)
openssl pkcs12 -export \
-in certificate.pem \
-inkey private.key \
-certfile chain.pem \
-out bundle.pfx \
-name "My Certificate"
# You'll be prompted to set a PFX password
PFX to PEM (extract cert and key)
# Extract certificate
openssl pkcs12 -in bundle.pfx -clcerts -nokeys -out certificate.pem
# Extract private key (will ask for PFX password, then set an output passphrase)
openssl pkcs12 -in bundle.pfx -nocerts -out private.key
# Extract private key without encryption
openssl pkcs12 -in bundle.pfx -nocerts -nodes -out private.key
# Extract the CA chain
openssl pkcs12 -in bundle.pfx -cacerts -nokeys -out chain.pem
CRT + KEY to PFX (combine existing files)
openssl pkcs12 -export -in certificate.crt -inkey private.key -out bundle.pfx
Remove passphrase from a private key
openssl rsa -in encrypted.key -out decrypted.key
# Enter the passphrase when prompted
Testing with openssl s_client
openssl s_client connects to a TLS server and shows you the full handshake — certificates, cipher suites, protocol version. It's the fastest way to debug TLS issues without a browser.
Basic connection
openssl s_client -connect example.com:443
This shows the full certificate chain, cipher suite negotiated, and protocol version. Press Ctrl+C or type quit to exit.
Check the certificate chain
openssl s_client -connect example.com:443 -showcerts
The -showcerts flag dumps every certificate in the chain (leaf + intermediates + root). Without it, you only see the leaf certificate.
Test with SNI (Server Name Indication)
Modern servers host multiple domains on one IP. SNI tells the server which certificate to present:
openssl s_client -connect 1.2.3.4:443 -servername example.com
Always include -servername when the IP hosts multiple domains.
Check certificate expiry via s_client
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -dates
Test a specific TLS version
# Test TLS 1.2 only
openssl s_client -connect example.com:443 -tls1_2
# Test TLS 1.3 only
openssl s_client -connect example.com:443 -tls1_3
If the connection fails, the server doesn't support that TLS version.
Test with STARTTLS (for SMTP, IMAP, etc.)
# SMTP
openssl s_client -connect mail.example.com:587 -starttls smtp
# IMAP
openssl s_client -connect mail.example.com:143 -starttls imap
Get just the certificate in PEM format
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -out downloaded_cert.pem
Key Generation and Signing
Generate an RSA private key
# 2048-bit (minimum acceptable for new keys)
openssl genrsa -out private.key 2048
# 4096-bit (higher security, slower)
openssl genrsa -out private.key 4096
# With AES-256 encryption (protects the key with a passphrase)
openssl genrsa -aes256 -out private.key 4096
Generate an EC (Elliptic Curve) private key
EC keys are smaller and faster than RSA at equivalent security levels:
# P-256 (recommended, supported everywhere)
openssl ecparam -name prime256v1 -genkey -noout -out ec_private.key
# P-384 (higher security, US government standard)
openssl ecparam -name secp384r1 -genkey -noout -out ec_private.key
Generate a self-signed certificate
openssl req -x509 -newkey rsa:2048 -keyout private.key -out certificate.pem \
-days 365 -nodes \
-subj "/C=US/ST=California/O=Dev/CN=localhost"
The -nodes flag means "no DES" — the private key won't be encrypted with a passphrase. For development use, this is convenient. For production, add encryption.
Self-signed certificate with SANs:
openssl req -x509 -newkey rsa:2048 -keyout private.key -out certificate.pem \
-days 365 -nodes \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,DNS:*.localhost,IP:127.0.0.1"
Verify a certificate and private key match
The modulus of a certificate and its corresponding private key must be identical:
# Get certificate modulus
openssl x509 -noout -modulus -in certificate.pem | openssl md5
# Get private key modulus
openssl rsa -noout -modulus -in private.key | openssl md5
If both MD5 hashes match, the key and certificate are a pair. If they differ, you have a mismatch.
OpenSSL Quick Reference
| Task | Command |
|---|---|
| View certificate | openssl x509 -in cert.pem -text -noout |
| View CSR | openssl req -in csr.pem -text -noout |
| View private key | openssl rsa -in key.pem -text -noout |
| Check expiry dates | openssl x509 -in cert.pem -dates -noout |
| Check SHA-256 fingerprint | openssl x509 -in cert.pem -fingerprint -sha256 -noout |
| Generate RSA key | openssl genrsa -out key.pem 2048 |
| Generate key + CSR | openssl req -new -newkey rsa:2048 -keyout key.pem -out csr.pem |
| Self-signed cert | openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes |
| PEM → DER | openssl x509 -in cert.pem -outform DER -out cert.der |
| DER → PEM | openssl x509 -in cert.der -inform DER -out cert.pem |
| PEM → PFX | openssl pkcs12 -export -in cert.pem -inkey key.pem -out bundle.pfx |
| PFX → PEM cert | openssl pkcs12 -in bundle.pfx -clcerts -nokeys -out cert.pem |
| PFX → PEM key | openssl pkcs12 -in bundle.pfx -nocerts -nodes -out key.pem |
| Test TLS connection | openssl s_client -connect host:443 |
| Check TLS with SNI | openssl s_client -connect host:443 -servername domain.com |
| Verify cert+key match | openssl x509 -modulus -in cert.pem | md5sum vs openssl rsa -modulus -in key.pem | md5sum |
When a GUI Tool Is Faster
The OpenSSL command line is powerful but verbose. For quick one-off tasks, browser-based tools are often faster — especially when you need to inspect a certificate you received from someone else and don't want to copy it to a file just to run a command:
- SSL Certificate Decoder — paste a PEM certificate, get formatted output instantly
- CSR Decoder — inspect a CSR without
openssl req -text - CSR Generator — generate a CSR without managing a
san.cnffile - Certificate Key Matcher — verify a certificate and key match by pasting both
- PEM Decoder — auto-detects the PEM type (cert, key, CSR) and formats the output
All of these run entirely in your browser — no data is uploaded to a server.
Common OpenSSL Errors
unable to load Private Key — The key file is encrypted with a passphrase. Use -passin pass:yourpassword or omit -nodes and enter the passphrase interactively.
PEM_read_bio_X509: no start line — The file isn't a valid PEM file, or you're using the wrong -inform. Try adding -inform DER if the file might be binary.
SSL handshake has read 0 bytes — The server is not responding on that port, or it doesn't support TLS (it might expect STARTTLS — use -starttls smtp).
depth=0 ... error 18 at 0 depth lookup: self-signed certificate — Expected for self-signed certs. Add -verify_return_error to make this a hard failure, or use -CAfile to specify the CA for verification.
SSL alert number 40 (handshake failure) — The server rejected the TLS version or cipher suite. Try specifying a different protocol: -tls1_2 or -tls1_3.