<aside> 🧭
Module 11 · Certificate Transparency, CAA & the Public Trust Ecosystem
Every module so far has quietly assumed the CAs behave. This one stops assuming. Module 05 showed that any CA in the trust store can sign for any name — so the real question is not "how do we stop a CA misbehaving?" but "how would we ever find out?". Certificate Transparency is the answer the industry actually built, and CAA is the one control you own yourself.
🧠 concept → 🧪 exercise → ✅ expected result (hidden) → 🎯 interview questions (answers hidden)
Prerequisite: Modules 01–10. You need X.509 extensions from Module 03 (C4–C5), the chain of trust and trust stores from Module 05, openssl verify error codes from Module 07, and the ACME account URI from Module 10 (B2).
</aside>
<aside> 🗝️
The picture to hold in your head for this whole module — every locksmith in the city can cut a key to your front door.
That is genuinely the situation Module 05 left you in. Your browser trusts around 150 root certificates. Any one of them can issue a certificate for your domain, without asking you, without telling you.
You cannot take the locksmiths' tools away — the web needs them. So the industry did two other things instead.
First, it forced every locksmith to publish every key they cut, in a public register that cannot be edited afterwards. That is Certificate Transparency. It does not prevent a bad key; it guarantees you can find out about it.
Second, it let you nail a notice to your own door saying which locksmiths you actually use. That is a CAA record. It is voluntary for you to publish, but mandatory for them to read.
Neither is prevention. Both are accountability — and in this ecosystem accountability turned out to be the thing that worked.
</aside>
<aside> 🖥️
Build the lab. Most of this module runs offline inside ~/tls-lab/m11/. Two sections use DNS lookups (dig) and two use openssl s_client against public sites — both read-only, neither changes anything on your machine.
mkdir -p ~/tls-lab/m11 && cd ~/tls-lab/m11
You will need dig. It ships with macOS. On Debian/Ubuntu: sudo apt-get install -y bind9-dnsutils. On RHEL/Fedora: sudo dnf install -y bind-utils.
All output in this module was produced on OpenSSL 3.0.13 with BIND 9.18 dig, except where a block is explicitly marked as coming from a public site.
</aside>
<aside> 📖
Official docs: RFC 6962 — Certificate Transparency · certificate.transparency.dev — How CT works · MDN — Certificate Transparency
</aside>
<aside> 🏦
The analogy — a bank that never sends statements.
Imagine a bank that will honour a cheque signed by any one of 150 branch managers, and never publishes a list of the cheques it honoured.
A dishonest manager could write cheques against your account for months, and the only way you would ever discover it is if you happened to be standing in the shop when one was cashed.
That is exactly the pre-2013 web. Certificate Transparency is the bank statement — it does not stop the dishonest manager, it just makes it impossible for the cheque to stay hidden.
</aside>
Module 05 established the rule that makes the whole web PKI work: a certificate is trusted if it chains to any root in your trust store. Module 07 showed the client checking that chain.
Now look at that rule from the other side. There is no field anywhere in X.509 that says "only this CA may issue for yourbank.com". The trust store is a flat list of equals. A small CA you have never heard of, in a jurisdiction you have never visited, can sign a certificate for your domain, and every browser on earth will accept it.
<aside> 🔑
The insight the whole module rests on: web PKI trust is the union of every CA, not the intersection.
Adding a CA to a trust store does not add a little bit of trust. It adds the full power to impersonate every website on the internet. There are around 150 of them.
This is why the interesting security question in public PKI is not cryptographic. The maths has been fine for twenty years. The question is governance: who watches the CAs?
</aside>
This is not theoretical. In 2011 a Dutch CA called DigiNotar was compromised. The attacker issued a valid certificate for *.google.com and it was used to intercept the Gmail traffic of an estimated 300,000 Iranian users. The certificate had been in the wild for weeks before anyone noticed — and it was noticed by accident, because one Chrome user in Iran had a build with hard-coded pinning for Google's own certificates and reported the error to a forum.
That is the whole problem in one sentence: the detection mechanism was a coincidence. Certificate Transparency exists to replace the coincidence with a guarantee.
🧪 Exercise A1.1 — Count the number of organisations that can impersonate your website
cd ~/tls-lab/m11
# how many roots does this machine trust? (Debian/Ubuntu path)
grep -c "BEGIN CERT" /etc/ssl/certs/ca-certificates.crt
# how many distinct organisations is that?
mkdir -p roots && cd roots
awk '/BEGIN CERT/{n++} {print > ("root-" n ".pem")}' /etc/ssl/certs/ca-certificates.crt
for f in root-*.pem; do openssl x509 -in "$f" -noout -subject 2>/dev/null; done \
| sed -n 's/.*O = \([^,]*\).*/\1/p' | sort -u | wc -l
cd ..
On macOS the bundle is not at that path. Use this instead, which exports the System roots from the keychain:
security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain > macos-roots.pem
grep -c "BEGIN CERT" macos-roots.pem