Appendix

File formats: PEM, DER, PKCS #12 and friends

In one sentence

The formats are wrappings of the same data: DER is binary, PEM is DER in Base64, PKCS #12 bundles a key with its certificates, and PKCS #7 carries certificates only.

Who is this for

Level: Practitioner

On this page
  1. What is the actual data inside?
  2. What are the main formats?
  3. What do the file extensions mean?
  4. How do I convert between them?
  5. Go deeper

A certificate is one fixed structure defined in RFC 5280. The file formats below are only different ways of storing or packing it, sometimes together with a private key or other certificates. Once you know which wrapping you have, converting is one command.

What is the actual data inside?

Certificates, CSRs, CRLs and keys are described in ASN.1 and stored as bytes using DER, the Distinguished Encoding Rules. DER always gives exactly one byte sequence for a given value, which matters because a signature is computed over those exact bytes. A DER certificate usually starts with the bytes 30 82: an ASN.1 SEQUENCE followed by a two-byte length.

od -An -tx1 -N4 cert.der
 30 82 01 b2

What are the main formats?

Format Encoding What it holds Typical extensions Where you meet it
DER Binary One certificate, CSR, CRL or key .der, .cer, .crt Windows, Java, embedded devices
PEM Text: Base64 of DER between -----BEGIN …----- and -----END …----- lines One or more objects, each with a label .pem, .crt, .cer, .key, .csr OpenSSL, nginx, Apache, Linux, Kubernetes secrets
PKCS #12 (PFX) Binary, password-protected A private key plus its certificate and chain .p12, .pfx Windows and IIS import and export, Java keystores, cloud services
PKCS #7 (P7B) Binary or PEM Certificates (and CRLs) only, no private key .p7b, .p7c Windows chain exports, some CAs’ downloads
PKCS #8 Usually PEM One private key, optionally encrypted .key, .pem Any modern library
PKCS #10 Usually PEM A certificate signing request .csr, .req Requests sent to a CA
JKS Binary, Java only Keys and trusted certificates .jks, .keystore Older Java applications

PEM: DER with a label

RFC 7468 standardises the PEM labels. The label tells you what is inside:

PEM label What it contains Defined in
CERTIFICATE An X.509 certificate RFC 5280
X509 CRL A certificate revocation list RFC 5280
CERTIFICATE REQUEST A PKCS #10 CSR RFC 2986
PKCS7 and CMS A PKCS #7 or CMS structure, such as a certificate bundle RFC 2315, RFC 5652
PRIVATE KEY An unencrypted PKCS #8 private key RFC 5208, RFC 5958
ENCRYPTED PRIVATE KEY A password-protected PKCS #8 private key RFC 5958
PUBLIC KEY A public key on its own (SubjectPublicKeyInfo) RFC 5280

You will also see labels outside that list. RSA PRIVATE KEY and EC PRIVATE KEY are older “traditional” key formats (PKCS #1 for RSA, SEC 1 for elliptic curves) that OpenSSL still reads and can still write:

openssl genrsa -out rsa.key 2048 && head -1 rsa.key
openssl genrsa -traditional -out rsa-old.key 2048 && head -1 rsa-old.key
-----BEGIN PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----

A PEM file can hold several objects one after another. A “full chain” file is the server certificate first, then each intermediate in order. Leave the root out: the client must already have it. RFC 7468 also allows text before the BEGIN line, which is why some tools write “Bag Attributes” lines there; most software ignores them.

PKCS #12 and PFX: the identity in one file

RFC 7292 defines PKCS #12. PFX is the older name for the same format; Windows still uses the .pfx extension. A PKCS #12 file can hold a private key, its certificate, the chain and a friendly name, all protected by a password. That makes it the usual way to move a server identity between systems, and also the file to guard most carefully.

openssl pkcs12 -in bundle.p12 -info -noout -passin pass:changeit
MAC: sha256, Iteration 2048
MAC length: 32, salt length: 8
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
Certificate bag
PKCS7 Data
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256

“Certificate bag” and “Shrouded Keybag” are the certificate and the encrypted private key. OpenSSL 3 protects both with AES-256 by default. Some older systems only open the legacy format, which -legacy produces; it protects the certificates with 40-bit RC2, which is weak, so use it only when you have no choice.

PKCS #7 and P7B: certificates without a key

A .p7b file is a PKCS #7 (or CMS, RFC 5652) SignedData structure that carries certificates but no signature and no key. It is a convenient way to ship a whole chain. To use it with OpenSSL-based software, unpack it into PEM certificates:

openssl pkcs7 -in bundle.p7b -print_certs -noout
subject=CN=www.example.com
issuer=CN=www.example.com

Add -inform DER if the file is binary, and replace -noout with -out certs.pem to write the certificates out.

Java keystores: JKS and PKCS #12

Java stores keys and trusted certificates in a keystore. The old Java-only format is JKS. Since JDK 9 the default keystore type is PKCS #12, the same standard format as above, so a .p12 file from OpenSSL can be used directly as a Java keystore. Each entry has an alias and is either a PrivateKeyEntry (a key with its certificate chain) or a trustedCertEntry (a CA certificate to trust). keytool itself recommends moving away from JKS; the cheat sheet has the conversion command and its warning text.

What do the file extensions mean?

Less than you would hope. An extension is a convention, not a promise:

  • .crt and .cer usually hold one certificate, but it can be PEM or DER. Windows’ certificate export offers both “DER encoded binary” and “Base-64 encoded” under the same .cer extension.
  • .pem says the file is text with BEGIN lines. It can hold certificates, keys or both.
  • .key usually holds a PEM private key, encrypted or not.
  • .p12 and .pfx are the same format.
  • .p7b and .p7c hold certificate bundles without keys.

So look inside instead. If the first line starts with -----BEGIN, it is PEM, and the label tells you the rest. If not, it is binary: try openssl x509 -inform DER, then openssl pkcs12 -info, then openssl pkcs7 -inform DER. On Linux and in Git Bash, file often recognises certificates:

file -b cert.pem cert.der req.csr
PEM certificate
Certificate, Version=3
PEM certificate request

Do not trust file blindly for keys: it can mislabel a PEM private key. The BEGIN line is more reliable.

How do I convert between them?

From To Command
PEM certificate DER openssl x509 -in cert.pem -outform DER -out cert.der
DER certificate PEM openssl x509 -in cert.der -inform DER -out cert.pem
PEM key + certificate + chain PKCS #12 openssl pkcs12 -export -in cert.pem -inkey key.pem -certfile chain.pem -out bundle.p12
PKCS #12 PEM certificates openssl pkcs12 -in bundle.p12 -nokeys -out certs.pem
PKCS #12 PEM key openssl pkcs12 -in bundle.p12 -nocerts -noenc -out key.pem
PKCS #7 / P7B PEM certificates openssl pkcs7 -in bundle.p7b -print_certs -out certs.pem
PEM certificates PKCS #7 / P7B openssl crl2pkcs7 -nocrl -certfile certs.pem -out bundle.p7b
Traditional RSA or EC key PKCS #8 openssl pkey -in old.key -out key.pem
PKCS #8 key Encrypted PKCS #8 openssl pkey -in key.pem -aes256 -out key-enc.pem
Private key Its public key openssl pkey -in key.pem -pubout -out pub.pem
DER Base64 (Windows) certutil -encode cert.der cert-b64.cer
JKS PKCS #12 keytool -importkeystore -srckeystore old.jks -destkeystore new.p12 -deststoretype PKCS12

Every command in this table was run for this page. -noenc writes an unencrypted key, so protect the result (chmod 600 on Linux) and delete copies you no longer need.

Paste any PEM certificate into the decoder to see the fields inside it:

Try it: Certificate decoderOpen the full tool

Runs in your browser. Nothing you paste is sent anywhere.

PEM text, several PEM blocks, or a .pem, .crt, .cer or .der file (drop it on the box). Certificates are public, so they are safe to paste.

Go deeper

Early edition. Checked against the standards; an independent expert review is in progress. Found a mistake? Tell us.

Last reviewed Edition 0.9