This describes how crates/psign-authenticode-trust composes crates for Linux/macOS-style Authenticode trust checks without CertGetCertificateChain / WinVerifyTrust.
| Layer | Crate | Role |
|---|---|---|
PKCS#7 shell, SignerInfo, authenticated attributes |
cms, der (via authenticode / picky) |
Parse SignedData, locate messageDigest, carry DER blobs. |
PE layout, indirect SpcIndirectData, image digest |
authenticode, psign-sip-digest |
Enumerate embedded PKCS#7 from the PE certificate table; recompute pe_authenticode_digest for the embedded hash algorithm. |
| CMS Authenticode rules + X.509 chain verification | picky (AuthenticodeSignature, authenticode_verifier, Cert::verifier) |
Validate messageDigest vs provided digest, signature over authenticated attributes, TBSCertificate signatures along issuer_chain, Basic Constraints / dates / EKU policy hooks. |
| Trust anchors | This crate (anchor, authroot_cache, authroot_cab, authroot_ctl) |
Phase A: load *.crt / *.cer / *.pem from --anchor-dir or repeatable --trusted-ca files. Phase B: automatically cache Microsoft authrootstl.cab at ~/.psign/authroot/ when no explicit anchors are supplied, then parse CAB *.stl → PKCS#7 SignedData eContent CTL SHA-1 subject identifiers plus PKCS#7-embedded certs. |
| Policy knobs | policy::AuthenticodeTrustPolicy |
Default strict code-signing EKU; CLI allow-loose-signing-cert, --prefer-timestamp-signing-time / --require-valid-timestamp (see Verification instant / timestamps), --as-of YYYY-MM-DD for exact_date. |
| Portable CLI | psign-tool portable |
trust-verify-pe, trust-verify-cab, trust-verify-catalog, trust-verify-detached share anchor, AuthRoot CAB/cache, AIA, OCSP, CRL revocation, timestamp-policy, and chain-diagnostic flags; detached uses pkcs7_wire::normalize_pkcs7_der_for_authenticode. inspect-authenticode emits JSON for PKCS#7 signers, timestamp-related OIDs, and nested signatures (1.3.6.1.4.1.311.2.4.1). Unified psign-tool --mode portable verify uses the portable trust commands by default for supported formats when automatic AuthRoot is enabled; PSIGN_NO_AUTO_TRUST=1 restores digest-only routing unless explicit trust inputs are present. |
| CMS inspection (no trust decision) | This crate inspect |
Uses cms SignedData + authenticode digest probe; complements picky trust_* paths. See psa-interoperability.md. |
- Parse PKCS#7 with
authenticode-rsto read the embeddedmessageDigestand inferPeAuthenticodeHashKind. - Recompute the PE Authenticode digest with
pe_authenticode_digest; fail fast if it does not match. - Parse the same DER with picky
AuthenticodeSignature::from_derand runauthenticode_verifier()withrequire_basic_authenticode_validation(pe_digest),ignore_chain_check()(chain is validated explicitly below), andexact_date(see Verification instant / timestamps).- CAB / non-PE
SpcIndirectData: when picky rejects the PKCS#7 shell, a CMS fallback validatesSpcIndirectData.messageDigestagainst the caller’s subject digest (not raw PKCS#9messageDigestsigned attributes, which can differ on CAB fixtures), verifies RSA PKCS#1 v1.5 / SHA-256 over authenticatedsignedAttrs, then builds the issuer chain using X.509NameDER equality so--anchor-dirCA certificates matchcms-parsed signers even when picky’sNameequality would not.--anchor-dirmust still contain the terminal self-signed root thumbprint (and any missing intermediates not present in the PKCS#7 bag).
- CAB / non-PE
- Merge picky-decoded embedded certs with anchor / CAB-extracted certs; resolve the signing cert; walk
issuer_chain_excluding_leafto the terminal root (or the CMS fallback equivalent above). - If
--online-aiais enabled and an issuer is missing, fetch HTTP AIAcaIssuerscertificates into memory only (or use--aia-url-overridefor deterministic local tests); no OS intermediate/root store is modified. - Require the terminal root’s SHA-1 thumbprint (full cert DER, Windows-style) to appear in the configured
AnchorStore. - If
--online-ocspor--ocsp-url-overrideis set with revocation enabled, POST a bounded OCSP request, require a successful BasicOCSPResponse, verify its RSA/SHA-256 signature with the issuing CA, match the requested serial, and apply good/revoked/unknown status. - If OCSP is not configured or does not return a definitive good status, fetch the CRL over bounded HTTP from
--crl-url-overrideor the first HTTP CRL Distribution Point URL, verify its RSA/SHA-256 signature with the issuing CA, and reject revoked leaf/intermediate serials. leaf.verifier().chain(...).exact_date(...).verify()to validate signatures along the path.
Normative background and CTL/bootstrap notes live in plan-linux-authenticode-trust-verify.md.
exact_date passed to picky controls not-before / not-after checks on the chain. Resolution order:
--as-of YYYY-MM-DD(CLI) /verification_instant_override— fixed UTC midnight for reproducible CI or expired-leaf fixtures (timestamp presence is not checked on this path).- Otherwise, if
prefer_timestamp_signing_timeis false (default): wall clockUtcDate::now(). - If
prefer_timestamp_signing_timeis true andrequire_valid_timestampis unset:rfc3161_extract::utc_date_from_authenticode_timestamp_tokenscans CMSSignedDataSignerInforows — first nested PKCS#7 withid-ct-TSTInfoencapsulated content and a parsableTSTInfo.genTimewins; if none, the first PKCS#9signing-timein signed attributes wins; if none, falls back to wall clock. - If
prefer_timestamp_signing_timeandrequire_valid_timestampare both set:trusted_utc_date_from_authenticode_timestamp_tokenrequires a nested RFC3161 token whoseMessageImprintmatches the primarySignerInfo.signaturedigest, whose timestamp CMSmessageDigestand RSA/SHA-256 signature verify, whose TSA signer hastimeStampingEKU, and whose TSA chain terminates in an explicit--trusted-ca/--anchor-dirtrust anchor. The TSA chain also goes through the configured revocation policy.
PKCS#9 signing-time remains a convenience for non-required timestamp instant selection. It does not satisfy --require-valid-timestamp.
- OS AuthRoot / Intermediate stores, PinRules, enterprise TrustedPublisher, or public-store policy. AIA and CRL retrieval are explicit and in-memory only.
- Indirect CRLs, delta CRLs, OCSP nonce policy, delegated OCSP responder authorization, and richer OCSP response variants are still future work; the implemented revocation path handles issuing-CA-signed OCSP and CRL responses over HTTP for
psign-servertests and rejects stalenextUpdatewindows. - RFC3161 support is intentionally narrow: RSA/SHA-256 timestamp CMS signatures, primary-signature
MessageImprint, explicit-anchor TSA chains, andtimeStampingEKU are covered; delegated responders, non-RSA/non-SHA-256 TSA signatures, richer timestamp policies, and timestamp token embedding during portable signing remain future work.