Certificate Transparency
Append-only Merkle logs of every issued cert. SCTs. Why Chrome enforces it.
Certificate Transparency
In 2011, DigiNotar — a Dutch CA that browsers trusted — was hacked. The attackers issued forged certificates for *.google.com, *.skype.com, and dozens of other high-value domains. Iranian users were intercepted on their Gmail accounts for months. The breach was discovered only because a Chrome user noticed a certificate warning and reported it.
DigiNotar collapsed within months, but the deeper lesson stuck: the CA system gives every CA the power to issue any certificate to anyone, and there's no global mechanism to detect when they do. Certificate Transparency is the answer.
The pact
CT is a deal between three parties:
- CAs publish every certificate they issue to public, append-only logs. Every cert. No exceptions.
- Logs publish every certificate to anyone who asks, signing the receipt.
- Domain owners monitor the logs for certificates they didn't authorise.
The system doesn't prevent mis-issuance. A compromised CA can still issue a forged cert for google.com. But within minutes — sometimes seconds — that cert appears in a public log, and Google's own monitoring (or any third-party monitor) sees it. The bad cert is detected, revoked, and the responsible CA is removed from browser trust stores. Detection beats prevention at scale.
The append-only Merkle log
A CT log is just an append-only Merkle tree of certificate hashes:
root_hash
/ \
/ \
/ \
h(L0,L1) h(L2,L3)
/ \ / \
L0 L1 L2 L3
↑ ↑ ↑ ↑
cert_0 cert_1 cert_2 cert_3
The log publishes its current root_hash and tree_size. Anyone can prove:
- Inclusion: "cert X is in the tree" — given X and the log's root, the proof is
O(log n)sibling hashes that, hashed up, reach the root. - Consistency: "the tree at size N is a prefix of the tree at size M (M ≥ N)" — proves the log only ever grows; no cert was ever removed.
If a log ever lies about either property, anyone can detect it. Independent monitors continually re-fetch and verify; a cheating log gets caught and ejected.
SCTs — the receipts CAs hand out
When a CA submits a pre-cert to a log, the log returns a Signed Certificate Timestamp (SCT) — a signed promise: "I will include this certificate in my tree within MMD (Maximum Merge Delay), normally 24 hours."
The SCT is then embedded in the final certificate, by one of three mechanisms:
- X.509v3 extension in the cert (pre-cert + SCT signed back into the final cert by the CA).
- TLS extension sent during the handshake.
- OCSP staple.
Chrome accepts whichever it sees, as long as ≥ 2 SCTs come from independent qualifying logs (with caveats about log diversity and age).
Chrome's enforcement
Chrome 68+ (since April 2018) enforces CT. A publicly-trusted certificate without sufficient SCTs is rejected, full stop. This is what makes CT a real defence and not just a logging exercise.
The enforcement criteria:
- Cert was issued after April 2018.
- Cert chain ends in a publicly-trusted root.
- ≥ 2 SCTs from logs that meet Google's qualification policy (independent operators, sufficiently old logs, log diversity).
The exemption: certs issued by enterprise CAs (whose roots were manually installed, not in the public root store) are not subject to CT enforcement. Inside corp networks with private CAs, CT plays no role.
Real-world catches
- 2015 — Symantec mis-issuance. Symantec issued thousands of test certs for high-profile domains (google.com, opera.com) without permission. Google found them via CT monitoring and forced Symantec out of the public CA business over the following years.
- 2017 — WoSign / StartCom. Mis-issued + back-dated certs detected via CT. Distrusted by all major browsers.
- Ongoing — phishing detection. Domain owners (and their bug bounty programs) use Cert Spotter / crt.sh to detect homoglyph attacks (
g00gle.com,paypaI.com) before phishing campaigns go live.
How to use CT today
As a domain owner
Set up monitoring. Every public domain you own should be watched. Free tools:
# Search every cert ever issued for example.com:
$ curl -s "https://crt.sh/?q=example.com&output=json" | jq '.[].name_value' | sort -u
Or sign up for Cert Spotter — free for personal use, sends an email when a new cert appears.
As an operator
Your TLS endpoints already include SCTs (the CA puts them in the cert at issuance time). Inspect them:
$ openssl s_client -connect example.com:443 -showcerts -tls1_3 2>/dev/null \
| openssl x509 -text -noout | grep -A 3 "Signed Certificate Timestamp"
Three SCTs from three logs is the typical good shape.
As an SRE building a service
If you're issuing your own certs from a private CA inside the org, you don't have to log them — but you should monitor your public domains for unauthorised certs from public CAs. CT enforcement protects you against an attacker who manages to socially-engineer a public CA into issuing a cert for one of your domains.
CTv2 (RFC 9162)
The original spec (RFC 6962) had some warts: SCT formats were awkward, the tree-leaf format conflated pre-certs and final certs. CTv2 cleans these up and is gradually rolling out alongside the v1 logs. For most operators it's transparent — you get more efficient certs and better log behaviour for free.
What CT is NOT
- It doesn't prevent mis-issuance. It detects it. The CA still has to issue something for it to appear in a log.
- It doesn't help against private CAs in trusted Enterprise stores. If MITM proxies have installed their own root in your machine, they can issue without CT.
- It doesn't replace HSTS / HPKP. HSTS forces TLS; HPKP (now deprecated) pinned specific certs. CT is a complement, not a replacement.
- It's only for X.509 / WebPKI. Code signing, S/MIME, IoT certs — separate worlds.
The big idea
CT inverted the model. Instead of trusting CAs to never mis-issue (they will), the world now assumes mis-issuance is inevitable and engineers a system that detects it within 24 hours. That's a far more achievable goal, and it works.
If you operate any service with a public-facing TLS endpoint, monitor CT for your domains. It's free, it's automated, and it's how you find out about phishing domains and rogue CAs before they cause damage.
Tools in the wild
4 tools- servicecrt.shfree tier
Free public search of every CT log. `?q=example.com` returns every cert ever issued for that domain.
- serviceCert Spotterfree tier
Real-time alerts when new certificates are issued for your domains. Free for personal use.
- serviceCensysfree tier
Searchable index of every public TLS cert + service banner. Aggregates CT and active scanning.
- libraryct-go (Trillian)free tier
Google's open-source append-only log infrastructure. Run your own CT log with this.