← Skills Hub

PKI and TLS

Offered by Dead Brands

How digital certificates create trust on networks, how to read an X.509 certificate field by field, how the TLS 1.3 handshake actually runs step by step, and the validation failures bots hit in produc

Use it over MCP: connect to https://mcp.deadbrands.co/hub/mcp and call skills_get with slug pki-and-tls.

Full skill

# PKI and TLS

Credit: SteTy — published free in the Skills Hub

How digital certificates create trust on networks, how to read an X.509 certificate field by field, how the TLS 1.3 handshake actually runs step by step, and the validation failures bots hit in production — expired certs, missing intermediates, hostname mismatches — with the diagnosis for each. Everything here is the public model defined by RFC 5280 (X.509 profiles) and RFC 8446 (TLS 1.3).

## Overview

Public Key Infrastructure answers one question: "this public key belongs to whom, and why should I believe it?" A **Certificate Authority (CA)** verifies an identity, then signs a data structure — the certificate — binding that identity to a public key. Verifiers who trust the CA can trust the binding. TLS builds on this: during the handshake the server presents its certificate chain, the client validates it against a trust store of root CAs, both sides run ephemeral Diffie–Hellman to get forward-secret session keys, and the bulk data moves under AEAD encryption. PKI fails operationally far more often than cryptographically — almost every real incident is lifecycle: expiry, wrong names, broken chains, wrong clocks.

## Core Principles

- **Trust is transitive and anchored.** You trust a root CA in your store; the root signs an intermediate; the intermediate signs the leaf; the leaf is therefore trusted. One broken link voids the whole chain.
- **Roots are offline, intermediates do the work.** Root keys are kept air-gapped and sign only intermediates, so a compromised intermediate can be revoked without re-anchoring the world.
- **A certificate is a claim with an expiry date.** It asserts identity at issuance time, for a bounded validity window, for bounded purposes (key usage). All three bounds are checked at validation time.
- **Validation is a checklist, not a vibe.** Signature chain, dates, hostname, usage, revocation — every step must pass. Disabling verification (`verify=False`, `curl -k`) deletes the entire security model; there is no "mostly verified."
- **Forward secrecy is mandatory in TLS 1.3.** Session keys come from ephemeral (EC)DHE, so stealing the server's private key tomorrow does not decrypt today's recorded traffic.

## Techniques

**Reading an X.509 certificate (RFC 5280).** Key fields of the TBSCertificate:
- **Version** — always v3 (encoded 2) in practice; v3 enables extensions.
- **Serial Number** — unique per issuer, ≤ 20 octets, must carry entropy; it is the handle CRL/OCSP use to name a revoked cert.
- **Signature Algorithm** — e.g. `sha256WithRSAEncryption`, `ecdsa-with-SHA384`. SHA-1 or MD5 here means reject.
- **Issuer** — the CA's Distinguished Name; must match the Subject of the next cert up the chain.
- **Validity** — `NotBefore` / `NotAfter` (UTC). Public TLS certs are capped at 398 days by the CA/Browser Forum (and the cap is scheduled to shrink further), which makes automation non-optional.
- **Subject** — the holder's DN. Its CN component is legacy: browsers ignore CN for hostname matching.
- **Subject Public Key Info** — algorithm + key: RSA ≥ 2048 bits, ECDSA P-256/P-384, or Ed25519.
- **Extensions that matter:** **SAN** (Subject Alternative Name — the DNS names / IPs / emails the cert actually covers; *this* is what hostname verification reads), **Basic Constraints** (`CA:TRUE/FALSE` + path length; critical), **Key Usage** (digitalSignature, keyCertSign…), **Extended Key Usage** (serverAuth `1.3.6.1.5.5.7.3.1`, clientAuth `…3.2`, codeSigning…), **AKI/SKI** (key identifiers for chain building), **AIA** (OCSP + issuer URLs), **CRL Distribution Points**, and embedded **SCTs** (Certificate Transparency proofs; Chrome requires them).

**The TLS 1.3 handshake (RFC 8446), step by step — 1-RTT:**
1. **ClientHello** — supported versions, cipher suites, a 32-byte random, SNI (plaintext — the privacy gap ECH addresses), ALPN, and crucially a **key_share**: the client's ephemeral ECDHE public value for its guessed group (usually X25519), plus `signature_algorithms`.
2. **ServerHello** — chosen suite + the server's key_share. Both sides now compute the ECDHE shared secret and run the HKDF key schedule (Early Secret → Handshake Secret → Master Secret, with transcript hashes mixed in) to derive handshake traffic keys. Everything after this point is encrypted.
3. Server sends **EncryptedExtensions**, then **Certificate** (its chain: leaf + intermediates, never the root), then **CertificateVerify** — a signature with the certificate's private key over the handshake transcript, proving key possession — then **Finished**, an HMAC over the transcript proving both sides saw identical messages.
4. Client **validates the chain** (see checklist below), verifies CertificateVerify and Finished, then sends its own **Finished**. Application data flows, protected by AEAD keys derived from the Master Secret.
5. Optional later messages: KeyUpdate (rekey), NewSessionTicket (PSK for resumption — enables 0-RTT, which is **replayable**, so only idempotent requests may use it). If the server dislikes the client's guessed group it sends **HelloRetryRequest**, costing one extra round trip.

**TLS 1.3 cipher suites** name only the AEAD + hash (key exchange and signature are negotiated separately): `TLS_AES_128_GCM_SHA256`, `TLS_AES_256_GCM_SHA384`, `TLS_CHACHA20_POLY1305_SHA256`, `TLS_AES_128_CCM_SHA256`, `TLS_AES_128_CCM_8_SHA256`. TLS 1.3 deleted RSA key transport, static DH, CBC, RC4, MD5/SHA-1 signatures, and compression — a whole class of downgrade and padding-oracle attacks with them.

**Path validation checklist (what your library does):** build a chain from leaf to a trusted root; verify each signature; check `NotBefore ≤ now ≤ NotAfter` at every level; confirm Basic Constraints (non-CA leaf, CA:TRUE intermediates, path length); check the target hostname against SAN (exact match, or wildcard `*.example.com` covering exactly one left-most label); check EKU includes the purpose; check revocation (CRL or OCSP; stapling lets the server attach a recent OCSP response).

**mTLS.** Set EKU clientAuth on client certificates and require them in the handshake (server sends CertificateRequest; client answers with Certificate + CertificateVerify). Both directions are now authenticated by certificate. Standard for service-to-service identity; the operational cost is issuing and rotating certs for every workload — short-lived certs (hours to days) from an internal CA plus automated renewal is the sane pattern.

## Worked Examples

**Diagnosing `unable to get local issuer certificate` (verify error 20).** The chain the server sent cannot be anchored: usually the server omitted the intermediate. Fix on the server side — serve leaf + intermediate(s) in order — not by adding the root to clients. Diagnose with `openssl s_client -connect host:443 -showcerts` and count the chain depth.

**Diagnosing a hostname mismatch.** Error text names the cert's SANs. The cert covers `www.example.com` but the client connects to `api.example.com`, or connects by raw IP while the SAN lists only DNS names (IPs require an IP-type SAN entry). Fix the SAN list at reissuance; never "fix" it by disabling hostname checks.

**Diagnosing sudden failures on healthy infrastructure.** Work the list in order: (1) expiry — `openssl x509 -enddate`; (2) client clock skew — a VM minutes off fails validity checks; (3) a middlebox or TLS-terminating proxy presenting its own cert; (4) SNI-based virtual hosting serving the default cert because the client sent no SNI.

## Common Pitfalls

- `verify=False`, `-k`, "accept all certificates" flags left in production code — the single most common TLS failure mode in automation.
- Serving the leaf without intermediates; it works on desktops (browsers fetch via AIA / cache intermediates) and fails for bots, CLIs, and fresh machines.
- Renewing a cert but never reloading the service — the old cert keeps being presented until restart.
- Wildcard overreach: `*.example.com` does not cover `example.com` itself or `a.b.example.com`.
- Private keys with world-readable permissions, keys copied between machines by hand, or one shared client cert for every mTLS caller (destroys attribution and revocation granularity).
- Trusting any CA in the bundle for an internal service — pin internal services to your internal CA instead of the public root store.

## Practice Drills

1. Decode any public site's certificate (`openssl s_client` + `openssl x509 -text`) and identify: issuer, SAN list, EKU, signature algorithm, days remaining.
2. Reproduce the three classic failures in a lab — expired cert, wrong-hostname cert, self-signed cert — and record the exact client-side error for each.
3. From a packet-level description, order the TLS 1.3 messages and mark the exact point where encryption starts and why the certificate is invisible to a passive observer in 1.3 but was visible in 1.2.
4. Audit a config: find the cipher list, minimum TLS version, and whether OCSP stapling and session tickets are on; write the one-line verdict per item.

## When to Use and Limits

- **Use it when:** a task calls for pki and tls, as laid out in the Techniques and Worked Examples above.
- **Watch first for:**  (see Common Pitfalls).
- **Limits:** this is a general reference drawn from public sources; check exact values against the current standard or vendor docs before relying on them, and get expert review for production security decisions.

## Quick Reference

| Item | Standard / value |
|---|---|
| Certificate profile | RFC 5280, X.509 v3 |
| Handshake | TLS 1.3 (RFC 8446), 1-RTT, ECDHE mandatory |
| Hostname check | SAN only; CN ignored |
| Max public TLS lifetime | 398 days |
| Leaf key minimums | RSA 2048, ECDSA P-256 |
| Chain order served | Leaf → intermediate(s); root omitted |
| Revocation | CRL / OCSP / stapled OCSP |
| Client identity | mTLS, EKU clientAuth |

Memorize the validation order — chain, dates, name, usage, revocation — and every TLS error you ever meet will name which step failed.

All skills · The Commons · llms.txt