OpenSSL is the command-line toolkit that underpins almost everything in the SSL/TLS world — CAs use it to sign certificates, servers use it to handle handshakes, and administrators use it to diagnose problems. Knowing a handful of core commands will let you generate keys, create CSRs, inspect what a CA returned, convert formats for your server, and confirm that a live site is actually serving the right certificate.
This guide covers the commands you will reach for most often, organised by task. All examples were tested on OpenSSL 3.5 LTS (the recommended production version, supported until April 2030). Where OpenSSL 4.0 — released April 14, 2026 — behaves differently, the difference is noted.
Prefer a browser tool?
My-SSL's free tools handle the most common tasks without the command line: CSR Generator, SSL Checker, and Certificate Converter.
1. Check your OpenSSL version
Run this first. The output tells you which version and build flags are active, and whether FIPS mode is compiled in. Some cipher and key operations behave differently between 1.x, 3.x, and 4.x.
# Full version string openssl version -a # Example output (OpenSSL 3.5 LTS on Ubuntu 24.04) # OpenSSL 3.5.0 8 Apr 2025 (Library: OpenSSL 3.5.0 8 Apr 2025) # built on: ... # OPENSSLDIR: "/usr/lib/ssl" # ENGINESDIR: "/usr/lib/x86_64-linux-gnu/engines-3" # MODULESDIR: "/usr/lib/x86_64-linux-gnu/ossl-modules" # List all available sub-commands openssl help
OpenSSL 1.x is end-of-life
OpenSSL 1.1.1 reached end-of-life in September 2023 and receives no security patches. If your system shows OpenSSL 1.x, upgrade your OS or build OpenSSL 3.5 from source. OpenSSL 3.0 receives security-only fixes until September 2026, then it too goes EOL.
2. Generate private keys
A private key is generated on your server and never sent to the CA. The CA only receives the CSR (which contains your public key). Keep the private key secure — if it is compromised, the certificate must be revoked.
RSA keys
RSA 2048-bit is the minimum accepted by all CAs. RSA 4096-bit offers a larger security margin at the cost of slightly slower TLS handshakes.
# RSA 2048-bit (widely compatible) openssl genrsa -out private.key 2048 # RSA 4096-bit (stronger, marginally slower handshakes) openssl genrsa -out private.key 4096 # RSA 2048-bit with AES-256 passphrase protection # (required before copying the key off the server) openssl genrsa -aes256 -out private.key 2048 # Remove passphrase from a protected key # (needed by Nginx/Apache — they can't prompt interactively) openssl rsa -in private-encrypted.key -out private.key
ECDSA keys
ECDSA keys are shorter and produce faster handshakes than RSA at equivalent security levels. P-256 and P-384 are universally supported by modern browsers and all major CAs.
# ECDSA P-256 (fastest; 128-bit security) openssl ecparam -name prime256v1 -genkey -noout -out private.key # ECDSA P-384 (192-bit security; preferred for high-assurance certs) openssl ecparam -name secp384r1 -genkey -noout -out private.key # OpenSSL 3.x alternative using the newer genpkey command # (works for both RSA and ECDSA; preferred in scripts) openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out private.key openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private.key
Inspect the key you just generated
# View RSA key details (modulus length, public exponent) openssl rsa -in private.key -text -noout # View ECDSA key details (curve, public key point) openssl ec -in private.key -text -noout # Print only the public key component (safe to share) openssl rsa -in private.key -pubout openssl ec -in private.key -pubout
3. Generate a Certificate Signing Request (CSR)
A CSR encodes your organisation details and public key, signed by your private key to prove ownership. You submit the CSR to your CA; the CA signs it and returns a certificate. The private key never leaves your server.
Since March 2026, publicly trusted certificates are capped at 199 days validity (CA/Browser Forum Ballot SC-081v3). This means you will be renewing certificates roughly every six months and generating new CSRs at each renewal.
Basic single-domain CSR
# Generate key and CSR in one step openssl req -new -newkey rsa:2048 -nodes -keyout private.key -out request.csr # You'll be prompted for: # Country Name (2-letter code): US # State or Province Name: California # Locality Name (City): San Francisco # Organization Name: Example Corp # Organizational Unit Name: (leave blank or enter dept) # Common Name: example.com # Email Address: (leave blank) # Challenge password: (leave blank) # Generate CSR from an existing private key (for renewal) openssl req -new -key private.key -out request.csr
CSR with Subject Alternative Names (SAN)
Modern CAs ignore the Common Name and use SANs for validation. Always include SANs when you need to secure multiple hostnames.
# Create a temporary config file cat > san.cnf << 'EOF' [req] distinguished_name = dn req_extensions = req_ext prompt = no [dn] C = US ST = California L = San Francisco O = Example Corp CN = example.com [req_ext] subjectAltName = DNS:example.com, DNS:www.example.com, DNS:api.example.com EOF # Generate key and CSR using the config openssl req -new -newkey rsa:2048 -nodes -keyout private.key -out request.csr -config san.cnf # Verify the SAN is embedded in the CSR openssl req -in request.csr -text -noout | grep -A3 "Subject Alternative"
Non-interactive CSR (CI/CD pipelines)
# Pass all fields as a single -subj string openssl req -new -key private.key -out request.csr -subj "/C=US/ST=California/L=San Francisco/O=Example Corp/CN=example.com"
Only need a certificate for local testing, with no CA involved? Adding -x509 to the same command produces a self-signed certificate instead of a CSR — see our self-signed certificates guide for when that's appropriate and how browsers treat the result.
4. Inspect certificates, CSRs, and keys
Before deploying a certificate, verify that the CN, SANs, validity dates, and issuer chain are exactly what you expect. These commands decode the DER structures into human-readable output.
Inspect a certificate file
# Full certificate details (subject, issuer, SANs, validity, signature) openssl x509 -in certificate.crt -text -noout # Print only the validity dates (notBefore / notAfter) openssl x509 -in certificate.crt -noout -dates # Print only the subject (CN, O, C) openssl x509 -in certificate.crt -noout -subject # Print only the issuer openssl x509 -in certificate.crt -noout -issuer # Print Subject Alternative Names only openssl x509 -in certificate.crt -noout -ext subjectAltName # Print the certificate fingerprint (SHA-256) openssl x509 -in certificate.crt -noout -fingerprint -sha256 # Print the serial number openssl x509 -in certificate.crt -noout -serial
Inspect a CSR
# Full CSR details (subject, public key, requested extensions) openssl req -in request.csr -text -noout # Verify the CSR signature (confirms key ownership) openssl req -in request.csr -verify -noout
Inspect a PFX / PKCS#12 file
# List contents of a PFX (will prompt for the PFX password) openssl pkcs12 -info -in certificate.pfx -noout # OpenSSL 3.x: if the PFX was created by old Windows tools using RC2/3DES openssl pkcs12 -info -in certificate.pfx -noout -legacy
Inspect a DER-encoded certificate
# DER is binary — add -inform der openssl x509 -in certificate.der -inform der -text -noout
Inspect a P7B / PKCS#7 chain file
# Print all certificates in the bundle openssl pkcs7 -in certificate.p7b -print_certs -noout
5. Verify private key matches certificate
A mismatched key is one of the most common SSL deployment errors. Nginx reports "SSL_CTX_use_PrivateKey_file failed", Apache reports "Init: Private key not found", and IIS silently refuses to bind. Always verify before reloading your server.
RSA certificates
# The MD5 hash of the modulus must be identical for both files. openssl x509 -noout -modulus -in certificate.crt | openssl md5 openssl rsa -noout -modulus -in private.key | openssl md5 # If both lines print the same hash (e.g. (stdin)= d41d8cd98f00b204...) # the key and certificate match.
ECDSA certificates
# Compare the public key extracted from the private key and from the cert openssl ec -noout -pubout -in private.key | openssl md5 openssl x509 -noout -pubkey -in certificate.crt | openssl md5
Verify the CSR matches the private key
# Use this after generating a CSR to confirm they are a pair openssl req -noout -modulus -in request.csr | openssl md5 openssl rsa -noout -modulus -in private.key | openssl md5
6. Convert certificate formats
Different servers expect different file formats. Apache and Nginx require PEM. IIS and Windows services require PFX (PKCS#12). Java keystores use JKS or PKCS#12 (since Java 9). See the SSL certificate formats guide for a full explanation, or use the My-SSL Certificate Converter for browser-based conversion.
PEM → PFX (PKCS#12)
Required for IIS, Windows Server, Exchange, and Azure services.
# Basic: certificate + private key → PFX # You will be prompted to set a PFX password. openssl pkcs12 -export -in certificate.crt -inkey private.key -out certificate.pfx # Include intermediate CA certificate in the bundle openssl pkcs12 -export -in certificate.crt -inkey private.key -certfile ca_bundle.crt -out certificate.pfx # Non-interactive (pass password on the command line — use in CI only) openssl pkcs12 -export -in certificate.crt -inkey private.key -out certificate.pfx -passout pass:YourPassword
PFX → PEM
# Extract the certificate (no private key) openssl pkcs12 -in certificate.pfx -nokeys -out certificate.crt # Extract the private key (no passphrase on output — ready for Nginx/Apache) openssl pkcs12 -in certificate.pfx -nocerts -nodes -out private.key # Extract everything (certificate + key) in one PEM file openssl pkcs12 -in certificate.pfx -nodes -out bundle.pem # OpenSSL 3.x flag for old RC2/3DES PFX files generated by legacy Windows tools openssl pkcs12 -in certificate.pfx -nokeys -out certificate.crt -legacy
PEM → DER
# Certificate PEM → DER binary openssl x509 -in certificate.crt -outform der -out certificate.der # DER binary → PEM text openssl x509 -in certificate.der -inform der -outform pem -out certificate.crt
PEM → P7B (PKCS#7)
P7B bundles contain only certificates (no private key). Windows and IIS use them to distribute certificate chains.
# Certificate + CA bundle → P7B openssl crl2pkcs7 -nocrl -certfile certificate.crt -certfile ca_bundle.crt -out certificate.p7b # P7B → PEM (extract all certificates) openssl pkcs7 -in certificate.p7b -print_certs -out bundle.pem
PEM → Java PKCS#12 keystore
# Java 9+ accepts PKCS#12 keystores directly — just create a PFX: openssl pkcs12 -export -in certificate.crt -inkey private.key -certfile ca_bundle.crt -name "myalias" -out keystore.p12 # Then import into Java with keytool (set storetype to PKCS12): # keytool -importkeystore # -srckeystore keystore.p12 -srcstoretype PKCS12 # -destkeystore keystore.jks -deststoretype JKS
7. Test a live TLS connection
openssl s_client connects to a server, completes the TLS handshake, and prints the certificate chain, negotiated protocol, and cipher. It is the fastest way to confirm that a newly deployed certificate is actually live.
Basic connection
# Connect to a web server and dump the full handshake openssl s_client -connect example.com:443 # Use -servername for SNI (required on servers hosting multiple certs) openssl s_client -connect example.com:443 -servername example.com # Quiet: just print the certificate (suppress handshake noise) echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -text -noout
Check protocol and cipher
# Show the protocol version and cipher negotiated echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | grep -E "^(Protocol|Cipher)"
Check expiry of a live certificate
# Print notBefore and notAfter dates for example.com echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
Force a specific TLS version
# Test TLS 1.3 only (fails if server doesn't support it) openssl s_client -connect example.com:443 -tls1_3 # Test TLS 1.2 only openssl s_client -connect example.com:443 -tls1_2 # Note: -ssl3, -tls1, -tls1_1 are removed in OpenSSL 4.0 and # were no-ops in 3.x (SSLv3/TLS 1.0/1.1 were already disabled).
Check SMTP STARTTLS (and other non-HTTPS)
# SMTP with STARTTLS openssl s_client -connect mail.example.com:587 -starttls smtp # IMAP with STARTTLS openssl s_client -connect mail.example.com:143 -starttls imap # PostgreSQL with TLS openssl s_client -connect db.example.com:5432 -starttls postgres
Test OCSP stapling
# Check whether the server is stapling an OCSP response echo | openssl s_client -connect example.com:443 -servername example.com -status 2>/dev/null | grep -A10 "OCSP response"
8. Verify the certificate chain
A broken certificate chain is the most common SSL misconfiguration. Chrome hides it by fetching missing intermediates automatically (AIA Fetching), but mobile clients, curl, and API consumers will reject an incomplete chain. See the certificate chain guide for a full explanation.
Verify against a CA bundle file
# Verify a certificate against a specific CA bundle openssl verify -CAfile ca_bundle.crt certificate.crt # Expected output: certificate.crt: OK # Verify including untrusted intermediates you have locally openssl verify -CAfile root.crt -untrusted intermediate.crt certificate.crt
Verify the chain served by a live server
# s_client with -showcerts prints the full chain the server sends echo | openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null | grep -E "^(subject|issuer)"
Verify against the system trust store
# Uses /etc/ssl/certs (Linux) or the OS keychain (macOS) as the root store openssl verify certificate.crt
9. Check OCSP revocation status
OCSP (Online Certificate Status Protocol) lets you ask a CA's responder whether a specific certificate has been revoked — without downloading a CRL. See the OCSP stapling guide to learn how to cache and serve OCSP responses on Nginx and Apache.
# Step 1: Get the OCSP responder URL from the certificate openssl x509 -in certificate.crt -noout -text | grep -A2 "Authority Information Access" # Typical output: OCSP - URI:http://ocsp.example-ca.com # Step 2: Send an OCSP request using the issuer certificate openssl ocsp -issuer intermediate.crt -cert certificate.crt -url http://ocsp.example-ca.com -text -noverify # Expected output includes: Response verify OK # And: example.crt: good (if the certificate is not revoked)
10. Quick reference table
One-line commands for the most common tasks.
| Task | Command |
|---|---|
| OpenSSL version | openssl version -a |
| Generate RSA 2048 key | openssl genrsa -out private.key 2048 |
| Generate ECDSA P-256 key | openssl ecparam -name prime256v1 -genkey -noout -out private.key |
| Generate CSR from key | openssl req -new -key private.key -out request.csr |
| Inspect certificate | openssl x509 -in cert.crt -text -noout |
| Check cert expiry dates | openssl x509 -in cert.crt -noout -dates |
| Inspect CSR | openssl req -in request.csr -text -noout |
| Verify key ↔ cert match (RSA) | openssl x509 -noout -modulus -in cert.crt | openssl md5 |
| PEM → PFX | openssl pkcs12 -export -in cert.crt -inkey private.key -out cert.pfx |
| PFX → PEM (cert only) | openssl pkcs12 -in cert.pfx -nokeys -out cert.crt |
| PFX → PEM (key only) | openssl pkcs12 -in cert.pfx -nocerts -nodes -out private.key |
| PEM → DER | openssl x509 -in cert.crt -outform der -out cert.der |
| DER → PEM | openssl x509 -in cert.der -inform der -out cert.crt |
| PEM → P7B | openssl crl2pkcs7 -nocrl -certfile cert.crt -certfile ca.crt -out cert.p7b |
| Test live TLS connection | openssl s_client -connect example.com:443 -servername example.com |
| Check live cert expiry | echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates |
| Verify cert chain | openssl verify -CAfile ca_bundle.crt certificate.crt |
| Check OCSP stapling | echo | openssl s_client -connect example.com:443 -status 2>/dev/null | grep -A10 'OCSP response' |
Common OpenSSL errors and fixes
unable to load Private Key
The file path is wrong, the key has a passphrase (add -passin pass:password), or the file is PEM for a different key type. Run openssl rsa -in private.key -check to diagnose.
error 20: unable to get local issuer certificate
Your CA bundle is missing or incomplete. Pass the correct -CAfile or concatenate root + intermediate into a bundle: cat intermediate.crt root.crt > ca_bundle.crt
error 18: self-signed certificate
The certificate is self-signed and not in any trust store. For testing, add -noverify (OCSP) or bypass verification — but never in production.
unable to load certificate (bad end line / bad base64)
The PEM file is truncated, has Windows CRLF line endings, or contains extra whitespace. Try: dos2unix certificate.crt or re-download the certificate from your CA.
PKCS12 mac verify error / bad password read
Wrong PFX password, or a legacy PFX encrypted with RC2/3DES. Add the -legacy flag on OpenSSL 3.x: openssl pkcs12 -legacy -in cert.pfx …
OpenSSL 4.0: What changed for certificate work
OpenSSL 4.0, released on April 14, 2026, is a feature release with breaking changes. Most Linux distributions have not yet shipped it as their system OpenSSL (Fedora 42 is an early adopter). If you install it alongside 3.5 for testing, be aware of the following differences that affect the commands in this guide:
Engine API removed
The -engine flag and OPENSSL_NO_ENGINE build option are gone. If you relied on HSM or PKCS#11 engine-based key storage, migrate to provider-based loading (openssl pkey -provider pkcs11 …).
SSLv3 and SSLv2 ClientHello removed
The -ssl3 flag no longer exists. All SSLv3-specific test options in s_client are removed. This only affects legacy diagnostic scenarios — no modern server supports SSLv3.
RSA hex output no longer has leading '00:'
When OpenSSL 4.0 prints an RSA modulus in hex (e.g., openssl x509 -modulus), the leading 00: that appeared on 3.x when the first byte was ≥ 0x80 is no longer printed. This affects scripts that compare raw modulus strings rather than their MD5 hashes.
pkcs12 -legacy still available
The -legacy flag for handling old RC2/3DES PFX files remains in 4.0, provided the legacy provider is loaded. Run openssl pkcs12 -legacy -provider legacy -provider default -in cert.pfx … if you encounter errors.
Related guides and tools
Not a command-line person? My-SSL's free CSR Generator creates a key and CSR in your browser with no software to install. The Certificate Converter handles PEM ↔ PFX ↔ DER ↔ P7B conversions with a file upload.