Repository navigation
Rust TLS: block the compromised eMudhra intermediates by SPKI hash in our reqwest/rustls verifier #1301
Copy link
Copy link
Open
Labels
SDKready-for-agentFully specified and ready for an AFK agentFully specified and ready for an AFK agent
Description
Background
On 2026-10-17 Mozilla received a report that the private keys of eight eMudhra intermediate CAs had been compromised (dev-security-policy announcement, disclosure site, affected-certificates.json). Each intermediate has a Sectigo cross-sign as well as its emSign original, so dropping the emSign roots doesn't stop a chain from validating. The intermediates themselves have to be blocked. Node is doing exactly this with a compiled-in SPKI-SHA256 blocklist (nodejs/node#66871), and Go did it in crypto/x509 (1.27.3 / 1.26.10).
Why we are exposed
Our Rust HTTP clients use reqwest 0.13 with rustls-platform-verifier (root Cargo.toml, packages/eql/Cargo.lock, languages/typescript/packages/protect-ffi/Cargo.lock):
- macOS / Windows: the OS verifier is used, so Apple's and Microsoft's blocks cover us.
- Linux (most production deployments of protect-ffi, stack-auth and stack-kms): the verifier reads the OS bundle via
rustls-native-certsand doesn't check revocation. The Sectigo cross-signs chain to a Sectigo root that stays in distro bundles, so these intermediates are still trusted. Anyone holding the keys could MITM ZeroKMS and auth traffic. - wasm32: reqwest goes through the runtime's
fetch, so the runtime's TLS applies and this issue doesn't cover it.
Task
- Find every place in this tree that builds a reqwest client or rustls
ClientConfig(start withpackages/stack-auth/src/transport.rsandpackages/stack-kms/src/connection/http.rs). Also check protect-ffi, which may get its client from the externalcipherstash-clientcrate. If a client is built outside this repo, say so in the PR and list it as a follow-up rather than forking the dependency. - Wrap
rustls_platform_verifier::Verifierin aServerCertVerifierthat calls the inner verifier and then rejects the connection when any certificate in the presented chain has a SubjectPublicKeyInfo SHA-256 hash on a compiled-in blocklist. Report it as a revoked-certificate error. Checking only the presented intermediates is acceptable, since Node does the same. Delegate signature checks to the inner verifier. - Seed the blocklist with the SPKI hashes of all 16 certificates (8 originals + 8 Sectigo cross-signs) from
affected-certificates.json. Note that the file's fingerprints are whole-certificate SHA-256 hashes, not SPKI hashes. Use the SPKI hash field if the file has one; otherwise derive and document how you derived it. Record the source URL and date next to the list. - Put the verifier in one shared place that the crates above can depend on, without adding a dependency cycle or a new published crate unless that's clearly required.
- Tests: a blocked SPKI in the chain is rejected, an unrelated chain is accepted, and the list has exactly the expected entries.
- Add changesets/version bumps as the repo's rules require (
@cipherstash/authchangeset ifstack-authchanges; follow AGENTS.md "Working on the Rust crates"). Keepcargo test --locked, clippy and fmt green.
Out of scope
The Go toolchain pin, which has its own issue.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
SDKready-for-agentFully specified and ready for an AFK agentFully specified and ready for an AFK agent
Activity
tobyhede commentedon Oct 20, 2026
Tracking the remaining gap (
@cipherstash/stackvia protect-ffi /cipherstash-client) in #1305. This issue stays open until that ships.Generated by Claude Code