Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions crates/clazel-x509/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# clazel-x509

X.509 certificate decoding, RFC 9525 name matching and the root certificate
table for the Clazel browser. Part of [Clazel](../../README.md), a web browser
whose parsers of untrusted input carry machine-checked proofs. The tier and
its status are in `Cargo.toml` and the
[status table](../../README.md#verification-status); this README covers only
the root table, which is plain data and not part of any proof.

## The root table (`roots`)

`roots::ROOTS` is Mozilla's set of trust anchors for TLS servers: one
`Root { label, der, sha256, server_distrust_after }` per root, in the order
of the source file. It is generated by `cargo xtask tables`
(`xtask/src/roots.rs`) into `src/roots/data.rs` from NSS's
`lib/ckfw/builtins/certdata.txt` (MPL-2.0), vendored byte for byte under
`data/nss-0a2b0c75/` (nss-dev/nss commit `0a2b0c75`, 20 October 2026) with its
`SOURCE.md` (URLs, commit, size, SHA-256) and licence. `cargo xtask check`
fails if the vendored file differs from its hash in `SOURCE.md`, if anything
else is in that directory, or if `src/roots/data.rs` differs from what the
generator produces. Nothing is downloaded at build or run time.

At that commit `certdata.txt` holds 169 certificates; the table has **118**.

### Modelling choices

- **Trust bit: server authentication only.** A certificate is in the table
exactly when its `CKO_NSS_TRUST` object (matched by `CKA_ISSUER` and
`CKA_SERIAL_NUMBER`) has `CKA_TRUST_SERVER_AUTH CK_TRUST
CKT_NSS_TRUSTED_DELEGATOR`. The other 51 are left out: 49 are trusted for
e-mail protection only, and 2 (Go Daddy Class 2 CA, Starfield Class 2 CA)
are trusted for nothing. No certificate in this file is code-signing-only or
`CKT_NSS_NOT_TRUSTED`, but the generator handles both (distrusted and
code-signing-only roots are excluded) and stops on any trust value it does
not know instead of guessing.
- **`CKA_NSS_SERVER_DISTRUST_AFTER` is carried, not applied.** `None` for
`CK_FALSE`, otherwise `Some("YYMMDDHHMMSSZ")`, NSS's own `UTCTime` text. At
this commit one root has a date: Izenpe.com, `260415235959Z`. Roots with a
date are kept because the date limits which leaf certificates they may
anchor, not whether the root is a root; deciding that needs the leaf's
`notBefore`, which is path validation's input, not the table's.
- **Not carried:** `CKA_NSS_EMAIL_DISTRUST_AFTER` (e-mail is out of scope),
`CKA_NSS_MOZILLA_CA_POLICY`, `CKA_TRUST_STEP_UP_APPROVED`, the e-mail and
code-signing trust bits, `CKA_SUBJECT`/`CKA_ISSUER`/`CKA_SERIAL_NUMBER`
(they are in the DER), and the legacy SHA-1 and MD5 hashes.
- **Fingerprint:** `sha256` is computed by the generator (a SHA-256 of its
own, with the FIPS 180-4 vectors as unit tests, so no dependency is added)
and must equal the `# Fingerprint (SHA-256)` comment NSS writes above both
of the certificate's objects, or generation stops.
- **Labels** are NSS's `CKA_LABEL`; they are names for people, not keys. Use
`sha256` or `der` to identify a root.
- Generation also stops if a certificate has no trust object (or the reverse),
if the two labels differ, if two certificates share an issuer and serial or
a DER encoding, or if a DER value is not one SEQUENCE covering its bytes.

### Evidence

`tests/trust_store.rs`: every root decodes with this crate's own decoders
(envelope, TBS, SubjectPublicKeyInfo, extensions, signature algorithms) and is
self-issued; the count, well-known labels and exclusions; no duplicate label,
DER or fingerprint; `ISRG Root X1`'s published fingerprint; `sha256` equals the
system `sha256sum`/`shasum` of `der`; and the table equals `certdata.txt` as
read by a second scanner in the test, which finds the roots through NSS's
fingerprint comments instead of the generator's issuer-and-serial join. The
conformance tier of Phase 3 item 3.5g (a real handshake against a chain to a
table root) is not done here.

### Updating

Follow "Updating" in `data/nss-0a2b0c75/SOURCE.md`: vendor the newer file in a
new `data/nss-<commit>/` directory, point `DATA_DIR` in `xtask/src/roots.rs`
and the `include_str!` and `ROOT_COUNT` in `tests/trust_store.rs` at it, run
`cargo xtask tables`, and commit the result. Review the diff of the table: a
root added to or removed from NSS's trust is a change to what the browser
trusts.
Loading
Loading