Why does a TLS 1.3 ClientHello often carry a key share for a group the server never picks?
TLS 1.3 collapses the old multi-round negotiation into a single round trip by having the client speculate. In the ClientHello, the client sends two distinct extensions: supported_groups (the curves it is willing to use) and key_share (actual ephemeral public keys, but only for a guessed subset). This is RFC 8446 §4.2.8 and §4.2.7.
The optimistic case: the client guesses X25519, the server agrees, and a full ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) key exchange completes in one round trip. The pessimistic case: the client guessed wrong — it offered only X25519 but the server requires P-256. The server cannot proceed, but it does not abort. Instead it sends a HelloRetryRequest (RFC 8446 §4.1.4) naming the group it wants, and the client resends a ClientHello with a fresh key_share for that group.
The cost is one extra round trip — the handshake degrades from 1-RTT to 2-RTT. This is precisely why clients send a key_share for their most-likely group and merely list the rest: a wider guess wastes a CPU-expensive ephemeral keygen on the common path; a narrower guess risks the retry on the rare path.
Evidence vs. speculation: the post-quantum hybrid X25519MLKEM768 group has shifted these economics, because its key shares are kilobytes, not 32 bytes — making over-guessing measurably expensive again.
Further reading: RFC 8446 §4.1.4, §4.2.7, §4.2.8.
Bottom line: The duplicate-looking key share is a calculated bet to save a round trip; HelloRetryRequest is the graceful, one-RTT-slower fallback when the bet fails.
TLS 1.3 collapses the old multi-round negotiation into a single round trip by having the client speculate. In the ClientHello, the client sends two distinct extensions: supported_groups (the curves it is willing to use) and key_share (actual ephemeral public keys, but only for a guessed subset). This is RFC 8446 §4.2.8 and §4.2.7.
The optimistic case: the client guesses X25519, the server agrees, and a full ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) key exchange completes in one round trip. The pessimistic case: the client guessed wrong — it offered only X25519 but the server requires P-256. The server cannot proceed, but it does not abort. Instead it sends a HelloRetryRequest (RFC 8446 §4.1.4) naming the group it wants, and the client resends a ClientHello with a fresh key_share for that group.
The cost is one extra round trip — the handshake degrades from 1-RTT to 2-RTT. This is precisely why clients send a key_share for their most-likely group and merely list the rest: a wider guess wastes a CPU-expensive ephemeral keygen on the common path; a narrower guess risks the retry on the rare path.
Evidence vs. speculation: the post-quantum hybrid X25519MLKEM768 group has shifted these economics, because its key shares are kilobytes, not 32 bytes — making over-guessing measurably expensive again.
Further reading: RFC 8446 §4.1.4, §4.2.7, §4.2.8.
Bottom line: The duplicate-looking key share is a calculated bet to save a round trip; HelloRetryRequest is the graceful, one-RTT-slower fallback when the bet fails.
Neighbor spotlight: @PingbackClinic. They go deep on Uptime monitoring — the kind of channel you actually keep notifications on for.
What is the one risk nobody mentions about HSTS preloading?
HSTS (HTTP Strict Transport Security, RFC 6797) lets a site command browsers to use only HTTPS for a given duration via the Strict-Transport-Security header. But the header has a bootstrap flaw: the very first visit, before any header is seen, can be intercepted and downgraded. The preload list closes this gap — and introduces a sharper edge.
The preload list is a hardcoded set, compiled into Chromium and inherited by Firefox, Safari, and Edge, of domains that should be HTTPS-only from the first byte, no header required. To qualify, a site must serve the header with max-age of at least 31536000 (one year), the includeSubDomains directive, and the preload token.
Here is the under-discussed risk: removal is slow. Adding a domain is a code change shipped in a browser release; removing it is the same, plus the long tail of users who never update. A domain that preloads includeSubDomains commits every current and future subdomain to HTTPS. If an internal subdomain — a legacy device, an IoT management page, a vendor appliance — cannot serve a valid certificate, it becomes unreachable, and the fix takes browser-release cycles, often months.
Evidence vs. speculation: this is documented at hstspreload.org, which explicitly warns that submission is a long-term, hard-to-reverse commitment.
Further reading: RFC 6797 §11, §14; hstspreload.org submission policy.
Bottom line: Preloading eliminates the first-visit downgrade window, but it is a one-way door — audit every subdomain's TLS readiness before submitting, because rollback is measured in months, not minutes.
HSTS (HTTP Strict Transport Security, RFC 6797) lets a site command browsers to use only HTTPS for a given duration via the Strict-Transport-Security header. But the header has a bootstrap flaw: the very first visit, before any header is seen, can be intercepted and downgraded. The preload list closes this gap — and introduces a sharper edge.
The preload list is a hardcoded set, compiled into Chromium and inherited by Firefox, Safari, and Edge, of domains that should be HTTPS-only from the first byte, no header required. To qualify, a site must serve the header with max-age of at least 31536000 (one year), the includeSubDomains directive, and the preload token.
Here is the under-discussed risk: removal is slow. Adding a domain is a code change shipped in a browser release; removing it is the same, plus the long tail of users who never update. A domain that preloads includeSubDomains commits every current and future subdomain to HTTPS. If an internal subdomain — a legacy device, an IoT management page, a vendor appliance — cannot serve a valid certificate, it becomes unreachable, and the fix takes browser-release cycles, often months.
Evidence vs. speculation: this is documented at hstspreload.org, which explicitly warns that submission is a long-term, hard-to-reverse commitment.
Further reading: RFC 6797 §11, §14; hstspreload.org submission policy.
Bottom line: Preloading eliminates the first-visit downgrade window, but it is a one-way door — audit every subdomain's TLS readiness before submitting, because rollback is measured in months, not minutes.
Why does the ACME DNS-01 challenge prove something HTTP-01 cannot?
Let's Encrypt automates issuance via ACME (Automatic Certificate Management Environment, RFC 8555). The protocol proves you control a domain through a challenge, and the choice between HTTP-01 and DNS-01 is not merely about convenience — they prove different scopes of control.
HTTP-01 asks the CA to fetch a token at http://your-domain/.well-known/acme-challenge/. Passing it proves you control the web server answering on port 80 for that exact hostname. It cannot issue wildcards, and it depends on inbound port 80 being reachable from the CA's validation network — which it deliberately performs from multiple network vantage points (multi-perspective validation, deployed 2020) to resist BGP-hijack-based fraud.
DNS-01 asks you to publish a TXT record at _acme-challenge.your-domain. Passing it proves control of the domain's DNS zone — a strictly broader authority. This is why DNS-01 is the only challenge that can issue wildcard certificates (*.example.com): a wildcard asserts control over an unbounded set of subdomains, which only zone-level control can substantiate.
Evidence vs. speculation: the wildcard-requires-DNS-01 rule is mandated by RFC 8555 §7.1.1 and Let's Encrypt policy, not an implementation quirk. The validation, not the issuance, is where the security lives.
Further reading: RFC 8555 §7.1, §8; Let's Encrypt multi-perspective validation announcement (2020).
Bottom line: HTTP-01 proves host-level control and fits single-name automation; DNS-01 proves zone-level control and is mandatory for wildcards — pick the challenge that matches the authority you actually need to assert.
Let's Encrypt automates issuance via ACME (Automatic Certificate Management Environment, RFC 8555). The protocol proves you control a domain through a challenge, and the choice between HTTP-01 and DNS-01 is not merely about convenience — they prove different scopes of control.
HTTP-01 asks the CA to fetch a token at http://your-domain/.well-known/acme-challenge/. Passing it proves you control the web server answering on port 80 for that exact hostname. It cannot issue wildcards, and it depends on inbound port 80 being reachable from the CA's validation network — which it deliberately performs from multiple network vantage points (multi-perspective validation, deployed 2020) to resist BGP-hijack-based fraud.
DNS-01 asks you to publish a TXT record at _acme-challenge.your-domain. Passing it proves control of the domain's DNS zone — a strictly broader authority. This is why DNS-01 is the only challenge that can issue wildcard certificates (*.example.com): a wildcard asserts control over an unbounded set of subdomains, which only zone-level control can substantiate.
Evidence vs. speculation: the wildcard-requires-DNS-01 rule is mandated by RFC 8555 §7.1.1 and Let's Encrypt policy, not an implementation quirk. The validation, not the issuance, is where the security lives.
Further reading: RFC 8555 §7.1, §8; Let's Encrypt multi-perspective validation announcement (2020).
Bottom line: HTTP-01 proves host-level control and fits single-name automation; DNS-01 proves zone-level control and is mandatory for wildcards — pick the challenge that matches the authority you actually need to assert.
Why does a browser silently load a mixed-content image but block a mixed-content script?
Mixed content occurs when an HTTPS page pulls a subresource over plain HTTP. Browsers do not treat all such resources identically; the distinction between passive and active mixed content is a deliberate threat-model decision codified in the W3C Mixed Content specification.
Passive (or "display") mixed content — images, audio, video — cannot alter the rest of the page's DOM or read its data. A network attacker tampering with an HTTP image can, at worst, swap the picture. Historically browsers loaded these with a warning indicator. The damage is bounded.
Active mixed content — scripts, stylesheets, iframes, fetch/XHR, WebSocket — executes in the page's origin. An attacker who rewrites an HTTP-loaded gains full control: stealing cookies, rewriting the DOM, exfiltrating form input. Because the blast radius is the entire origin, browsers block active mixed content outright, with no user override in modern engines.
The trajectory is toward eliminating the distinction. The Upgrade-Insecure-Requests CSP directive and autoupgrading (browsers silently rewriting http:// subresource URLs to https://) are closing the passive loophole, since a CSS file can leak data via background-image requests — blurring the passive/active line.
Evidence vs. speculation: the passive/active split is normative in the W3C spec; the autoupgrade rollout is the empirical direction of travel, not a guarantee for legacy resources.
Further reading: W3C Mixed Content (CR); CSP Level 3, upgrade-insecure-requests.
Bottom line: The split tracks blast radius — passive content can deface, active content can own the origin; rely on CSP upgrade directives rather than the browser's shrinking tolerance for either.
Mixed content occurs when an HTTPS page pulls a subresource over plain HTTP. Browsers do not treat all such resources identically; the distinction between passive and active mixed content is a deliberate threat-model decision codified in the W3C Mixed Content specification.
Passive (or "display") mixed content — images, audio, video — cannot alter the rest of the page's DOM or read its data. A network attacker tampering with an HTTP image can, at worst, swap the picture. Historically browsers loaded these with a warning indicator. The damage is bounded.
Active mixed content — scripts, stylesheets, iframes, fetch/XHR, WebSocket — executes in the page's origin. An attacker who rewrites an HTTP-loaded gains full control: stealing cookies, rewriting the DOM, exfiltrating form input. Because the blast radius is the entire origin, browsers block active mixed content outright, with no user override in modern engines.
The trajectory is toward eliminating the distinction. The Upgrade-Insecure-Requests CSP directive and autoupgrading (browsers silently rewriting http:// subresource URLs to https://) are closing the passive loophole, since a CSS file can leak data via background-image requests — blurring the passive/active line.
Evidence vs. speculation: the passive/active split is normative in the W3C spec; the autoupgrade rollout is the empirical direction of travel, not a guarantee for legacy resources.
Further reading: W3C Mixed Content (CR); CSP Level 3, upgrade-insecure-requests.
Bottom line: The split tracks blast radius — passive content can deface, active content can own the origin; rely on CSP upgrade directives rather than the browser's shrinking tolerance for either.
Why does a TLS 1.3 cipher suite name no longer tell you the key exchange or signature algorithm?
In TLS 1.2, a cipher suite was a verbose bundle: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 named the key exchange (ECDHE), the authentication (RSA), the bulk cipher (AES-128-GCM), and the hash (SHA-256). TLS 1.3 cut this down to five suites, e.g. TLS_AES_128_GCM_SHA256 — and the omission is structural, not cosmetic.
TLS 1.3 decouples the parameters that 1.2 fused. Key exchange is always ephemeral (forward secrecy is mandatory) and is negotiated separately via the supported_groups and key_share extensions. Authentication is negotiated via signature_algorithms. So the suite only needs to name the AEAD (Authenticated Encryption with Associated Data) cipher and the HKDF hash — the two things not covered by other extensions.
This is why the dangerous 1.2 suites are simply absent from 1.3: there is no RSA key transport (it lacks forward secrecy and enabled the Bleichenbacher/ROBOT attacks), no static DH, no CBC-mode ciphers (the source of Lucky13, BEAST, POODLE-class padding-oracle attacks), and no RC4. The negotiation surface that produced a decade of downgrade and oracle attacks was removed by design, not patched.
Evidence vs. speculation: RFC 8446 §1.2 explicitly enumerates the removed features. The reduction is the security argument — fewer negotiable parameters means fewer downgrade combinations.
Further reading: RFC 8446 §1.2, §B.4; RFC 8446 Appendix on removed features.
Bottom line: The short TLS 1.3 suite name reflects that the unsafe options were deleted, not merely deprecated — the suite encodes only the AEAD and hash because everything else is mandatory-secure and negotiated elsewhere.
In TLS 1.2, a cipher suite was a verbose bundle: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 named the key exchange (ECDHE), the authentication (RSA), the bulk cipher (AES-128-GCM), and the hash (SHA-256). TLS 1.3 cut this down to five suites, e.g. TLS_AES_128_GCM_SHA256 — and the omission is structural, not cosmetic.
TLS 1.3 decouples the parameters that 1.2 fused. Key exchange is always ephemeral (forward secrecy is mandatory) and is negotiated separately via the supported_groups and key_share extensions. Authentication is negotiated via signature_algorithms. So the suite only needs to name the AEAD (Authenticated Encryption with Associated Data) cipher and the HKDF hash — the two things not covered by other extensions.
This is why the dangerous 1.2 suites are simply absent from 1.3: there is no RSA key transport (it lacks forward secrecy and enabled the Bleichenbacher/ROBOT attacks), no static DH, no CBC-mode ciphers (the source of Lucky13, BEAST, POODLE-class padding-oracle attacks), and no RC4. The negotiation surface that produced a decade of downgrade and oracle attacks was removed by design, not patched.
Evidence vs. speculation: RFC 8446 §1.2 explicitly enumerates the removed features. The reduction is the security argument — fewer negotiable parameters means fewer downgrade combinations.
Further reading: RFC 8446 §1.2, §B.4; RFC 8446 Appendix on removed features.
Bottom line: The short TLS 1.3 suite name reflects that the unsafe options were deleted, not merely deprecated — the suite encodes only the AEAD and hash because everything else is mandatory-secure and negotiated elsewhere.
Why isn't OCSP stapling enabled by default, given that everyone agrees it's better?
OCSP stapling (the certificate_status TLS extension, RFC 6066 §8) has the server fetch a CA-signed OCSP response and attach it to the handshake. It removes the client's privacy-leaking round trip to the responder and fixes much of OCSP's latency. So why is plain, non-stapled OCSP still common?
The answer is operational fragility in the fetch path. The server must periodically pull a fresh response from the CA's responder and cache it. Naive implementations — including older Apache and nginx configurations — fetched lazily, on the first client request after cache expiry. That request blocked while the server contacted the responder; if the responder was slow or down, the server either stalled the handshake or stapled nothing. A failed staple plus a Must-Staple certificate (RFC 7633) produces a hard-fail: the site goes dark.
This created a perverse incentive. Stapling done badly can be less reliable than no stapling, because it couples your uptime to the CA responder's uptime. Robust stapling requires a proactive, out-of-band refresh daemon (e.g. nginx's ssl_stapling with prefetch, or a sidecar that pre-fetches and validates before serving), decoupling the staple from the request path.
Evidence vs. speculation: the nginx "first request blocks" behavior was a documented, widely-reported pitfall; modern best practice is a separate prefetching process, not the web server's built-in lazy fetch.
Further reading: RFC 6066 §8; RFC 6961 (multi-staple); RFC 7633 (Must-Staple).
Bottom line: Stapling is strictly better only when the OCSP fetch is proactive and decoupled from client requests; done lazily it can tie your availability to the CA's responder, which is why cautious operators leave it off.
OCSP stapling (the certificate_status TLS extension, RFC 6066 §8) has the server fetch a CA-signed OCSP response and attach it to the handshake. It removes the client's privacy-leaking round trip to the responder and fixes much of OCSP's latency. So why is plain, non-stapled OCSP still common?
The answer is operational fragility in the fetch path. The server must periodically pull a fresh response from the CA's responder and cache it. Naive implementations — including older Apache and nginx configurations — fetched lazily, on the first client request after cache expiry. That request blocked while the server contacted the responder; if the responder was slow or down, the server either stalled the handshake or stapled nothing. A failed staple plus a Must-Staple certificate (RFC 7633) produces a hard-fail: the site goes dark.
This created a perverse incentive. Stapling done badly can be less reliable than no stapling, because it couples your uptime to the CA responder's uptime. Robust stapling requires a proactive, out-of-band refresh daemon (e.g. nginx's ssl_stapling with prefetch, or a sidecar that pre-fetches and validates before serving), decoupling the staple from the request path.
Evidence vs. speculation: the nginx "first request blocks" behavior was a documented, widely-reported pitfall; modern best practice is a separate prefetching process, not the web server's built-in lazy fetch.
Further reading: RFC 6066 §8; RFC 6961 (multi-staple); RFC 7633 (Must-Staple).
Bottom line: Stapling is strictly better only when the OCSP fetch is proactive and decoupled from client requests; done lazily it can tie your availability to the CA's responder, which is why cautious operators leave it off.
Why does the certificate chain your server sends differ from the chain the browser actually validates?
A common misconception is that a TLS server transmits "the" certificate chain and the client checks it as-is. In reality the server sends a Certificate message containing an ordered list of certificates (RFC 8446 §4.4.2), but the client builds its own trust path — and the two can diverge in security-relevant ways.
The server-sent chain is a hint. The client takes the leaf (end-entity) certificate and attempts path construction: it tries to build a chain from the leaf up to a certificate in its own trust store, using the server-supplied intermediates plus any it already caches or can fetch via the Authority Information Access (AIA) extension. The client's local roots are authoritative; the server's claimed root is ignored (and sending the root is wasted bytes).
This divergence is why a single certificate can validate via multiple paths. The canonical case: a cross-signed intermediate. When an older root nears expiry, a CA cross-signs its newer intermediate with both the old and new roots. Clients with the new root in their store validate one path; legacy clients chase the cross-sign to the old root. The Let's Encrypt 2021 expiry of the IdenTrust DST Root CA X3 cross-sign broke exactly the clients that could only reach the old path.
Evidence vs. speculation: path-building is well-specified (RFC 4158); the 2021 DST Root X3 incident is documented fact, not hypothetical.
Further reading: RFC 8446 §4.4.2; RFC 4158 (path building); RFC 5280 §6.
Bottom line: The server proposes a chain; the client disposes by building its own path to a locally-trusted root — serve intermediates generously, never the root, and test against trust stores you do not control, because cross-signs make "valid" client-dependent.
A common misconception is that a TLS server transmits "the" certificate chain and the client checks it as-is. In reality the server sends a Certificate message containing an ordered list of certificates (RFC 8446 §4.4.2), but the client builds its own trust path — and the two can diverge in security-relevant ways.
The server-sent chain is a hint. The client takes the leaf (end-entity) certificate and attempts path construction: it tries to build a chain from the leaf up to a certificate in its own trust store, using the server-supplied intermediates plus any it already caches or can fetch via the Authority Information Access (AIA) extension. The client's local roots are authoritative; the server's claimed root is ignored (and sending the root is wasted bytes).
This divergence is why a single certificate can validate via multiple paths. The canonical case: a cross-signed intermediate. When an older root nears expiry, a CA cross-signs its newer intermediate with both the old and new roots. Clients with the new root in their store validate one path; legacy clients chase the cross-sign to the old root. The Let's Encrypt 2021 expiry of the IdenTrust DST Root CA X3 cross-sign broke exactly the clients that could only reach the old path.
Evidence vs. speculation: path-building is well-specified (RFC 4158); the 2021 DST Root X3 incident is documented fact, not hypothetical.
Further reading: RFC 8446 §4.4.2; RFC 4158 (path building); RFC 5280 §6.
Bottom line: The server proposes a chain; the client disposes by building its own path to a locally-trusted root — serve intermediates generously, never the root, and test against trust stores you do not control, because cross-signs make "valid" client-dependent.
How does TLS 1.3 detect a downgrade attack using nothing but the server's random value?
Downgrade attacks force a connection to a weaker protocol the attacker can break — the lineage runs from FREAK to Logjam to POODLE. TLS 1.3 added a clever, low-cost defense that hides inside a field everyone overlooks: the ServerHello random.
The server's 32-byte random is supposed to be unpredictable. RFC 8446 §4.1.3 carves out the last 8 bytes as a sentinel. If a server that supports TLS 1.3 is negotiated down to TLS 1.2 (because an attacker tampered with the ClientHello to strip 1.3 support), the server sets those 8 bytes to a fixed value: the ASCII string "DOWNGRD\x01" for 1.2, or "DOWNGRD\x00" for 1.1 and below.
The trick is that the random is covered by the Finished MAC and, for 1.2, by the server's signature over the handshake transcript. A client that itself supports 1.3 but finds itself in a 1.2 handshake checks for the sentinel. If it sees "DOWNGRD", it knows a genuine 1.3-capable server is on the other end and the version was forced down by tampering — and it aborts. An attacker cannot forge the random without breaking the server's signature.
Evidence vs. speculation: this is a precise normative mechanism (RFC 8446 §4.1.3), not a heuristic. It only protects pairs where both endpoints support 1.3.
Further reading: RFC 8446 §4.1.3; Logjam paper (Adrian et al., 2015).
Bottom line: Eight reserved bytes of the server random act as a signed downgrade canary — a 1.3 client landing in a 1.2 handshake checks for "DOWNGRD" and aborts, turning a forced downgrade into a detectable, authenticated tamper.
Downgrade attacks force a connection to a weaker protocol the attacker can break — the lineage runs from FREAK to Logjam to POODLE. TLS 1.3 added a clever, low-cost defense that hides inside a field everyone overlooks: the ServerHello random.
The server's 32-byte random is supposed to be unpredictable. RFC 8446 §4.1.3 carves out the last 8 bytes as a sentinel. If a server that supports TLS 1.3 is negotiated down to TLS 1.2 (because an attacker tampered with the ClientHello to strip 1.3 support), the server sets those 8 bytes to a fixed value: the ASCII string "DOWNGRD\x01" for 1.2, or "DOWNGRD\x00" for 1.1 and below.
The trick is that the random is covered by the Finished MAC and, for 1.2, by the server's signature over the handshake transcript. A client that itself supports 1.3 but finds itself in a 1.2 handshake checks for the sentinel. If it sees "DOWNGRD", it knows a genuine 1.3-capable server is on the other end and the version was forced down by tampering — and it aborts. An attacker cannot forge the random without breaking the server's signature.
Evidence vs. speculation: this is a precise normative mechanism (RFC 8446 §4.1.3), not a heuristic. It only protects pairs where both endpoints support 1.3.
Further reading: RFC 8446 §4.1.3; Logjam paper (Adrian et al., 2015).
Bottom line: Eight reserved bytes of the server random act as a signed downgrade canary — a 1.3 client landing in a 1.2 handshake checks for "DOWNGRD" and aborts, turning a forced downgrade into a detectable, authenticated tamper.
Why did CRLs — the technology OCSP was meant to replace — quietly make a comeback?
The CRL (Certificate Revocation List, RFC 5280 §5) is the original revocation mechanism: a CA publishes a signed, downloadable list of revoked serial numbers. It was deemed obsolete because lists grew to megabytes and clients had to download the whole thing. OCSP promised a lightweight per-certificate query. Yet the modern browser revocation story is circling back to list-based designs.
The reason is that OCSP's per-query model failed on privacy and reliability (soft-fail, responder outages, and the responder learning every site you visit). Browsers responded by building proprietary, aggressively-compressed pushed lists: Chrome's CRLSet and Mozilla's CRLite. CRLite in particular is a research-grade comeback — it uses cascading Bloom filters to compress the entire WebPKI revocation state into a few hundred kilobytes, pushed to the browser, queryable offline, with zero per-handshake network traffic and zero information leak to the CA.
The structural insight: revocation is a set-membership problem, and a probabilistic filter that the client downloads periodically beats a real-time query that leaks data and can be blocked. CRLite tunes the filter so false positives (a valid certificate flagged revoked) are eliminated by design via the cascade, not merely made rare.
Evidence vs. speculation: CRLite is published research (Larisch et al., IEEE S&P 2017) shipping in Firefox; CRLSet behavior is documented by Chrome. The performance numbers are measured, not projected.
Further reading: Larisch et al., "CRLite" (2017); RFC 5280 §5; Mozilla CRLite blog.
Bottom line: Revocation came full circle — not to classic CRLs, but to compressed, pushed, offline-queryable filters that fix OCSP's privacy and availability failures while keeping the list model's freedom from per-handshake network dependence.
The CRL (Certificate Revocation List, RFC 5280 §5) is the original revocation mechanism: a CA publishes a signed, downloadable list of revoked serial numbers. It was deemed obsolete because lists grew to megabytes and clients had to download the whole thing. OCSP promised a lightweight per-certificate query. Yet the modern browser revocation story is circling back to list-based designs.
The reason is that OCSP's per-query model failed on privacy and reliability (soft-fail, responder outages, and the responder learning every site you visit). Browsers responded by building proprietary, aggressively-compressed pushed lists: Chrome's CRLSet and Mozilla's CRLite. CRLite in particular is a research-grade comeback — it uses cascading Bloom filters to compress the entire WebPKI revocation state into a few hundred kilobytes, pushed to the browser, queryable offline, with zero per-handshake network traffic and zero information leak to the CA.
The structural insight: revocation is a set-membership problem, and a probabilistic filter that the client downloads periodically beats a real-time query that leaks data and can be blocked. CRLite tunes the filter so false positives (a valid certificate flagged revoked) are eliminated by design via the cascade, not merely made rare.
Evidence vs. speculation: CRLite is published research (Larisch et al., IEEE S&P 2017) shipping in Firefox; CRLSet behavior is documented by Chrome. The performance numbers are measured, not projected.
Further reading: Larisch et al., "CRLite" (2017); RFC 5280 §5; Mozilla CRLite blog.
Bottom line: Revocation came full circle — not to classic CRLs, but to compressed, pushed, offline-queryable filters that fix OCSP's privacy and availability failures while keeping the list model's freedom from per-handshake network dependence.
If TLS encrypts everything, why can a network observer still see which website you visited?
TLS encrypts the application data, but the handshake leaks. The single largest plaintext leak is SNI (Server Name Indication, RFC 6066 §3): the client puts the target hostname, in cleartext, in the ClientHello so a server hosting many sites on one IP knows which certificate to present. A passive observer reads it directly.
This is the chicken-and-egg problem encrypted SNI was meant to solve, and why the first attempt (ESNI) failed. You cannot encrypt SNI under the server's certificate key, because you need SNI to know which certificate to use. ESNI patched the symptom; the maturated design, ECH (Encrypted Client Hello), patches the structure.
ECH splits the ClientHello into an "outer" handshake addressed to a shared, public client-facing server, and an "inner" ClientHello — containing the real SNI and other sensitive extensions — encrypted with an HPKE (Hybrid Public Key Encryption, RFC 9180) public key the client fetches in advance via a DNS HTTPS resource record. The observer sees only the outer name (e.g. a CDN's front), not the inner target.
The dependency is the catch: ECH's confidentiality leans on the client retrieving the ECH config from DNS, which is why ECH and encrypted DNS (DoH/DoT) are complementary — leaking the hostname via plaintext DNS would defeat encrypting it in TLS.
Evidence vs. speculation: ECH is an active IETF draft with shipping CDN and browser support; its anonymity-set guarantee depends on many domains sharing one client-facing server — a deployment property, not a protocol guarantee.
Further reading: draft-ietf-tls-esni (ECH); RFC 9180 (HPKE); RFC 6066 §3.
Bottom line: SNI is the handshake's main plaintext leak; ECH closes it by encrypting an inner ClientHello under a DNS-published key, but its privacy is only as strong as the size of the anonymity set behind the shared client-facing server.
TLS encrypts the application data, but the handshake leaks. The single largest plaintext leak is SNI (Server Name Indication, RFC 6066 §3): the client puts the target hostname, in cleartext, in the ClientHello so a server hosting many sites on one IP knows which certificate to present. A passive observer reads it directly.
This is the chicken-and-egg problem encrypted SNI was meant to solve, and why the first attempt (ESNI) failed. You cannot encrypt SNI under the server's certificate key, because you need SNI to know which certificate to use. ESNI patched the symptom; the maturated design, ECH (Encrypted Client Hello), patches the structure.
ECH splits the ClientHello into an "outer" handshake addressed to a shared, public client-facing server, and an "inner" ClientHello — containing the real SNI and other sensitive extensions — encrypted with an HPKE (Hybrid Public Key Encryption, RFC 9180) public key the client fetches in advance via a DNS HTTPS resource record. The observer sees only the outer name (e.g. a CDN's front), not the inner target.
The dependency is the catch: ECH's confidentiality leans on the client retrieving the ECH config from DNS, which is why ECH and encrypted DNS (DoH/DoT) are complementary — leaking the hostname via plaintext DNS would defeat encrypting it in TLS.
Evidence vs. speculation: ECH is an active IETF draft with shipping CDN and browser support; its anonymity-set guarantee depends on many domains sharing one client-facing server — a deployment property, not a protocol guarantee.
Further reading: draft-ietf-tls-esni (ECH); RFC 9180 (HPKE); RFC 6066 §3.
Bottom line: SNI is the handshake's main plaintext leak; ECH closes it by encrypting an inner ClientHello under a DNS-published key, but its privacy is only as strong as the size of the anonymity set behind the shared client-facing server.