← Back to Blog

35,000 of 4 Million: CRLSets, Bloom Filters and the Revocation Gap

Chrome's CRLSet covers roughly 1% of revoked certificates. Here is why, how Bloom filters (and their successors) let Firefox cover all of them, and why short-lived certificates change the question.

A certificate is a promise that lasts until its expiry date. Sometimes you need to break that promise early: the private key leaked, the CA issued it by mistake, the domain changed hands. The mechanism for that is revocation, and it is the part of the web PKI that works the least well. This article explains why browsers stopped asking CAs about revocation in real time, what Chrome's CRLSets do in its place, and how the small internal CA I run at home sidesteps the whole problem.

The two original answers, and why they failed

The standard defines two ways to find out whether a certificate is revoked. A CRL (certificate revocation list) is a file published by the CA listing the serial numbers of revoked certificates. It is simple, but it grows with every revocation and the client has to download all of it. OCSP (Online Certificate Status Protocol) lets the client ask the CA about a single certificate, which is lighter, but it has costs of its own:

That last question is the one that broke it. Browsers chose soft-fail: if the revocation server does not answer, assume the certificate is fine, because otherwise a CA outage would take half the web down. But an attacker who can intercept your traffic well enough to use a stolen key can also drop the OCSP request. Soft-fail therefore protects against nothing in exactly the situation where you need it. Revocation checking that an attacker can switch off by blocking a request is, as security people say, a speed bump.

CRLSets: a curated list pushed to the browser

Chrome's answer is the CRLSet. Instead of asking a CA at connection time, Chrome receives a small list of revoked certificates through its own update channel, in the background, like any other component. The list is compact and chosen by Google: it is built from the CRLs that CAs publish, but it is deliberately not complete. Chromium's documentation states a size limit of 250 KB, and it describes how entries are picked: only revocations with no reason code, or with a reason such as key compromise or CA compromise, are included, and CRLs covering intermediates and EV certificates are taken in preference.

How much does that fit? Mozilla, which has every reason to measure it, reports in its 2025 post on CRLite that Chrome's CRLSet is about 600 kB a day and holds roughly 35,000 revocations. The web has about 4 million revoked certificates at any time. That is around 1%. (Those figures come from a competitor and describe 2025; Chromium's own page does not state an entry count, and its 250 KB limit differs from the size Mozilla observed, so treat both as orders of magnitude.)

The consequences are worth spelling out:

The size problem has a history: mass revocations, the best-known being the aftermath of the Heartbleed bug in 2014, produced far more revoked certificates than a list this small can carry. That event is much of why people stopped believing in revocation as a safety net.

Fitting 4 million revocations in a few hundred kilobytes

Mozilla attacked the completeness problem instead. CRLite encodes all revocations, not a selection, and ships them to Firefox. According to Mozilla, that is about 300 kB of data per day plus a snapshot of roughly 4 MB every 45 days, against about 300 MB for the raw CRLs. It is enabled for desktop Firefox since version 137. The trick is a probabilistic data structure.

A Bloom filter answers "is this item in the set?" using a few bits per item. It can say "definitely not" or "probably yes". It never forgets an item it holds (no false negatives), but it sometimes claims to contain one it does not (false positives). For revocation that is the wrong way round if you use it naively: a false positive would mean wrongly rejecting a perfectly valid certificate.

CRLite's original design fixed this with a cascade. The first filter holds the revoked certificates. Every valid certificate that wrongly matches it, which Mozilla can enumerate because it knows the whole set of publicly logged certificates, goes into a second filter. The few revoked certificates that falsely match that one go into a third, and so on until nothing is left. Walk the levels and you get an exact answer for every certificate that was known when the cascade was built. The current implementation replaces the stack of Bloom filters with a two-level cascade of more compact Ribbon filters (the "Clubcards" design), which is why the numbers above are so small.

The trade-off is the mirror image of Chrome's: complete coverage and exactness, but only for certificates that appear in Certificate Transparency logs, and only as fresh as the pipeline that rebuilds it.

OCSP stapling and the "Must-Staple" extension are a third path: the server fetches a signed OCSP response itself and presents it during the handshake, so the browser does not have to contact the CA. It fixes latency and privacy, but not the soft-fail problem unless the certificate says the staple is mandatory, and few sites ask for that.

The industry's real fix: make certificates expire sooner

If revocation is unreliable, the other lever is lifetime. A certificate that expires in a week needs no revocation: by the time you notice a problem, it is already nearly gone. The CA/Browser Forum has been moving in this direction. Maximum validity dropped to 398 days years ago, and a 2025 ballot schedules a staged reduction, with a ceiling of 200 days that is already in force and further cuts planned in the following years. Automation (ACME) is what makes it possible: nobody renews 47-day certificates by hand. Some CAs now offer certificates that live for only a few days. Responders have followed: the CA/B Forum made OCSP optional and CRLs mandatory for public CAs, and Let's Encrypt has dropped OCSP in favour of CRLs.

What this means for a homelab PKI

My internal CA is a step-ca instance: an offline root key, an intermediate on the server, ACME to issue certificates to Caddy. I did not build any revocation infrastructure, and I do not intend to, for three reasons:

It also matches how browsers treat private roots: the curated, centrally updated revocation data they ship is built for public CAs, so a certificate chaining to a root you installed yourself should not be expected to benefit from it. For a private PKI, short lifetimes are not just a convenience, they are the revocation strategy.

Takeaways

Sources