PEM vs DER — Certificate & Key Encoding Compared
Every X.509 certificate, RSA key, and CSR is ultimately ASN.1 DER-encoded binary data. But how you store and transmit that data depends on the encoding format: DER (binary) or PEM (Base64 ASCII). They contain the same data — the difference is purely in the encoding wrapper. Choosing the wrong format causes "invalid certificate" errors, failed TLS handshakes, and smart card personalization failures. This guide covers everything you need to know.
Specs at a Glance
| Property | PEM | DER |
|---|---|---|
| Full name | Privacy-Enhanced Mail | Distinguished Encoding Rules |
| Encoding | Base64-encoded ASCII text | Raw binary |
| Line length | 64 chars per line (RFC 1421) | N/A (binary) |
| Headers | Yes: -----BEGIN ...----- / -----END ...----- | No headers |
| Human-readable | Partially (headers visible, content is Base64) | No (binary) |
| Typical file size | ~33% larger than DER | Smallest possible |
| File extensions | .pem, .crt, .cer, .key, .csr | .der, .cer, .crt, .key |
| Multi-object support | Yes (concatenate multiple PEM blocks) | No (one object per file) |
| Standard | RFC 7468 (originally RFC 1421) | ITU-T X.690 |
1. DER — The Binary Format
DER (Distinguished Encoding Rules) is the actual encoding of ASN.1 data. It produces a single canonical binary representation. Every X.509 certificate, RSA key, and CSR is DER-encoded at its core.
DER Structure
DER = Tag || Length || Value (TLV encoding)
Example: An X.509 certificate in DER starts with:
30 82 03 E7 → SEQUENCE, length 0x03E7 (999 bytes)
30 82 03 A3 → SEQUENCE (tbsCertificate)
A0 03 → [0] (version = v3)
02 01 02 → INTEGER 2
02 08 → INTEGER (serial number)
4A 3B C8 ...
...
DER is used by:
- Smart cards — X.509 certificates stored on smart cards (PIV, CAC) are in DER format
- Java Keystores (JKS) — certificates stored in Java keystores are DER internally
- Windows Certificate Store — uses DER internally
- EMV cards — issuer certificates on EMV chips are DER-encoded
- MIFARE DESFire — card certificates are DER
2. PEM — The Text Format
PEM wraps DER data in Base64 encoding with text headers. This makes it safe for email, copy-paste, configuration files, and any text-based protocol.
PEM Structure
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKQb8v3m5JUmMA0GCSqGSIb3DQEBCwUAMFUxCzAJ
BgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4g
RnJhbmNpc2NvMQ8wDQYDVQQKDAZDYXJkV2lzZT...
-----END CERTIFICATE-----
The Base64 content between the headers is the exact same DER data, just encoded in Base64 (per RFC 4648). No data is added or lost in conversion.
Common PEM Header Types
| PEM Header | Content | ASN.1 Type |
|---|---|---|
BEGIN CERTIFICATE | X.509 certificate | Certificate |
BEGIN CERTIFICATE REQUEST | PKCS#10 CSR | CertificationRequest |
BEGIN RSA PRIVATE KEY | RSA private key (PKCS#1) | RSAPrivateKey |
BEGIN PRIVATE KEY | Private key (PKCS#8, algorithm-agnostic) | PrivateKeyInfo |
BEGIN EC PRIVATE KEY | EC private key (SEC 1) | ECPrivateKey |
BEGIN PUBLIC KEY | Public key (PKCS#1 / X.509 SubjectPublicKeyInfo) | SubjectPublicKeyInfo |
BEGIN ENCRYPTED PRIVATE KEY | Encrypted PKCS#8 private key | EncryptedPrivateKeyInfo |
BEGIN PKCS7 | PKCS#7 / CMS message | SignedData / EnvelopedData |
BEGIN X509 CRL | Certificate Revocation List | CertificateList |
BEGIN TRUSTED CERTIFICATE | Certificate with trust settings (OpenSSL) | Certificate + trust info |
3. Key Differences in Practice
Multi-Object Files
PEM supports multiple objects in one file by concatenating PEM blocks. This is how certificate chains work:
-----BEGIN CERTIFICATE-----
... (server certificate) ...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (intermediate CA) ...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (root CA) ...
-----END CERTIFICATE-----
DER can only hold one object per file. For certificate chains in DER, you need separate files or a PKCS#7/CMS container.
File Extension Confusion
-----BEGIN, it's PEM; if it starts with binary bytes like 30 82, it's DER.| Extension | Usually PEM | Usually DER | Ambiguous? |
|---|---|---|---|
| .pem | Yes | No | No |
| .der | No | Yes | No |
| .crt | Often | Often | Yes |
| .cer | Often | Often (Windows) | Yes |
| .key | Often | Often | Yes |
| .csr | Often | Often | Yes |
| .p7b / .p7c | Yes (PKCS#7 PEM) | Yes (PKCS#7 DER) | Yes |
| .p12 / .pfx | No | Yes (PKCS#12 binary) | No |
4. Smart Card and PKI Use Cases
| Context | Format | Why |
|---|---|---|
| PIV/CAC card storage | DER | Smart card file system stores binary DER directly |
| EMV issuer certificate | DER | Card chip stores DER in AIP/AFL records |
| GlobalPlatform secure channel | DER | SCP02/SCP03 keys and data in DER |
| Nginx / Apache TLS | PEM | Web servers read PEM config files |
| OpenSSL CLI default | PEM | openssl x509 outputs PEM by default |
| Java KeyStore import | DER | keytool -import expects DER by default |
| Windows Certificate Store | DER | Windows uses DER internally; double-click .crt imports as DER |
| Kubernetes secrets | PEM | K8s TLS secrets expect PEM format |
| AWS IAM certificates | PEM | AWS console and CLI require PEM |
| Apple iOS provisioning profiles | DER | .mobileprovision uses DER-encoded CMS |
5. OpenSSL Conversion Commands
Certificate: PEM → DER
openssl x509 -in cert.pem -outform DER -out cert.der
Certificate: DER → PEM
openssl x509 -in cert.der -inform DER -outform PEM -out cert.pem
Private Key: PEM → DER (PKCS#8)
openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -out key.der -nocrypt
Private Key: DER → PEM (PKCS#8)
openssl pkcs8 -inform DER -outform PEM -in key.der -out key.pem -nocrypt
RSA Key: PEM (PKCS#1) → DER
openssl rsa -in rsa_key.pem -outform DER -out rsa_key.der
CSR: PEM → DER
openssl req -in request.pem -outform DER -out request.der
CSR: DER → PEM
openssl req -in request.der -inform DER -outform PEM -out request.pem
Detect format
# Check if file is PEM (starts with "-----BEGIN")
head -1 cert.pem
# → -----BEGIN CERTIFICATE-----
# Check if file is DER (starts with 0x30 = SEQUENCE)
xxd cert.der | head -1
# → 00000000: 3082 03e7 3082 ...
6. Python: PEM/DER Conversion
import base64
def pem_to_der(pem_text: str) -> bytes:
"""Convert PEM text to DER binary data."""
lines = pem_text.strip().split('\n')
# Remove header and footer lines
b64_lines = [l.strip() for l in lines
if not l.startswith('-----')]
b64_data = ''.join(b64_lines)
return base64.b64decode(b64_data)
def der_to_pem(der_data: bytes, label: str = "CERTIFICATE") -> str:
"""Convert DER binary data to PEM text."""
b64 = base64.b64encode(der_data).decode('ascii')
lines = [b64[i:i+64] for i in range(0, len(b64), 64)]
result = f"-----BEGIN {label}-----\n"
result += '\n'.join(lines) + '\n'
result += f"-----END {label}-----\n"
return result
# Example
der = pem_to_der(open('cert.pem').read())
pem = der_to_pem(der, 'CERTIFICATE')
print(f"DER length: {len(der)} bytes")
print(pem[:80] + '...')
7. JavaScript: PEM/DER Conversion
// PEM → DER (Uint8Array)
function pemToDer(pem) {
const b64 = pem
.replace(/-----BEGIN.*?-----/g, '')
.replace(/-----END.*?-----/g, '')
.replace(/\s/g, '');
const binary = atob(b64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
// DER → PEM
function derToPem(der, label = 'CERTIFICATE') {
let binary = '';
for (let i = 0; i < der.length; i++) {
binary += String.fromCharCode(der[i]);
}
const b64 = btoa(binary);
const lines = b64.match(/.{1,64}/g) || [];
return `-----BEGIN ${label}-----\n` +
lines.join('\n') + '\n' +
`-----END ${label}-----\n`;
}
// Usage with Web Crypto API
async function importPemCertificate(pem) {
const der = pemToDer(pem);
return await crypto.subtle.importCertificate(
'x509', der, {}, ['verify']
);
}
8. Common Errors and Fixes
-inform DER to your OpenSSL command, or convert to PEM first.-inform DER flag, or convert PEM to DER first.9. Summary — Which to Use?
| If you need… | Use | Why |
|---|---|---|
| Web server TLS config (Nginx/Apache) | PEM | Web servers read PEM by default |
| Smart card certificate storage | DER | Cards store binary, no text parsing needed |
| Email / copy-paste certificate | PEM | Safe for text-based transmission |
| Windows Certificate Store import | DER | Windows uses DER internally |
| Kubernetes / Docker TLS secrets | PEM | K8s expects PEM in secrets |
| Certificate chain file | PEM | Multiple PEM blocks in one file |
| Java KeyStore import | DER | keytool defaults to DER |
| Minimal file size | DER | 33% smaller than PEM |
| Git / version control | PEM | Text-based, diff-friendly |
For related tools, see our X.509 Certificate Parser, ASN.1 DER Parser, and Base64 Encoder. For a deeper dive, read our X.509 Certificates Explained guide.