Skip to content
ecdsa.com

PEM ⇄ DER · OpenSSL

How to convert a certificate and a private key between PEM and DER with OpenSSL

To convert a certificate between PEM and DER with OpenSSL, run openssl x509 with -outform DER (or -inform DER to go back); for a private key, openssl pkcs8 -topk8 -nocrypt -outform DER gives PKCS#8 DER on every OpenSSL version. This recipe converts a certificate, a key and its public key both ways and checks that the round trip is byte-identical.

Tested with OpenSSL 3.5.7 (Debian 13).

certificate PEM ⇄ DER
# Certificate: PEM -> DER, and DER -> PEM
openssl x509 -in cert.pem -outform DER -out cert.der
openssl x509 -in cert.der -inform DER -out cert-again.pem
private key PEM ⇄ PKCS#8 DER, and the public key as DER
# Private key -> PKCS#8 DER on every OpenSSL version (unencrypted: -nocrypt)
openssl pkcs8 -topk8 -nocrypt -in key.pem -outform DER -out key.der
# ...and back to PKCS#8 PEM ("BEGIN PRIVATE KEY")
openssl pkey -in key.der -inform DER -out key-again.pem
# The public key as DER (SubjectPublicKeyInfo)
openssl pkey -in key.pem -pubout -outform DER -out pub.der

How it works

  1. PEM is DER in base64 between -----BEGIN …----- and -----END …----- lines, so the conversion changes the encoding, never the content: the certificate's DER is 563 bytes here and converting it back gives a file identical to the original PEM.
  2. openssl x509 -outform DER writes the binary form; -inform DER reads it, and without -outform DER the output is PEM again.
  3. openssl pkcs8 -topk8 -nocrypt -outform DER writes the key as PKCS#8 (PrivateKeyInfo, 138 bytes for this P-256 key) — the form crypto.subtle.importKey("pkcs8"), Java's PKCS8EncodedKeySpec and most libraries expect. Drop -nocrypt to get an encrypted PKCS#8 DER.
  4. openssl pkey -pubout -outform DER writes the public key as SubjectPublicKeyInfo DER (91 bytes for P-256).

Gotchas

  • On OpenSSL 3.5 and earlier (3.5.7 in the run), openssl pkey -outform DER writes an EC key in the traditional SEC1 structure (ECPrivateKey, 121 bytes, first INTEGER 01), not PKCS#8 (first INTEGER 00) — even though the PEM it reads is PKCS#8. OpenSSL 3.6 writes PKCS#8 there; openssl pkcs8 -topk8 gives PKCS#8 on every version.
  • DER has no label: a .der file does not say whether it holds a certificate, a SEC1 key or a PKCS#8 key. Name files after their content, or inspect them with openssl asn1parse -inform DER.
  • OpenSSL 3 detects the input format when reading — openssl x509 -in cert.der works without -inform DER — but output is PEM unless you pass -outform DER.

Related recipes