Search…

Public key infrastructure and certificates

In this series (16 parts)
  1. How attackers think: the attacker mindset
  2. Networking fundamentals for security
  3. Cryptography fundamentals
  4. Public key infrastructure and certificates
  5. Authentication and authorization
  6. Web application security: OWASP Top 10
  7. Network attacks and defenses
  8. Linux privilege escalation
  9. Windows security fundamentals
  10. Malware types and analysis basics
  11. Reconnaissance and OSINT
  12. Exploitation basics and CVEs
  13. Post-exploitation and persistence
  14. Defensive security: hardening and monitoring
  15. Incident response
  16. CTF skills and practice labs

Every HTTPS connection relies on certificates to prove the server is who it claims to be. Without certificates, encryption alone is not enough. You could have a perfectly encrypted connection to an attacker’s server. PKI (Public Key Infrastructure) solves this by creating a chain of trust from a small set of trusted authorities down to individual websites.

Prerequisites

You should understand cryptography fundamentals, specifically asymmetric encryption and digital signatures.

What is a certificate?

An X.509 certificate is a digitally signed document that binds a public key to an identity (like a domain name). It contains:

  • Subject: who the certificate belongs to (e.g., CN=example.com)
  • Issuer: who signed it (e.g., CN=DigiCert Global G2)
  • Public key: the server’s public key
  • Validity period: not before / not after dates
  • Serial number: unique identifier
  • Signature: the issuer’s digital signature over all the above

The chain of trust

graph TD
  A["Root CA<br/>Self-signed, stored in your OS/browser<br/>e.g., DigiCert Global Root G2"] -->|Signs| B["Intermediate CA<br/>Signed by Root CA<br/>e.g., DigiCert G2 TLS RSA SHA256"]
  B -->|Signs| C["Server Certificate<br/>Signed by Intermediate CA<br/>e.g., CN=example.com"]
  style A fill:#f9a825,stroke:#f57f17,color:#000
  style B fill:#64b5f6,stroke:#1976d2,color:#000
  style C fill:#81c784,stroke:#388e3c,color:#000
  1. Root CA is self-signed and pre-installed in your operating system or browser. You trust it because your OS vendor or browser vendor vetted it.
  2. Intermediate CA is signed by the Root CA. This adds a layer of protection. If the intermediate is compromised, the root can revoke it without replacing every certificate.
  3. Server certificate is signed by the Intermediate CA. This is what the web server presents.

When your browser connects to a site, it:

  1. Receives the server certificate and any intermediates
  2. Verifies the signature on the server cert using the intermediate’s public key
  3. Verifies the signature on the intermediate using the root’s public key
  4. Checks if the root is in its trusted store
  5. If the chain is valid and the domain matches, the connection is trusted

Certificate fields to inspect

# Inspect a website's certificate
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -text | head -40

Output:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            0a:bc:de:f0:12:34:56:78:90:ab:cd:ef:01:23:45:67
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, O = DigiCert Inc, CN = DigiCert Global G2 TLS RSA SHA256 2020 CA1
        Validity
            Not Before: Jan 13 00:00:00 2024 GMT
            Not After : Feb 13 23:59:59 2025 GMT
        Subject: CN = example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:example.com, DNS:www.example.com
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Server Authentication

Key things to check:

  • Subject / SAN: does the domain match what you expected?
  • Issuer: is it a trusted CA?
  • Validity: is it expired?
  • Key size: RSA should be at least 2048 bits
  • Signature algorithm: should be SHA-256 or better (not SHA-1 or MD5)

Common certificate errors

ErrorMeaningSecurity risk
NET::ERR_CERT_DATE_INVALIDCertificate expiredCould be misconfiguration or a revoked cert being reused
NET::ERR_CERT_AUTHORITY_INVALIDIssuer not trustedSelf-signed cert, or MITM attack
NET::ERR_CERT_COMMON_NAME_INVALIDDomain doesn’t matchWrong cert installed, or MITM
NET::ERR_CERT_REVOKEDCertificate was revokedCA determined the cert was compromised
SSL_ERROR_WEAK_SERVER_CERT_KEYKey too smallRSA < 2048 bits

⚠ Never tell users to “just click through” certificate warnings. Each warning could indicate an active attack.

Certificate transparency

CT is a system of public logs where all certificates are recorded. This means:

  • Domain owners can monitor for unauthorized certificates issued for their domain
  • Researchers can detect mis-issued certificates
  • CAs are held accountable
# Check certificate transparency logs
curl -s "https://crt.sh/?q=example.com&output=json" | python3 -m json.tool | head -30

Let’s Encrypt and ACME

Let’s Encrypt provides free, automated certificates. The ACME protocol automates the entire process:

# Install certbot
sudo apt install -y certbot python3-certbot-nginx

# Get a certificate for your domain
sudo certbot --nginx -d example.com -d www.example.com

# Auto-renewal is set up automatically
sudo certbot renew --dry-run

Let’s Encrypt certificates are valid for 90 days. The short validity period limits the damage from compromised certificates and encourages automation.

Example 1: Inspect a real certificate with OpenSSL

Let’s inspect Google’s certificate and understand every field:

# Download and display the certificate
echo | openssl s_client -connect google.com:443 -servername google.com 2>/dev/null | openssl x509 -noout -text

Extract specific fields:

# Just the subject
echo | openssl s_client -connect google.com:443 2>/dev/null | openssl x509 -noout -subject

Output:

subject=CN = *.google.com
# Validity dates
echo | openssl s_client -connect google.com:443 2>/dev/null | openssl x509 -noout -dates

Output:

notBefore=May 13 08:38:47 2026 GMT
notAfter=Aug  5 08:38:46 2026 GMT
# The issuer (who signed it)
echo | openssl s_client -connect google.com:443 2>/dev/null | openssl x509 -noout -issuer

Output:

issuer=C = US, O = Google Trust Services, CN = WR2
# Subject Alternative Names (all domains covered)
echo | openssl s_client -connect google.com:443 2>/dev/null | openssl x509 -noout -ext subjectAltName

Output:

X509v3 Subject Alternative Name:
    DNS:*.google.com, DNS:*.appengine.google.com, DNS:*.bdn.dev, DNS:*.cloud.google.com, ...
# Check certificate fingerprint
echo | openssl s_client -connect google.com:443 2>/dev/null | openssl x509 -noout -fingerprint -sha256

Output:

sha256 Fingerprint=AB:CD:EF:12:34:56:78:90:AB:CD:EF:12:34:56:78:90:...

Example 2: Trace the chain of trust for a public website

# Show the full certificate chain
echo | openssl s_client -connect google.com:443 -servername google.com -showcerts 2>/dev/null

This shows multiple certificates. Let’s extract and verify the chain:

# Save the chain
echo | openssl s_client -connect google.com:443 -showcerts 2>/dev/null > /tmp/chain.pem

# Extract each certificate
csplit -f /tmp/cert- -b '%02d.pem' /tmp/chain.pem '/-----BEGIN CERTIFICATE-----/' '{*}' 2>/dev/null

# Inspect each level
for cert in /tmp/cert-*.pem; do
    if openssl x509 -in "$cert" -noout 2>/dev/null; then
        echo "=== $(basename $cert) ==="
        openssl x509 -in "$cert" -noout -subject -issuer
        echo ""
    fi
done

Output:

=== cert-01.pem ===
subject=CN = *.google.com
issuer=C = US, O = Google Trust Services, CN = WR2

=== cert-02.pem ===
subject=C = US, O = Google Trust Services, CN = WR2
issuer=C = US, O = Google Trust Services LLC, CN = GTS Root R1

The chain:

  1. *.google.com signed by WR2 (Intermediate CA)
  2. WR2 signed by GTS Root R1 (Root CA)
  3. GTS Root R1 is in your system’s trusted certificate store

Verify the chain:

# This checks the entire chain against the system's CA bundle
openssl verify -verbose /tmp/cert-01.pem

Output:

/tmp/cert-01.pem: OK

If the chain were broken or a certificate expired:

error 10 at 1 depth lookup: certificate has expired

Clean up:

rm -f /tmp/chain.pem /tmp/cert-*.pem

TLS/SSL versions

VersionStatusNotes
SSL 2.0BrokenNever use
SSL 3.0BrokenPOODLE attack
TLS 1.0DeprecatedShould be disabled
TLS 1.1DeprecatedShould be disabled
TLS 1.2SecureWidely supported, still safe
TLS 1.3SecurePreferred, faster handshake

Check what a server supports:

# Test TLS 1.3
openssl s_client -connect example.com:443 -tls1_3 2>&1 | head -5

# Test TLS 1.2
openssl s_client -connect example.com:443 -tls1_2 2>&1 | head -5

What comes next

The next article covers Authentication and authorization, where you will learn about password hashing, MFA, OAuth, and JWT tokens.

For a deeper understanding of the math behind digital signatures, see probability fundamentals.

Start typing to search across all content
navigate Enter open Esc close