Understanding the Difference Between PEM Certificate and Public Key: A Technical Deep Dive for Developers


2 views

When working with OpenSSL and cryptographic operations, developers frequently encounter two similar-looking PEM formats:

// Certificate format
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAL...
-----END CERTIFICATE-----

// Public key format 
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG...
-----END PUBLIC KEY-----

A certificate contains the public key plus additional metadata:

  • Subject information (CN, O, OU fields)
  • Issuer details
  • Validity period
  • Signature algorithm
  • X.509 extensions

Whereas a public key contains just the raw key material in SubjectPublicKeyInfo (SPKI) format.

Extracting the public key from a certificate:

openssl x509 -in cert.pem -pubkey -noout > pubkey.pem

Converting between formats (DER/PEM):

# Certificate to DER
openssl x509 -in cert.pem -outform DER -out cert.der

# Public key to DER
openssl rsa -pubin -in pubkey.pem -outform DER -out pubkey.der

Certificate (BEGIN CERTIFICATE) is required for:

  • TLS handshakes
  • Code signing verification
  • PKI chain validation

Public Key (BEGIN PUBLIC KEY) is used for:

  • Asymmetric encryption
  • JWT signature verification
  • Embedding in configurations

The certificate's public key (in SPKI format) is actually embedded within the certificate structure. You can inspect this using:

openssl asn1parse -in cert.pem -strparse 19

This reveals the identical public key bits that would appear in a standalone PUBLIC KEY file.

1. Trying to use a certificate where a public key is expected (e.g., in JWT libraries):

// Wrong
const publicKey = fs.readFileSync('cert.pem');

// Right  
const publicKey = fs.readFileSync('pubkey.pem');

2. Assuming both formats work interchangeably in OpenSSL commands


When working with OpenSSL and cryptographic operations, you'll encounter two similar-looking PEM formats:

// Certificate format
-----BEGIN CERTIFICATE-----
BASE64_ENCODED_DATA
-----END CERTIFICATE-----

// Public key format  
-----BEGIN PUBLIC KEY-----
BASE64_ENCODED_DATA
-----END PUBLIC KEY-----

A CERTIFICATE PEM contains:

  • Public key
  • Identity information (subject)
  • Issuer details
  • Validity period
  • Signature algorithm
  • Digital signature

A PUBLIC KEY PEM contains only the raw public key material in SubjectPublicKeyInfo format (ASN.1 DER encoded).

Here's how to extract the public key from a certificate:

openssl x509 -in certificate.pem -pubkey -noout > publickey.pem

To inspect the ASN.1 structure:

openssl asn1parse -in certificate.pem
openssl asn1parse -in publickey.pem

Certificate PEMs are used when:

// Node.js HTTPS server
const https = require('https');
const fs = require('fs');

const options = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt') // CERTIFICATE PEM
};

Public Key PEMs are used when:

// Python RSA verification
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding

with open("public_key.pem", "rb") as key_file:
    public_key = serialization.load_pem_public_key(
        key_file.read()
    )

The Certificate structure includes:

Certificate ::= SEQUENCE {
    tbsCertificate       TBSCertificate,
    signatureAlgorithm   AlgorithmIdentifier,
    signatureValue       BIT STRING
}

While the Public Key structure is simpler:

SubjectPublicKeyInfo ::= SEQUENCE {
    algorithm        AlgorithmIdentifier,
    subjectPublicKey BIT STRING
}

Certificate verification requires chain validation:

openssl verify -CAfile root-ca.crt intermediate.crt

Public key verification just checks key format:

openssl rsa -in publickey.pem -pubin -check -noout