Fix process-name ownership and module lookup outputs, add explicit SPKI hashing and bounded chain access, and improve WDM integration. Deprecate superseded entry points with migration guidance and align branch code and tests with the library style. Add CI validation helpers with explicit signature selection and owned results Document runtime-confirmed CI signer selection and crypto reuse Expand CI compatibility matrix to twenty verified samples Extend CI export matrix with Windows 11 x64 and ARM64 samples Document CI API availability and historical mincrypt layouts Add explicit Authenticode workflows and correct CI helper contracts Document CI validation flag 0x20 and add kernel probe Harden CI digest parsing and failure cleanup
8.6 KiB
Authenticode digests and legacy verification
Prefer DomitoCalculatePortableExecutableDigestEx when computing a PE digest.
It takes an explicit SHA-1/256/384/512 algorithm, validates its supported PE layout,
and returns a digest independently of whether the file has an embedded signature.
This allows SHA-256 catalog lookup for a file without an embedded certificate.
Hash calculation is separate from signature verification and signer acceptance.
The older DomitoCalculatePortableExecutableDigest and
DomitoGetPortableExecutableDigestKind retain their compatibility behavior:
linear byte hashing and heuristic pattern discovery with a SHA-1 fallback. They
remain bounded, but should not be used to discover a general signature policy.
The new API is additive so existing callers do not silently acquire different
selection or rejection rules.
Supported PE layout
The explicit API validates DOS/NT/optional-header spans, PE32 and PE32+ magic,
declared data-directory count, the complete section table, SizeOfHeaders, every
nonempty section's raw interval, and the certificate table. It sorts section
descriptors by raw file offset before validating their sequence. At most 96
sections are accepted, keeping stack storage and sorting work bounded.
Nonempty sections must form a contiguous sequence starting at SizeOfHeaders.
Section-header order can differ from raw-file order. Zero-raw-size sections
contribute no bytes. An overlay between the raw sections and the certificate
table, or EOF for an unsigned file, is included. The checksum and physical
certificate-directory slot are excluded. A present certificate table must be
8-byte aligned and end at EOF; every entry must have a bounded length, version
0x200, type PKCS#7 SignedData, and complete 8-byte alignment storage.
For this subset, sorted section bytes coincide with linear file order, so the implementation can stream validated ranges directly to BCrypt without copying or allocating a whole-file scratch buffer. Digest allocation is the only pool allocation in the hashing path and is released on every failure.
Gaps, overlapping raw sections, certificates in the middle of a file, and absent
certificate-directory slots are unsupported. Some malformed inputs return a
format error; ambiguous or excluded layouts return STATUS_NOT_SUPPORTED.
The missing-slot boundary is deliberate: Windows SIP produced a different hash
than the old linear helper on a fixture with zero declared directories. Do not
infer Windows parity from the older helper's successful return on that input.
This is a validated subset, not a claim that every PE accepted by every Windows SIP is supported. Microsoft's PE format documentation describes section ordering and exclusions, but unusual overlay behavior requires measurements against the relevant Windows implementation. The local tests use the actual CryptSIPCreateIndirectData provider as a differential oracle, rather than treating a prose summary as the complete algorithm. SIP hash agreement does not establish CI trust-policy parity.
Discovering the first embedded content's digest algorithm
DomitoGetPortableExecutableDigestKindEx navigates a bounded DER subset:
PKCS#7 ContentInfo / SignedData / encapsulated SpcIndirectDataContent /
DigestInfo.AlgorithmIdentifier. It reads the algorithm associated with the
file digest, avoiding unrelated algorithm patterns in certificates, attributes,
timestamps, or signer information. SHA-1/256/384/512 are recognized. Algorithm
parameters may be absent or ASN.1 NULL; the digest OCTET STRING must have the
corresponding length. DER lengths must be bounded, definite, and minimally
encoded. Up to seven zero bytes of aligned padding after the outer DER are
accepted when included in WIN_CERTIFICATE.dwLength, as observed on Microsoft
system binaries. Other trailing bytes are rejected.
An absent certificate table returns STATUS_NOT_FOUND, an unsupported algorithm
or certificate type returns STATUS_NOT_SUPPORTED, and malformed supported
structure returns a format error. The output algorithm is zero on failure; no
default algorithm is silently manufactured.
The caller supplies an array containing the security-directory entry and a stable input buffer. The helper inspects the first table entry. It does not enumerate nested/multiple signatures, validate the entire ASN.1 document, validate signerInfos, verify cryptographic signatures, or establish trust. Indefinite-length BER is outside this supported DER subset. Choose explicit algorithms when handling catalog-only files or application-defined lookup order.
Explicit legacy catalog policy
DomitoValidateFileLegacyModeEx takes a caller-selected
AcceptedCatalogPolicyBits mask, a RequireTrustedCatalog marker gate, and a
ValidationSource output. Source is DOMITO_CI_SOURCE_EMBEDDED or
DOMITO_CI_SOURCE_CATALOG on success and zero on failure.
This helper accepts SHA-1 with exactly 20 bytes or SHA-256 with exactly 32 bytes.
Unsupported algorithms return STATUS_NOT_SUPPORTED; mismatched lengths return
STATUS_INVALID_PARAMETER. The underlying observed embedded API supports more
algorithms than this helper's catalog workflow, as documented in
the mincrypt contracts.
Both policy objects must be zero-initialized before first use, or own valid CI
results. The helper frees previous contents on entry and before each retry and
clears signing time between attempts. The caller owns both final policy results,
including any returned on failure, and frees them with CiFreePolicyInfo.
Embedded-to-catalog fallback and catalog reload occur only for
STATUS_INVALID_IMAGE_HASH; resource, I/O, and other policy errors propagate.
Before certificate allocation, the helper references the file object and checks
the supplied table interval against the current file size. It then uses the
exact-read DomitoReadFileAt, which waits on a private completion event. An EOF
short read fails before CI sees any uninitialized bytes. The caller must keep
file identity/bytes stable between hashing and consumption; a size check cannot
prevent concurrent mutation. Handles must be valid in the current process
context and satisfy the documented kernel I/O/APC requirements.
The older DomitoValidateFileLegacyMode delegates with the existing
DOMITO_CI_LEGACY_CATALOG_POLICY_BITS (0x2007F) and a false marker gate. That
value is a compatibility default with broad categories, not an application trust
recommendation. The explicit mask uses any-overlap catalog filtering.
For a catalog-only file, choose an allowed algorithm sequence as application
policy (for example SHA-256 followed by SHA-1 when legacy acceptance is intended).
For each algorithm, call DomitoCalculatePortableExecutableDigestEx, then
DomitoValidateFileLegacyModeEx with a zero security directory. Free the digest
and both policy objects before retrying. Continue to another algorithm only on
the specifically intended lookup/signature-mismatch result, not on all failures.
Preserve the actual algorithm and validation source in the application's result.
This supports an explicit search strategy; it does not reproduce every native
CI scenario-selection rule or WinVerifyTrust policy.
Validation performed
On the local Windows 26100 system, host tests compare all four digest algorithms
against Windows SIP for PE32/PE32+, unsigned/signed fixtures, overlays, reverse
section-header order, multiple certificate entries, and certificate alignment.
The installed ci.dll, ntdll.dll, kernel32.dll, and notepad.exe form a
real-file corpus. Embedded digest algorithms are independently extracted with
Crypt32, and computed file digests are compared with the signed
SpcIndirectDataContent values where an embedded signature exists. This reads
files and hashes bytes; it does not load or execute them as code.
Guard-page truncations, malformed offsets/lengths, unsupported layouts, algorithm selection, injected CNG/allocation failures, retry ownership, exact read failures, and explicit catalog controls are also covered. Actual CI calls are mocked in those host tests. The kernel translation units and layout assertions compile for x64/ARM64 with warnings treated as errors; the opt-in 26100 runtime-layout observations remain x64-specific.
Still pending are historical/ARM64 CI runtime compatibility, Driver Verifier, real catalog-only acceptance across algorithms, nested/multiple-signature selection, weak-crypto/revocation/timestamp policy, and extension of supported PE layouts. Use the remaining-work ledger and the flag probe to plan the VM run.