Skip to content

clazel-x509: Mozilla root trust store generated from NSS certdata.txt - #15

Merged
atiernan merged 4 commits into
phase3/x509from
phase3/roots
Oct 27, 2026
Merged

atiernan merged 4 commits into
phase3/x509from
phase3/roots

Conversation

@atiernan

Copy link
Copy Markdown
Member

Stacked on #14. This is the trust-store half of Phase 3 item 3.5g, following the design in phase-3.md §3.5b: NSS's certdata.txt, vendored at a pinned commit, is converted by cargo xtask tables into a Rust table of DER roots, the same way the Public Suffix List is.

What's in it

  • Vendored source: crates/clazel-x509/data/nss-0a2b0c75/ holds certdata.txt at nss-dev/nss 0a2b0c75 (2026-10-20, 1,356,175 bytes) and NSS's COPYING (MPL-2.0), with a SOURCE.md giving URLs, sizes, SHA-256 and the update procedure.
  • Generator: xtask/src/roots.rs, wired into cargo xtask tables, and into cargo xtask check as a staleness check like the PSL one. It joins each trust object to its certificate by issuer and serial. It stops on an unknown trust value, an unlinked object, a label mismatch, a duplicate, malformed DER, or a SHA-256 that disagrees with NSS's fingerprint comment. It has its own SHA-256, tested against FIPS vectors, so it adds no new dependency.
  • Table: crates/clazel-x509/src/roots/ is plain data outside verus!. Each entry holds the label, the DER, the SHA-256, and server_distrust_after.

Modelling choices (also in the crate README)

  • Included: only roots whose server-auth trust is CKT_NSS_TRUSTED_DELEGATOR. That is 118 of 169.
  • Excluded: 49 email-only roots (server auth MUST_VERIFY) and 2 roots trusted for nothing (Go Daddy Class 2, Starfield Class 2). None are distrusted or code-signing-only in this file, but the generator handles both.
  • CKA_NSS_SERVER_DISTRUST_AFTER is carried, not applied. Path validation (3.5b) must enforce it. Only Izenpe.com sets it among the included roots (260415235959Z).

Tests (tests/trust_store.rs, 8 tests)

  • All 118 roots decode with our own decoders and are self-issued; the list of roots our decoders reject is empty.
  • The count, well-known labels and exclusions, and the absence of duplicates are checked, along with ISRG Root X1's published fingerprint and the distrust-after value.
  • A second, independent scan of certdata.txt agrees with the table.
  • Each SHA-256 is checked against the system sha256sum/shasum. That test, and the independent-scan test, are ignored under Miri.

Local results

I re-ran these after restacking from phase3/trust-store onto this base:

  • cargo xtask check reported STATIC CHECKS PASSED, including the new table check.
  • cargo fmt --all --check and strict clippy (clazel-x509, xtask) are clean.
  • cargo test -p clazel-x509 gives 63 passed, 0 failed.
  • Verus accepts the crate with the table present: module exec gives 14 verified, 0 errors.

No full verify has run, and the crate stays at tier 0. Not done: handshake conformance against a table root (3.5g).

🤖 Generated with Claude Code

@atiernan
atiernan added this pull request to stack #16 October 26, 2026 16:31
atiernan added a commit that referenced this pull request Oct 26, 2026
`the_decode_check_can_fail` leaked a Vec to build a `&'static` Root, which
Miri reports as a memory leak (#15, Verify (base, macOS)). decode_failure
now takes the DER slice, so the damaged copy stays an owned Vec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@atiernan
atiernan marked this pull request as ready for review October 27, 2026 11:04
atiernan and others added 4 commits October 27, 2026 11:06
Byte for byte, with SOURCE.md (URLs, commit, size, SHA-256, update
procedure) and the MPL-2.0 licence text.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
cargo xtask tables converts the vendored NSS file into clazel_x509::roots
(118 TLS server roots, with label, DER, SHA-256 and the server
distrust-after date). cargo xtask check fails if the table is stale or the
vendored file's hash differs from SOURCE.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Document the table, its modelling choices and the update procedure.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
`the_decode_check_can_fail` leaked a Vec to build a `&'static` Root, which
Miri reports as a memory leak (#15, Verify (base, macOS)). decode_failure
now takes the DER slice, so the damaged copy stays an owned Vec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@atiernan
atiernan merged commit ed07d28 into main Oct 27, 2026
7 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant