Signatures: RFC 3161 timestamps, document timestamps, DSS/VRI and revocation verification (non-network half) (#69)

* Signatures: RFC 3161 timestamp tokens (PAdES B-T) behind a transport-free TSA interface

* Signatures: document timestamps, DSS/VRI evidence embedding, trusted verification time

* Signatures: revocation evidence verification (CRL and OCSP) wired into validation

* Signatures: real-world certificate compatibility (CRLDP, tolerant extensions) and XFA-aware DocMDP classification

* Signatures: RFC 6960 encodings, delegated-responder verification, TSA trust anchoring, try_oid overflow

* Signatures: harden PR #69 validation (XFA, metadata, revocation, TSA trust, token digest)

- Remove the XFA "form fill" reclassification: it read the new revision, so
  an update could add /XFA + /NeedsRendering and replace the page tree while
  approval and P=2/3 certification signatures stayed Valid. Classification
  (including catalog /Extensions) is back to main's.
- A changed stream tagged /Type /Metadata counts as metadata only when it is
  the signed catalog's /Metadata stream or was already metadata when signed;
  a relabelled page Form XObject is "other changes".
- A verified revocation stays Invalid when the certificate was also outside
  its validity at signing time (was softened to Unknown).
- An embedded timestamp whose TSA does not chain to the trust store is
  reported as an unverified timestamp and no longer sets the validity or
  revocation time; the signer's claimed time is used, as on main.
- parse_token checks the TSTInfo messageDigest with the SignerInfo digest
  algorithm, not the imprint's.

Each fix has a regression test in crates/sign/tests/pdf.rs that fails on
the PR head.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Justin John
2026-10-07 23:02:40 -04:00
committed by GitHub
co-authored by Claude Opus 5.5 Brandon Thomas
parent 355de9038e
commit 4d0078aeff
15 changed files with 1877 additions and 67 deletions
+18 -18
View File
@@ -5999,11 +5999,11 @@ title = "Add a document timestamp (RFC 3161)"
area = "H"
tier = "P1"
milestone = "M9"
status = "planned"
status = "partial"
commands = []
tools = []
evidence = []
notes = ""
evidence = ["crates/sign/tests/pdf.rs::a_document_timestamp_covers_the_file_and_validates"]
notes = "timestamp_document appends a standalone /ETSI.RFC3161 signature dictionary over the whole file; validation discovers and verifies these (imprint, token signature, TSA cert validity) and reports the trusted time. Missing: automation tool and timestamp-server configuration (transport is caller-injected)."
[[feature]]
id = "sign.timestamp-servers"
@@ -6023,11 +6023,11 @@ title = "PAdES B-T (signature timestamp)"
area = "H"
tier = "P1"
milestone = "M9"
status = "planned"
status = "partial"
commands = []
tools = []
evidence = []
notes = ""
evidence = ["crates/sign/tests/pdf.rs::signing_with_a_timestamp_embeds_a_verified_rfc3161_token"]
notes = "Sign with an embedded RFC 3161 token (sign_with_timestamp): imprint and TSA signature verified at signing and validation time, trusted time reported. Missing: timestamp-server configuration and a fetcher (transport is caller-injected), the standalone document timestamp, automation tool."
[[feature]]
id = "sign.ltv"
@@ -6035,11 +6035,11 @@ title = "Long-term validation (DSS/VRI)"
area = "H"
tier = "P1"
milestone = "M9"
status = "planned"
status = "partial"
commands = []
tools = []
evidence = []
notes = ""
evidence = ["crates/sign/tests/pdf.rs::embedding_ltv_evidence_adds_a_dss_and_keeps_signatures_valid", "crates/sign/tests/pdf.rs::an_embedded_verified_revocation_invalidates_the_signature"]
notes = "dss::embed merges caller-supplied evidence into the catalog /DSS with /VRI entries per signature, deduplicating blobs, as a permitted incremental change; revocation.rs verifies the embedded CRLs and OCSP responses (signature, responder identity, CertID, window) and a verified revocation invalidates the signature. Missing: fetching evidence, automation tool."
[[feature]]
id = "sign.pades-blta"
@@ -6047,11 +6047,11 @@ title = "PAdES B-LT and B-LTA"
area = "H"
tier = "P1"
milestone = "M9"
status = "planned"
status = "partial"
commands = []
tools = []
evidence = []
notes = ""
evidence = ["crates/sign/tests/pdf.rs::sign_then_ltv_then_timestamp_makes_a_b_lta_file"]
notes = "The B-LT/B-LTA chain works with caller-supplied evidence: sign, embed DSS (B-LT), then append a document timestamp over the result (B-LTA); earlier signatures stay valid with the store classified as a permitted change. Missing: OCSP/CRL verification of the evidence, re-timestamping automation."
[[feature]]
id = "sign.ocsp-crl"
@@ -6059,11 +6059,11 @@ title = "Revocation checking (OCSP and CRL)"
area = "H"
tier = "P1"
milestone = "M9"
status = "planned"
status = "partial"
commands = []
tools = []
evidence = []
notes = ""
evidence = ["crates/sign/tests/crypto.rs::crls_verify_and_report_revocation", "crates/sign/tests/crypto.rs::ocsp_responses_verify_and_match_the_certificate", "crates/sign/tests/pdf.rs::an_embedded_verified_revocation_invalidates_the_signature"]
notes = "RFC 5280 CRLs and RFC 6960 OCSP responses are parsed and verified (issuer/responder signature, delegated responder's OCSP-signing EKU, CertID hash match, validity window) and checked against the DSS during validation. Missing: network fetching of fresh evidence and the OS trust store."
[[feature]]
id = "sign.validate-all"
@@ -6191,11 +6191,11 @@ title = "Verification time (signing time, timestamp, now)"
area = "H"
tier = "P1"
milestone = "M9"
status = "planned"
status = "partial"
commands = []
tools = []
evidence = []
notes = ""
evidence = ["crates/sign/tests/pdf.rs::signing_with_a_timestamp_embeds_a_verified_rfc3161_token", "crates/sign/tests/pdf.rs::an_untrusted_timestamp_does_not_set_the_validation_time"]
notes = "Validation prefers the verified RFC 3161 timestamp time over /M when checking certificate validity and revocation, but only when the TSA chains to the trust store; an untrusted token is reported as an unverified timestamp and its time is not used. Missing: an explicit verification-time option (verify at a chosen date / now) in the validation API."
[[feature]]
id = "sign.changes-after-signing"