Documentation

# Certificate Chain of Trust (PKI)

PUBLIC KEY INFRASTRUCTURE X.509 TRUST FOUNDATION

# What is PKI?

CORE DEFINITION

Simple Definition: Public Key Infrastructure (PKI) is the framework of policies, procedures, hardware, software, and people used to create, manage, distribute, use, store, and revoke digital certificates. It's the trust system that powers HTTPS, code signing, email encryption, and digital signatures.

What PKI Provides:

  • Identity Verification - Proves a server is who it claims to be
  • Encryption Key Distribution - Securely shares public keys
  • Secure Communications - Enables HTTPS and TLS
  • Digital Signatures - Proves authenticity and integrity
  • Centralized Trust Management - Trusted Certificate Authorities

# The Certificate Hierarchy

# Understanding the Chain

┌─────────────────────────────────────────┐
│   ROOT CA (Self-Signed)                 │  Level 1: Trust Anchor
│   ┌───────────────────────────────┐    │
│   │ DigiCert Global Root CA       │    │  ← Pre-installed in
│   │ Valid: 2006-2031               │    │     OS/Browser
│   │ Self-signed                    │    │     (Ultimate trust)
│   └───────────────┬───────────────┘    │
└────────────────────┼───────────────────┘
                     │ Issues & Signs
                     ▼
┌─────────────────────────────────────────┐
│   INTERMEDIATE CA                       │  Level 2: Operational CA
│   ┌───────────────────────────────┐    │
│   │ DigiCert SHA2 Secure          │    │  ← Daily operations
│   │ Server CA                      │    │     Kept online
│   │ Valid: 2013-2023               │    │     Issues end-entity
│   │ Signed by Root CA              │    │     certificates
│   └───────────────┬───────────────┘    │
└────────────────────┼───────────────────┘
                     │ Issues & Signs
                     ▼
┌─────────────────────────────────────────┐
│   END-ENTITY CERTIFICATE (Leaf)        │  Level 3: Server Cert
│   ┌───────────────────────────────┐    │
│   │ www.example.com                │    │  ← Your website
│   │ Valid: 2024-2025               │    │     What clients
│   │ Signed by Intermediate CA      │    │     validate
│   └───────────────────────────────┘    │
└─────────────────────────────────────────┘

# Why This Structure?

1. Root CA Protection

  • Private key kept offline (cold storage)
  • Physically secured in HSM (Hardware Security Module)
  • Rarely used (only to sign intermediate CAs)
  • If compromised, entire PKI collapses

2. Intermediate CA Flexibility

  • Private key online for daily operations
  • Can be revoked without affecting root
  • Multiple intermediates for different purposes
  • Easier to replace if compromised

3. Separation of Duties

  • Root CA: High-security, low-frequency operations
  • Intermediate CA: Regular certificate issuance
  • End-entity: Single website/server
                      Root CA
                         |
        ┌────────────────┼────────────────┐
        ▼                ▼                ▼
    Server CA        Code Sign CA      Email CA
        |                |                |
    ┌───┴───┐        ┌───┴───┐      ┌───┴───┐
    ▼       ▼        ▼       ▼      ▼       ▼
  Web1   Web2    Software   App  Email1  Email2
  Cert   Cert      Cert     Cert   Cert    Cert

Different CAs for:

  • TLS/SSL certificates (web servers)
  • Code signing certificates
  • Email (S/MIME) certificates
  • Document signing
  • Time stamping

# X.509 Certificate Structure

# Anatomy of a Certificate

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            0e:fd:a3:84:6c:5f:4e:3d:52:a0:8d:0d:38:9e:f0:b7
        
        Signature Algorithm: sha256WithRSAEncryption
        
        Issuer: C=US, O=DigiCert Inc, CN=DigiCert SHA2 Secure Server CA
        
        Validity
            Not Before: Jan  1 00:00:00 2024 GMT
            Not After : Jan  1 23:59:59 2025 GMT
        
        Subject: C=US, ST=California, L=San Francisco,
                 O=Example Inc, CN=www.example.com
        
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:b4:31:98:0a:c3:fa:1c:73:4d:89:2b:e0:cc:84:
                    6c:4a:6d:2f:be:0e:95:a1:cf:09:28:19:8a:64:d5:
                    ...
                Exponent: 65537 (0x10001)
        
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:FALSE
            
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            
            X509v3 Extended Key Usage:
                TLS Web Server Authentication, TLS Web Client Authentication
            
            X509v3 Subject Alternative Name:
                DNS:example.com, DNS:www.example.com, 
                DNS:api.example.com, DNS:*.example.com
            
            X509v3 CRL Distribution Points:
                Full Name:
                  URI:http://crl3.digicert.com/sha2-ev-server-g2.crl
            
            Authority Information Access:
                OCSP - URI:http://ocsp.digicert.com
                CA Issuers - URI:http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt
            
            X509v3 Subject Key Identifier:
                4E:46:D7:F3:89:2F:7C:69:7A:0E:10:F4:F0:F6:5A:65:C1:6F:C9:95
            
            X509v3 Authority Key Identifier:
                keyid:0F:80:61:1C:82:31:61:D5:2F:28:E7:8D:46:38:B4:2C:E1:C6:D9:E2
            
            CT Precertificate SCTs:
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : B2:1E:05:CC:8B:A2:CD:8A:20:4E:87:66:F9:2B:B9:8A:
                                25:20:67:6B:DA:FA:70:E7:B2:49:53:2D:EF:8B:90:5E
                    Timestamp : Jan  1 10:30:00.000 2024 GMT
    
    Signature Algorithm: sha256WithRSAEncryption
         3d:4a:c0:5b:7e:8f:9a:12:d7:c1:ef:10:6f:7a:b4:4c:89:3c:
         d2:68:8f:0e:67:32:9c:2c:7e:35:fb:cc:d1:2a:72:94:35:ed:
         ...

# Key Certificate Fields

Field Purpose Example
Version X.509 standard version v3 (supports extensions)
Serial Number Unique ID for certificate 0e:fd:a3:84...
Signature Algorithm How certificate is signed sha256WithRSAEncryption
Issuer Who issued this cert DigiCert SHA2 Secure Server CA
Validity Not Before / Not After 2024-01-01 to 2025-01-01
Subject Who owns this cert www.example.com
Public Key Server's public key RSA 2048-bit key
Extensions Additional metadata SANs, Key Usage, OCSP, etc.
Signature CA's digital signature Proves authenticity

# Certificate Validation

# The Complete Validation Process

When a browser connects to https://example.com, it must validate the certificate:

Step 1: Receive Certificate Chain

Server sends:
  1. Leaf certificate (example.com)
  2. Intermediate certificate(s)
  3. (Root certificate not sent - already trusted)

Step 2: Build Certificate Chain

def build_chain(leaf_cert, intermediates, trust_store):
    chain = [leaf_cert]
    current = leaf_cert
    
    while current.issuer != current.subject:  # Until self-signed
        # Find issuer in intermediates or trust store
        issuer = find_issuer(current.issuer, intermediates + trust_store)
        
        if not issuer:
            raise ValidationError("Incomplete chain")
        
        chain.append(issuer)
        current = issuer
    
    return chain

Step 3: Verify Signatures

def verify_signatures(chain):
    for i in range(len(chain) - 1):
        cert = chain[i]
        issuer_cert = chain[i + 1]
        
        # Verify cert was signed by issuer
        if not verify_signature(cert, issuer_cert.public_key):
            raise ValidationError(f"Invalid signature on {cert.subject}")

Step 4: Check Trust Anchor

def check_trust(chain, trust_store):
    root_cert = chain[-1]
    
    if root_cert not in trust_store:
        raise ValidationError("Untrusted root CA")
    
    # Verify root is self-signed
    if not verify_signature(root_cert, root_cert.public_key):
        raise ValidationError("Invalid root signature")

Step 5: Validate Certificate Fields

def validate_fields(cert, hostname):
    # Check expiration
    now = datetime.now()
    if now < cert.not_before or now > cert.not_after:
        raise ValidationError("Certificate expired or not yet valid")
    
    # Check hostname
    if not matches_hostname(cert.subject_alt_names, hostname):
        raise ValidationError("Hostname mismatch")
    
    # Check key usage
    if not has_key_usage(cert, "digitalSignature", "keyEncipherment"):
        raise ValidationError("Invalid key usage")
    
    # Check extended key usage
    if not has_ext_key_usage(cert, "serverAuth"):
        raise ValidationError("Not valid for TLS server auth")

Step 6: Check Revocation Status

def check_revocation(cert):
    # Try OCSP first
    if cert.has_aia_ocsp():
        status = check_ocsp(cert)
        if status == "revoked":
            raise ValidationError("Certificate revoked (OCSP)")
    
    # Fall back to CRL
    elif cert.has_crl_url():
        status = check_crl(cert)
        if status == "revoked":
            raise ValidationError("Certificate revoked (CRL)")

# Common Validation Errors

Certificate: CN=www.example.com, SAN=example.com, www.example.com
User visits: https://api.example.com

Error: ERR_CERT_COMMON_NAME_INVALID

Solution: Add all hostnames to Subject Alternative Names (SAN):

SAN: DNS:example.com, DNS:www.example.com, DNS:api.example.com
Certificate validity: 2024-01-01 to 2024-12-31
Current date: 2025-01-15

Error: ERR_CERT_DATE_INVALID

Solution: Renew certificate before expiration (automated with Let's Encrypt).

Certificate chain:
  Leaf → Intermediate → Unknown Root CA

Error: ERR_CERT_AUTHORITY_INVALID

Solution: Use well-known CA (DigiCert, Let's Encrypt, etc.) or install root in trust store.

Server sends: Leaf certificate only
Missing: Intermediate certificate

Error: ERR_CERT_AUTHORITY_INVALID

Solution: Configure server to send complete chain:

ssl_certificate /path/to/fullchain.pem;  # Includes intermediates

# Root Certificate Stores

# Where Root CAs Are Trusted

Windows:

certmgr.msc → Trusted Root Certification Authorities
Location: C:\Windows\System32\certsrv.msc

macOS:

Keychain Access → System Roots
Location: /System/Library/Keychains/SystemRootCertificates.keychain

Linux:

Debian/Ubuntu: /etc/ssl/certs/ca-certificates.crt
RHEL/CentOS: /etc/pki/tls/certs/ca-bundle.crt

Chrome/Edge:

  • Uses OS trust store (Windows/macOS)
  • Uses NSS trust store (Linux)

Firefox:

  • Uses own trust store (NSS)
  • Independent of OS
  • about:preferences#privacy → View Certificates

Safari:

  • Uses macOS Keychain

# Major Certificate Authorities

CA Market Share Known For
Let's Encrypt ~40% Free, automated (ACME protocol)
DigiCert ~15% Enterprise, EV certificates
Sectigo (Comodo) ~10% Affordable, wide range
GlobalSign ~5% IoT, enterprise
GoDaddy ~5% Domain registrar integration

# Working with Certificates

# Viewing Certificates

[OpenSSL - View Certificate]
# View certificate from file
openssl x509 -in cert.pem -text -noout

# View certificate from server
openssl s_client -connect example.com:443 -showcerts

# 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
[Python - Parse Certificate]
from cryptography import x509
from cryptography.hazmat.backends import default_backend

# Load certificate
with open('cert.pem', 'rb') as f:
    cert = x509.load_pem_x509_certificate(f.read(), default_backend())

# Extract fields
print(f"Subject: {cert.subject}")
print(f"Issuer: {cert.issuer}")
print(f"Not Before: {cert.not_valid_before}")
print(f"Not After: {cert.not_valid_after}")
print(f"Serial: {cert.serial_number}")

# Get Subject Alternative Names
san_ext = cert.extensions.get_extension_for_class(
    x509.SubjectAlternativeName
)
for san in san_ext.value:
    print(f"SAN: {san.value}")
[Node.js - Parse Certificate]
const tls = require('tls');
const fs = require('fs');

// Load certificate from file
const certPem = fs.readFileSync('cert.pem');
const cert = tls.parseCertificate(certPem);

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('Serial Number:', cert.serialNumber);

// Get from server
const socket = tls.connect(443, 'example.com', () => {
    const cert = socket.getPeerCertificate();
    console.log('Server cert:', cert.subject);
    console.log('SANs:', cert.subjectaltname);
    socket.end();
});

# Building Certificate Chains

# Combine leaf + intermediate + root
cat leaf.pem intermediate.pem root.pem > fullchain.pem

# Or just leaf + intermediate (root not needed)
cat leaf.pem intermediate.pem > chain.pem

# Verify chain
openssl verify -CAfile root.pem -untrusted intermediate.pem leaf.pem
# Output: leaf.pem: OK

# Testing Certificate Chains

# Test server's certificate chain
openssl s_client -connect example.com:443 -showcerts

# Check certificate chain is complete
curl --verbose https://example.com 2>&1 | grep -A 10 "SSL certificate"

# Use SSL Labs for comprehensive test
# Visit: https://www.ssllabs.com/ssltest/analyze.html?d=example.com

# Certificate Formats

# Common Formats

Format Extension Encoding Contains
PEM .pem, .crt, .cer Base64 Certificate, private key, or chain
DER .der, .cer Binary Single certificate
PKCS#7 .p7b, .p7c Base64/Binary Certificate chain (no private key)
PKCS#12 .pfx, .p12 Binary Certificate + private key (password protected)

# Converting Between Formats

[PEM ↔ DER]
# PEM to DER
openssl x509 -in cert.pem -outform DER -out cert.der

# DER to PEM
openssl x509 -in cert.der -inform DER -out cert.pem -outform PEM
[PEM ↔ PKCS#7]
# PEM to PKCS#7 (chain)
openssl crl2pkcs7 -nocrl -certfile fullchain.pem -out cert.p7b

# PKCS#7 to PEM
openssl pkcs7 -in cert.p7b -print_certs -out cert.pem
[PEM ↔ PKCS#12]
# PEM to PKCS#12 (includes private key)
openssl pkcs12 -export -out cert.pfx \
  -inkey private.key \
  -in cert.pem \
  -certfile chain.pem

# PKCS#12 to PEM
openssl pkcs12 -in cert.pfx -out cert.pem -nodes

# Certificate Pinning

# What is Certificate Pinning?

Definition: Hardcoding or caching a certificate/public key in your application to prevent man-in-the-middle attacks.

Without Pinning:

App → Trusts any certificate signed by trusted CA
Attacker → Gets certificate from compromised CA
App → Accepts attacker's certificate ❌

With Pinning:

App → Only trusts specific certificate/public key
Attacker → Gets certificate from compromised CA
App → Rejects certificate (doesn't match pin) ✓

# Implementation

[Python - Certificate Pinning]
import ssl
import hashlib
import socket

# Calculate certificate fingerprint
def get_cert_fingerprint(hostname, port=443):
    cert_pem = ssl.get_server_certificate((hostname, port))
    cert_der = ssl.PEM_cert_to_DER_cert(cert_pem)
    return hashlib.sha256(cert_der).hexdigest()

# Expected fingerprint (pinned)
PINNED_FINGERPRINT = "a1b2c3d4e5f6..."

# Verify pinned certificate
def verify_pinned_cert(hostname):
    actual_fingerprint = get_cert_fingerprint(hostname)
    
    if actual_fingerprint != PINNED_FINGERPRINT:
        raise Exception("Certificate pin mismatch!")
    
    return True
[Node.js - Public Key Pinning]
const https = require('https');
const crypto = require('crypto');

const PINNED_PUBLIC_KEY = 'sha256/AAAAAAAAAA...';

const options = {
  hostname: 'example.com',
  port: 443,
  path: '/',
  method: 'GET',
  checkServerIdentity: (hostname, cert) => {
    // Calculate public key hash
    const pubkey = cert.pubkey;
    const hash = crypto.createHash('sha256').update(pubkey).digest('base64');
    const pin = `sha256/${hash}`;
    
    if (pin !== PINNED_PUBLIC_KEY) {
      throw new Error('Public key pin mismatch!');
    }
  }
};

https.request(options, (res) => {
  console.log('Connected with valid pin');
}).end();
[Android - Certificate Pinning]
import android.net.http.HttpsURLConnection;
import java.security.cert.Certificate;
import java.security.MessageDigest;

public class PinningExample {
    private static final String PINNED_HASH = "a1b2c3d4...";
    
    public void makeRequest() throws Exception {
        URL url = new URL("https://example.com");
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        
        conn.connect();
        
        // Get certificate
        Certificate[] certs = conn.getServerCertificates();
        Certificate cert = certs[0];
        
        // Calculate hash
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] hash = md.digest(cert.getEncoded());
        String hashHex = bytesToHex(hash);
        
        // Verify pin
        if (!PINNED_HASH.equals(hashHex)) {
            throw new Exception("Certificate pin mismatch!");
        }
        
        // Proceed with request
    }
}

# Certificate vs Public Key Pinning

Type Pins Rotation Flexibility
Certificate Pinning Entire certificate Must update app Less flexible
Public Key Pinning Just public key Can rotate cert with same key More flexible

Recommendation: Pin public key, not certificate.

# Pinning Best Practices

Pin multiple keys - Primary + backup Include intermediate CA - More flexible than leaf Plan for rotation - Have update mechanism Set expiration - Pins should expire Avoid root CA pinning - Too inflexible Don't pin in browsers - Use HPKP header (deprecated) or Expect-CT


# Best Practices

# Certificate Management

  • Use reputable CAs (Let's Encrypt, DigiCert, etc.)
  • Automate renewal (certbot for Let's Encrypt)
  • Monitor expiration (alert 30 days before)
  • Include all SANs (all domains/subdomains)
  • Send complete chain (leaf + intermediates)
  • Use 2048-bit RSA or 256-bit ECC minimum
  • Enable OCSP stapling (faster, private)
  • Rotate certificates regularly
  • Keep private keys secure (HSM, encrypted storage)
  • Use Certificate Transparency (detect mis-issuance)

# Validation

  • Test with SSL Labs (https://www.ssllabs.com/ssltest/)
  • Verify complete chain locally
  • Check all SANs work correctly
  • Test OCSP/CRL revocation checking
  • Validate in all browsers (Chrome, Firefox, Safari, Edge)
  • Test mobile devices (iOS, Android)

# Next Steps

# Related Topics

TLS/SSL Basics - Understanding HTTPS HSTS - Force HTTPS connections Certificate Revocation - CRL and OCSP Cipher Suites - Encryption configuration

# Tools & Resources

SSL Labs - Test certificate configuration crt.sh - Certificate Transparency search Let's Encrypt - Free automated certificates


# Protected by Layerd AI

Layerd AI Guardian Proxy provides certificate management:

Certificate Validation - Verifies complete chain Expiration Monitoring - Alerts before expiration Pin Management - Enforces certificate pinning CT Log Monitoring - Detects unauthorized certificates

Learn more about Layerd AI Protection →


Last updated: November 2025