X.509 Certificate Decoding Explained
You need to verify a TLS certificate, debug SSL errors, or extract certificate details for authentication. But X.509 certificates are encoded in binary formats, contain cryptic OIDs, and include extensions with complex purposes. Understanding how to decode certificates and interpret their fields is essential for security audits, troubleshooting HTTPS connections, and implementing certificate-based authentication.
What is an X.509 Certificate?
An X.509 certificate is a digital document that binds a public key to an identity (domain name, organization, or individual). It's the foundation of TLS/SSL, enabling secure HTTPS connections and digital signatures.
Certificates contain:
- Subject: Who the certificate is issued to (CN=example.com, O=Company)
- Issuer: Who issued the certificate (Certificate Authority)
- Public Key: The cryptographic key used for encryption/verification
- Validity Period: Not Before / Not After dates
- Extensions: Additional constraints and purposes (SAN, EKU, etc.)
- Signature: CA's digital signature proving authenticity
PEM vs DER: Certificate Formats
X.509 certificates can be encoded in two primary formats:
PEM (Privacy-Enhanced Mail)
PEM is Base64-encoded DER data wrapped with header/footer lines. It's human-readable and the most common format for web certificates.
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKL0UG+mRqqUMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRAwDgYDVQQHDAdPYWtsYW5kMQ8w
DQYDVQQKDAZFeGFtcGxlMB4XDTE2MDQwODA4NDEzNFoXDTI2MDQwNjA4NDEzNFow
...
-----END CERTIFICATE-----Features:
- Text-based, can be copied/pasted
- File extensions:
.pem,.crt,.cer - Used by Apache, Nginx, OpenSSL
- Can contain multiple certificates (certificate chain)
DER (Distinguished Encoding Rules)
DER is a binary ASN.1 encoding. It's more compact but not human-readable.
30 82 03 5d 30 82 02 45 a0 03 02 01 02 02 09 00
a2 f4 50 6f a6 46 aa 94 30 0d 06 09 2a 86 48 86
...Features:
- Binary format, more compact
- File extensions:
.der,.cer - Used by Windows, Java
- One certificate per file
Converting Between Formats
# PEM to DER
openssl x509 -in cert.pem -outform DER -out cert.der
# DER to PEM
openssl x509 -in cert.der -inform DER -outform PEM -out cert.pemCertificate Structure
An X.509v3 certificate has three main sections:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: a2:f4:50:6f:a6:46:aa:94
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
Validity:
Not Before: Jan 1 00:00:00 2026 GMT
Not After : Mar 31 23:59:59 2026 GMT
Subject: CN=example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus: 00:ab:cd:ef:...
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:example.com, DNS:www.example.com
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Key Usage:
Digital Signature, Key Encipherment
Signature Algorithm: sha256WithRSAEncryption
12:34:56:78:...Core Certificate Fields
Serial Number
A unique identifier assigned by the Certificate Authority. Used for revocation tracking in CRLs (Certificate Revocation Lists).
Serial Number: 03:e7:e4:d4:d5:3c:d8:d9:ff:ac:b7:5b:6e:8f:5c:6a:6c:15Issuer and Subject
Issuer: The Certificate Authority that signed the certificate
Subject: The entity the certificate is issued to
Both use Distinguished Name (DN) format:
Issuer: C=US, O=Let's Encrypt, CN=R3
Subject: CN=example.comCommon DN components:
CN(Common Name): Domain name or person's nameO(Organization): Company nameOU(Organizational Unit): DepartmentC(Country): Two-letter country codeST(State): State or provinceL(Locality): City
Validity Period
Certificates have a time range during which they're considered valid:
Not Before: Jan 1 00:00:00 2026 GMT
Not After : Mar 31 23:59:59 2026 GMTImportant: Certificates can't be used before the "Not Before" date or after the "Not After" date. Most browsers enforce this strictly.
Public Key
The public key used for encryption and signature verification:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:c2:a6:c8:d3:4b:9e:7a:1c:4f:6e:3d:9b:8c:7f:
...
Exponent: 65537 (0x10001)Common algorithms:
- RSA 2048-bit: Most common, widely supported
- RSA 4096-bit: Higher security, larger certificates
- ECDSA P-256: Elliptic curve, smaller and faster
- ECDSA P-384: Higher security elliptic curve
Signature Algorithm
The cryptographic hash and signature algorithm used:
Signature Algorithm: sha256WithRSAEncryptionModern certificates use:
sha256WithRSAEncryption— SHA-256 + RSA (most common)ecdsa-with-SHA256— SHA-256 + ECDSAecdsa-with-SHA384— SHA-384 + ECDSA
Avoid: sha1WithRSAEncryption (deprecated, insecure)
Certificate Extensions
X.509v3 extensions add functionality beyond basic identification:
Subject Alternative Name (SAN)
The most important extension for web certificates. Specifies additional hostnames the certificate is valid for:
X509v3 Subject Alternative Name:
DNS:example.com, DNS:www.example.com, DNS:*.example.comWhy it matters: Modern browsers only check SAN, not the Subject CN. A certificate without SAN won't work for HTTPS.
Wildcards: *.example.com matches www.example.com, api.example.com, but NOT example.com or subdomain.api.example.com.
Extended Key Usage (EKU)
Specifies what the certificate can be used for:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client AuthenticationCommon EKU values:
- serverAuth (1.3.6.1.5.5.7.3.1): TLS/SSL server certificates (HTTPS)
- clientAuth (1.3.6.1.5.5.7.3.2): Client certificates (mutual TLS)
- codeSigning (1.3.6.1.5.5.7.3.3): Code signing
- emailProtection (1.3.6.1.5.5.7.3.4): S/MIME email encryption
- timeStamping (1.3.6.1.5.5.7.3.8): Trusted timestamping
Key Usage
Restricts cryptographic operations the key can perform:
X509v3 Key Usage: critical
Digital Signature, Key EnciphermentValues:
- Digital Signature: Sign data (authentication, integrity)
- Key Encipherment: Encrypt session keys (RSA key exchange)
- Key Agreement: Establish shared secrets (ECDH key exchange)
- Certificate Sign: Sign other certificates (CA certificates only)
- CRL Sign: Sign certificate revocation lists
Basic Constraints
Indicates whether this is a CA certificate and limits certificate chain depth:
X509v3 Basic Constraints: critical
CA:FALSECA:TRUE: This certificate can sign other certificates (intermediate or root CA)
CA:FALSE: End-entity certificate (leaf certificate)
Authority Key Identifier (AKI) and Subject Key Identifier (SKI)
Identifiers for linking certificates in a chain:
X509v3 Authority Key Identifier:
keyid:A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1
X509v3 Subject Key Identifier:
12:34:56:78:9A:BC:DE:F0:11:22:33:44:55:66:77:88:99:AA:BB:CCAKI: Points to the issuer's public key (used to verify signature)
SKI: Unique identifier for this certificate's public key
Authority Information Access (AIA)
URLs for downloading the issuer certificate and checking revocation:
Authority Information Access:
OCSP - URI:http://ocsp.letsencrypt.org
CA Issuers - URI:http://cert.letsencrypt.org/lets-encrypt-r3.derOCSP: Online Certificate Status Protocol — real-time revocation checking
CA Issuers: Where to download the intermediate CA certificate
CRL Distribution Points
URLs for downloading Certificate Revocation Lists:
X509v3 CRL Distribution Points:
Full Name:
URI:http://crl.letsencrypt.org/lets-encrypt-r3.crlCertificate Fingerprints
A fingerprint is a hash of the entire certificate. It's used for certificate pinning and quick verification:
SHA-256 Fingerprint:
3B:4A:7C:2F:8D:1E:9B:3A:5F:6C:8D:2E:7A:4B:9C:1D:
6E:3F:8A:2C:5B:7D:9E:1F:4A:6B:8C:3D:5E:7F:9A:2B
SHA-1 Fingerprint:
A8:3E:6F:2C:7D:1B:4A:8E:5F:9C:2D:6B:3A:7E:1C:4F:8D:5B:9A:2ECalculating Fingerprints
# Using OpenSSL
openssl x509 -in cert.pem -fingerprint -sha256 -noout
openssl x509 -in cert.pem -fingerprint -sha1 -noout
# Using Python
import hashlib
with open('cert.pem', 'rb') as f:
cert_data = f.read()
# SHA-256 fingerprint
fingerprint = hashlib.sha256(cert_data).hexdigest()
print(':'.join(fingerprint[i:i+2] for i in range(0, len(fingerprint), 2)).upper())Certificate Chain Validation
Browsers validate certificates by checking a chain of trust from the end-entity certificate to a trusted root CA:
[End-Entity Certificate] <- example.com
↓ signed by
[Intermediate CA] <- Let's Encrypt R3
↓ signed by
[Root CA] <- ISRG Root X1 (in browser trust store)Validation Steps
- Signature verification: Each certificate's signature is verified using the issuer's public key
- Chain building: Intermediate certificates are downloaded if missing (using AIA extension)
- Expiry check: All certificates must be within their validity period
- Revocation check: Check OCSP or CRL for revoked certificates
- Name validation: Hostname matches SAN or CN
- Purpose validation: EKU and Key Usage match intended purpose
Common Validation Errors
"certificate has expired" — Current time is outside Not Before/Not After range
"unable to get local issuer certificate" — Missing intermediate certificate
"certificate name mismatch" — Hostname not in SAN
"self signed certificate" — Certificate not issued by trusted CA
"certificate revoked" — Certificate has been revoked by CA
Decoding Certificates with OpenSSL
# Display certificate details
openssl x509 -in cert.pem -text -noout
# Extract specific fields
openssl x509 -in cert.pem -noout -subject
openssl x509 -in cert.pem -noout -issuer
openssl x509 -in cert.pem -noout -dates
openssl x509 -in cert.pem -noout -fingerprint
# Download and decode a website's certificate
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -text -noout
# Check certificate expiry
openssl x509 -in cert.pem -noout -enddate
# Verify certificate chain
openssl verify -CAfile ca-bundle.crt cert.pemDecoding Certificates Programmatically
Python (cryptography library)
from cryptography import x509
from cryptography.hazmat.backends import default_backend
import datetime
# Load certificate
with open('cert.pem', 'rb') as f:
cert_data = f.read()
cert = x509.load_pem_x509_certificate(cert_data, default_backend())
# Extract fields
print("Subject:", cert.subject)
print("Issuer:", cert.issuer)
print("Serial:", cert.serial_number)
print("Not Before:", cert.not_valid_before)
print("Not After:", cert.not_valid_after)
# Check if expired
now = datetime.datetime.utcnow()
is_expired = now > cert.not_valid_after
print("Expired:", is_expired)
# Get SAN
try:
san = cert.extensions.get_extension_for_oid(
x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME
)
dns_names = san.value.get_values_for_type(x509.DNSName)
print("SAN DNS Names:", dns_names)
except x509.ExtensionNotFound:
print("No SAN extension")
# Get fingerprint
fingerprint = cert.fingerprint(hashes.SHA256())
print("SHA-256 Fingerprint:", fingerprint.hex())JavaScript (Node.js)
const tls = require('tls');
const https = require('https');
// Get certificate from HTTPS server
const options = {
host: 'example.com',
port: 443,
method: 'GET',
rejectUnauthorized: false
};
const req = https.request(options, (res) => {
const cert = res.socket.getPeerCertificate();
console.log('Subject:', cert.subject);
console.log('Issuer:', cert.issuer);
console.log('Valid From:', cert.valid_from);
console.log('Valid To:', cert.valid_to);
console.log('Fingerprint (SHA-256):', cert.fingerprint256);
console.log('Serial Number:', cert.serialNumber);
console.log('Subject Alt Names:', cert.subjectaltname);
});
req.end();Using Certificate Decoding Tools
When working with X.509 certificates, use tools that provide visual parsing and validation:
- Certificate Decoder — Decode PEM and DER certificates with field-by-field breakdown
The certificate decoder on DevToys Pro provides:
- Automatic format detection (PEM/DER)
- All standard and extension fields
- SAN, EKU, and Key Usage parsing
- Fingerprint calculation (SHA-1, SHA-256)
- Expiry warnings
- Certificate chain display
Best Practices
- Always include SAN extension — CN alone is insufficient
- Use 2048-bit RSA minimum — or ECDSA P-256 for modern systems
- Prefer 90-day validity — shorter lifespans reduce risk from compromised keys
- Set appropriate EKU — don't use serverAuth certificates for code signing
- Include intermediate certificates — configure web servers to send full chain
- Monitor expiry dates — automate renewal before expiration
- Use SHA-256 signatures — avoid deprecated SHA-1
Common Pitfalls
- Missing intermediate certificate — causes "unable to get issuer" errors
- Hostname not in SAN — certificate won't validate for domain
- Expired certificates — monitor and renew before expiry
- Wrong certificate format — server expects PEM but receives DER
- Private key mismatch — certificate and private key don't match
- Self-signed in production — browsers won't trust without manual import
Key Takeaways
- X.509 certificates bind public keys to identities for TLS/SSL and code signing
- PEM format is Base64-encoded, DER is binary — both contain the same data
- Subject Alternative Name (SAN) is required for modern HTTPS certificates
- Extended Key Usage (EKU) specifies allowed uses (serverAuth, clientAuth, etc.)
- Fingerprints are hashes of certificates used for pinning and verification
- Certificate chains link end-entity certificates to trusted root CAs
- Always validate certificate chains, expiry, hostname, and revocation status
Related Tools:
- Certificate Decoder — Decode and parse X.509 certificates
- Base64 Decoder — Decode PEM format certificates
- Hash Generator — Calculate certificate fingerprints