1
votes

I want to walk the certificate chain of a authenticode signed PE binary using the Windows API.

To get the certificate store I followed the example from Microsoft:
https://support.microsoft.com/en-us/help/323809/how-to-get-information-from-authenticode-signed-executables
With that I get the leaf certificate and the intermediate certificate, but not the root certificate. Tested with different Windows binaries (eg. explorer.exe)
I tried the following loops to walk the store:

while (pCertContext = CertFindCertificateInStore(hStore, ENCODING, 0, CERT_FIND_ANY, NULL, pCertContext));
while (pCertContext = CertEnumCertificatesInStore(hStore, pCertContext));

Is the root certificate not included in the authenticode signature?
Do I miss some option?

1
root cert can be in another storeRbMm
thanks RbMm, do you mean the system store? Do you know how I can find the corresponding root certificate?user2369952
why not use CertGetCertificateChainRbMm
Thanks, that's it. First look for the leaf cert, then build chain with CertGetCertificateChain. You can find the pCertContext in pChainContext->rgpChain[0]->rgpElement[i]->pCertContextuser2369952

1 Answers

0
votes

Thanks @RbMm for your suggestion with CertGetCertificateChain, that does solve my question.
To get the whole chain, you need to start at the leaf certificate (store seams to start top-down).

Adapted from https://docs.microsoft.com/de-de/windows/desktop/SecCrypto/example-c-program-creating-a-certificate-chain:

CERT_INFO CertInfo;

CertInfo.Issuer = pSignerInfo->Issuer;
CertInfo.SerialNumber = pSignerInfo->SerialNumber;

pCertContext = CertFindCertificateInStore(hStore, ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)&CertInfo, NULL);
if (!pCertContext) {
    _tprintf(_T("CertFindCertificateInStore failed with %x\n"), GetLastError());
    __leave;
}

CERT_ENHKEY_USAGE        EnhkeyUsage;
CERT_USAGE_MATCH         CertUsage;
CERT_CHAIN_PARA          ChainPara;

EnhkeyUsage.cUsageIdentifier = 0;
EnhkeyUsage.rgpszUsageIdentifier = NULL;
CertUsage.dwType = USAGE_MATCH_TYPE_AND;
CertUsage.Usage = EnhkeyUsage;
ChainPara.cbSize = sizeof(CERT_CHAIN_PARA);
ChainPara.RequestedUsage = CertUsage;

if (!CertGetCertificateChain(
    NULL,                  // use the default chain engine
    pCertContext,          // pointer to the end certificate
    NULL,                  // use the default time
    NULL,                  // search no additional stores
    &ChainPara,            // use AND logic and enhanced key usage 
                           //  as indicated in the ChainPara 
                           //  data structure
    dwFlags,
    NULL,                  // currently reserved
    &pChainContext)) {
    cerr << "Error on CertGetCertificateChain" << endl;
    __leave;
}

PCERT_SIMPLE_CHAIN    rgpChain   = NULL;
PCERT_CHAIN_ELEMENT   rgpElement = NULL;

rgpChain = pChainContext->rgpChain[0];

for (int j = 0; j < rgpChain->cElement; j++) {
    rgpElement = rgpChain->rgpElement[j];
    PrintCertificateInfo(rgpElement->pCertContext);
    cout << endl;
}