Add reusable certificate and file validation helpers

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
This commit is contained in:
nefarius committed 2026-10-27 00:17:25 +01:00
1 parent 7985b23be5
commit 3fbfe31d15
38 files changed
+9201 -751

No files matched your search

+142
View File
@@ -0,0 +1,142 @@
# 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](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format)
describes section ordering and exclusions, but unusual overlay behavior requires
measurements against the relevant Windows implementation. The local tests use
the actual [CryptSIPCreateIndirectData](https://learn.microsoft.com/en-us/windows/win32/api/mssip/nf-mssip-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](mincrypt-contracts.md).
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](implementation-status.md) and the
[flag probe](ci-validate-file-object.md) to plan the VM run.
+651
View File
@@ -0,0 +1,651 @@
{
"schema_version": 2,
"scope": "Observed named PE exports in exact architecture-specific ci.dll samples; not runtime or ABI certification",
"source_hash_encoding": "Canonical JSON: UTF-8, sorted keys, comma/colon separators, ensure_ascii=false",
"generated_from": {
"corpus-index.json": "d2c6507794314ca38a2015c74f3b66e81a4bd82d982be0ed1911dcff1d79475a",
"iso-corpus-index.json": "ba526a8548f3be100e8d13019aed57de9703a142615c509870720572bc636217",
"manifest.json": "bd215ebd3deb480a39b5d71a6ed709dad20368cbe90879a52070b56b023284d4",
"ci-26100.8328-evidence.json": "ea0f939df9d8b7abde40e3402c01b2ac398253728f329e8c2b7134de8df6305f"
},
"apis": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetCertPublisherName",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"samples": [
{
"label": "Windows 10 1507",
"ci_file_version": "10.0.10240.16463",
"architecture": "x64",
"sha256": "e83d900f4675c6e6ffc3fb7dcd3074610876a1398e495796769988df810fd3bc",
"source": "corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetPEInformation",
"CiInitialize",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": false,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": false,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 1511",
"ci_file_version": "10.0.10586.0",
"architecture": "x64",
"sha256": "f949bfa614addea6174b28c3818c56b327c9290fd41bd91dfc545414b3df6783",
"source": "corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetPEInformation",
"CiInitialize",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": false,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": false,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 1607",
"ci_file_version": "10.0.14393.2189",
"architecture": "x64",
"sha256": "ef0c02ecbd0818e84be9f61421f919825f96a3c59199460cab08548eee2881df",
"source": "corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetPEInformation",
"CiInitialize",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": false,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": false,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 1703",
"ci_file_version": "10.0.15063.0",
"architecture": "x64",
"sha256": "3705aaf408f05326e028621380aa5c96a1f3583a2de8a139b188da4b82577863",
"source": "corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": false,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 1709",
"ci_file_version": "10.0.16299.125",
"architecture": "x64",
"sha256": "1db7ae5a08bd2361fc7fcdd373fb980e8d680035e67b02e5967095db0443effd",
"source": "corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": false,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 1803",
"ci_file_version": "10.0.17134.1130",
"architecture": "x64",
"sha256": "8ce3b8fe38c23b699f30b045383640019a429d3a9d513285c655bffe03a796d9",
"source": "corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": false,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 1809 initial x64 ISO",
"ci_file_version": "10.0.17763.1",
"architecture": "x64",
"sha256": "eb177481f2aea3cae0c2f97f7058e7447c0695e4489428406598f168d4dcc5e8",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": false,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 1809 October v2 x64 ISO",
"ci_file_version": "10.0.17763.348",
"architecture": "x64",
"sha256": "da8282173cbce7ea38f8fca64db0972c3d9614ddbca98f6b96d11a4cadde92ad",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": false,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 1903 v1 x64 ISO",
"ci_file_version": "10.0.18362.1",
"architecture": "x64",
"sha256": "5d01bb84fa516e23c25def8ea03fc6b696082ccc67a61575fd00d1fe7c273d72",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": false,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 1903 v2 x64 ISO",
"ci_file_version": "10.0.18362.329",
"architecture": "x64",
"sha256": "d12131f14f781f8c314a795384e02afc3c2902bf67da9c2e75d8163c891bdd89",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": false,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 1909 x64 ISO",
"ci_file_version": "10.0.18362.418",
"architecture": "x64",
"sha256": "c3c5d32da42fa69b0795cd0f8c57252670d673fb036685db5c7d6392ffee0293",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": false,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 2004 ISO",
"ci_file_version": "10.0.19041.1",
"architecture": "x64",
"sha256": "2955710d34db26e352e62b20861ba338f0216cc36b378d128057be955e184282",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": false,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 22H2 consumer ISO",
"ci_file_version": "10.0.19041.1865",
"architecture": "x64",
"sha256": "d0408a9f64eafb72e8aa1cf127d07d919f0cab38a6bdf2b406255909c85e3a8d",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetCertPublisherName",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": true,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 11 English x64 v1 ISO",
"ci_file_version": "10.0.22000.318",
"architecture": "x64",
"sha256": "301ae49ac5b87cf1cbe07d9d3c6486a066d045b6bf55fc8eb392d52951ec69ff",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetCertPublisherName",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": true,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 11 23H2 English ISO",
"ci_file_version": "10.0.22621.2792",
"architecture": "x64",
"sha256": "9ed77b8a53946ced8c3540edb26a765060dff908544634e7b069aa49f2b41559",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetCertPublisherName",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": true,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 11 24H2 sample",
"ci_file_version": "10.0.26100.9444",
"architecture": "x64",
"sha256": "c7d23814f3202c51fb23e3ca3d4328855787383cee5d14c4a986a13ec2aeda0b",
"source": "ci-26100.8328-evidence.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetCertPublisherName",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": true,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
},
"display_file_version": "10.0.26100.8328"
},
{
"label": "Windows 10 21H2 ARM64 ISO (archive Raspberry Pi folder)",
"ci_file_version": "10.0.19041.1566",
"architecture": "ARM64",
"sha256": "a35f651261691cc67acc9c8bfd00bba7a64dd9f16d2c4b6fe1d183e34aeead78",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetCertPublisherName",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": true,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 10 22H2.7 ARM64 ISO",
"ci_file_version": "10.0.19041.2965",
"architecture": "ARM64",
"sha256": "33f2d1256f60392bbb84c4251d6435461dfa852a100e065376f83dc8a4dd2ec6",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetCertPublisherName",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": true,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 11 22H2.9 ARM64 ISO",
"ci_file_version": "10.0.22621.1702",
"architecture": "ARM64",
"sha256": "4164ac08fd19628c5ab6cbca6234265ac2bf7f39d5149f57d3845646d8a8ad60",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetCertPublisherName",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": true,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
},
{
"label": "Windows 11 24H2 ARM64 ISO",
"ci_file_version": "10.0.26100.1591",
"architecture": "ARM64",
"sha256": "a0eba64a9a3f2006d5832079412eca42cc1b9ed66d19b9b0adb7e59ea354415d",
"source": "iso-corpus-index.json",
"named_exports": [
"CiCheckSignedFile",
"CiFindPageHashesInCatalog",
"CiFindPageHashesInSignedFile",
"CiFreePolicyInfo",
"CiGetCertPublisherName",
"CiGetPEInformation",
"CiInitialize",
"CiSetTrustedOriginClaimId",
"CiValidateFileObject",
"CiVerifyHashInCatalog"
],
"ordinal_only_export_count": 3,
"api_presence": {
"CiCheckSignedFile": true,
"CiFindPageHashesInCatalog": true,
"CiFindPageHashesInSignedFile": true,
"CiFreePolicyInfo": true,
"CiGetCertPublisherName": true,
"CiGetPEInformation": true,
"CiInitialize": true,
"CiSetTrustedOriginClaimId": true,
"CiValidateFileObject": true,
"CiVerifyHashInCatalog": true
}
}
]
}
+184
View File
@@ -0,0 +1,184 @@
# CI API compatibility matrix
This matrix records **named export presence in 20 exact `ci.dll` files**,
with architecture stated separately for each sample.
**Yes** means the complete PE export directory contains the name; **No** means
it does not. Neither result is inferred from a header, import library or PDB.
Export presence alone does not establish a compatible ABI or successful verification.
Versions in the tables are **CI file versions**, not necessarily the kernel version.
In particular, the Windows 10 22H2 consumer ISO contains CI **19041.1865**.
Do not extrapolate a cell to every servicing revision of that Windows release.
[Machine-readable matrix](ci-api-compatibility.json) includes exact SHA-256 identities,
all per-API results and canonical JSON hashes of the retained source inventories.
Source hashes ignore whitespace and line-ending differences between checkouts;
the binary SHA-256 identities always cover the exact original bytes.
The tables use numeric `VS_FIXEDFILEINFO` versions. The original modern x64
sample has **fixed version 26100.9444** but its string `FileVersion` reports
**26100.8328**. Original research/header labels retain that string version;
they identify the same SHA-256 file, not two different CI samples.
## Windows 10 1507–1803 x64 samples
| API | 10240.16463 | 10586.0 | 14393.2189 | 15063.0 | 16299.125 | 17134.1130 |
| --- | --- | --- | --- | --- | --- | --- |
| `CiCheckSignedFile` | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiFindPageHashesInCatalog` | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiFindPageHashesInSignedFile` | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiFreePolicyInfo` | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiGetCertPublisherName` | No | No | No | No | No | No |
| `CiGetPEInformation` | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiInitialize` | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiSetTrustedOriginClaimId` | No | No | No | Yes | Yes | Yes |
| `CiValidateFileObject` | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiVerifyHashInCatalog` | Yes | Yes | Yes | Yes | Yes | Yes |
## Later Windows 10 x64 samples
| API | 17763.1 | 17763.348 | 18362.1 | 18362.329 | 18362.418 | 19041.1 | 19041.1865 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `CiCheckSignedFile` | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiFindPageHashesInCatalog` | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiFindPageHashesInSignedFile` | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiFreePolicyInfo` | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiGetCertPublisherName` | No | No | No | No | No | No | Yes |
| `CiGetPEInformation` | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiInitialize` | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiSetTrustedOriginClaimId` | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiValidateFileObject` | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| `CiVerifyHashInCatalog` | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
## Windows 11 x64 samples
| API | 22000.318 | 22621.2792 | 26100.9444 |
| --- | --- | --- | --- |
| `CiCheckSignedFile` | Yes | Yes | Yes |
| `CiFindPageHashesInCatalog` | Yes | Yes | Yes |
| `CiFindPageHashesInSignedFile` | Yes | Yes | Yes |
| `CiFreePolicyInfo` | Yes | Yes | Yes |
| `CiGetCertPublisherName` | Yes | Yes | Yes |
| `CiGetPEInformation` | Yes | Yes | Yes |
| `CiInitialize` | Yes | Yes | Yes |
| `CiSetTrustedOriginClaimId` | Yes | Yes | Yes |
| `CiValidateFileObject` | Yes | Yes | Yes |
| `CiVerifyHashInCatalog` | Yes | Yes | Yes |
## Windows 10 ARM64 samples
| API | 19041.1566 | 19041.2965 |
| --- | --- | --- |
| `CiCheckSignedFile` | Yes | Yes |
| `CiFindPageHashesInCatalog` | Yes | Yes |
| `CiFindPageHashesInSignedFile` | Yes | Yes |
| `CiFreePolicyInfo` | Yes | Yes |
| `CiGetCertPublisherName` | Yes | Yes |
| `CiGetPEInformation` | Yes | Yes |
| `CiInitialize` | Yes | Yes |
| `CiSetTrustedOriginClaimId` | Yes | Yes |
| `CiValidateFileObject` | Yes | Yes |
| `CiVerifyHashInCatalog` | Yes | Yes |
## Windows 11 ARM64 samples
| API | 22621.1702 | 26100.1591 |
| --- | --- | --- |
| `CiCheckSignedFile` | Yes | Yes |
| `CiFindPageHashesInCatalog` | Yes | Yes |
| `CiFindPageHashesInSignedFile` | Yes | Yes |
| `CiFreePolicyInfo` | Yes | Yes |
| `CiGetCertPublisherName` | Yes | Yes |
| `CiGetPEInformation` | Yes | Yes |
| `CiInitialize` | Yes | Yes |
| `CiSetTrustedOriginClaimId` | Yes | Yes |
| `CiValidateFileObject` | Yes | Yes |
| `CiVerifyHashInCatalog` | Yes | Yes |
## Exact sample identities
- Windows 10 1507: **10.0.10240.16463 x64**, SHA-256
`e83d900f4675c6e6ffc3fb7dcd3074610876a1398e495796769988df810fd3bc`.
- Windows 10 1511: **10.0.10586.0 x64**, SHA-256
`f949bfa614addea6174b28c3818c56b327c9290fd41bd91dfc545414b3df6783`.
- Windows 10 1607: **10.0.14393.2189 x64**, SHA-256
`ef0c02ecbd0818e84be9f61421f919825f96a3c59199460cab08548eee2881df`.
- Windows 10 1703: **10.0.15063.0 x64**, SHA-256
`3705aaf408f05326e028621380aa5c96a1f3583a2de8a139b188da4b82577863`.
- Windows 10 1709: **10.0.16299.125 x64**, SHA-256
`1db7ae5a08bd2361fc7fcdd373fb980e8d680035e67b02e5967095db0443effd`.
- Windows 10 1803: **10.0.17134.1130 x64**, SHA-256
`8ce3b8fe38c23b699f30b045383640019a429d3a9d513285c655bffe03a796d9`.
- Windows 10 1809 initial x64 ISO: **10.0.17763.1 x64**, SHA-256
`eb177481f2aea3cae0c2f97f7058e7447c0695e4489428406598f168d4dcc5e8`.
- Windows 10 1809 October v2 x64 ISO: **10.0.17763.348 x64**, SHA-256
`da8282173cbce7ea38f8fca64db0972c3d9614ddbca98f6b96d11a4cadde92ad`.
- Windows 10 1903 v1 x64 ISO: **10.0.18362.1 x64**, SHA-256
`5d01bb84fa516e23c25def8ea03fc6b696082ccc67a61575fd00d1fe7c273d72`.
- Windows 10 1903 v2 x64 ISO: **10.0.18362.329 x64**, SHA-256
`d12131f14f781f8c314a795384e02afc3c2902bf67da9c2e75d8163c891bdd89`.
- Windows 10 1909 x64 ISO: **10.0.18362.418 x64**, SHA-256
`c3c5d32da42fa69b0795cd0f8c57252670d673fb036685db5c7d6392ffee0293`.
- Windows 10 2004 ISO: **10.0.19041.1 x64**, SHA-256
`2955710d34db26e352e62b20861ba338f0216cc36b378d128057be955e184282`.
- Windows 10 22H2 consumer ISO: **10.0.19041.1865 x64**, SHA-256
`d0408a9f64eafb72e8aa1cf127d07d919f0cab38a6bdf2b406255909c85e3a8d`.
- Windows 11 English x64 v1 ISO: **10.0.22000.318 x64**, SHA-256
`301ae49ac5b87cf1cbe07d9d3c6486a066d045b6bf55fc8eb392d52951ec69ff`.
- Windows 11 23H2 English ISO: **10.0.22621.2792 x64**, SHA-256
`9ed77b8a53946ced8c3540edb26a765060dff908544634e7b069aa49f2b41559`.
- Windows 11 24H2 sample: **10.0.26100.9444 x64**, SHA-256
`c7d23814f3202c51fb23e3ca3d4328855787383cee5d14c4a986a13ec2aeda0b`.
String FileVersion: **10.0.26100.8328** (original research label).
- Windows 10 21H2 ARM64 ISO (archive Raspberry Pi folder): **10.0.19041.1566 ARM64**, SHA-256
`a35f651261691cc67acc9c8bfd00bba7a64dd9f16d2c4b6fe1d183e34aeead78`.
- Windows 10 22H2.7 ARM64 ISO: **10.0.19041.2965 ARM64**, SHA-256
`33f2d1256f60392bbb84c4251d6435461dfa852a100e065376f83dc8a4dd2ec6`.
- Windows 11 22H2.9 ARM64 ISO: **10.0.22621.1702 ARM64**, SHA-256
`4164ac08fd19628c5ab6cbca6234265ac2bf7f39d5149f57d3845646d8a8ad60`.
- Windows 11 24H2 ARM64 ISO: **10.0.26100.1591 ARM64**, SHA-256
`a0eba64a9a3f2006d5832079412eca42cc1b9ed66d19b9b0adb7e59ea354415d`.
## What callers can rely on
- `CiValidateFileObject` is already exported in the sampled Windows 10 1507 file.
- `CiSetTrustedOriginClaimId` is present in the sampled 1703 file and absent in
the three earlier samples. This does not prove its first introduction build.
- On sampled x64 files, `CiGetCertPublisherName` is absent in 19041.1
and present in 19041.1865.
Its first Windows 10 servicing update remains unknown. It is also present
in the sampled 22000.318 and 26100.9444 fixed-version files.
- The Windows 10 ARM64 21H2 sample already exports the publisher-name API
in CI 19041.1566. That does not establish x64 availability at that revision.
- CI entry points currently use static imports from `ci.lib`. An unavailable
import can prevent driver loading; this matrix does not add an automatic
`STATUS_NOT_IMPLEMENTED` fallback. Supporting these older samples requires
avoiding unavailable imports or implementing optional resolution.
- Choose structures using a verified runtime profile. The sampled x64 chain
headers differ: 1507 uses 56 bytes, 1511 uses 72, and 1607–1803 use 104.
Export presence, compile-target `NTDDI_VERSION` and total allocation `Size`
do not select a compatible layout. See [mincrypt contracts](mincrypt-contracts.md).
## Coverage gaps and evidence
**Unknown / not sampled:** x86 export availability; pre-Windows-10;
earlier Windows 10 ARM64 releases; and other servicing revisions
or architecture/release combinations absent from these tables.
These are gaps, not negative export results. No interval between
two samples is certified. Runtime verification and cross-version ABI checks
remain in the [implementation ledger](implementation-status.md).
The tables cover every named export found in these samples, including
`CiInitialize`; inclusion is not a recommendation to call initialization or
global-policy routines. Each sample also has three ordinal-only exports,
which are outside this named-API matrix. Private `Mincrypt*` PDB symbols are
not automatically callable exports.
Source inventories are retained in the companion
[CodeIntegrity-RE repository](https://git.nefarius.at/nefarius/CodeIntegrity-RE):
`corpus-index.json` (VM samples), `iso-corpus-index.json` (ISO samples), and
`ci-26100.8328-evidence.json` with `manifest.json` (original 26100 sample).
Regenerate with its `generate_compatibility_matrix.py --output <Domito/docs>`.
ARM64 cells establish export presence only; the historical x64 layout views
must not be selected for ARM64 solely because the same API name is exported.
No Windows binary or PDB is distributed with the matrix.
+236
View File
@@ -0,0 +1,236 @@
# CiValidateFileObject: validation flag 0x00000020
Issue #3 is **documented; its TESTSIGNING-off runtime experiment is pending**.
A related signer-selection experiment has now run successfully on Windows 11
22631 with TESTSIGNING enabled (below). That run does not close the requested
19041/19045 flag 0 versus 0x20 TESTSIGNING-off comparison.
## Meaning supported by the evidence
`DOMITO_CI_VALIDATE_FLAG_BROADEN_ROOT_ACCEPTANCE` is Domito's descriptive name for
`0x00000020` in the second argument, `ValidationFlags`. It is not a recovered
Microsoft macro name. On the analyzed **ci.dll 10.0.26100.8328 x64**, the flag
causes `CipGetAcceptedRootKeys` to OR `0xA4FF` into its accepted-root mask in the
branch where the global at RVA `0x45A88` is zero. Other global state, flags, and
the requested signing level also affect the result.
The assembly at preferred image base `0x180000000` establishes the operation:
```text
0x180089e40: MOV EDX, 0xa4ff
0x180089e4c: BT ECX, EDI ; ECX = 0x8c in this branch; EDI = signing level
0x180089e4f: JC 0x180089e57
0x180089e51: TEST SIL, 0x20 ; saved ValidationFlags
0x180089e55: JZ 0x180089e59
0x180089e57: OR EBX, EDX ; broaden accepted-root mask
```
For requested level 0, flags 0, the branch above, and all other optional global
additions disabled, the mask is `0x80AA`; setting only `0x20` makes it `0xA4FF`
(additional bits `0x2455`). This is an arithmetic witness, **not a measurement of
the running OS's initialized policy**. Levels 2, 3, and 7 already trigger the OR
through `0x8C`. When the global at RVA `0x45A88` is nonzero, the helper returns
`0xA4FF` directly, so the flag need not change its result.
Later processing can still remove bit `0x8` when the helper's third argument is
nonzero and validation flag `0x00400000` is present. The surrounding
`CipDisallowEmbeddedPicrootIfTrusted` path can add that latter flag itself.
Thus `0xA4FF` is not a promise about every final policy result.
The widened mask includes categories associated with test roots and unresolved
chains as well as other roots. It must not be named "trust any Authenticode
signer", "require Microsoft", or "enable TESTSIGNING". It changes the acceptance
policy for this operation; it does not change the system boot setting. Further
signature, chain, signing-level, and policy checks still matter. A successful
call alone does not establish equivalence with WinVerifyTrust or the caller's
intended publisher trust policy.
`CipGetHashAlgorithmForLegacyScenario` does not test `0x20`: the flag is not a
fixed SHA-1/SHA-256 selector. Also distinguish this **input flag** from the
unrelated `MINCRYPT_POLICY_INFO.PolicyBits` output bit `0x20`, associated with
the built-in DMD root category in this build.
## Historical generation differences
The same numeric flag does not imply the same internal root mask across Windows
versions. Static analysis of the extracted x64 corpus adds these bounded facts:
- On sampled `10.0.10240.16463` (1507), `10.0.10586.0` (1511),
`10.0.14393.2189` (1607) and `10.0.15063.0` (1703), the recovered
`CipGetAcceptedRootKeys` bodies have no direct `flag & 0x20` broadening branch.
They still test larger masks containing that bit, so this is not evidence that
the flag has no effect anywhere in those verifiers.
- On sampled `10.0.16299.125` (1709) and `10.0.17134.1130` (1803), when the
helper's main global mode is zero,
`flag & 0x20` selects mask `0x224FF` (assignment), rather than the modern
`mask |= 0xA4FF` operation. A signing-level predicate can select the same mask.
Other global additions occur afterward. The other global mode returns
`0x204FF` directly.
The observed helper masks include branch-specific diagnostics/categories and
must not be interpreted as an official stable root enum. The descriptive Domito
constant names the intended broadening use without promising a single mask or
identical behavior on every build.
The ISO-derived **10.0.19041.1 x64** helper provides direct static evidence for
the reported build family: in its main global mode it uses `mask |= 0x24FF`
when flag `0x20` or the signing-level predicate applies; the alternate mode
returns `0x24FF`. With requested level zero and optional global additions
disabled, `0xAA` becomes `0x24FF` (added bits `0x2455`). This is an arithmetic
witness, not a measurement of initialized OS policy. The exact CI SHA-256 is
`2955710d34db26e352e62b20861ba338f0216cc36b378d128057be955e184282`.
CodeIntegrity-RE retains matched-PDB pseudocode and assembly in
`historical/ci-19041.1-contracts.json` and `historical/ci-19041.1-assembly.json`,
with batch evidence ID
`ev_13f89502777ee38ea98410f7a07f078bb934e78d792b662ab242f7b11d27e747`.
Other 19041/19045 servicing revisions and the TESTSIGNING-off runtime workaround
still require their own evidence.
Historical records in CodeIntegrity-RE:
`historical/ci-14393-contracts.json`
`ev_e63a4c4b7613e231795051b784b9571605b9bf81258b5dcd04d32ddc681abb41`,
`historical/ci-15063-contracts.json`
`ev_338658fb82559fa6daa8ae5487b90fe84b8e408ea7578feed6d8dff5d590e114`,
`historical/ci-16299-contracts.json`
`ev_fe5731175f0726f0d46af2f78ca615d284f8598939296815e26b5589db3001cf`,
and `historical/ci-17134-contracts.json`
`ev_0c3e3359b8b7486318006afa6b95eb2257a18abeec9041a86a32db487bcbe996`.
## Evidence and compatibility limits
The [upstream report](https://github.com/Ido-Moshe-Github/CiDllDemo/issues/5#issuecomment-2725851295)
describes success with flags `0x20`, signing level 0, and TESTSIGNING off on
Windows builds 19041 and 19045. That is third-party runtime evidence, not a
reproduction by this project. Its behavior is consistent with broader root
acceptance; it does not establish identical internals across those builds.
Our static evidence uses REA 6.8.0 / Ghidra 12.1.3 and the binary SHA-256
`c7d23814f3202c51fb23e3ca3d4328855787383cee5d14c4a986a13ec2aeda0b`.
Public-symbol mapping uses ci.pdb GUID `1CAE574B-CF1F-3564-5F74-49567A128629`, age 1.
The companion CodeIntegrity-RE repository retains:
- `ci-flag20-assembly-evidence.json`: assembly evidence
`ev_ea763b9be7643a6241b0c805eae5f735a4b4a0a82df1383b1e68da4207f85fb4`.
- `evidence/CipGetAcceptedRootKeys.c`: decompilation
`ev_c905f03db9470c8b2d89a6295080143f25d5780ca0909de0ca554e40d078a3f3`.
- `evidence/CipGetHashAlgorithmForLegacyScenario.c`:
`ev_addf8f1bc18da58db80db54eeab0dd78ec5ab88b219ece3e082ebd9a8e50b257`.
- `evidence/CipDisallowEmbeddedPicrootIfTrusted.c`:
`ev_2475a5804fc87683a54b06acebd3785e5e8eb31f4f542f699fc2ff414c1ab7fe`.
- `evidence/CipValidateFileObjectByFileOrPageHash.c`: capacity contract
`ev_3897aa76c17cc64a30f60e72b994e695b88c8eda2ae6f246766bdc9314f06cca`.
No complete enumeration of downstream uses of the flag, historical Microsoft
name, or cross-version/architecture guarantee is claimed. The public declaration
keeps the existing parameter widths. Names now describe the known inputs; on
26100 x64 the third argument is consumed as a byte. Narrowing the ABI everywhere
requires separate evidence.
## Kernel experiment prepared for the VM
Add `tests/ci-file-object-probe.cpp` to an existing signed test driver and add
`include/` to its include path. Link the existing CI imports (`ci.lib`). Include
`ntifs.h`, `Domito.MinCrypt.h`, and `tests/ci-file-object-probe.h` at the call site.
Invoke `DomitoProbeCiValidateFileObject` at PASSIVE_LEVEL with a referenced
file object for the fixture and an array of `DOMITO_CI_PROBE_RESULT_COUNT` results.
Keep the file bytes stable and hold the object reference for the entire probe.
The surrounding driver owns opening/referencing/closing the file and exporting
the result records. The probe has no DriverEntry or installation side effects.
It makes six calls, always at requested level 0:
1. Flags `0`, then `0x20`, then `0x20`, then `0`, with 64-byte capacity each time.
2. Flags `0`, then `0x20`, with declared capacity 63 (64-byte backing storage).
Each call uses fresh policies, hash capacity, algorithm, and signing-time storage.
Both policy objects are freed after capture, including on failure. The records
capture status, both policy statuses/bits, chain presence, signing time, digest
algorithm/length/bytes, and a trailing buffer guard. The digest is a **file hash**,
not a certificate thumbprint. Failed-call outputs are raw diagnostics, not valid
verification results. Chain internals are deliberately not dereferenced.
The repeated order helps reveal cache/order effects but does not eliminate them.
Also run the reversed initial order in a fresh VM snapshot when comparing policy.
For the analyzed 26100 helper, both 63-byte-capacity calls should return
`STATUS_BUFFER_TOO_SMALL` and set length 64, regardless of the eventual algorithm.
Treat older-build differences as observations to investigate, not silently as
test success. Every guard must remain intact; successful hash sizes must be at
most 64. Inspect non-success statuses rather than treating all failures as
invalid signatures (I/O and resource errors are possible).
Run on Windows 10 19041 and 19045 and a current Windows 11 build. The decisive
reproduction uses a driver loadable with TESTSIGNING **off**. Record that setting,
Secure Boot, HVCI/WDAC policy, OS build, CI version/hash, driver identity, fixture
SHA-256, and each complete result. Keep policy constant between paired calls.
Use these fixtures:
- A known third-party RSA Authenticode executable (ideally the reported fixture).
- A Microsoft-signed executable and a catalog-signed file as controls.
- An unsigned executable and a copy of the signed file with a byte changed in a
hashed section, leaving its certificate table unchanged.
- A self-signed/test-root fixture to characterize the broader acceptance policy.
- If available, timestamped, expired, revoked, and ECC variants, with expectations
recorded in advance and revocation/configuration differences retained.
Compare with `signtool verify /pa /v` as a separate user-mode policy observation,
not an equality oracle. The report is reproduced only when the same valid
third-party fixture changes from rejection at 0 to success at `0x20`, under the
reported environment, with usable outputs. Unchanged success can mean the
existing policy already accepts it. Unchanged failure is a result to investigate.
Unsigned and tampered fixtures must not become accepted as valid signatures.
Self-signed acceptance must be reported explicitly, not confused with public-CA
publisher trust. Do not use this flag as a new production default based only on
one positive fixture.
## Multiple signatures: a separate kernel experiment
`0x20` is an accepted-root control, not a recovered "PE image" type flag.
In the examined 22621.2792 and modern 26100 x64 bodies it leaves the
preferred-signing-level search active. `PolicyInfo` can therefore describe a
nested Microsoft signature even when the primary company signature also verifies.
The first-success guard tests aggregate masks `0xE47FFF87` (22621.2792) and
`0xE41FFF87` (modern 26100). `0x20` intersects neither; `0x80` intersects both.
Compare flags `0x20` versus `0xA0`, requested signing level zero, on the same
stable dual-signed file. Record the actual selected leaf/thumbprint, both policy
statuses and signing time. Do not interpret status success alone as selection
of the company certificate. First successful does not necessarily mean first
listed: CI may reject the primary and continue.
`0x80` has additional policy and fallback effects. Domito exposes it only as
`DOMITO_CI_VALIDATE_FLAG_FIRST_SUCCESS_EXPERIMENTAL` and through the opt-in
`DomitoCiSignatureSelectionFirstSuccessfulExperimental` mode in
`DomitoValidateFileObjectEx`. It is not a production default or a stable signer
index. See the [validation helper contracts](ci-validation-helpers.md). The companion research
`SIGNATURE-SELECTION.md` provides the full static evidence and an alternative
primary-signature path using `CiCheckSignedFile`.
A user-run kernel probe on Windows 11 **10.0.22631 x64**, CI options **0x00080207**
(TESTSIGNING enabled), confirms the selection difference for the exact dual-signed
BthPS3 fixture: `0x20` returns Microsoft, while `0xA0` returns the Nefarius leaf
`FF0CCF318FD8C14775023A0B52C28FFCCA59D7F7` and signing time
**2026-10-02T18:32:01.000Z**. Direct primary SHA-256 `CiCheckSignedFile` returns
the same Nefarius leaf, signer/timestamp policies and signing time. All three
calls return STATUS_SUCCESS; all policy VerificationStatus fields also succeed.
The file digest is identical across calls, before/after file hashes match, and
TraceFmt reports 149 events with no losses, format errors or unknown formats.
The companion `signature-selection/runtime-22631-bthps3.json` records exact
trace hashes and the on-disk CI hash. This is one test-signing-enabled run;
TESTSIGNING-off, other builds/policies and general signature enumeration remain
unverified. `0xA0` does not mean "select any desired publisher".
## Checks available without the VM
From an x64 Visual Studio developer shell:
```powershell
python tests\run-ci-probe-tests.py
```
This compiles the actual probe body with mock CI calls and constants extracted
from the public header. It verifies call order, input forwarding, fresh capacity
and outputs, result capture, and freeing both policies after success and failure.
It does **not** emulate the flag's trust semantics. Kernel compilation checks
the real headers separately; neither compilation nor mock tests substitute for
the VM run above.
+118
View File
@@ -0,0 +1,118 @@
# CI validation helpers
These additive APIs are declared in `Domito.h` for Windows 10 compile targets.
They reuse CI for cryptographic verification. They do not implement RSA/ECDSA,
certificate-chain building or timestamp-signature verification themselves.
Raw CI declarations and existing digest/legacy helpers are unchanged.
## Result lifetime
Zero-initialize `DOMITO_CI_VALIDATION_RESULT` before first use. Each validation
call frees its previous signer/timestamp policies before reuse and resets the
result. Do not pass uninitialized storage or copy an owning result as a second
owner. On every exit, including a failed call, release it with
`DomitoFreeCiValidationResult`. The destructor accepts NULL and empty results.
All three APIs require PASSIVE_LEVEL. Referenced input objects/buffers must stay
valid and file bytes must stay stable throughout validation and consumption.
On success, `Hash`/`HashSize`/`HashAlgId` describe a known SHA-1/256/384/512 file
digest with a consistent length. Unused digest bytes are zero. This is not a
certificate thumbprint. On failure, digest bytes/length/algorithm and signing
time are zero; policy objects may retain owned diagnostic allocations. Input
flags/level forwarded to the file-object export remain recorded if it was called.
Those fields are not CI's final internally normalized policy flags.
Check the returned NTSTATUS first. Policy verification status, policy bits,
certificate identity, timestamps and the application's intended trust policy
remain separate observations/checks. Returning STATUS_SUCCESS does not pin a
company signer, reproduce WinVerifyTrust policy or prove driver-load acceptance.
No helper traverses the private chain layout or matches a certificate for you.
## File-object path
`DomitoValidateFileObjectEx` takes a referenced FILE_OBJECT, caller-selected
validation flags, a byte-sized requested signing level and a selection mode.
It supplies fresh 64-byte hash capacity and initialized policy/time outputs on
every call. It does not read, duplicate or acquire ownership of the file object.
- `DomitoCiSignatureSelectionNative` forwards the caller's flags unchanged.
This is native policy, not a guarantee of preferred-level selection: the
caller's other flags may already change the search/exit path.
- `DomitoCiSignatureSelectionFirstSuccessfulExperimental` additionally sets
`DOMITO_CI_VALIDATE_FLAG_FIRST_SUCCESS_EXPERIMENTAL` (0x80). On examined x64
builds this changes a successful-candidate early-exit predicate. It also
affects other policy/fallback paths. This explicit mode returns
STATUS_NOT_SUPPORTED on non-x64 builds. No runtime behavior on ARM64 is implied.
Neither mode automatically adds `0x20`. Broadening accepted roots is a separate
caller decision. Neither mode selects an arbitrary signer index or guarantees
that signature zero succeeds. A rejected primary may still lead to another signer.
```c
DOMITO_CI_VALIDATION_RESULT result = {0};
NTSTATUS status = DomitoValidateFileObjectEx(
fileObject,
DOMITO_CI_VALIDATE_FLAG_BROADEN_ROOT_ACCEPTANCE,
0,
DomitoCiSignatureSelectionFirstSuccessfulExperimental,
&result
);
if (NT_SUCCESS(status))
{
// Apply your expected-certificate/trust policy to result.PolicyInfo.
// result.SigningTime belongs to that selected verification result.
}
DomitoFreeCiValidationResult(&result);
```
The native kernel experiment on the supplied dual-SHA256 BthPS3 fixture returned
Microsoft for flags 0x20 and Nefarius for flags 0xA0 on a Windows 11 22631 x64
TESTSIGNING-enabled machine. It does not establish all older builds, TESTSIGNING-off
behavior or every side effect of 0x80. See [the flag evidence](ci-validate-file-object.md).
Do not rename this mode "require our company" or "select primary signature".
## Embedded PE-buffer path
`DomitoValidatePortableExecutableEmbeddedSignature` accepts a stable PE buffer
and an explicit CALG_SHA1/CALG_SHA_256/CALG_SHA_384/CALG_SHA_512. It calls
`DomitoCalculatePortableExecutableDigestEx` and supplies the resulting digest
and original first WIN_CERTIFICATE to `CiCheckSignedFile`. The digest allocation
is always freed, and only copied digest bytes/owned CI policies remain in the
result. Unsupported algorithm/layout and CI errors propagate without trying a
different algorithm or a catalog. An absent certificate returns
STATUS_INVALID_IMAGE_HASH; the helper cannot turn an unsigned file into a
successful catalog verification.
```c
DOMITO_CI_VALIDATION_RESULT result = {0};
NTSTATUS status = DomitoValidatePortableExecutableEmbeddedSignature(stablePeBytes, peSize, CALG_SHA_256, &result);
if (NT_SUCCESS(status))
{
// Enforce the expected certificate and intended trust policy here.
}
DomitoFreeCiValidationResult(&result);
```
This uses the explicit digest helper's [supported PE layout subset](authenticode-digests.md):
bounded headers, contiguous nonoverlapping raw sections in file order and an EOF
certificate table. It is not an arbitrary PE/SIP parser. CI can select nested
signatures according to its algorithm rules, so the helper is deliberately named
**embedded**, not **force primary**. The matching SHA-256 request selected the
company primary in the tested BthPS3 layout; another layout may select another
signer or fail. General enumeration remains separate work.
## Support and validation
The functions are C-compatible and compile for x64/ARM64. The experimental
file-object mode is deliberately gated to x64; native forwarding/embedded code
compilation does not certify every architecture/build's CI runtime ABI. CI
imports are static and must exist on the target OS, as described in the
[availability matrix](ci-api-compatibility.md). Structure/chain interpretation
remains subject to the [mincrypt contracts](mincrypt-contracts.md).
The new host suite checks production code forwarding, hash invariants, failures,
partial allocations, cleanup, result reuse and the non-x64 conditional branch.
The existing digest suite independently compares Windows SIP and Crypt32 results.
Kernel compilation covers the full library, public C clients and layout checks.
CodeIntegrity-RE probe v2 now calls the new APIs; a further kernel run is needed
to validate these wrappers rather than merely their previously tested raw calls.
+247
View File
@@ -0,0 +1,247 @@
# Migrating consumer Authenticode helpers
These helpers centralize file validation, certificate inspection, hashing and
allocation cleanup. The contracts keep application identity and trust policy
explicit. Host tests and kernel compilation do not establish new CI runtime
guarantees.
## Verified fixes and existing coverage
- **Implementation defect fixed:** `DomitoGetProcessImageName` freed its allocation
on a failed second query but left that freed address in the caller's output.
It also left old caller output untouched on earlier failures. It now clears
the output first, publishes only a successful bounded result, and frees its
local allocation on all other paths. The process handle uses limited-query
access (`0x1000`) instead of `PROCESS_ALL_ACCESS`. A PID is resolved once to a
process handle; no later query re-resolves that PID.
- **Output-contract defect fixed:** `DomitoFindModuleBaseAddress` could preserve
an old address when lookup failed. It now clears the optional output first and
validates the counted module name. The export-by-module wrapper preserves the
underlying status, including missing exports and unsupported forwarders.
- **Annotation defect fixed:** the `DomitoReadFileAt` definition's single-object
output annotation disagreed with its public byte-count annotation. Both now
describe `BufferSize` writable bytes.
- **Already addressed before this review:** exact file reads return
`STATUS_END_OF_FILE` on short reads and wait for their own pending request.
Explicit digest helpers bound PE32/PE32+ headers, sections, certificate spans
and DER navigation. Certificate pointers borrow the stable input buffer.
[CI validation results](ci-validation-helpers.md) initialize outputs and own
both policies, including diagnostic allocations on failure. The current raw
CI declaration names the flags and byte-sized signing level; `0x20` broadens
root acceptance in examined builds, rather than declaring a file to be PE.
Applications should avoid truncating file lengths to `EndOfFile.LowPart`,
reparsing fixed-kind PE headers, consuming uninitialized CI policies, skipping
cleanup on failure, or accepting invalid hexadecimal digits. The helpers below
provide reusable primitives without defining application authorization policy.
## File object, handle and path validation
`DomitoValidateFileObjectEx`, `DomitoValidateFileHandleEx` and
`DomitoValidateFilePathEx` expose the same explicit flags, requested signing
level, selection mode and owning `DOMITO_CI_VALIDATION_RESULT`. None adds flags
or falls back to a different validation policy. They require PASSIVE_LEVEL and
Windows 10 compile targets; the CI imports must exist on the target OS.
They do not require `DomitoInit`.
The handle wrapper requires a trusted **kernel handle** with `FILE_READ_DATA`.
It references its FILE_OBJECT, releases that reference on every exit and leaves
the caller's handle open. Never pass an unchecked user handle: the reference is
made using KernelMode. The caller must keep the handle valid during validation.
The path wrapper accepts a counted absolute native path, for example
`\??\C:\Program Files\Example\app.exe`. It creates a read-only kernel handle,
shares only reads, references that same opened file for CI, and closes its own
handle. Existing incompatible writers cause an open failure. Special kernel APCs
must be enabled for synchronous I/O. Reparse points may redirect the open;
validation describes the opened object. It does not establish the identity of
a previously looked-up process image or certify in-memory process contents.
File-object/handle callers must independently provide stable file bytes.
```c
DOMITO_CI_VALIDATION_RESULT result = {0};
NTSTATUS status = DomitoValidateFilePathEx(&nativePath, selectedCiFlags, 0, DomitoCiSignatureSelectionNative, &result);
if (NT_SUCCESS(status) && NT_SUCCESS(result.PolicyInfo.VerificationStatus))
{
// Apply caller-provided certificate/publisher/pin policy here.
// A nonzero SigningTime is a separate consumer requirement, if desired.
}
DomitoFreeCiValidationResult(&result); // Also on CI or application-policy failure.
```
Modern file-object verification can select a preferred Microsoft nested signer
where direct embedded verification selected the company signer. Changing paths
therefore requires an explicit migration decision. Keep
`DomitoValidatePortableExecutableEmbeddedSignature` for the stable PE-buffer,
explicit-algorithm route. Its supported PE subset and nested-selection limitations
still apply. It verifies the original first WIN_CERTIFICATE through CI, with no
algorithm retry or catalog fallback. Existing legacy/catalog APIs remain
available with explicit catalog policy; new convenience wrappers do not invoke
them implicitly. An absent optional API is not permission to relax trust policy.
## Certificate fingerprints and SPKI pins
`DomitoGetCertificateSpki` extracts two borrowed views from stable certificate
DER: `Encoded` contains the complete SPKI SEQUENCE TLV; `Content` omits that
sequence's tag and length. It handles optional X.509 version fields and bounded,
minimal definite DER lengths. It validates navigation/framing and the SPKI field
shape, rather than every X.509 field, extension, name, algorithm parameter or
signature. It does not verify trust. Failed extraction clears both views.
`DomitoHashBuffer` hashes exact bytes using SHA-1/256/384/512 and Windows CNG.
`HashSize` is capacity on entry, actual length on success, required length on
`STATUS_BUFFER_TOO_SMALL`, and zero on other failures. A NULL hash buffer queries
the required size. Operational CNG failures erase the selected digest bytes.
Input/output buffers must not overlap. Only consume a digest after success.
`DomitoHashCertificate` takes an explicit `DOMITO_CERTIFICATE_HASH_KIND`:
- `DomitoCertificateHashDer`: exact complete certificate bytes, suitable for a
DER thumbprint. This mode hashes bytes; it does not parse or validate them.
- `DomitoCertificateHashSpkiDer`: complete SPKI encoding, including outer TLV.
- `DomitoCertificateHashSpkiContentLegacy`: **preserves the consumers' existing
content-only convention**. Existing pins must use this mode. Switching to the
complete encoding requires recomputing pins from the intended certificates;
do not silently treat hashes from the two representations as interchangeable.
```c
UCHAR pin[MINCRYPT_SHA256_LENGTH];
ULONG pinSize = sizeof(pin);
status =
DomitoHashCertificate(cert.Data, cert.Size, DomitoCertificateHashSpkiContentLegacy, CALG_SHA_256, pin, &pinSize);
```
`DomitoDecodeHex` accepts an exact counted Unicode hex string for a caller-selected
binary length, rejects invalid digits/odd or mismatched lengths, and zeroes its
destination on malformed input. `DomitoEncodeHex` writes uppercase Unicode hex
with a NUL terminator; its capacity is in WCHARs including the terminator.
Decode configuration pins once into binary and compare like representations.
The library embeds no publisher names, root pins, or certificate allowlists.
Hashing does not prove that a certificate is a root or trusted issuer.
## Chain inspection and publisher ownership
`DomitoGetCiChainView` requires a known, readable, initialized CI-owned policy
and an explicit `DomitoCiChainLayoutObservedX64` argument. This asserts the
sampled x64 common prefix (+0x28 elements, +0x30 count, +0x34 opaque RootId,
minimum 56-byte header, 120-byte elements). It is **not** automatic OS/layout
detection. Non-x64 builds return `STATUS_NOT_SUPPORTED`; allocation size and
compile-target NTDDI cannot establish runtime layout compatibility.
The accessor bounds the element array and every exposed certificate/name blob
within CI's owned allocation before returning a view. It rejects oversized hash
lengths and absent certificate bytes. It exposes neither trailing attributes nor
EKU/public-key arrays. It cannot make a forged or freed kernel pointer safe;
allocation extent/readability and the asserted layout remain caller preconditions.
All returned pointers expire when the policy is freed or its result reused.
Sampled CI results are leaf-first. Inspect `Elements[0]` for that selected leaf.
`Elements[Count-1]` is the last represented certificate; this API does **not**
promise it is self-signed, the configured trust anchor, or that the chain includes
every certificate through a root. `RootId` is opaque and does not establish those
properties. A consumer requiring a specific root must establish its intended CI
policy and represented-anchor assumptions instead of inferring trust from position.
The accessor deliberately imposes no bytewise issuer/next-subject equality.
CI name blobs are not an independent chain verifier;
their encoding and representation are version-sensitive. Current evidence does
not establish universal byte equality as a CI API contract. Preserve such a check
as an explicit downstream restriction if compatibility demands it, and assess its
false-rejection risk. CI return status, policy verification status and application
identity/pin requirements remain separate checks.
`DomitoGetCertificatePublisherName` dynamically resolves the optional CI export
instead of adding a static import. It requires `DomitoInit`; missing modules,
exports and unsupported export forwarders propagate their lookup status.
The caller passes an empty `UNICODE_STRING`, and uses
`DomitoFreeCertificatePublisherName` to release/reset it. Partial allocations on
failure are cleaned internally; the destructor is safe again afterward. Its
private pool allocator is independent of configurable Domito callbacks. Never
free this string through `G_Memory`, RtlFreeUnicodeString or the process-name free
API. Display-name comparison remains caller policy, not certificate identity.
## Process names, allocators and optional exports
`DomitoGetProcessImageName` returns one Domito allocation containing the
`UNICODE_STRING` and its buffer. `DomitoFreeProcessImageName` frees the entire
allocation once, without querying callbacks in consumer code. Its output is
NULL on failure. The existing ULONG PID interface remains; a PID lookup can race
process exit/reuse before the initial open and is not a durable process identity.
`DomitoGetProcessImageNameEx` instead accepts a caller-referenced PEPROCESS.
It uses `SeLocateProcessImageName`, copies the name into the same Domito-owned
representation and frees the OS allocation internally. The caller must keep the
process referenced for the call. No Domito initialization is needed for this Ex
API. The PID API still requires `DomitoInit` for its query routine.
Neither name API proves that a subsequent path open addresses the original
image file. WDF/requestor-process lifetime and authorization remain downstream.
**Allocator contract:** the existing callback API does not attach allocator
provenance to each result and is not synchronized for concurrent replacement.
Configure a compatible allocate/free pair during initialization, before concurrent
calls, and keep it unchanged until all callback-backed allocations and in-flight
calls are released. A dedicated free name does not make changing callback pairs
with outstanding allocations safe. Do not retrofit a hidden prefix onto existing
allocations: callers may already free the public base address with their callback.
CI policies and the publisher helper use their dedicated free APIs instead.
`DomitoFindModuleExportedFunctionAddress` combines the existing full-module-path
and export-name lookups, clears its output and preserves useful failure status.
It requires `DomitoInit`, and does not pin the module. The caller must guarantee
that the module remains mapped throughout lookup and use of its returned address.
## Integration and consumer boundary
Import `Domito.props` from the Domito package location or override
`DomitoRootPath`. The default root is the sheet's own directory. x64/ARM64 and
Debug/Release remain selected by the project; `DomitoLibraryPlatform` can override
the library platform directory. Both WDM and KMDF final driver projects receive
Domito, CI and CNG dependencies. Importing a sheet into a static library does not
make link dependencies transitive: import it into the final driver as well.
WDF caches, PID caches, administrator checks, developer bypasses, request allowlists,
build expiry and selected-signing-time requirements stay in consumer code.
No default trust evaluator is added: that would silently choose policy absent
from the generic SDK. WPP diagnostics can enumerate the bounded chain view without
fixed-depth indentation arrays. Report the returned NTSTATUS and local policy
failure reason separately rather than mapping all failures inside the SDK.
The new host suite compiles the production code unchanged apart from its kernel
include, uses deterministic kernel doubles for ownership/failure paths, compares
SPKI bytes and fingerprints with Crypt32, and uses real CNG for hashing. It tests
both architecture conditional branches, which is not ARM64 runtime emulation.
Real WDK compilation separately covers x64 and ARM64. These checks do not certify
kernel CI behavior, every chain layout, or full X.509 validation.
References: [SeLocateProcessImageName ownership](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-selocateprocessimagename),
[BCryptCreateHash memory management and kernel requirements](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptcreatehash).
## Deprecated compatibility entry points
The public header uses MSVC `__declspec(deprecated("migration guidance"))` for
four older functions. Calling or taking their address produces C4996 in C and
C++; declarations and binary entry points remain available. Projects treating
warnings as errors must migrate, or suppress C4996 locally around a deliberate
compatibility call. Do not disable the warning globally to conceal accidental use.
- `DomitoGetPortableExecutableDigestKind` →
`DomitoGetPortableExecutableDigestKindEx`: check NTSTATUS; unrecognized input
no longer silently chooses SHA-1. Neither function validates signature trust.
- `DomitoCalculatePortableExecutableDigest` →
`DomitoCalculatePortableExecutableDigestEx`: select the algorithm explicitly
and review the supported layout/rejection rules. This is not a drop-in semantic
change for arbitrary files previously accepted by linear hashing.
- `DomitoValidateFileLegacyMode` → `DomitoValidateFileLegacyModeEx`: select catalog
policy and trusted-catalog requirements explicitly, and consume the validation
source. The Ex legacy path remains available where catalog/older-OS behavior
is required; migration does not implicitly switch to modern signer selection.
- `DomitoGetProcessImageName` → `DomitoGetProcessImageNameEx`: acquire and hold the
intended PEPROCESS reference, then use the dedicated name destructor. Looking
up a PID immediately before the Ex call cannot eliminate an earlier PID-reuse
race; obtain the process reference from the operation's intended identity.
This migration does not solve subsequent path-reopen identity races.
No old type has an unconditional replacement. Raw CI/mincrypt types still
describe the native ABI; the owning validation result and borrowed chain view
serve different purposes. Raw Windows CI exports, allocator callbacks, module
lookup primitives, exact file reads and digest cleanup remain supported.
+127
View File
@@ -0,0 +1,127 @@
# CI SDK implementation status
This ledger tracks the source audit S01–S18 and the remaining binary research.
The original CodeIntegrity-RE audit remains a snapshot of commit `7985b23`;
it should not be read as describing the corrected source unchanged.
## Implemented with host tests or compilation
- Additive CI result/selection helpers now package native file-object validation,
opt-in x64 first-success selection and explicit embedded verification, with
shared policy/digest cleanup. Existing APIs retain their behavior. See the
[helper contracts](ci-validation-helpers.md). Host failure/forwarding tests and
x64/ARM64 builds cover the wrappers; WPP probe v2 consumes them and awaits a
returned kernel trace. The previous v1 trace establishes the raw native routes.
- **S01–S04:** subtraction-safe PE ranges, no fixed 4 MiB copy, bounded certificate
intervals, deterministic failure outputs, and digest cleanup. Compatibility
and explicit paths share the bounded hashing core.
- **S05:** actual certificate read length checked; allocation bounded against
file size; per-operation completion waits through the exact-read helper.
- **S06:** `DomitoReadFileAt` uses an explicit offset and private kernel event;
`DomitoReadFile` reads exactly from offset zero. Pending completion cannot
outlive its stack state or caller buffer. Short reads return EOF.
- **S10:** export lookup uses the name ordinal to index the EAT, bounds tables,
names and resolved RVAs, and rejects forwarders. A valid loader-mapped module
remains a precondition because the API has no externally supplied image size.
- **S11–S12:** corrected policy pointer typedef and publisher return/ownership docs.
- **S14:** policy cleanup before embedded/catalog/reload retries, with host tests
allocating results even on failures. Real CI failure ownership still needs
the VM tests below.
- **S17:** legacy hash algorithm/length combinations validated and calculation
versus verification capabilities documented.
- **S18:** byte-count SAL, buffer-capacity rules, scalar input annotations, and
kernel read context/APC requirements documented.
## Implemented within an explicit support boundary
- **S07:** new bounded DER discovery reads the first outer SPC file-digest
AlgorithmIdentifier; new explicit digest API needs no discovery. The old
heuristic entry point retains compatibility behavior. Arbitrary BER, nested
signatures, and full signature enumeration remain outside this parser.
- **S08:** unsigned/catalog-only files can be hashed with a caller-chosen
SHA-1 or SHA-256 strategy. The policy-explicit legacy helper forwards catalog
controls and reports the successful source. Real catalog lookup comparisons
across OS versions are pending; no implicit algorithm retry policy is imposed.
- **S09:** the explicit digest path enforces a contiguous raw-section subset and
EOF certificate tables, with Windows SIP and real embedded-digest comparisons.
Gaps, overlaps, missing directory slots and nonterminal certificates are
rejected. The old linear compatibility entry point is not a universal hasher.
- **S13/S15/S16:** recovered fields, parameter meanings, policy categories, sizes,
name encoding, borrowed lifetimes, and allocator ownership are documented.
The opt-in x64 26100 header provides distinct observed layouts and assertions.
Default declarations retain source compatibility; later chain fields require
a confirmed runtime layout. The sampled 1507 chain header is 56 bytes and has
no attributes descriptor at +0x38; 1511 uses 72 bytes; 1607–1803 samples use 104.
Distinct views are available in `Domito.MinCrypt.Historical.h`. Neither
`NTDDI_VERSION` nor total allocation Size identifies the layout.
## Requires the test VM or additional matching binaries
The first user-run kernel trace is available for Windows 11 22631 x64 with
TESTSIGNING enabled. It confirms the BthPS3 signer-selection comparison and
primary-signature CI path below. That one run, extracted artifacts, host mocks
and compilation do not close the remaining work:
1. Run the paired `CiValidateFileObject` flag `0`/`0x20` probe on 19041/19045
with TESTSIGNING off and a loadable signed test driver. Preserve complete
statuses, policies and fixture/environment identities (issue #3).
2. Complete historical and ARM64 ABI/structure verification and runtime tests.
The [published export matrix](ci-api-compatibility.md) now covers all ten
named APIs across 20 exact Windows 10/11 x64 and ARM64 CI files.
ISO coverage includes Windows 10 1809/1903 revisions, 1909, 21H2/22H2 ARM64,
and Windows 11 23H2 x64 plus 22H2/24H2 ARM64.
The ARM64 observations establish export presence; their structure layouts
and runtime behavior remain unverified. This closes the initial export-presence
matrix; additional releases, servicing revisions and architectures remain
unsampled. It does not certify ABI or runtime behavior. The six 1507–1803
sampled bodies establish the
48-byte policy storage and 64-byte hash-capacity gate. Chain constructors
establish 56/72/104-byte headers; opt-in views prevent treating 1507 payload
as the later attributes descriptor. Unsampled layouts/runtime remain open.
3. Test real CI policy ownership on every failure/retry path under Driver
Verifier, including allocation failures and initialized outputs.
4. Compare real embedded/catalog-only SHA-1/SHA-256 results, catalog cache/reload
behavior, trust-mask choices, requested signing levels and flag combinations.
5. Measure signing-time propagation, zero/sentinel values, timestamp expiry,
revocation freshness/network policy and weak-crypto policy. Record OS policy,
Secure Boot/HVCI/WDAC and exact files, not just a boolean result.
6. Extend the observed multiple/nested selection result beyond the first run.
On Windows 11 22631 x64 with TESTSIGNING enabled, `0x20` returns Microsoft;
`0xA0` and direct primary SHA-256 `CiCheckSignedFile` return Nefarius with the
same signing time and matching signer/timestamp policy observations. All
calls and policy statuses succeed, the file snapshots match, and no trace
events are lost. TESTSIGNING-off, general enumeration, full `0x80` semantics
and cross-build/policy behavior remain open. Extend supported PE gaps/overlays
only after differential evidence.
7. Resolve page-hash allocation destruction, normalized-entry/truncation meaning,
terminal-entry handling and cross-version layouts before publishing a general
page-hash API. `CiFreePolicyInfo` is not an established destructor for it.
8. Investigate protected-media/initialization and ordinal-only exports separately
if they are needed. Recovered export names alone are insufficient contracts.
## Checks
Run the six host runners in `tests/README.md`. Kernel compilation also covers
the default modern x64/ARM64 structures, the pre-Windows-10 x64 compile variant,
and 14 assertions in the 26100 opt-in header plus 12 historical-view assertions. Those are build checks,
not a claim that historical or ARM64 CI runtime ABI has been verified.
## Consumer-driven helpers
The [consumer migration review](consumer-helpers.md) separates verified defects,
existing corrections, new helpers and downstream policy. Additions include
handle/path native CI wrappers, explicit SPKI representation/hash helpers,
strict hex conversion, an explicit-layout x64 chain view, optional publisher
resolution with matching cleanup, a referenced-process name API and dedicated
process-name cleanup. The PID path fixes dangling failure output and excessive
process access; module-base lookup clears stale output. WDM/KMDF linking is
covered by the package-relative property sheet. No default publisher/root trust
policy, automatic legacy fallback, or process authorization/cache is introduced.
Four compatibility functions carry MSVC deprecation annotations with explicit
migration messages: heuristic digest-kind discovery, compatibility PE hashing,
implicit-policy legacy validation and PID-based process-name lookup. Native CI
types/functions remain available for low-level callers. The compile-only
deprecation suite checks actual public headers in C/C++, including modern API
controls and expected C4996 diagnostics for each older entry point.
+327
View File
@@ -0,0 +1,327 @@
# Code Integrity and mincrypt contracts
The default header retains the existing structure layouts and calling shapes.
Parameter names and ownership comments now distinguish the known controls from
the verification result. `VerificationStatus` is an `NTSTATUS` with the same
32-bit storage. The additional `Domito.MinCrypt.26100.h` header is an **opt-in
description of ci.dll 10.0.26100.8328 x64**. It neither adds imports nor extends
the default structures on every Windows target.
The evidence is static REA/Ghidra analysis of SHA-256
`c7d23814f3202c51fb23e3ca3d4328855787383cee5d14c4a986a13ec2aeda0b`, with
Microsoft ci.pdb GUID `1CAE574B-CF1F-3564-5F74-49567A128629`, age 1 supplying the
address/name map. The companion CodeIntegrity-RE repository retains the full
records and readable `evidence/` files. The historical corpus below adds
sampled x64 Windows 10 observations; ARM64 and unsampled-build compatibility
remain open. Compile-target `NTDDI_VERSION` is not runtime layout negotiation.
The original modern research and `Domito.MinCrypt.26100.h` use the string
`FileVersion` label **26100.8328**. That same exact binary has numeric
`VS_FIXEDFILEINFO` version **26100.9444**, which the export matrix uses. Its
SHA-256 and recovered contracts are unchanged; these labels identify one file.
## Historical x64 corpus: availability and structure evolution
The [CI API compatibility matrix](ci-api-compatibility.md) lists observed named
exports for 20 exact x64/ARM64 CI files, including the later ISO samples. Consult it
for import availability, and the contracts below for layout and ownership limits.
[NOTES.md](../NOTES.md) lists the exact identities of six sampled Windows 10
files: `10.0.10240.16463`, `10.0.10586.0`, `10.0.14393.2189`, `10.0.15063.0`,
`10.0.16299.125`, and `10.0.17134.1130`. All export `CiValidateFileObject` and
the digest/catalog functions. The global setter is already present in sampled
1703, correcting the old 1709 note. The publisher-name export is absent from
all six. ISO samples additionally show absence in 19041.1 and presence in
19041.1865 and 22000.318 x64; the original 26100 file also exports it. The first
Windows 10 servicing update adding it remains unresolved. See CodeIntegrity-RE
`iso-corpus-index.json`. Header guards do not negotiate runtime import availability.
All six sampled x64 file-object exports transfer 48 bytes into each caller
policy, with the owned chain pointer at `+0x10`; cleanup zeros `0x30` bytes. Their
file-object helpers require hash capacity >=64, return `STATUS_BUFFER_TOO_SMALL`
and required length 64 for a smaller buffer, and consume the third input as a
byte. This supports the stable policy storage prefix on these exact artifacts;
it does not establish all field semantics or every servicing build's behavior.
**The chain header evolves within Windows 10. The default header's
`NTDDI_VERSION >= NTDDI_WIN10` condition cannot safely expose every later field
on Windows 10 1507.** Constructor evidence establishes:
- `10.0.10240.16463` (1507): fixed header 56 bytes (`0x38`), root ID at `+0x34`,
variable payload beginning at `+0x38`. There is **no AuthenticodeAttributes
header field at `+0x38`**. Accessing the default structure's member on this
layout would interpret variable payload bytes as a blob descriptor.
- `10.0.10586.0` (1511): fixed header 72 bytes (`0x48`), attributes descriptor at
`+0x38`, payload beginning at `+0x48`.
- Sampled 1607/1703/1709/1803: fixed header 104 bytes (`0x68`), root ID still at
`+0x34`, attributes at `+0x38`, payload beginning at `+0x68`. Constructor evidence
establishes space for the 32-byte extension at `+0x48`, not its semantic
contents on every build. The historical view leaves this region reserved.
`Domito.MinCrypt.Historical.h` supplies distinct opt-in x64 views for those
observed profiles with 12 compile-time assertions. The common prefix ends after
root ID at `+0x34`; chain elements use 120-byte strides in these constructors,
but the prefix views expose their storage as opaque. Do not assume every element
field is populated on every version. The 26100-specific header separately names
its recovered binary-ID field.
Choose a view only after establishing the runtime artifact/layout. `Size` is
**total allocation bytes including payload**: a 1507 allocation can be larger
than 72 or 104 bytes, so `Size >= sizeof(later_header)` is not version detection.
Once layout identity is established, a size check is an additional field-read
bound, not a substitute for identity. The default declarations remain unchanged
for source compatibility; their later fields require this explicit runtime scope.
Successful exported/helper records in CodeIntegrity-RE retain the evidence:
- `historical/1507-export-contracts.json`:
`ev_489c3b57057b0bc5c86950d7bb4ea25108bbc7762abc363e1be7eb5cca034796`.
- `historical/ci-10240-helpers.json`:
`ev_6d602c57de9614e7c5c28b9532c139f750f0e014b151000ecb41ad36f54bf764`.
- `historical/ci-10586-exports.json`:
`ev_a09e04976cfd90e9ba69cc6618892f15c3da166c64fa9241efae0db85234fd6e`.
- `historical/ci-10586-helpers.json`:
`ev_3403d5b8bf7c322fd924880d4cd9b296b98e94238cac2e1c1e9605c4b4d27255`.
- `historical/ci-14393-contracts.json`:
`ev_e63a4c4b7613e231795051b784b9571605b9bf81258b5dcd04d32ddc681abb41`.
- `historical/ci-15063-contracts.json`:
`ev_338658fb82559fa6daa8ae5487b90fe84b8e408ea7578feed6d8dff5d590e114`.
- `historical/ci-16299-contracts.json`:
`ev_fe5731175f0726f0d46af2f78ca615d284f8598939296815e26b5589db3001cf`.
- `historical/ci-17134-contracts.json`:
`ev_0c3e3359b8b7486318006afa6b95eb2257a18abeec9041a86a32db487bcbe996`.
## Results and trust policy
Check the API's returned `NTSTATUS` first. `PolicyInfo.VerificationStatus`,
`PolicyBits`, signer details, and timestamps supply additional observations.
Successful chain processing does not imply that the caller's file digest matched
the signed digest; the comparison can occur afterward. Diagnostic policy data
may exist on failure. An extracted publisher name is display information and
does not establish publisher identity or signer trust.
Define the policy the application needs: embedded signature validation,
membership in an accepted installed catalog, an expected publisher/key, or a
Windows signing scenario. Preserve which path produced a result. A nonzero
`PolicyBits` value is not automatically failure, and any one root bit is not a
complete trust decision. File bytes and object identity must remain tied to the
bytes the application will subsequently use.
The [file-object flag document](ci-validate-file-object.md) covers `0x20`, hash
capacity, signing level, and its pending VM experiment. Other observed flag
effects on 26100.8328 x64 are:
- `0x1` selects hash scenario 5.
- Otherwise `0x2` selects scenario 4 for signing levels <=4; higher levels use
the level mapping.
- Otherwise `0x80000000` selects scenario 5 for levels <=4; higher levels use
the level mapping. It takes precedence over `0x4`.
- Otherwise `0x4` selects scenario 1; without these choices the signing level
maps to a scenario.
- `0x00400000` suppresses accepted-root bit `0x8` when the relevant helper mode
is enabled; CI can add this flag internally. Bits `0x2` and `0x8` also affect
later signing-level/EKU restrictions.
The scenarios resolve through initialized signing-policy state. Static defaults
are not a guarantee of a running system's algorithm, and the flags should not
be named as universal fixed SHA selectors. Unknown bits remain unknown. Evidence:
`CipGetHashAlgorithmForLegacyScenario`, `CipGetAcceptedRootKeys`, and
`CipMinCryptToSigningLevel` in the research bundle.
## Ownership and initialization
Zero-initialize both `MINCRYPT_POLICY_INFO` output objects before their first
use. Free both with `CiFreePolicyInfo` after use and before reuse, including
failure paths. Never call the destructor on arbitrary uninitialized stack data.
Do not clear a nonzero `Size` while a chain is still owned: the observed cleanup
helper skips an object whose `Size` is zero.
`ChainInfo` owns one allocation. Public-key blobs, names, encoded certificates,
EKUs, attributes, and chain elements are borrowed views into it. Do not free
children separately or retain them after releasing the owner. Copying the policy
structure with `memcpy` creates two aliases to one allocation, not independent
ownership. CI's internal deep-copy helper uses the total allocation size and
rebases interior pointers; Domito does not expose that helper.
The default `CiFreePolicyInfo` declaration retains its legacy `PVOID` return to
avoid a broad source compatibility change. **Ignore that value**: observed x64
assembly provides no defined pointer result. The opt-in build-specific function
pointer type uses `VOID`.
`CatalogName` is a separate `RtlDuplicateUnicodeString` allocation in the observed
catalog export. Initialize it empty, release a returned buffer with
`RtlFreeUnicodeString`, and release both policies separately. Publisher-name
storage is allocated through the caller's callback and must be released with
that allocator's matching free operation, including an allocated buffer on a
later conversion failure. It is not owned by either policy object.
Evidence: `MincryptFreePolicyInfo`, `MincryptCopyPolicyInfo`,
`I_MincryptAddChainInfo`, `CiVerifyHashInCatalog`, and `CiGetCertPublisherName`.
The additive [validation helpers](ci-validation-helpers.md) package safe result
ownership, explicit file-object selection and embedded CI verification. They do
not change raw CI declarations or existing legacy-helper behavior.
## Multiple signatures and selected results
`CiValidateFileObject` returns one selected signature result and its timestamp
policy. Those two policy outputs do not enumerate two file signatures. The
output file digest and algorithm are not expected-certificate selectors.
REA tracing of x64 CI 22621.2792 and the original 26100 sample found a
flag-dependent distinction: ordinary `0x20` can continue nested-signature
verification and retain a policy-preferred signing level. Adding `0x80` enters
an early-exit path after the first successful full candidate verification.
`0xA0` is therefore a concrete kernel experiment, not a proved stable
"select primary signature" flag: `0x80` also affects other policy/fallback paths.
An arbitrary signer index, expected-certificate predicate and continuation
interface are not exposed by these examined wrappers.
For the supplied BthPS3 fixture, host SignTool verifies a primary Nefarius
SHA-256 signature and a nested Microsoft SHA-256 signature. On both examined CI
builds, `CiCheckSignedFile` with the matching SHA-256 digest follows the primary
signature directly. This gives a CI-based alternative worth testing without
implementing RSA/ECDSA, chain or timestamp verification. A subsequent user-run
probe on Windows 11 22631 x64 with TESTSIGNING enabled confirms that `0x20`
returns Microsoft while `0xA0` and direct SHA-256 `CiCheckSignedFile` return the
Nefarius leaf and its signing time. Every top-level and signer/timestamp policy
status succeeds; the two company-signer routes have matching policy observations.
The companion `signature-selection/runtime-22631-bthps3.json` retains exact
fixture/trace identities. This does not establish TESTSIGNING-off or general
cross-build behavior. A different layout may still require bounded signature
framing/enumeration.
The companion CodeIntegrity-RE `SIGNATURE-SELECTION.md` retains fixture hashes,
56 procedure bodies, assembly, flag side effects and the kernel test plan.
The 23H2 batch is
`ev_049bd7d3aa492a9e3e4d8fcbf365ae00a6057751b26f93f3c1663c9436952ff7`;
its primary-selection helper is in
`ev_c867c73ca7eae7e4fbca2f44c6f6fb5904fb00459d0b84f2da8294b5b05a3866`.
## Digest-based verification inputs
`CiCheckSignedFile` consumes a caller-computed file digest. It does not reopen
the file or compute its Authenticode hash. On the observed build it accepts
SHA-1/256/384/512 with exactly 20/32/48/64 bytes respectively. A wrong algorithm,
length, or digest fails the final comparison.
Its signature input points to a `WIN_CERTIFICATE` header. The observed wrapper
requires 4-byte pointer alignment, supplied size >=12, revision `0x200`, type 2,
and `8 < dwLength <= supplied size`. The PKCS#7 payload begins at header+8.
The wrapper selects the first certificate-table entry. Multiple table entries
and nested signatures are separate concepts; this is not a complete signature
enumeration interface.
These exports are present in all six sampled Windows 10 x64 files and the
analyzed Windows 11 file. The older header's “Win7–8.1 only” comments described
a workflow, not verified export availability. Earlier first-available builds
and pre/post-KB3033929 ABI changes still require matching Windows 7/8 artifacts.
Import-library names and stdcall stack-byte counts alone do not settle semantics.
## Catalog controls
`ReloadCatalogs` controls catalog-store reload and related context setup.
`RequireTrustedCatalog` is a nonzero gate requiring an observed catalog extension
marker: its matching bytes include `PE`, integer `0x10001`, and `TRUSTED`.
The marker is an additional catalog condition, not proof of a Microsoft signer.
`AcceptedCatalogPolicyBits` accepts a candidate when
`(RequestedMask & Catalog.PolicyInfo.PolicyBits) != 0`: **any overlap** is enough.
It neither enables policy flags nor requires every requested bit. The existing
Domito compatibility value is named `DOMITO_CI_LEGACY_CATALOG_POLICY_BITS`
(`0x2007F`). It includes test/DMD categories and diagnostic bit `0x20000`, while
omitting other categories. It is retained as an existing behavior, not promoted
as a universally safe trust mask. Establish and test the application's accepted
signer policy before changing it.
Observed file-hash lookup supports SHA-1 and SHA-256; the internal path has no
SHA-384/512 file-hash case. Embedded-signature algorithm support and catalog
lookup support are different capabilities. Catalog-only files need an explicit,
tested algorithm strategy rather than assuming SHA-1 from an absent embedded
table. Catalog stores, caches, silo/process context, and signing policy affect
results. The new `DomitoValidateFileLegacyModeEx` forwards a caller-selected mask and
marker gate and reports embedded/catalog origin. Its compatibility wrapper retains
the existing mask. See [digest and workflow details](authenticode-digests.md).
Domito's older-Windows helper keeps its system-process attachment until
historical runtime evidence supports changing it.
Evidence: `I_FindFileOrHeaderHashInLoadedCatalogs` and its assembly
`ev_c42e7ee76099d55e7cf7cdd3d9f79e99030ba637680365612afb4906694ae3a8`,
`I_ParseCatalog`, and marker matcher
`ev_a1d3a5844a2b6be6c16175e307956c9819d0b64a4fe70216f292c12e4ea38d82`.
## Opt-in x64 26100 structure observations
The version header has distinct type names and 14 compile-time layout assertions.
Use it only after independently establishing the matching runtime build and
architecture. A large `ChainInfo->Size` alone does not identify the header: it
includes variable trailing data, so an older allocation could also be large.
Only after layout identity is established may a size check protect a field read.
- `DOMITO_CI26100_NAME_BLOB`: pointer at +0, byte length at +8, ASN.1 string tag
at +10. Names are not necessarily NUL-terminated. Observed conversion handles
UTF8String tag `0x0C` and BMPString `0x1E`; `PCHAR` in the default declaration
must not be read as a guarantee of ANSI encoding.
- `DOMITO_CI26100_CHAIN_INFO`: `Size` is total allocation bytes; fixed header is
104 bytes. Root ID at +0x34 is an opaque integer, not policy bits. The 32 bytes
at +0x48 are a platform-manifest binary ID from an authenticated attribute,
not a file digest or certificate thumbprint. Zero/nonzero does not by itself
prove trust. Require the matching layout and `Size >=104` before reading it.
- `DOMITO_CI26100_POLICY_INFO`: 48 bytes; `NotBefore`/`NotAfter` come from the
signer certificate validity fields, not an intersection of the whole chain.
Interpret `RevocationTime` only with the relevant result. A zero signing time
is not a real timestamp to display as a signing date.
Construction/copy evidence: `ev_d7110cfc711074a4af1874b5c8e701c13bcc3dc58a1596c64dca4ca98966c79e`,
`ev_858afecf2170484325379b6a8bc307fb72dad2f9a5a765169192c7363a3386af`,
`ev_f82cbee977715399323bb398781c125a9d19b4ea29acd05063ec55b711cfc670`.
## Partial policy-bit dictionary
Names in the opt-in header are Domito descriptions of observed 26100 branches,
not official Microsoft constants or a universal trusted-root enumeration.
Root/provenance categories include `0x1` self-issued terminal path, `0x2` selected
built-in Microsoft roots, `0x4` test roots, `0x8` the built-in root associated with
embedded picroot handling, `0x10` tolerated partial/unresolved chain, `0x20` DMD,
`0x40` DMD test, `0x80` another built-in Microsoft root, `0x400` flight root,
`0x2000` third-party marketplace, `0x4000` explicit supplied certificate/key
acceptance, and `0x8000` Microsoft Identity Root 2020. `0x800` and `0x1000` are
additional discriminators on some root entries; their independent meanings
remain unresolved. These categories do not establish a full trust result.
Observed diagnostic branches set `0x20000` chain failure, `0x40000` invalid
cryptographic/signature data, `0x80000` unmet EKU, `0x100000` page-hash failure,
`0x200000` revocation, `0x400000` certificate validity failure (including
not-yet-valid), `0x08000000` path-length constraints, `0x10000000` generic fallback,
and `0x20000000` CA/BasicConstraints failure. `0x04000000` marks a no-usable-
timestamp branch during revoked-certificate recovery, not universal timestamp
absence. `0x50000` and `0x60000` are observed composites; do not infer a unique
meaning for every constituent bit. Timestamp-before-revocation processing can
clear a revocation bit. Internal checks of high bits are not a replacement for
the API status and application policy.
## Remaining runtime and API coverage
The missing page-hash exports have recovered argument shapes in the research
report. Their normalized allocation uses a 24-byte x64 header and 24-byte entries
even for stronger source algorithms. Field meaning, truncation intent, source
terminal-entry handling, and a supported destructor remain open. `CiFreePolicyInfo`
is not a demonstrated destructor for that allocation. No universal page-hash SDK
or static import is added until those ownership and cross-version contracts can
be tested.
`CiGetPEInformation` is a protected-media dispatcher, not a general PE parser.
`CiInitialize` is initialization machinery. `CiSetTrustedOriginClaimId` writes a
CI global; it is not an ordinary per-file trust selector. Ordinal-only exports
and other initialization interfaces require their own evidence and callers.
Still required: complete sampled-build/ARM64 layout and parameter verification, real CI
output lifetimes and retry behavior under failures, timestamp propagation,
revocation freshness/network policy, weak-crypto selection, multiple/nested
signatures, catalog-only algorithms, and extension of the bounded digest subset to additional PE layouts.
The explicit digest helper now has local Windows SIP and real embedded-digest
comparisons; this does not close those historical or unusual-layout cases. Run the prepared probes in disposable VMs with exact OS,
CI binary, configuration, and fixture identities. Compilation and host mocks do
not close those runtime questions.