OpenSSL Cheatsheet

Format Conversion

Use this OpenSSL reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

The formats, at a glance

Everything is the same ASN.1 structure. The differences are the encoding and what else is bundled alongside.

FormatExtensionsWhat it is
PEM.pem .crt .cer .keyBase64 DER wrapped in -----BEGIN X-----
DER.der .cer .crtRaw binary ASN.1, one object per file
PKCS#1.key .pemRSA key, BEGIN RSA PRIVATE KEY
PKCS#8.key .p8Any key type, BEGIN PRIVATE KEY
PKCS#12.p12 .pfxEncrypted bundle: key + cert + chain
PKCS#7.p7b .p7cCertificates only, no key

The PEM header tells you what you actually have:

HeaderContents
BEGIN CERTIFICATEX.509 certificate
BEGIN CERTIFICATE REQUESTCSR
BEGIN PRIVATE KEYPKCS#8, unencrypted, any algorithm
BEGIN ENCRYPTED PRIVATE KEYPKCS#8, passphrase protected
BEGIN RSA PRIVATE KEYPKCS#1, RSA only, legacy
BEGIN EC PRIVATE KEYSEC1, EC only, legacy
BEGIN PUBLIC KEYSubjectPublicKeyInfo
BEGIN OPENSSH PRIVATE KEYNot OpenSSL, use ssh-keygen

PEM and DER

-inform describes the input, -outform the output. Same pair on every subcommand.

# Certificates
openssl x509 -in cert.pem -outform DER -out cert.der
openssl x509 -in cert.der -inform DER -out cert.pem

# Keys
openssl pkey -in key.pem -outform DER -out key.der
openssl pkey -in key.der -inform DER -out key.pem

# CSRs
openssl req -in req.csr -outform DER -out req.der
openssl req -in req.der -inform DER -out req.csr

Tell them apart without reading the file:

file cert.der          # "data" for DER, "ASCII text" for PEM
head -1 cert.pem       # PEM starts with -----BEGIN

PKCS#1, SEC1, PKCS#8

PKCS#8 is the modern container and the one OpenSSL 3.x writes by default. Older Java, some appliances, and Go's x509.ParsePKCS1PrivateKey want the legacy forms.

# legacy (BEGIN RSA PRIVATE KEY)  ->  PKCS#8 (BEGIN PRIVATE KEY)
openssl pkcs8 -topk8 -nocrypt -in rsa1.key -out pkcs8.key

# PKCS#8  ->  legacy
openssl rsa -in pkcs8.key -traditional -out rsa1.key
openssl pkey -in pkcs8.key -traditional -out rsa1.key

# PKCS#8, encrypted with a modern PBES2 cipher
openssl pkcs8 -topk8 -in key.pem -out enc.key -v2 aes-256-cbc

# decrypt an encrypted PKCS#8
openssl pkcs8 -in enc.key -out key.pem

-nocrypt on -topk8 means "write it unencrypted". Leave it off and OpenSSL prompts for a passphrase and encrypts.

PKCS#12 (.p12 and .pfx)

One password protected file holding the key, the leaf, and the chain. Windows, macOS Keychain, Java keystores, and most load balancers import this.

# Build one
openssl pkcs12 -export -out bundle.p12 \
  -inkey key.pem -in cert.pem -certfile chain.pem \
  -name "example.com"

# Build one and let OpenSSL find the chain in the trust store
openssl pkcs12 -export -out bundle.p12 -inkey key.pem -in cert.pem -chain

Take it apart:

openssl pkcs12 -in bundle.p12 -out all.pem -noenc       # key + all certs
openssl pkcs12 -in bundle.p12 -nokeys -out certs.pem    # certs only
openssl pkcs12 -in bundle.p12 -nocerts -noenc -out key.pem
openssl pkcs12 -in bundle.p12 -clcerts -nokeys -out cert.pem   # leaf only
openssl pkcs12 -in bundle.p12 -cacerts -nokeys -out chain.pem  # chain only
openssl pkcs12 -in bundle.p12 -info -noout              # what is inside

Non-interactive, for scripts:

openssl pkcs12 -export -out bundle.p12 -inkey key.pem -in cert.pem \
  -passout pass:changeit
openssl pkcs12 -in bundle.p12 -nokeys -out certs.pem -passin pass:changeit

An empty password is -passout pass: with nothing after the colon, which some Java tools require.

PKCS#7 and bundles

PKCS#7 carries certificates only, never a key. .p7b files from Windows CAs are this.

openssl pkcs7 -in chain.p7b -print_certs -out chain.pem
openssl pkcs7 -in chain.p7b -inform DER -print_certs -out chain.pem
openssl pkcs7 -in chain.p7b -print_certs -noout            # just list them

# PEM bundle -> PKCS#7
openssl crl2pkcs7 -nocrl -certfile chain.pem -out chain.p7b

A multi-certificate PEM bundle is literally concatenation, so cat and split are valid tools:

cat cert.pem intermediate.pem root.pem > bundle.pem

Gotchas

- OpenSSL 3.x refuses to read old PKCS#12 files made with RC2 or 40-bit RC4 and errors with unsupported or error:0308010C. Add -legacy, and add -legacy when writing a file for an ancient client too. - -descert on export writes 3DES, only needed for pre-2010 importers. The 3.x default is PBES2 with PBKDF2 and AES-256-CBC, which old Java rejects. - -nodes is now -noenc. Both still parse, -noenc is what the help text shows. - openssl rsa, openssl ec, and openssl dsa are algorithm specific. openssl pkey handles all of them, so scripts should use pkey. - DER holds exactly one object. There is no such thing as a DER chain file, so a chain must be PEM, PKCS#7, or PKCS#12. - .cer and .crt say nothing about the encoding. Windows exports both DER and PEM as .cer. Check the first line before you convert. - Java keytool cannot import a bare PEM key. Go through PKCS#12: keytool -importkeystore -srckeystore bundle.p12 -srcstoretype PKCS12 -destkeystore ks.jks.