Skip to content

Commit 08cc890

Browse files
beurdoucheclaude
andcommitted
Add Signature Properties manual-test PDF corpus generator
Adds a Python generator that builds a small corpus of digitally signed PDFs covering every visible UI state of the Signature Properties doorhanger (verified, untrusted, expired, invalid, unknown, plus three multi-signature variants — both verified, outer-verified+inner-untrusted, outer-verified+inner-expired). Each PDF embeds a PKCS#7 detached signature whose messageDigest matches the file's actual /ByteRange bytes, produced by shelling out to mozilla-central's security/manager/tools/pycms.py. The trusted leaves are issued by the test trust anchors that Firefox already bundles (pdf-sign-ca, pdf-sign-ca-expired) — gated behind the security.pdf_signature_verification.enable_test_trust_anchors pref, default false. The visible page content of every generated PDF is the description of the expected UI state for that case, so the user can read the spec and compare it against the rendered doorhanger side by side. The signed_multi_outer_verified_inner_expired.pdf case directly exercises the worst-status-wins banner aggregation: the outer signature is fully valid but the inner signature's cert is expired, so the banner must show the orange "...with an expired certificate" message even though the top-level signature is fine. Generated PDFs are .gitignored; only the script, README, and a user.js.example pref snippet are tracked. Revoked is intentionally out of scope (needs OCSP/CRL/OneCRL infra). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent cb6df4a commit 08cc890

4 files changed

Lines changed: 859 additions & 0 deletions

File tree

test/pdfs/sig_corpus/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.pdf
2+
*.p7s
3+
*.pkcs7spec

test/pdfs/sig_corpus/README.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Signature Properties — manual-test PDF corpus
2+
3+
This directory ships a Python generator that produces a small corpus
4+
of digitally signed PDFs covering every visible state of the
5+
**Signature Properties** doorhanger. The intent is manual visual
6+
testing: open each PDF in a Firefox build that has the new signature
7+
verification UI, and compare what the toolbar / banner / cards
8+
render against what the PDF's own page content says they should
9+
render.
10+
11+
The PDFs themselves are **not committed** (`*.pdf` is ignored). Only
12+
`generate.py` and this README are tracked, so you regenerate the
13+
corpus when you need it.
14+
15+
## Prerequisites
16+
17+
1. A built mozilla-central checkout at `/opt/mozilla/firefox` — the
18+
generator shells out to that tree's
19+
`security/manager/tools/pycms.py` and reuses its vendored Python
20+
modules under `third_party/python/{ecdsa,rsa,pyasn1,pyasn1_modules,six}`.
21+
2. The Firefox build at
22+
`/opt/mozilla/firefox/obj-aarch64-apple-darwin25.4.0/dist/Nightly.app`
23+
already includes the pdf.js viewer + chrome bridge that powers
24+
the Signature Properties UI (commit `9a8ea32008be` in
25+
mozilla-central, `9149247c0` in pdf.js).
26+
27+
## Generate
28+
29+
From the pdf.js root:
30+
31+
```sh
32+
python3 test/pdfs/sig_corpus/generate.py
33+
```
34+
35+
You should see eight `.pdf` files appear in this directory.
36+
37+
## Enable the test trust anchors pref
38+
39+
Three of the cases (`signed_verified`, both verified multi-sig PDFs,
40+
and the outer-half of `signed_multi_outer_verified_inner_expired`)
41+
need Firefox to trust the bundled `pdf-sign-ca` test root. That root
42+
is gated behind one pref:
43+
44+
```
45+
security.pdf_signature_verification.enable_test_trust_anchors = true
46+
```
47+
48+
The pref defaults to `false` in every Firefox build (Release, Beta,
49+
Nightly, local), so by default a release Firefox cannot validate
50+
PDFs signed with these test certs. To enable it for testing:
51+
52+
- Easiest: append the contents of `user.js.example` (next to this
53+
README) to your dev profile's `user.js` and (re)launch Firefox.
54+
- Or via `about:config` → search for the pref name → toggle to
55+
`true`.
56+
57+
⚠️ **Do not enable this in your normal browsing profile.** With the
58+
pref on, any PDF signed with the publicly known mozilla-central test
59+
private key validates as "trusted" until those certs expire
60+
(`pdf-sign-ca` notAfter = 2027-01-01).
61+
62+
## Open the PDFs
63+
64+
Launch the dev Firefox:
65+
66+
```sh
67+
/opt/mozilla/firefox/obj-aarch64-apple-darwin25.4.0/dist/Nightly.app/Contents/MacOS/firefox \
68+
file:///$(pwd)/test/pdfs/sig_corpus/signed_verified.pdf
69+
```
70+
71+
Or `./mach run -- file:///…/signed_verified.pdf` from the firefox
72+
checkout.
73+
74+
The page content of every PDF describes the expected toolbar icon,
75+
banner, status row, and certificate row. Compare it against the
76+
doorhanger.
77+
78+
## Cases
79+
80+
| File | Toolbar icon | Banner | Notes |
81+
|---|---|---|---|
82+
| `signed_verified.pdf` | green ✓ | green | leaf ← `pdf-sign-ca` |
83+
| `signed_untrusted.pdf` | orange ! | orange | self-signed root |
84+
| `signed_expired.pdf` | orange ! | orange | leaf ← `pdf-sign-ca-expired` |
85+
| `signed_invalid.pdf` | red × | red | one byte tampered post-sign |
86+
| `signed_unknown.pdf` | red × | red | `/SubFilter /ETSI.CAdES.detached` (unsupported by pdf.js) |
87+
| `signed_multi_verified.pdf` | green ✓ | green | both sigs valid, "Sub-signatures (1)" |
88+
| `signed_multi_mixed.pdf` | orange ! | orange | outer verified, inner self-signed/untrusted |
89+
| `signed_multi_outer_verified_inner_expired.pdf` | orange ! | orange | outer verified, inner expired — exercises worst-status-wins logic |
90+
91+
The last entry is the most informative for verifying that the
92+
banner aggregation isn't accidentally clamped to the outermost
93+
signature.
94+
95+
## Out of scope
96+
97+
- **`revoked` status.** Producing a revoked-certificate state
98+
end-to-end against NSS requires either an OCSP responder, a CRL
99+
file in the right path, or a OneCRL fixture — none of which are
100+
feasible to ship as a static PDF corpus. The UI path for
101+
`revoked` (red banner / red cert row / red toolbar icon) is
102+
exercised only via the existing xpcshell tests.
103+
- **CAdES validation.** `signed_unknown.pdf` only proves that pdf.js
104+
short-circuits to `unknown` for `ETSI.CAdES.detached`; real CAdES
105+
signature validation is follow-up Firefox work.
106+
107+
## Sanity check the safeguard
108+
109+
Open `signed_verified.pdf` with the pref **off** (default). Every
110+
single PDF should now report `untrusted (unknown issuer)`. That's
111+
the expected behavior in shipping Firefox and confirms the pref
112+
guard is doing its job.

0 commit comments

Comments
 (0)