Practical OpenSSL: Essential Commands for SSL Certificate Management

A practical starter guide to OpenSSL commands for installing, inspecting, splitting, exporting, and working with PFX certificates.

OpenSSL is an open-source toolkit used to work with TLS/SSL, certificates, keys, and cryptographic operations.

If you work in DevOps or platform engineering, you don’t need to be a full-time PKI specialist to benefit from it. You just need a reliable set of commands you can use when the usual certificate tasks show up.

In real environments, this comes up more often than people expect:

  • checking if a certificate is valid or expired
  • inspecting certificate details during incident response
  • converting certificate formats between teams and tools
  • extracting certs and keys from .pfx files for load balancers, ingress, or app configs

Knowing a few practical OpenSSL commands helps you troubleshoot faster, automate safely, and avoid guesswork when security-related changes are on the critical path.

This guide keeps it hands-on: copy/paste-ready commands, plain-English explanations, and no crypto gatekeeping.

OpenSSL Installation

First up, let’s install OpenSSL and make sure your terminal can find it straight away.

1
2
3
4
5
6
7
8
# Install OpenSSL Package
winget install --exact --id 'FireDaemon.OpenSSL'

# Reload Environment Paths
$env:Path = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path', 'User')

# Check OpenSSL Version
openssl version
1
2
3
4
5
# Install OpenSSL Package
sudo apt install -y openssl

# Check OpenSSL Version
openssl version

OpenSSL Commands

The examples below use a local cert-lab folder so you can test safely before touching real certificates.

Important

IMPORTANT
These examples are for local testing and learning only. Don’t use self-signed certs in production.

Generate a local test certificate

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Create a local working folder
New-Item -ItemType Directory -Path .\cert-lab -Force | Out-Null
Set-Location .\cert-lab

# Generate key + self-signed cert (30 days)
openssl req -x509 -newkey rsa:2048 -sha256 -days 30 -nodes `
  -keyout localhost.key `
  -out localhost.crt `
  -subj "/CN=localhost" `
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"

# Quick sanity check
openssl x509 -in localhost.crt -noout -subject -issuer -dates -ext subjectAltName
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Create a local working folder
mkdir -p ./cert-lab
cd ./cert-lab

# Generate key + self-signed cert (30 days)
openssl req -x509 -newkey rsa:2048 -sha256 -days 30 -nodes \
  -keyout localhost.key \
  -out localhost.crt \
  -subj "/CN=localhost" \
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"

# Quick sanity check
openssl x509 -in localhost.crt -noout -subject -issuer -dates -ext subjectAltName

Generate a local test certificate pfx

This is useful when an app, gateway, or platform expects a .pfx/.p12 bundle.

1
2
3
4
5
# Create Pfx Certificate file
openssl pkcs12 -export -out .\cert-lab\localhost.pfx -inkey .\cert-lab\localhost.key -in .\cert-lab\localhost.crt -passout pass:ChangeMe123!

# Inspect package metadata (no key output)
openssl pkcs12 -info -in .\cert-lab\localhost.pfx -noout -passin pass:ChangeMe123!
1
2
3
4
openssl pkcs12 -export -out ./cert-lab/localhost.pfx -inkey ./cert-lab/localhost.key -in ./cert-lab/localhost.crt -passout pass:ChangeMe123!

# Inspect package metadata (no key output)
openssl pkcs12 -info -in ./cert-lab/localhost.pfx -noout -passin pass:ChangeMe123!

Inspect certificate details

1
openssl x509 -in .\cert-lab\localhost.crt -text -noout
1
openssl x509 -in ./cert-lab/localhost.crt -text -noout

Check expiry and validity window quickly

1
2
3
4
5
# Show notBefore / notAfter
openssl x509 -in .\cert-lab\localhost.crt -noout -dates

# Returns success if cert is valid for at least 30 more days (2,592,000 seconds)
openssl x509 -checkend 2592000 -noout -in .\cert-lab\localhost.crt
1
2
3
4
5
# Show notBefore / notAfter
openssl x509 -in ./cert-lab/localhost.crt -noout -dates

# Returns success if cert is valid for at least 30 more days (2,592,000 seconds)
openssl x509 -checkend 2592000 -noout -in ./cert-lab/localhost.crt

Check and validate a CSR

Use this before submitting a request to your CA so you can catch mistakes early.

1
2
3
4
5
# Full CSR details + signature verification
openssl req -in .\cert-lab\request.csr -noout -text -verify

# Quick subject check
openssl req -in .\cert-lab\request.csr -noout -subject
1
2
3
4
5
# Full CSR details + signature verification
openssl req -in ./cert-lab/request.csr -noout -text -verify

# Quick subject check
openssl req -in ./cert-lab/request.csr -noout -subject

Decrypt an encrypted private key (remove passphrase)

Use this when automation or a service account needs a non-interactive key file.

Important

IMPORTANT
A decrypted private key is sensitive. Lock down file permissions and only use where required.

1
2
3
4
5
# Convert encrypted key -> unencrypted key (you will be prompted for the input key passphrase)
openssl pkey -in .\cert-lab\encrypted.key -out .\cert-lab\private.key

# Optional: confirm key is readable
openssl pkey -in .\cert-lab\private.key -check -noout
1
2
3
4
5
# Convert encrypted key -> unencrypted key (you will be prompted for the input key passphrase)
openssl pkey -in ./cert-lab/encrypted.key -out ./cert-lab/private.key

# Optional: confirm key is readable
openssl pkey -in ./cert-lab/private.key -check -noout

Split a .pfx into leaf cert, chain certs, and private key

This is one of the most common DevOps tasks when moving certs between systems.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Create output folder for split artifacts
New-Item -ItemType Directory -Path .\cert-lab\decompiled -Force | Out-Null

# Leaf/end-entity certificate only
openssl pkcs12 -in .\cert-lab\localhost.pfx -clcerts -nokeys -out .\cert-lab\decompiled\leaf.crt -passin pass:ChangeMe123!

# CA chain certificates (intermediate/root if present in bundle)
openssl pkcs12 -in .\cert-lab\localhost.pfx -cacerts -nokeys -out .\cert-lab\decompiled\chain.crt -passin pass:ChangeMe123!

# Private key
openssl pkcs12 -in .\cert-lab\localhost.pfx -nocerts -nodes -out .\cert-lab\decompiled\private.key -passin pass:ChangeMe123!

# Quick inspect: identify leaf vs chain by Subject/Issuer
openssl x509 -in .\cert-lab\decompiled\leaf.crt -noout -subject -issuer

# You now have split outputs in .\cert-lab\decompiled\
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Create output folder for split artifacts
mkdir -p ./cert-lab/decompiled

# Leaf/end-entity certificate only
openssl pkcs12 -in ./cert-lab/localhost.pfx -clcerts -nokeys -out ./cert-lab/decompiled/leaf.crt -passin pass:ChangeMe123!

# CA chain certificates (intermediate/root if present in bundle)
openssl pkcs12 -in ./cert-lab/localhost.pfx -cacerts -nokeys -out ./cert-lab/decompiled/chain.crt -passin pass:ChangeMe123!

# Private key
openssl pkcs12 -in ./cert-lab/localhost.pfx -nocerts -nodes -out ./cert-lab/decompiled/private.key -passin pass:ChangeMe123!

# Quick inspect: identify leaf vs chain by Subject/Issuer
openssl x509 -in ./cert-lab/decompiled/leaf.crt -noout -subject -issuer

# You now have split outputs in ./cert-lab/decompiled/

Verify that certificate / CSR / private key match

The safest way is to compare a hash of each public key.

If the hashes are the same, they belong together.

1
2
3
4
5
6
7
8
# Cert public key fingerprint
openssl x509 -in .\cert-lab\decompiled\leaf.crt -noout -pubkey | openssl pkey -pubin -outform der | openssl sha256

# Private key public key fingerprint
openssl pkey -in .\cert-lab\decompiled\private.key -pubout -outform der | openssl sha256

# CSR public key fingerprint
openssl req -in .\cert-lab\request.csr -noout -pubkey | openssl pkey -pubin -outform der | openssl sha256
1
2
3
4
5
6
7
8
# Cert public key fingerprint
openssl x509 -in ./cert-lab/decompiled/leaf.crt -noout -pubkey | openssl pkey -pubin -outform der | openssl sha256

# Private key public key fingerprint
openssl pkey -in ./cert-lab/decompiled/private.key -pubout -outform der | openssl sha256

# CSR public key fingerprint
openssl req -in ./cert-lab/request.csr -noout -pubkey | openssl pkey -pubin -outform der | openssl sha256

Troubleshooting and Issues

Even when your commands are correct, certificate tasks can fail for non-obvious reasons. Here are the issues that come up most often.

“Key values mismatch” or cert won’t bind to service

Cause: The certificate and private key are from different keypairs.
Fix: Compare public key fingerprints from cert and key. They must match.

1
2
openssl x509 -in .\cert-lab\decompiled\leaf.crt -noout -pubkey | openssl pkey -pubin -outform der | openssl sha256
openssl pkey -in .\cert-lab\decompiled\private.key -pubout -outform der | openssl sha256
1
2
openssl x509 -in ./cert-lab/decompiled/leaf.crt -noout -pubkey | openssl pkey -pubin -outform der | openssl sha256
openssl pkey -in ./cert-lab/decompiled/private.key -pubout -outform der | openssl sha256

Browser/app says hostname is invalid

Cause: The certificate SAN does not include the hostname you’re using.
Fix: Reissue cert with the correct subjectAltName values (DNS/IP).

Quick check:

1
openssl x509 -in .\cert-lab\decompiled\leaf.crt -noout -ext subjectAltName
1
openssl x509 -in ./cert-lab/decompiled/leaf.crt -noout -ext subjectAltName

Certificate chain errors (incomplete chain / unknown CA)

Cause: Only leaf cert is deployed, missing intermediate(s).
Fix: Deploy full chain in the order your platform expects (usually leaf + intermediate).

Quick check:

1
openssl verify -CAfile .\cert-lab\decompiled\chain.crt .\cert-lab\decompiled\leaf.crt
1
openssl verify -CAfile ./cert-lab/decompiled/chain.crt ./cert-lab/decompiled/leaf.crt

“bad decrypt” / “mac verify failure” when opening .pfx

Cause: Wrong password, corrupted file, or incompatible encoding/transfer.
Fix:

  • Re-check password source (watch hidden whitespace)
  • Re-export PFX from original source if possible
  • Re-transfer file in binary-safe mode

Quick check:

1
openssl pkcs12 -info -in .\cert-lab\localhost.pfx -noout
1
openssl pkcs12 -info -in ./cert-lab/localhost.pfx -noout

“unable to load private key”

Cause: Wrong file format, encrypted key without passphrase provided, or key file damage.
Fix:

  • Try reading with openssl pkey -in ...
  • Convert to PKCS#8 if needed
  • Confirm the file begins with a valid PEM header (for PEM files)

Quick check:

1
openssl pkey -in .\cert-lab\decompiled\private.key -check -noout
1
openssl pkey -in ./cert-lab/decompiled/private.key -check -noout

CSR looks fine but issued cert is still wrong

Cause: CA template/profile overrides CSR fields (common in enterprise PKI).
Fix: Validate both sides:

  • inspect CSR before submission
  • inspect issued cert after issuance
  • compare SAN/subject/key usage/extended key usage

Wrap Up

OpenSSL covers a lot of ground, but most day-to-day certificate work comes down to a small set of commands you’ll reach for repeatedly — inspecting certs, checking expiry, exporting to .pfx, splitting bundles, and verifying key pairs.

The cert-lab setup at the start of this guide gives you a safe place to practice all of it without touching production certificates. Run through the commands, break things intentionally, and get comfortable reading the output before you need it under pressure.

A few things worth keeping in mind:

  • Always verify a cert/key pair matches before deploying
  • Check SANs match the hostname your service is actually using
  • When in doubt about a chain error, openssl verify is your first stop
  • Decrypted private keys need tight file permissions — treat them like passwords

If you hit an error not covered here, the output from openssl ... -text -noout usually gives you enough to work with.

Share with your network!

Built with Hugo - Theme Stack designed by Jimmy