We're writing a browser from scratch in Rust. It's called Mars: own HTML parser and layout engine, own JS engine, own HTTP framing on top of rustls, native macOS shell. When you own the network stack you also own the question Apple is getting shouted at about this week: which certificate authorities does the thing trust, and who updates that list?
How Mars gets its roots
Our network crate, Relay, builds a rustls RootCertStore from webpki_roots::TLS_SERVER_ROOTS once at startup and keeps it in a OnceLock. That's it. No OS keychain, no /etc/ssl/cert.pem, no runtime download. The trust anchors are whatever the webpki-roots crate contained the day the lockfile was written. That's a normal choice for rustls users, and it has one property worth saying out loud: the trust store ships inside the binary, so it only changes when you rebuild.
What I found today
The eMudhra / emSign compromise is around ten days old. Mozilla, Google, Microsoft and most Linux distros dropped the roots within days. Apple blocked the certificates in Safari and Mail but left the macOS command line tools reading a cert.pem that still trusts them, which is why Hacker News is on fire.
In that thread someone asked whether there's a Rust crate that compiles root certs into binaries. There is, and we use it. So I checked. Both crates that do TLS in Mars pinned webpki-roots = "=1.0.9", released July 18. Grepping src/lib.rs in each release:
- 1.0.9 (Jul 18): emSign Root CA - G1, emSign Root CA - C1, emSign ECC Root CA - G3, emSign ECC Root CA - C3
- 1.0.10 (Oct 19): removed emSign ECC Root CA - G3
- 1.0.11 (Oct 23): removed emSign Root CA - C1 and emSign ECC Root CA - C3, tracking the CCADB removals
So Mars, as of this morning, had the same hole as /usr/bin/curl on a Mac. Nothing at runtime would have told us. rustls does no revocation checking unless you hand it CRLs, and we don't. There is no blocklist. The bundle is the whole story.
The fix and the lesson
The fix took four minutes: bump both pins to =1.0.11, cargo update -p webpki-roots, cargo check. It compiles and it's in the tree.
The lesson is the uncomfortable one. Mars pins dependencies to exact versions, and an exact pin on a root bundle is a decision to stop receiving CA removals. It means someone has to watch that crate's releases the way an OS vendor watches the CCADB. For a browser that isn't optional, so it goes on the release checklist. I'd like to know how other rustls users handle it: Dependabot on that one crate, a CI job that diffs root names between versions, or just reading the release notes.
Repo: https://github.com/OyadotAI/oya-browser, folder mars/. Source-available under a Sustainable Use License, SDK and CLI MIT.
Top comments (0)