Add CI validation helpers with explicit signature selection and owned results
This commit is contained in:
1 parent
28f284be8f
commit
1f4d62ae95
13 files changed
+596
-3
No files matched your search
@@ -0,0 +1,116 @@
|
||||
# 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.
|
||||
Reference in new issue
Block a user