All posts
Vojtěch

Find every certificate you forgot you issued

How Tidelock's Certificate Discovery tool uses public Certificate Transparency logs to enumerate every subdomain of a domain, then audits the TLS cert on each one.

You almost certainly own more certificates than you think. A staging box from two years ago. A vendor subdomain someone provisioned for a webhook integration. A legacy. host nobody monitors. Each one is a quiet expiry waiting to take down something at 3am.

The new Certificate Discovery tool gives you a full picture in one paste: type a root domain, get back every subdomain a public CA has ever issued a cert for, plus a live audit of the cert each one is currently serving.

Why CT logs make this possible

Since 2018, every certificate trusted by Chrome, Safari, and Firefox has to be published to at least two append-only public logs — that's Certificate Transparency. The original goal was detection: if a CA mis-issues a cert for your-bank.com, you want a public record so you can catch it. The side effect is that CT logs are now the single best subdomain inventory on the internet, far better than DNS scraping or brute-forcing wordlists.

If you've ever wanted to know "what's actually exposed under our domain?", the CAs have already told you. You just have to ask.

How discovery works

The discovery half is a single call to the CertSpotter API — we ask for every issuance whose SAN list mentions the root domain or anything under it, and expand the DNS names so we get the full SAN inventory back rather than just issuance metadata.

From there it's housekeeping:

  • Lowercase and dedupe the DNS names.
  • Drop wildcard entries (*.example.com) — those aren't a host you can connect to.
  • Drop anything outside the requested root, since a single cert's SAN list can list multiple unrelated domains (this is how shared-hosting and CDN certs show up in CT logs for domains that have nothing to do with each other).
  • Validate each name against a strict domain regex to throw out garbage.
  • Sort the result and cap it at 100 hosts to keep the audit phase tractable.

That's it for the discovery half. The interesting part is what happens next.

Auditing each host, one at a time

A list of hostnames is only useful if you also know whether the cert each one is currently serving is healthy. So the frontend takes the discovered list and fires a per-host inspection request back to the server. Each one opens a real TLS connection on port 443 and captures the leaf certificate the host hands back.

Three details about that handshake matter:

  • SNI must be set to the hostname you're checking. Without it, hosts on shared IPs (which is most of the modern internet) hand back the wrong certificate — usually a default vhost cert that has nothing to do with the name you asked for. This is the #1 reason naive cert checkers report hostname mismatches that aren't real.
  • Peer verification must be disabled. Counterintuitive, but we want the handshake to complete even when the cert is expired or doesn't match. Refusing the connection at the TLS layer would tell us nothing; capturing the cert anyway lets us report exactly why it's broken.
  • Connect timeout has to be aggressive. A scan of 100 hosts will always include a few that are firewalled, dead, or pointed at IPs that no longer answer. Four seconds per host is enough for any reachable server and short enough that the whole audit doesn't stall on a handful of black holes.

Once we have the certificate bytes, we parse them and pull out: issuer (common name + organisation), subject CN, validFrom / validTo timestamps, all SAN entries, and days remaining until expiry.

The status taxonomy

Once we have the parsed cert, the verdict is a small ladder. The first one that matches wins:

Status Meaning
Expired now > validTo
Not yet valid now < validFrom (rare, but a real failure mode for misconfigured renewals)
Hostname mismatch Neither the CN nor any SAN matches the host we connected to
Expires very soon ≤ 7 days left
Renewal due ≤ 30 days left
Healthy Everything above passed

Hostname matching respects wildcards correctly — *.example.com matches api.example.com but not deep.api.example.com, per RFC 6125. A wildcard only covers a single label. That's a subtle one: plenty of in-house cert checkers get it wrong and either over-match (treating *.example.com as matching anything ending in .example.com, which would let one cert masquerade as a different security boundary) or refuse to match wildcards at all and produce false mismatches on every CDN-fronted subdomain.

What it doesn't do

A few honest limits:

  • No port-other-than-443. If you have a cert on :8443, this tool won't see it. CT logs don't carry port information, and we'd rather report nothing than guess.
  • No private CA / internal hosts. CT only covers publicly-trusted CAs. An internal PKI rooted in your own CA is invisible here — which is the correct behaviour, but worth knowing.
  • No history. We show what's serving right now. The CT log itself contains the full history, but for a snapshot tool that would be noise.
  • Cap of 100 hosts per scan. Big domains have thousands of issuances; we surface the most useful slice and stay polite to CertSpotter's API.

Why this is the start, not the end

A scan is a moment in time. The cert that's healthy today is the one expiring six weeks from now while everyone's on holiday. Discovery tells you what exists; monitoring tells you what's about to break. The free tool answers the first question. Tidelock answers the second — but you don't need an account to use the discovery tool, and you probably should, at least once, just to see what comes back.

Try it: tidelock.dev/ssl/certificate-discovery.