97 lines
4.1 KiB
C++
97 lines
4.1 KiB
C++
// Host tests validate the probe plumbing, NOT CI trust behavior.
|
|
#define WIN32_NO_STATUS
|
|
#include <windows.h>
|
|
#undef WIN32_NO_STATUS
|
|
#include <ntstatus.h>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include "ci-probe-constants.inc"
|
|
#define NT_SUCCESS(s) (((NTSTATUS)(s)) >= 0)
|
|
#define DOMITO_CI_PROBE_HOST_TEST
|
|
typedef void* PFILE_OBJECT;
|
|
struct MINCRYPT_POLICY_INFO {
|
|
ULONG Size, VerificationStatus, PolicyBits;
|
|
void* ChainInfo;
|
|
};
|
|
static unsigned calls, frees, outstanding, checks;
|
|
static bool failureMode;
|
|
static int fileToken, chainToken;
|
|
static void Check(bool value, const char* label)
|
|
{
|
|
++checks;
|
|
if (!value) { std::fprintf(stderr, "FAIL: %s\n", label); std::exit(1); }
|
|
}
|
|
static NTSTATUS CiValidateFileObject(PFILE_OBJECT file, ULONG flags, ULONG level,
|
|
MINCRYPT_POLICY_INFO* policy, MINCRYPT_POLICY_INFO* timestamp,
|
|
LARGE_INTEGER* time, UCHAR* hash, UINT32* size, ALG_ID* algorithm)
|
|
{
|
|
const ULONG expectedFlags[] = {0, 0x20, 0x20, 0, 0, 0x20};
|
|
Check(calls < 6 && flags == expectedFlags[calls], "paired flags and order");
|
|
Check(file == &fileToken && level == 0, "same file and level zero");
|
|
Check(outstanding == 0, "previous outputs freed before next call");
|
|
Check(policy->Size == sizeof(*policy) && timestamp->Size == sizeof(*timestamp), "policy sizes");
|
|
Check(!policy->ChainInfo && !timestamp->ChainInfo && !policy->PolicyBits &&
|
|
!timestamp->PolicyBits, "fresh policy objects");
|
|
Check(*size == (calls < 4 ? 64u : 63u), "capacity reset for every call");
|
|
Check(*algorithm == 0 && time->QuadPart == 0, "fresh scalar outputs");
|
|
for (unsigned i = 0; i < 64; ++i) Check(hash[i] == 0, "fresh hash buffer");
|
|
++calls;
|
|
if (*size < 64) { *size = 64; return STATUS_BUFFER_TOO_SMALL; }
|
|
policy->ChainInfo = timestamp->ChainInfo = &chainToken;
|
|
outstanding = 2;
|
|
policy->PolicyBits = 0xA5;
|
|
timestamp->PolicyBits = 0x5A;
|
|
policy->VerificationStatus = failureMode ? STATUS_INVALID_IMAGE_HASH : STATUS_SUCCESS;
|
|
timestamp->VerificationStatus = STATUS_SUCCESS;
|
|
// Also allocate on simulated failure to exercise unconditional cleanup.
|
|
if (failureMode) return STATUS_INVALID_IMAGE_HASH;
|
|
std::memset(hash, 0xCC, 32);
|
|
*size = 32;
|
|
*algorithm = 0x800C;
|
|
time->QuadPart = 123;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
static void CiFreePolicyInfo(MINCRYPT_POLICY_INFO* policy)
|
|
{
|
|
++frees;
|
|
if (policy->ChainInfo) { Check(outstanding > 0, "owned chain"); --outstanding; }
|
|
*policy = {};
|
|
}
|
|
#include "ci-file-object-probe.cpp"
|
|
|
|
int main()
|
|
{
|
|
for (unsigned pass = 0; pass < 2; ++pass)
|
|
{
|
|
failureMode = pass != 0;
|
|
calls = frees = outstanding = 0;
|
|
DOMITO_CI_PROBE_RESULT results[DOMITO_CI_PROBE_RESULT_COUNT];
|
|
std::memset(results, 0xFF, sizeof(results));
|
|
DomitoProbeCiValidateFileObject(&fileToken, results);
|
|
Check(calls == 6 && frees == 12 && outstanding == 0, "all calls and frees");
|
|
for (unsigned i = 0; i < 6; ++i)
|
|
{
|
|
const auto& r = results[i];
|
|
Check(r.HashGuardIntact, "buffer guard");
|
|
const NTSTATUS expected = i >= 4 ? STATUS_BUFFER_TOO_SMALL :
|
|
failureMode ? STATUS_INVALID_IMAGE_HASH : STATUS_SUCCESS;
|
|
Check(r.Status == expected, "status preserved");
|
|
if (i < 4) {
|
|
Check(r.PolicyBits == 0xA5 && r.TimeStampPolicyBits == 0x5A, "policy capture");
|
|
Check(r.HasChain && r.HasTimeStampChain, "chain presence captured before free");
|
|
}
|
|
if (NT_SUCCESS(r.Status)) {
|
|
Check(r.HashSize == 32 && r.HashAlgId == 0x800C && r.SigningTime.QuadPart == 123,
|
|
"digest metadata and signing time");
|
|
for (unsigned j = 0; j < 64; ++j)
|
|
Check(r.Hash[j] == (j < 32 ? 0xCC : 0), "digest copied and tail cleared");
|
|
} else {
|
|
for (auto byte : r.Hash) Check(byte == 0, "no digest from failed call");
|
|
}
|
|
if (i >= 4) Check(r.HashSize == 64, "required capacity captured");
|
|
}
|
|
}
|
|
std::printf("PASS: %u probe checks (mock CI; no runtime trust validation)\n", checks);
|
|
}
|