applied · level 7

Certificate Transparency

Append-only Merkle logs of every issued cert. SCTs. Why Chrome enforces it.

200 XP

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:

  1. X.509v3 extension in the cert (pre-cert + SCT signed back into the final cert by the CA).
  2. TLS extension sent during the handshake.
  3. 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
  • crt.shfree tier

    Free public search of every CT log. `?q=example.com` returns every cert ever issued for that domain.

    service
  • Cert Spotterfree tier

    Real-time alerts when new certificates are issued for your domains. Free for personal use.

    service
  • Censysfree tier

    Searchable index of every public TLS cert + service banner. Aggregates CT and active scanning.

    service
  • Google's open-source append-only log infrastructure. Run your own CT log with this.

    library