OpenSSL Essentials: SSL Certificates, Private Keys, and Certificate Signing Requests
OpenSSL is a command-line toolkit commonly used by administrators to generate keys, create certificate signing requests (CSRs), work with X.509 certificates, inspect PEM files, and convert certificate formats for servers and clients. This guide covers practical openssl commands for RSA and elliptic-curve keys, CSRs with Subject Alternative Names (SANs), self-signed certificates, certificate verification, live TLS testing with s_client, and workflows involving PEM, DER, PKCS12, and PKCS7 formats. It is intended for administrators who manage HTTPS on Linux servers, submit CSRs to public or private certificate authorities, or diagnose TLS handshake and trust issues.
How to Use This OpenSSL Guide
- If you need an introduction to CSRs, Distinguished Name fields, and the non-interactive
-subjoption, begin with What Is OpenSSL and Why It Matters for SSL/TLS Management and Creating Certificate Signing Requests (CSRs). - Refer to Generating Private Keys with OpenSSL when creating RSA or EC keys, applying password protection, or comparing RSA 2048, RSA 4096, and P-256.
- Go to Creating Self-Signed Certificates for development, laboratory, or private TLS environments where public browser trust is unnecessary.
- Use Inspecting and Decoding Certificates, CSRs, and Keys, Verifying Certificate Validity and Expiry, and Testing Live TLS Connections with openssl s_client when checking certificate files or remote TLS services.
- See Converting Certificate Formats when Windows, Java, or older applications require DER, PFX, or P7B files.
- Many commands use line continuation characters (
\) to improve readability. They can be pasted as multiple lines or combined into a single command.
Key Takeaways
- Create RSA private keys with
genrsaorgenpkeyand EC keys withecparam, with optional AES-256 password encryption. - Create CSRs with
-newkey, an existing private key, an existing certificate, or an OpenSSL configuration file containing SAN entries for DNS names and IP addresses. - Create self-signed certificates for non-production environments and include SAN entries with
-addextwhen using OpenSSL 1.1.1 or later. - Inspect PEM certificates and CSRs, display RSA key information with
openssl rsa -text, and verify whether a key belongs to a certificate or CSR by comparing RSA modulus hashes or EC public keys. - Inspect
notBeforeandnotAfterdates, verify certificates against CA files, and validate complete chains with-untrustedintermediate certificates. - Troubleshoot live TLS connections with
openssl s_client, including SNI, TLS 1.2 and TLS 1.3 tests, and stapled OCSP responses. - Convert certificates between PEM, DER, PKCS12/PFX, and PKCS7/P7B formats, including the PKCS12
-legacycompatibility option for older software.
What Is OpenSSL and Why It Matters for SSL/TLS Management
OpenSSL is included with many Linux distributions and provides the openssl command for most file-based TLS certificate operations, including generating private keys, creating CSRs, signing certificates, inspecting PEM files, and converting between certificate formats. Software such as Apache, NGINX, HAProxy, Postfix, and many Python and Node.js TLS libraries can use OpenSSL, allowing the same toolkit used to create a CSR to generate the private keys consumed by production services.
OpenSSL’s Role in Certificate Workflows
A TLS certificate normally passes through five main stages: private key generation, CSR creation, certificate signing by a public CA, private CA, or self-signing process, deployment to the service that uses the certificate, and renewal before expiration. OpenSSL provides commands that support every stage. Certificates created during the signing phase use the X.509 certificate format described by RFC 5280.
Private Key Generation
|
v
CSR Creation
|
v
CA Signing (or Self-Sign)
|
v
Certificate Deployment
|
v
Renewal / Revocation
Private Keys, CSRs, and Certificates Explained
Private key: A secret file, typically stored in PEM or DER format, that must remain on systems or hardware security modules under your control. It is used for cryptographic operations during TLS handshakes and should never be sent by email, pasted into support tickets, or committed to version-control repositories.
CSR (certificate signing request): A PKCS#10 request, commonly PEM encoded, containing a public key together with a Distinguished Name and optional extensions such as SANs. The CSR is provided to a certificate authority, which can issue an identity-bound certificate without receiving the corresponding private key.
Certificate: An X.509 public-key certificate defined by RFC 5280. It associates a subject name and SAN entries with a public key, includes validity dates, and can form part of a chain leading to a trusted root certificate. TLS clients use this relationship when authenticating servers.
A Brief History of OpenSSL
OpenSSL originated from SSLeay, Eric Young’s SSL library from the 1990s, which became the foundation for the first OpenSSL releases. The Heartbleed vulnerability disclosed in 2014 affected the TLS heartbeat implementation in OpenSSL 1.0.1 and led to widespread patching, key replacement, and increased attention to project maintenance. The OpenSSL Software Foundation now oversees the codebase. OpenSSL 3.0 was released in September 2021 with a five-year LTS support period, followed by version 3.1 in March 2023, 3.2 in November 2023, 3.3 in April 2024, and 3.4 in October 2024. OpenSSL 1.1.1 reached end of life in September 2023, so production systems should use OpenSSL 3.0 LTS or another maintained version.
Generating Private Keys with OpenSSL
Private keys form the foundation of TLS identities. Generate them on trusted systems, limit access to the files, for example with chmod 600, and keep passphrases outside configuration repositories whenever encrypted private keys are used.
Generate an RSA Private Key
The following command generates an unencrypted 2048-bit RSA private key and saves it as a PEM file:
# genrsa: RSA key generation; -out defines the PEM path; 2048 specifies the modulus size in bits
openssl genrsa -out domain.key 2048
Example output:
Generating RSA private key, 2048 bit long modulus
........................................................................+++++
............+++++
writing new private key to 'domain.key'
| Flag or Argument | Purpose |
|---|---|
genrsa |
OpenSSL command used to generate an RSA private key. |
-out domain.key |
Defines the destination of the PEM-encoded private key. |
2048 |
Sets the RSA modulus size in bits. |
OpenSSL 3.x still supports genrsa, although the documentation recommends openssl genpkey for newer scripts because it provides a unified interface for different algorithms. An equivalent RSA command is:
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out domain.key
| Flag | Purpose |
|---|---|
-algorithm RSA |
Creates an RSA key pair. |
-pkeyopt rsa_keygen_bits:2048 |
Defines a 2048-bit RSA modulus. |
-out domain.key |
Specifies the PEM output file. |
Generate an EC Elliptic-Curve Private Key
The following command creates a P-256, also known as prime256v1, elliptic-curve private key in PEM format:
openssl ecparam -genkey -name prime256v1 -noout -out ec.key
| Flag | Purpose |
|---|---|
ecparam |
Utility for EC parameter and key generation. |
-genkey |
Creates a private key from the selected curve. |
-name prime256v1 |
Selects the widely supported NIST P-256 curve. |
-noout |
Prevents EC parameters from being written to standard output. |
-out ec.key |
Saves the PEM private key to the specified file. |
A P-256 EC key provides a security level comparable to RSA 3072 while using a much smaller key size. On modern x86 systems, P-256 signing can be roughly an order of magnitude faster than RSA 2048 signing, reducing CPU usage on servers processing large numbers of new TLS handshakes. RSA verification is generally faster than P-256 verification, but TLS servers typically sign once per handshake while clients perform the verification, which can make EC attractive on the server side.
Generate a Password-Protected Private Key
The following command creates a new 2048-bit RSA key encrypted with AES-256:
openssl genrsa -aes256 -out domain.key 2048
| Flag | Purpose |
|---|---|
genrsa |
Generates an RSA private key. |
-aes256 |
Encrypts the private key with AES-256 before it is written. |
-out domain.key |
Defines the output file. |
2048 |
Sets the RSA modulus size. |
OpenSSL requests a passphrase interactively. Older documentation often uses -des3. Triple-DES remains available for compatibility, although AES-256 is preferable for newly generated keys.
The following legacy command can still be used when a Triple-DES-encrypted PEM file is specifically required:
openssl genrsa -des3 -out domain.key 2048
| Flag | Purpose |
|---|---|
-des3 |
Encrypts the generated key using Triple-DES. |
-out |
Defines the PEM destination. |
2048 |
Defines the RSA modulus size. |
Encrypt an existing unencrypted private key:
openssl rsa -aes256 \
-in unencrypted.key \
-out encrypted.key
| Flag | Purpose |
|---|---|
rsa |
Processes an RSA private key. |
-aes256 |
Encrypts the resulting key using AES-256. |
-in unencrypted.key |
Specifies the existing unencrypted PEM private key. |
-out encrypted.key |
Defines the encrypted PEM output file. |
Triple-DES can also be applied to an existing RSA key when compatibility with older environments is necessary:
openssl rsa -des3 \
-in unencrypted.key \
-out encrypted.key
| Flag | Purpose |
|---|---|
-des3 |
Encrypts the private key with Triple-DES. |
-in |
Defines the source PEM key. |
-out |
Defines the encrypted PEM destination. |
Decrypt an encrypted RSA key:
openssl rsa \
-in encrypted.key \
-out decrypted.key
| Flag | Purpose |
|---|---|
rsa |
Runs the RSA key-processing utility. |
-in encrypted.key |
Specifies the encrypted PEM input. |
-out decrypted.key |
Writes the decrypted private key. |
RSA 2048 vs RSA 4096 vs EC P-256
| Key Type | Approximate Security Level | Signing Compared with RSA 2048 | Verification Compared with RSA 2048 | Typical Use Case |
|---|---|---|---|---|
| RSA 2048 | Approximately 112 bits | 1x baseline | 1x baseline | Common default for public HTTPS where broad client compatibility is important. |
| RSA 4096 | Approximately 140 bits | Roughly 5x to 7x slower | Roughly 3x slower | Internal certificate authorities, regulated environments requiring larger keys, and root or intermediate CAs. |
EC P-256 (prime256v1) |
Approximately 128 bits | Roughly 10x to 20x faster | Roughly 3x to 5x slower | Modern web servers, CDNs, and mTLS environments with EC support across the certificate chain. |
To obtain measurements for your own system, run openssl speed rsa2048 rsa4096 ecdsap256. The relative differences normally remain similar on x86_64 servers, while absolute performance depends on the processor, available acceleration features, and cryptographic configuration.
Creating Certificate Signing Requests (CSRs)
A CSR contains a subject, public key, and requested certificate extensions so that a certificate authority can issue a certificate corresponding to the required DNS names and identity information.
About Certificate Signing Requests
When obtaining an SSL/TLS certificate from a public or private certificate authority, you normally create a CSR containing the public key and identity information required by the CA. Those elements are incorporated into the resulting certificate.
When a CSR is generated interactively, OpenSSL asks for Distinguished Name values. If SANs are not present, the Common Name (CN) must correspond to the primary hostname. Modern certificates should instead contain SAN entries for every hostname clients are expected to use.
The remaining DN fields describe the organization or entity requesting the certificate. Commercial certificate authorities may require accurate organization names and location details.
Typical interactive prompts look like this:
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:New York
Locality Name (eg, city) []:Brooklyn
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example Brooklyn Company
Organizational Unit Name (eg, section) []:Technology Division
Common Name (e.g. server FQDN or YOUR name) []:examplebrooklyn.com
Email Address []:
To provide the subject values without interactive prompts, append -subj to an openssl req command:
openssl req \
-newkey rsa:2048 -nodes -keyout domain.key \
-out domain.csr \
-subj "/C=US/ST=New York/L=Brooklyn/O=Example Brooklyn Company/CN=examplebrooklyn.com"
Generate a CSR and Private Key in One Command
Use this approach when both a new RSA private key and a CSR are required for submission to a certificate authority:
openssl req \
-newkey rsa:2048 -nodes -keyout domain.key \
-out domain.csr \
-sha256
Complete the interactive CSR questions unless -subj is also supplied.
| Flag | Purpose |
|---|---|
req |
Handles certificate signing requests and certificate requests. |
-newkey rsa:2048 |
Creates a new 2048-bit RSA key pair. |
-nodes |
Leaves the generated private key unencrypted. |
-keyout domain.key |
Specifies the private key destination. |
-out domain.csr |
Specifies the CSR output file. |
-sha256 |
Signs the CSR using SHA-256. |
Generate a CSR Using an Existing Private Key
Use this method when the private key already exists and only a new CSR needs to be created:
openssl req \
-key domain.key \
-new -out domain.csr
| Flag | Purpose |
|---|---|
req |
Runs the CSR-processing command. |
-key domain.key |
Uses the existing private key. |
-new |
Creates a new CSR. |
-out domain.csr |
Writes the CSR to the specified file. |
Generate a CSR from an Existing Certificate and Private Key
This method is useful during certificate renewal or reissuance when the original CSR is no longer available and the new CSR should reuse the subject information from an existing certificate:
openssl x509 \
-in domain.crt \
-signkey domain.key \
-x509toreq -out domain.csr
| Flag | Purpose |
|---|---|
x509 |
Runs the X.509 certificate utility. |
-in domain.crt |
Specifies the source PEM certificate. |
-signkey domain.key |
Uses the private key corresponding to the certificate. |
-x509toreq |
Converts X.509 certificate information into a CSR. |
-out domain.csr |
Defines the CSR destination. |
Generate a CSR with a Configuration File and SANs
A configuration file allows SAN values and other request data to be defined without interactive input while documenting the requested DNS names and IP addresses in a reusable file.
1. Create san.cnf:
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = req_ext
[dn]
C = US
ST = New York
L = Brooklyn
O = Example Brooklyn Company
CN = examplebrooklyn.com
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = examplebrooklyn.com
DNS.2 = www.examplebrooklyn.com
IP.1 = 192.168.1.10
2. Generate the CSR:
openssl req \
-new \
-key domain.key \
-out domain.csr \
-config san.cnf
| Flag | Purpose |
|---|---|
-new |
Creates a new CSR. |
-key domain.key |
Uses an existing private key. |
-out domain.csr |
Specifies the CSR output file. |
-config san.cnf |
Reads the subject and requested extensions from the configuration file. |
Common san.cnf errors:
Error opening config file san.cnf: the relative path cannot be resolved. Use an absolute path or execute OpenSSL from the directory containing the configuration file.- SAN values are missing from the CSR: verify that
req_extensions = req_extappears under[req]and that[req_ext]points to[alt_names]. A misspelled section name can result in a CSR without SAN values. error in req: make sure every DN entry in[dn]has its own line and uses an equals sign. Trailing whitespace or BOM characters in the file can also cause parsing errors.
3. Confirm the SAN entries:
openssl req -text -noout -in domain.csr | grep -A1 "Subject Alternative"
| Flag or Fragment | Purpose |
|---|---|
-text |
Displays decoded CSR fields. |
-noout |
Prevents the PEM block from being printed. |
-in |
Defines the CSR input file. |
grep -A1 |
Prints the matching SAN line and one following context line. |
SANs are not added simply by specifying -subj. Use a configuration file such as the one above or use -addext with OpenSSL 1.1.1 or later.
Single-command CSR using -addext with OpenSSL 1.1.1 or newer:
openssl req \
-newkey rsa:2048 -nodes -keyout domain.key \
-out domain.csr \
-subj "/C=US/ST=New York/L=Brooklyn/O=Example Brooklyn Company/CN=examplebrooklyn.com" \
-addext "subjectAltName=DNS:examplebrooklyn.com,DNS:www.examplebrooklyn.com"
| Flag | Purpose |
|---|---|
-newkey rsa:2048 |
Generates a new RSA private key. |
-nodes |
Leaves the generated key unencrypted. |
-keyout / -out |
Defines the key and CSR output files. |
-subj |
Provides the Distinguished Name inline. |
-addext |
Adds the SAN extension expression. |
Creating Self-Signed Certificates
Self-signed certificates provide TLS encryption but are not automatically trusted by public certificate stores. They are suitable for development systems, administrative interfaces, laboratories, and private networks where trusted roots can be distributed manually.
Generate a Self-Signed Certificate from a New Key
The following command generates a new RSA key and a self-signed certificate:
openssl req \
-newkey rsa:2048 -nodes -keyout domain.key \
-x509 -days 365 -out domain.crt
| Flag | Purpose |
|---|---|
-newkey rsa:2048 |
Creates a new RSA private key. |
-nodes |
Leaves the private key unencrypted. |
-keyout |
Sets the private key destination. |
-x509 |
Produces a certificate rather than only a CSR. |
-days 365 |
Defines the certificate validity period. |
-out |
Defines the certificate output file. |
Generate a Self-Signed Certificate from an Existing Private Key
The following command creates a self-signed certificate from a private key that already exists. OpenSSL asks for subject details unless -subj is supplied:
openssl req \
-key domain.key \
-new \
-x509 -days 365 -out domain.crt
| Flag | Purpose |
|---|---|
-key |
Uses an existing private key. |
-new |
Creates the signing input interactively or from configuration. |
-x509 |
Produces a self-signed certificate. |
-days 365 |
Defines the validity duration. |
-out |
Defines the output certificate. |
Generate a Self-Signed Certificate from an Existing Private Key and CSR
openssl x509 \
-signkey domain.key \
-in domain.csr \
-req -days 365 -out domain.crt
| Flag | Purpose |
|---|---|
-signkey |
Specifies the private key used to self-sign the certificate. |
-in |
Defines the CSR input. |
-req |
Treats the input as a CSR. |
-days |
Defines the certificate validity period. |
-out |
Specifies the certificate output. |
Generate a Self-Signed Certificate with SANs
Modern TLS clients expect hostname information in the SAN extension, including when a certificate is self-signed:
openssl req \
-newkey rsa:2048 -nodes -keyout domain.key \
-x509 -days 365 -out domain.crt \
-subj "/CN=examplebrooklyn.com" \
-addext "subjectAltName=DNS:examplebrooklyn.com,DNS:www.examplebrooklyn.com"
| Flag | Purpose |
|---|---|
-addext |
Adds the SAN list and requires OpenSSL 1.1.1 or newer. |
| Other flags | Perform the same functions as in the previous self-signed certificate examples. |
Current browsers use the SAN extension as the authoritative source for hostnames. A self-signed certificate without SAN entries can therefore fail hostname validation even after the certificate itself has been manually trusted.
Deploy the Certificate to a Web Server
After creating the private key and certificate, move the files to locations accessible to the web server, apply suitable permissions, and reload the service.
A common Linux file layout is:
sudo mv domain.crt /etc/ssl/certs/domain.crt
sudo mv domain.key /etc/ssl/private/domain.key
sudo chmod 644 /etc/ssl/certs/domain.crt
sudo chmod 600 /etc/ssl/private/domain.key
sudo chown root:root /etc/ssl/certs/domain.crt /etc/ssl/private/domain.key
After updating NGINX to reference the certificate and key, validate the configuration and reload it:
sudo nginx -t && sudo systemctl reload nginx
For Apache:
sudo apachectl configtest && sudo systemctl reload apache2
Always validate the configuration before reloading the web server. An invalid NGINX or Apache TLS directive can prevent the service from starting correctly after a reload. Commands such as nginx -t and apachectl configtest parse the configuration without activating the changes.
Inspecting and Decoding Certificates, CSRs, and Private Keys
OpenSSL can display certificate, CSR, and private-key information directly without first converting the files to another format.
View the Contents of a Certificate
The following command displays decoded X.509 certificate fields for inspection:
openssl x509 -text -noout -in domain.crt
| Flag | Purpose |
|---|---|
x509 |
Runs OpenSSL’s certificate-processing utility. |
-text |
Shows the certificate in human-readable form. |
-noout |
Prevents the PEM representation from being written to standard output. |
-in |
Defines the certificate input file. |
Truncated example:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
...
Issuer: CN = Example CA
Validity
Not Before: Jan 1 00:00:00 2026 GMT
Not After : Dec 31 23:59:59 2027 GMT
Subject: CN = examplebrooklyn.com
...
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:examplebrooklyn.com, DNS:www.examplebrooklyn.com
Decode and View CSR Details
openssl req -text -noout -verify -in domain.csr
| Flag | Purpose |
|---|---|
req |
Uses OpenSSL’s CSR utilities. |
-text |
Displays the CSR in readable form. |
-noout |
Suppresses the PEM representation. |
-verify |
Verifies the CSR signature. |
-in |
Defines the CSR input file. |
Example:
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C = US, ST = New York, L = Brooklyn, O = Example Brooklyn Company, CN = examplebrooklyn.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Attributes:
Requested Extensions:
X509v3 Subject Alternative Name:
DNS:examplebrooklyn.com, DNS:www.examplebrooklyn.com
View Private Key Details
For an RSA private key:
openssl rsa -text -noout -in domain.key
| Flag | Purpose |
|---|---|
rsa |
Parses an RSA private key. |
-text |
Displays the modulus, exponents, and prime values. |
-noout |
Suppresses the PEM representation. |
-in |
Defines the private-key file. |
For EC private keys, replace rsa with ec:
openssl ec -text -noout -in ec.key
| Flag | Purpose |
|---|---|
ec |
Processes an EC private key. |
-text |
Displays the curve parameters and key structure. |
-noout |
Suppresses PEM output. |
-in ec.key |
Specifies the PEM key input. |
Validate an RSA private-key file without displaying the entire structure:
openssl rsa -check -in domain.key
| Flag | Purpose |
|---|---|
rsa |
Runs the RSA private-key utility. |
-check |
Tests key consistency without displaying the complete key structure. |
-in domain.key |
Defines the PEM private-key input. |
Encrypted private keys request their passphrase. Successful processing confirms that OpenSSL can parse the PEM key.
Never publish private-key material, decrypted key output, or output from rsa -text in public support tickets, chat systems, or monitoring logs.
Verify That a Private Key Matches a Certificate and CSR
The following commands calculate RSA modulus digests so that a certificate, CSR, and private key can be checked for a common key pair:
openssl rsa -noout -modulus -in domain.key | openssl md5
openssl x509 -noout -modulus -in domain.crt | openssl md5
openssl req -noout -modulus -in domain.csr | openssl md5
| Pipeline Element | Purpose |
|---|---|
-noout -modulus |
Outputs the RSA modulus for comparison. |
openssl md5 |
Creates a short digest suitable for manual comparison. |
Identical MD5 output indicates that the same RSA key pair is associated with each file.
Common problem: modulus mismatch. If the digests are different, the files were produced from different private keys. A common cause is generating a new private key after the original CSR was created and then trying to use the old CSR with the replacement key. Another cause is installing a CA-signed certificate together with the wrong private key. Generate a replacement CSR from the correct key or restore the private key that was originally used for the CSR.
With EC private keys, compare exported public keys instead of RSA modulus values:
openssl ec -pubout -in ec.key | openssl md5
openssl x509 -pubkey -noout -in domain.crt | openssl md5
Matching MD5 output confirms that the EC private key corresponds to the certificate.
Verifying Certificate Validity and Expiry
These commands can be used to check whether a certificate is currently valid and whether it forms a valid chain to a trusted certificate authority. The openssl verify command validates against the certificate file or directory explicitly supplied through -CAfile or -CApath.
Check a Certificate’s Expiry Date
openssl x509 -enddate -noout -in domain.crt
Example:
notAfter=Dec 31 23:59:59 2027 GMT
To display both validity boundaries:
openssl x509 -dates -noout -in domain.crt
| Flag | Purpose |
|---|---|
-enddate |
Displays the notAfter value. |
-dates |
Displays both notBefore and notAfter. |
-noout |
Suppresses the PEM certificate. |
-in |
Defines the certificate input. |
Verify a Certificate Against a CA Bundle
openssl verify -verbose -CAfile ca.crt domain.crt
| Flag | Purpose |
|---|---|
verify |
Validates the certificate chain against trusted anchors. |
-verbose |
Provides additional information about the verification process. |
-CAfile |
Specifies the PEM file containing trusted CA certificates. |
| Final argument | Specifies the leaf certificate to validate. |
An exit status of 0 means OpenSSL successfully constructed a path to a trusted anchor according to the applicable X.509 validation rules.
A verification failure can resemble:
CN = wrong.example.com
error 62 at 0 depth lookup: Hostname mismatch
domain.crt: verification failed
Verify a Full Certificate Chain
openssl verify -CAfile ca-chain.pem -untrusted intermediate.pem domain.crt
| Flag | Purpose |
|---|---|
-CAfile |
Provides the trusted root certificate or CA bundle. |
-untrusted |
Provides intermediate certificates that can form the validation path but are not trusted roots. |
| Final argument | Defines the server or leaf certificate being checked. |
Use -untrusted for intermediate certificates when testing how a signed TLS certificate can be chained to a trusted root. Public certificate authorities are expected to issue subscriber certificates with appropriate certificate-chain relationships.
Common chain-verification errors:
unable to get local issuer certificate: the verifier cannot locate the intermediate certificate that issued the leaf certificate. Provide it through-untrusted intermediate.pemor add it to the appropriate CA bundle.self signed certificate in certificate chain: a root certificate in the chain is being treated as untrusted. Add the root to-CAfilewhen it should be trusted, or remove an unnecessary self-signed root from the chain sent to clients.certificate has expired: inspectnotAfterwithopenssl x509 -enddate -noout -in cert.pem. If the leaf certificate is still valid, perform the same check for every intermediate certificate.
Testing Live TLS Connections with openssl s_client
The openssl s_client command can reproduce client-side TLS handshakes directly from the command line without requiring a browser.
Connect to a Remote Server and Inspect Its Certificate
openssl s_client -connect example.com:443 -servername example.com
| Flag | Purpose |
|---|---|
-connect host:port |
Defines the TCP endpoint. |
-servername |
Sends the SNI hostname, which is required when a server hosts multiple certificates. |
Example of shortened output:
CONNECTED(00000003)
---
Certificate chain
0 s:CN = example.com
i:C = US, O = Example CA, CN = Example Intermediate
---
Server certificate
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject=CN = example.com
issuer=C = US, O = Example CA, CN = Example Intermediate
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Exit the connection with Ctrl+C, or press Q if OpenSSL remains waiting for standard input after displaying the handshake information.
Test Specific TLS Protocol Versions
# Test TLS 1.2
openssl s_client -connect example.com:443 -tls1_2
# Test TLS 1.3
openssl s_client -connect example.com:443 -tls1_3
| Flag | Purpose |
|---|---|
-connect host:port |
Defines the endpoint used for the TLS handshake. |
-tls1_2 |
Restricts the test to TLS 1.2. |
-tls1_3 |
Restricts the test to TLS 1.3 as defined by RFC 8446. |
If the remote server does not support the requested protocol version, the handshake normally fails immediately. This indicates that the protocol is unavailable and does not automatically mean the production configuration is defective.
Check OCSP Stapling and Certificate Revocation
openssl s_client -connect example.com:443 -status 2>/dev/null | grep -A 17 'OCSP response:'
| Flag or Fragment | Purpose |
|---|---|
-connect |
Specifies the remote hostname and port. |
-status |
Requests a stapled OCSP response from the server. |
2>/dev/null |
Hides standard error so that the filtered console output is easier to read. |
grep -A 17 |
Displays the OCSP section and the following lines. |
OCSP stapling allows a server to attach a recent revocation response directly to the TLS handshake. If OpenSSL displays OCSP response: no response sent, the server did not provide a stapled response. This is common and does not necessarily indicate an error.
Add -showcerts when you want OpenSSL to display every certificate supplied by the peer so that the chain can be examined or saved as PEM files.
Diagnose Common TLS Errors with s_client
Several recurring TLS handshake problems can be identified directly from s_client output.
Hostname mismatch: The hostname used for the connection does not appear in the certificate’s SAN entries.
verify error:num=62:Hostname mismatch
Issue a replacement certificate containing the required SAN entries, or connect using a hostname that is already included in the SAN list.
Expired certificate or expired chain element:
verify return code: 10 (certificate has expired)
Check every certificate presented by the server, including intermediate certificates. The following pipeline separates the chain into individual files and displays the subject and expiration date of each certificate:
openssl s_client -connect example.com:443 -showcerts </dev/null 2>/dev/null \
| awk '/BEGIN CERTIFICATE/{n++} n{print > ("/tmp/cert-" n ".pem")}' \
&& for f in /tmp/cert-*.pem; do openssl x509 -subject -enddate -noout -in "$f"; done \
&& rm /tmp/cert-*.pem
The awk command writes each PEM certificate into a numbered file inside /tmp/. The for loop displays each certificate’s subject and notAfter value, and the final rm removes the temporary files. The pipeline uses standard awk functionality and can run on Linux, macOS, and BSD systems.
Untrusted intermediate because the server sent only the leaf certificate:
verify return code: 21 (unable to verify the first certificate)
The server is not providing the required intermediate certificate. For NGINX, concatenate the leaf certificate and intermediate certificate and configure ssl_certificate to use the resulting chain file:
cat domain.crt intermediate.crt > fullchain.crt
Test mutual TLS client-certificate authentication:
openssl s_client \
-connect example.com:443 \
-cert client.crt \
-key client.key
Use this test when the server requires a client certificate. If mTLS is mandatory and the client does not supply a certificate, the server can terminate the TLS handshake with tlsv13 alert certificate required.
Converting Certificate Formats
Certificate Format Overview and Conversion Paths
| From Format | To Format | Typical Use Case | Command Summary |
|---|---|---|---|
| PEM | DER | Java keystores and Windows imports. | openssl x509 -outform der |
| DER | PEM | Working with certificates using text-based tools. | openssl x509 -inform der |
| PEM | PKCS12 | Windows IIS and bundled client certificates. | openssl pkcs12 -export |
| PKCS12 | PEM | Extracting keys and certificates. | openssl pkcs12 -nodes |
| PEM | PKCS7 | P7B certificate bundles used by some Microsoft workflows. | openssl crl2pkcs7 |
| PKCS7 | PEM | Inspecting certificates stored in P7B files. | openssl pkcs7 -print_certs |
Convert PEM to DER
openssl x509 \
-in domain.crt \
-outform der -out domain.der
| Flag | Purpose |
|---|---|
x509 |
Uses the X.509 certificate conversion utility. |
-in |
Defines the PEM certificate input. |
-outform der |
Selects binary DER output. |
-out |
Defines the output file. |
Convert DER to PEM
This command converts a binary DER certificate into PEM format:
openssl x509 \
-inform der -in domain.der \
-out domain.crt
| Flag | Purpose |
|---|---|
-inform der |
Tells OpenSSL to interpret the input as DER. |
-in |
Defines the DER certificate path. |
-out |
Specifies the PEM output file. |
Convert PEM to PKCS12 PFX
To export the certificate together with the private key and CA chain:
openssl pkcs12 \
-export \
-inkey domain.key \
-in domain.crt \
-certfile ca-chain.pem \
-out domain.pfx
| Flag | Purpose |
|---|---|
-export |
Creates a PKCS#12 container. |
-inkey |
Specifies the private key. |
-in |
Defines the leaf certificate. |
-certfile |
Includes additional certificates, usually intermediates. |
-out |
Defines the PKCS12/PFX output file. |
Minimal export without a separate CA chain file:
This remains valid when the leaf PEM file already contains the required intermediate certificates.
openssl pkcs12 \
-inkey domain.key \
-in domain.crt \
-export -out domain.pfx
| Flag | Purpose |
|---|---|
-inkey |
Specifies the PEM private key. |
-in |
Defines the certificate PEM file. |
-export |
Creates a PKCS#12 container instead of reading one. |
-out |
Specifies the PKCS#12 destination. |
An empty export password can be used if the receiving software permits it.
OpenSSL 3 changed the default algorithms used for PKCS#12 files. Add -legacy if an older Windows component or Java keystore cannot import a PFX file created using the newer defaults.
Convert PKCS12 to PEM
openssl pkcs12 \
-in domain.pfx \
-nodes -out domain.combined.crt
| Flag | Purpose |
|---|---|
-in |
Defines the PKCS12 source file. |
-nodes |
Leaves the private key unencrypted in the resulting PEM output. |
-out |
Creates a combined PEM file containing the key and certificates. |
Convert PEM to PKCS7 P7B
openssl crl2pkcs7 -nocrl \
-certfile domain.crt \
-certfile ca-chain.crt \
-out domain.p7b
| Flag | Purpose |
|---|---|
crl2pkcs7 |
Creates PKCS#7 objects. |
-nocrl |
Prevents a certificate revocation list from being embedded. |
-certfile |
Adds one or more PEM certificate files. |
-out |
Defines the PKCS#7 output file. |
Convert PKCS7 to PEM
openssl pkcs7 \
-in domain.p7b \
-print_certs -out domain.crt
| Flag | Purpose |
|---|---|
pkcs7 |
Runs the PKCS#7 processing utility. |
-in |
Defines the PKCS#7 input file. |
-print_certs |
Outputs the certificates contained in the file as PEM. |
-out |
Defines the destination PEM file. |
Check the OpenSSL Version
The openssl version command reports the installed OpenSSL version and build configuration, which can determine whether specific commands and features are available.
openssl version -a
| Flag | Purpose |
|---|---|
version |
Displays OpenSSL library version information. |
-a |
Includes compiler information, directories, build flags, and other details. |
Example OpenSSL 3.x output:
OpenSSL 3.0.13 30 Jan 2024
built on: Wed Apr 10 12:00:00 2024 UTC
platform: linux-x86_64
compiler: gcc ...
OPENSSLDIR: "/usr/lib/ssl"
ENGINESDIR: "/usr/lib/x86_64-linux-gnu/engines-3"
MODULESDIR: "/usr/lib/x86_64-linux-gnu/ossl-modules"
Seeding source: os-specific
The upstream OpenSSL 1.0.x and 1.1.x branches are no longer maintained. Production systems should use a maintained OpenSSL 3.x release supplied by the operating-system vendor or follow the OpenSSL release policy when compiling OpenSSL from source.
OpenSSL vs LibreSSL, BoringSSL, and Rustls
OpenSSL remains a widely used toolkit on Linux servers and provides extensive support for file-based public-key infrastructure tasks. Other TLS libraries exist because different projects prioritize factors such as licensing, code size, API stability, platform requirements, or memory safety.
| Library | Maintained By | TLS 1.3 Support | Primary Strength | Typical Use |
|---|---|---|---|---|
| OpenSSL | OpenSSL team and community | Yes | Broad cryptographic algorithm support | General Linux administration, Apache mod_ssl, NGINX, and common server environments. |
| LibreSSL | OpenBSD project | Yes | Focused feature set | OpenBSD-focused environments or installations that prefer fewer legacy compatibility layers. |
| BoringSSL | Yes | Designed around Google’s application requirements | Chromium-derived software and environments tied to the corresponding consumer codebase. | |
| Rustls | Rustls contributors | Yes | Rust memory-safety model | Rust applications and services requiring TLS without linking against OpenSSL. |
When to Consider an OpenSSL Alternative
BoringSSL is suitable when software is closely aligned with Google’s TLS requirements or Chromium networking components. LibreSSL can be appropriate when an environment standardizes on OpenBSD and accepts differences in the command-line interface. Rustls is suited to Rust applications that require a native Rust TLS implementation without an OpenSSL dependency. OpenSSL remains a practical choice for everyday Linux certificate administration because it has broad documentation, distribution support, and third-party integration.
Renewing and Automating Certificate Rotation
Manual renewal can be practical for a very small number of servers. Larger environments should automate certificate renewal. Two approaches cover many common deployments.
ACME automation with Certbot can be used for public certificates from Let’s Encrypt or another ACME-compatible certificate authority:
sudo certbot renew --dry-run
A successful dry run confirms that the renewal configuration can function before the real certificate reaches its expiration date. Check whether the associated systemd timer is enabled:
sudo systemctl list-timers | grep certbot
Custom renewal scripts can be used with private certificate authorities or certificates that cannot be managed through ACME. Such a script should:
- Create a CSR using the same
san.cnfconfiguration used during the original issuance. - Submit the CSR to the applicable certificate authority endpoint or signing process.
- Replace the certificate under
/etc/ssl/certs/atomically. - Reload the application or web server only after a successful configuration test.
- Send a success or failure notification.
When possible, execute the script with a systemd timer instead of a traditional cron job. systemd timers provide journal logging, service dependencies, and support for retry behavior after temporary failures.
Certificate expiration should also be monitored independently from the renewal process. A broken timer or silently failing script can still result in an expired certificate. A weekly scheduled command that feeds openssl x509 -enddate -noout output into an alerting system can identify renewal failures before the certificate expires.
OpenSSL FAQ
How Do I Generate a CSR Using an Existing Private Key?
Run openssl req with -key pointing to the existing PEM private key and -new to generate a new CSR:
openssl req -key existing.key -new -out request.csr
Add -subj to avoid interactive prompts or -config when the CSR needs SAN entries or other configuration-defined extensions.
How Do I Add Subject Alternative Names to a CSR?
Define SAN entries under [req_ext] in an OpenSSL configuration file supplied through -config, or use -addext 'subjectAltName=DNS:example.com,DNS:www.example.com' with OpenSSL 1.1.1 or newer:
openssl req -new -key domain.key -out domain.csr -config san.cnf
Verify the result with openssl req -text -noout -in domain.csr.
How Do I Check When an SSL Certificate Expires?
Display the certificate’s notAfter field:
openssl x509 -enddate -noout -in domain.crt
Use -dates when both the notBefore and notAfter values are required.
How Do I Verify That a Private Key Matches a Certificate?
For RSA certificates, compare the modulus hashes:
openssl rsa -noout -modulus -in domain.key | openssl md5
openssl x509 -noout -modulus -in domain.crt | openssl md5
Identical results indicate that both files use the same RSA key pair.
How Do I Decode and Read a CSR?
Use req -text together with -verify to inspect the CSR and verify its signature:
openssl req -text -noout -verify -in domain.csr
The decoded output contains the subject Distinguished Name and requested SAN entries.
How Do I Convert a PEM Certificate to PFX or PKCS12?
Use pkcs12 -export and provide the private key, leaf certificate, and optional CA chain:
openssl pkcs12 -export -inkey domain.key -in domain.crt -certfile ca-chain.pem -out domain.pfx
Add -legacy when an older importer cannot process the default PKCS#12 algorithms used by OpenSSL 3.
What Is the Difference Between RSA 2048 and RSA 4096?
RSA 4096 uses a larger modulus than RSA 2048. This increases the amount of asymmetric cryptographic work required during TLS operations while providing a greater security margin against classical attacks. RSA 2048 remains a common choice for public TLS certificates, while RSA 4096 is appropriate when a security policy explicitly requires a larger key.
How Do I Use openssl s_client to Test a Live TLS Connection?
Create a client connection and display the negotiated TLS information:
openssl s_client -connect example.com:443 -servername example.com
Add -tls1_2 or -tls1_3 to test a specific TLS protocol version, and add -showcerts to display the PEM certificates sent by the remote server.
Test Specific TLS Protocol Versions
# Test TLS 1.2
openssl s_client -connect example.com:443 -tls1_2
# Test TLS 1.3
openssl s_client -connect example.com:443 -tls1_3
| Flag | Purpose |
|---|---|
-connect host:port |
Defines the TCP endpoint used for the TLS handshake. |
-tls1_2 |
Limits the client handshake to TLS 1.2. |
-tls1_3 |
Limits the client handshake to TLS 1.3 as defined by RFC 8446. |
If the server does not support the protocol version selected in the command, the handshake normally fails immediately. This should be interpreted as an indication of protocol support rather than automatically being considered a production configuration problem.
Check OCSP Stapling and Certificate Revocation
openssl s_client -connect example.com:443 -status 2>/dev/null | grep -A 17 'OCSP response:'
| Flag or Fragment | Purpose |
|---|---|
-connect |
Specifies the remote hostname and port. |
-status |
Requests a stapled OCSP response from the server. |
2>/dev/null |
Suppresses standard error so the filtered console output remains easier to read. |
grep -A 17 |
Displays the OCSP section together with the following lines. |
OCSP stapling allows a server to include a recent certificate-revocation response directly in the TLS handshake. If the result contains OCSP response: no response sent, the server has not supplied a stapled response. This behavior is common and does not necessarily indicate a problem.
Add -showcerts when you need to display every certificate provided in the remote certificate chain for offline inspection or storage as PEM files.
Diagnose Common TLS Errors with s_client
Several frequently encountered TLS handshake failures produce recognizable output when tested with s_client.
Hostname mismatch. The hostname used for the connection does not appear in the certificate’s SAN list:
verify error:num=62:Hostname mismatch
Issue a replacement certificate containing the correct SAN entries, or connect using a hostname that is already included in the certificate’s SAN list.
Expired certificate or certificate-chain element:
verify return code: 10 (certificate has expired)
Inspect every certificate supplied by the server, including all intermediate certificates. The following pipeline separates the certificate chain into individual files and displays the subject and expiration date of each certificate:
openssl s_client -connect example.com:443 -showcerts </dev/null 2>/dev/null \
| awk '/BEGIN CERTIFICATE/{n++} n{print > ("/tmp/cert-" n ".pem")}' \
&& for f in /tmp/cert-*.pem; do openssl x509 -subject -enddate -noout -in "$f"; done \
&& rm /tmp/cert-*.pem
The awk command stores each PEM block in a numbered file inside /tmp/. The for loop then displays the subject and notAfter value for every certificate, while the final rm command removes the temporary files. The pipeline relies on standard awk functionality and can be used on Linux, macOS, and BSD systems.
Untrusted intermediate certificate when the server sends only the leaf certificate:
verify return code: 21 (unable to verify the first certificate)
The server is not supplying the required intermediate certificate. With NGINX, concatenate the leaf certificate and intermediate certificate into a single file and configure ssl_certificate to use that file:
cat domain.crt intermediate.crt > fullchain.crt
Test mutual TLS client-certificate authentication:
openssl s_client \
-connect example.com:443 \
-cert client.crt \
-key client.key
Use this command when the server requires the client to provide a certificate. If mutual TLS is mandatory but no client certificate is supplied, the server can terminate the handshake with tlsv13 alert certificate required.
Converting Certificate Formats
Certificate Format Overview and Conversion Paths
| From Format | To Format | Common Use Case | Command Summary |
|---|---|---|---|
| PEM | DER | Java keystores and Windows certificate imports. | openssl x509 -outform der |
| DER | PEM | Working with certificates using text-oriented tools. | openssl x509 -inform der |
| PEM | PKCS12 | Windows IIS and bundled client certificates. | openssl pkcs12 -export |
| PKCS12 | PEM | Separating private keys and certificates. | openssl pkcs12 -nodes |
| PEM | PKCS7 | P7B certificate bundles used by some Microsoft-based workflows. | openssl crl2pkcs7 |
| PKCS7 | PEM | Inspecting certificates contained in P7B files. | openssl pkcs7 -print_certs |
Convert PEM to DER
openssl x509 \
-in domain.crt \
-outform der -out domain.der
| Flag | Purpose |
|---|---|
x509 |
Runs the X.509 certificate conversion utility. |
-in |
Specifies the PEM certificate input. |
-outform der |
Selects binary DER as the output format. |
-out |
Defines the destination file. |
Convert DER to PEM
The following command converts a binary DER-encoded certificate into a PEM-encoded certificate:
openssl x509 \
-inform der -in domain.der \
-out domain.crt
| Flag | Purpose |
|---|---|
-inform der |
Instructs OpenSSL to interpret the source as DER. |
-in |
Defines the DER input file. |
-out |
Defines the PEM output file. |
Convert PEM to PKCS12 PFX
Use the following command to export the private key, leaf certificate, and CA chain into one PKCS12 file:
openssl pkcs12 \
-export \
-inkey domain.key \
-in domain.crt \
-certfile ca-chain.pem \
-out domain.pfx
| Flag | Purpose |
|---|---|
-export |
Creates a PKCS#12 container. |
-inkey |
Specifies the private key. |
-in |
Specifies the leaf certificate. |
-certfile |
Adds extra certificates, usually intermediate certificates. |
-out |
Defines the PKCS12 output file. |
Minimal export without a separate certificate-chain file can be used when the leaf PEM file already contains the necessary intermediate certificates:
openssl pkcs12 \
-inkey domain.key \
-in domain.crt \
-export -out domain.pfx
| Flag | Purpose |
|---|---|
-inkey |
Defines the PEM private key. |
-in |
Defines the leaf certificate PEM file. |
-export |
Creates a PKCS#12 container instead of parsing an existing one. |
-out |
Defines the PKCS#12 output path. |
The export password can be left empty when the receiving software permits an unprotected export.
OpenSSL 3 introduced different default algorithms for PKCS#12 files. Add -legacy when a PFX file must be imported into older Windows components or Java keystores that cannot process the newer key-derivation settings.
Convert PKCS12 to PEM
openssl pkcs12 \
-in domain.pfx \
-nodes -out domain.combined.crt
| Flag | Purpose |
|---|---|
-in |
Defines the PKCS12 source file. |
-nodes |
Leaves the private key unencrypted in the resulting PEM file. |
-out |
Creates a combined PEM file containing the private key and certificates. |
Convert PEM to PKCS7 P7B
openssl crl2pkcs7 -nocrl \
-certfile domain.crt \
-certfile ca-chain.crt \
-out domain.p7b
| Flag | Purpose |
|---|---|
crl2pkcs7 |
Creates PKCS#7 objects. |
-nocrl |
Prevents a certificate revocation list from being embedded. |
-certfile |
Adds PEM certificate files and can be supplied more than once. |
-out |
Defines the PKCS#7 output file. |
Convert PKCS7 to PEM
openssl pkcs7 \
-in domain.p7b \
-print_certs -out domain.crt
| Flag | Purpose |
|---|---|
pkcs7 |
Runs the PKCS#7 processing utility. |
-in |
Defines the PKCS#7 source file. |
-print_certs |
Outputs the certificates contained in the file as PEM. |
-out |
Defines the destination PEM file. |
Check the OpenSSL Version
The openssl version command displays information about the installed OpenSSL binary and its build configuration, which can affect the availability of individual features.
openssl version -a
| Flag | Purpose |
|---|---|
version |
Displays OpenSSL library version information. |
-a |
Includes build flags, directories, compiler details, and related information. |
Example output from an OpenSSL 3.x installation:
OpenSSL 3.0.13 30 Jan 2024
built on: Wed Apr 10 12:00:00 2024 UTC
platform: linux-x86_64
compiler: gcc ...
OPENSSLDIR: "/usr/lib/ssl"
ENGINESDIR: "/usr/lib/x86_64-linux-gnu/engines-3"
MODULESDIR: "/usr/lib/x86_64-linux-gnu/ossl-modules"
Seeding source: os-specific
The upstream OpenSSL 1.0.x and 1.1.x branches have reached end of life. Production servers should therefore use maintained OpenSSL 3.x packages supplied by the operating-system provider or follow the official OpenSSL release strategy when compiling the software from source.
OpenSSL vs Alternatives: LibreSSL, BoringSSL, and Rustls
OpenSSL remains one of the most commonly used TLS toolkits on Linux servers and provides extensive functionality for file-based public-key infrastructure management. Alternative TLS libraries exist because different projects prioritize factors such as licensing, code-review scope, API stability, platform requirements, and memory-safety guarantees.
| Library | Maintained By | TLS 1.3 Support | Primary Strength | Typical Use |
|---|---|---|---|---|
| OpenSSL | OpenSSL team and community | Yes | Broad cryptographic algorithm coverage | General Linux administration, Apache mod_ssl, NGINX, and typical server environments. |
| LibreSSL | OpenBSD project | Yes | Focused feature set | OpenBSD-oriented deployments or systems designed with fewer legacy compatibility layers. |
| BoringSSL | Yes | Designed around the requirements of its primary consumers | Chromium-derived software and other applications that follow the corresponding TLS implementation. | |
| Rustls | Rustls contributors | Yes | Rust memory-safety model | Rust applications and services that require TLS without linking to OpenSSL. |
When to Consider an OpenSSL Alternative
BoringSSL can be appropriate when software needs to follow the TLS behavior expected by Chromium-based networking components. LibreSSL can be considered when a platform is standardized around OpenBSD and differences in command-line behavior are acceptable. Rustls is suitable for Rust applications that require a native Rust TLS implementation without an OpenSSL dependency. OpenSSL remains a practical option for general Linux server certificate administration because of its extensive documentation, distribution packages, and broad integration with other software.
Renewing and Automating Certificate Rotation
Manual certificate renewal can be manageable for one or two systems. Larger deployments generally benefit from automated renewal. Two approaches cover many common environments.
ACME automation with Certbot can be used for public certificates issued by Let’s Encrypt or another ACME-compatible certificate authority:
sudo certbot renew --dry-run
A successful dry run confirms that the configured renewal mechanism can renew certificates before they expire. Check whether the corresponding systemd timer is active:
sudo systemctl list-timers | grep certbot
A custom renewal script can be used for private certificate authorities or certificates that are not managed through ACME. The script should:
- Generate a CSR from the same
san.cnfconfiguration used during the original certificate issuance. - Submit the CSR to the appropriate certificate authority endpoint or signing utility.
- Replace the certificate file in
/etc/ssl/certs/atomically. - Reload the service that uses the certificate only after a successful configuration test.
- Send a notification indicating whether the process succeeded or failed.
When possible, run the renewal script through a systemd timer rather than a traditional cron job. systemd timers write information to the journal, support service dependencies, and can retry after temporary failures.
Certificate expiration should also be monitored independently of the renewal process. An incorrectly configured timer or a renewal script that fails silently can still result in an expired certificate. A weekly scheduled task that passes openssl x509 -enddate -noout output into an alerting system can identify situations where automatic renewal has stopped working.
OpenSSL FAQ
How Do I Generate a CSR Using an Existing Private Key Instead of Creating a New One?
Run openssl req with -key pointing to the existing PEM private key and use -new to create a new CSR file:
openssl req -key existing.key -new -out request.csr
Add -subj when you want to avoid interactive prompts, or use -config when SAN values or other configuration-defined extensions need to be included.
How Do I Add Subject Alternative Names SANs to a CSR?
Define SAN entries in the [req_ext] section of an OpenSSL configuration file referenced through -config, or use -addext 'subjectAltName=DNS:example.com,DNS:www.example.com' when running OpenSSL 1.1.1 or newer:
openssl req -new -key domain.key -out domain.csr -config san.cnf
Verify the resulting CSR with openssl req -text -noout -in domain.csr.
How Do I Check When an SSL Certificate Expires?
Display the certificate’s notAfter field:
openssl x509 -enddate -noout -in domain.crt
Use -dates when both the notBefore and notAfter values are required.
How Do I Verify That a Private Key Matches a Certificate?
For RSA certificates, compare the modulus hashes:
openssl rsa -noout -modulus -in domain.key | openssl md5
openssl x509 -noout -modulus -in domain.crt | openssl md5
If both commands produce identical output, the certificate and private key belong to the same RSA key pair.
How Do I Decode and Read the Contents of a CSR?
Use req -text together with -verify to inspect the CSR structure and validate its signature:
openssl req -text -noout -verify -in domain.csr
The decoded information includes the subject Distinguished Name and any requested SAN entries.
How Do I Convert a PEM Certificate to PFX or PKCS12 Format?
Use pkcs12 -export and reference the private key, leaf certificate, and optional CA chain:
openssl pkcs12 -export -inkey domain.key -in domain.crt -certfile ca-chain.pem -out domain.pfx
Add -legacy if an older certificate importer cannot process the default PKCS#12 algorithms used by OpenSSL 3.
What Is the Difference Between RSA 2048 and RSA 4096 for a Private Key?
RSA 4096 uses a larger modulus than RSA 2048. This increases the amount of asymmetric cryptographic processing required during TLS operations while providing an additional security margin under classical threat models. RSA 2048 remains a commonly used default for public TLS certificates, while RSA 4096 is appropriate when organizational or regulatory policies specifically require a larger key.
How Do I Use openssl s_client to Test a Live TLS Connection?
Create a client connection and display the negotiated TLS parameters with the following command:
openssl s_client -connect example.com:443 -servername example.com
Add -tls1_2 or -tls1_3 to restrict the test to a specific TLS version, and use -showcerts when you need OpenSSL to display the PEM certificate chain supplied by the remote server.
Conclusion
This guide covered OpenSSL workflows for RSA and EC private keys, CSR creation with SAN entries using configuration files and -addext, several methods for generating self-signed certificates, SAN support for self-signed certificates, PEM inspection commands, RSA modulus comparison, certificate-expiration checks, CA bundle verification, certificate-chain validation with intermediate certificates, live TLS testing with openssl s_client, and conversion between PEM, DER, PKCS12, and PKCS7 formats.
These techniques allow administrators to create private keys securely, submit CSRs that comply with modern hostname-validation requirements, validate certificates before enabling HTTPS, diagnose TLS handshake behavior on remote endpoints, and create certificate bundles for mixed Linux and Windows environments while taking the OpenSSL 3 PKCS12 defaults into account.


