I'm trying to verify that the certificate from a signature chains back to a particular root certificate, which is not trusted by Windows (it's a private certificate for the app).
My current attempt to do this involves creating a chaining engine which only trusts the specific certificate I want as the root, so that no other chains can be generated.
HCERTSTORE hPrivateRootStore = CertOpenStore(CERT_STORE_PROV_FILENAME, dwEncoding,
NULL, CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG,
_T("C:\\Test\\PrivateRoot.cer"));
CERT_CHAIN_ENGINE_CONFIG config;
memset(&config, 0, sizeof(config));
config.cbSize = sizeof(config);
config.hRestrictedTrust = hPrivateRootStore;
config.dwFlags = CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL | CERT_CHAIN_ENABLE_SHARE_STORE;
HCERTCHAINENGINE hEngine;
CertCreateCertificateChainEngine(&config, &hEngine);
CERT_CHAIN_PARA params;
memset(¶ms, 0, sizeof(params));
params.cbSize = sizeof(params);
PCCERT_CHAIN_CONTEXT chains = NULL;
if (CertGetCertificateChain(hEngine, pCertContext, NULL, hStore, ¶ms,
0, NULL, &chains))
...
(error checking omitted for clarity; pCertContext
and hStore
came from CryptQueryObject
extracting the signature and related certificates from a signed binary file.)
Unfortunately, this doesn't seem to work; despite using a custom chaining engine it still seems to be searching the OS store, and either doesn't find a chain or finds one to a different root (which is trusted by the OS). I can only get the chain I want by adding my private root certificate to the OS trusted store.
I've also tried setting config.hRestrictedOther
to an empty memory store, since the docs suggest that having hRestrictedTrust
non-NULL will bring in the system stores again, but that doesn't make any difference.
Is there something I'm missing, or a better way to do this?
Edit: just to give a bit more context, I'm trying to do something similar to the driver signing certificates, where the signing certificate chains back to two different roots: one standard CA root trusted by the OS and one internal root (which in drivers is also trusted by the OS but in my case will only be trusted by my app). The cross occurs somewhere mid-way up the "main" chain; there could potentially be a number of different files all signed with different "real" CAs but still chained back to my internal certificate.
hExclusiveRoot
member added toCERT_CHAIN_ENGINE_CONFIG
in Win7. I think the associated description makes it clear thatCertCreateCertificateChainEngine
doesn't provide any mechanism to ignore the system stores in older versions (which makes me wonder what the heck it's actually for, but that's a separate issue). So, new question: is there some other way to enumerate possible chains back to my desired root? Something compatible withCertVerifyCertificateChainPolicy
would be nice, although I can probably live without it if need be. - MiralPCCERT_CONTEXT
. - Miral