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.
6.1 KiB
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.
DomitoCiSignatureSelectionNativeforwards 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.DomitoCiSignatureSelectionFirstSuccessfulExperimentaladditionally setsDOMITO_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.
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. 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.
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: 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. Structure/chain interpretation remains subject to the mincrypt contracts.
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.