2020-09-30 17:12:32 +02:00

881 lines
29 KiB
C++

// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
// File: certtrst.cpp
// Contents: Microsoft Internet Security Provider
// Functions: WintrustCertificateTrust
// ** local functions **
// _WalkChain
// History: 07-Jun-1997 pberkman created
#include "global.hxx"
// support for MS test roots!!!!
static BYTE rgbTestRoot[] =
{
# include "certs\\mstest1.h"
};
static BYTE rgbTestRootCorrected[] =
{
# include "certs\\mstest2.h"
};
static BYTE rgbTestRootBeta1[] =
{
# include "certs\\mstestb1.h"
};
#define NTESTROOTS 3
static CERT_PUBLIC_KEY_INFO rgTestRootPublicKeyInfo[NTESTROOTS] =
{
{szOID_RSA_RSA, 0, NULL, sizeof(rgbTestRoot), rgbTestRoot, 0},
{szOID_RSA_RSA, 0, NULL, sizeof(rgbTestRootCorrected), rgbTestRootCorrected, 0},
{szOID_RSA_RSA, 0, NULL, sizeof(rgbTestRootBeta1), rgbTestRootBeta1, 0}
};
#define MAX_CERT_CHAIN 20
BOOL _WalkChain(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, DWORD *pdwError,
BOOL fCounterSigner, DWORD idxCounterSigner);
BOOL _IE4TrustWalkChain(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, DWORD *pdwError,
BOOL fCounterSigner, DWORD idxCounterSigner);
HRESULT WINAPI WintrustCertificateTrust(CRYPT_PROVIDER_DATA *pProvData)
{
if ((_ISINSTRUCT(CRYPT_PROVIDER_DATA, pProvData->cbStruct, fRecallWithState)) &&
(pProvData->fRecallWithState == TRUE))
{
return(S_OK);
}
DWORD dwError;
dwError = S_OK;
if (pProvData->csSigners < 1)
{
pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = TRUST_E_NOSIGNATURE;
return(S_FALSE);
}
if (pProvData->dwProvFlags & WTD_USE_IE4_TRUST_FLAG) {
if (pProvData->chStores == 0)
{
// signature provider didn't open them.... let's do it now!
DWORD i;
DWORD cs;
HCERTSTORE pas[WVT_STOREID_MAX];
cs = WVT_STOREID_MAX;
if (TrustOpenStores(pProvData->hProv, &cs, &pas[0], 0))
{
for (i = 0; i < cs; i++)
{
pProvData->psPfns->pfnAddStore2Chain(pProvData, pas[i]);
CertCloseStore(pas[i], 0);
}
}
}
}
// loop through all signers
for (int i = 0; i < (int)pProvData->csSigners; i++)
{
if (pProvData->pasSigners[i].csCertChain < 1)
{
pProvData->pasSigners[i].dwError = TRUST_E_NO_SIGNER_CERT;
pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = TRUST_E_NO_SIGNER_CERT;
continue;
}
if (pProvData->dwProvFlags & WTD_USE_IE4_TRUST_FLAG)
_IE4TrustWalkChain(pProvData, i, &dwError, FALSE, 0);
else
_WalkChain(pProvData, i, &dwError, FALSE, 0);
for (int i2 = 0; i2 < (int)pProvData->pasSigners[i].csCounterSigners; i2++)
{
if (pProvData->pasSigners[i].pasCounterSigners[i2].csCertChain < 1)
{
pProvData->pasSigners[i].pasCounterSigners[i2].dwError = TRUST_E_NO_SIGNER_CERT;
pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = TRUST_E_COUNTER_SIGNER;
dwError = S_FALSE;
continue;
}
if (pProvData->dwProvFlags & WTD_USE_IE4_TRUST_FLAG)
_IE4TrustWalkChain(pProvData, i, &dwError, TRUE, i2);
else
_WalkChain(pProvData, i, &dwError, TRUE, i2);
}
}
return(dwError);
}
HCERTCHAINENGINE GetChainEngine(
IN CRYPT_PROVIDER_DATA *pProvData
)
{
CERT_CHAIN_ENGINE_CONFIG Config;
HCERTSTORE hStore = NULL;
HCERTCHAINENGINE hChainEngine = NULL;
if (NULL == pProvData->pWintrustData ||
pProvData->pWintrustData->dwUnionChoice != WTD_CHOICE_CERT ||
!_ISINSTRUCT(WINTRUST_CERT_INFO,
pProvData->pWintrustData->pCert->cbStruct, dwFlags) ||
0 == (pProvData->pWintrustData->pCert->dwFlags &
(WTCI_DONT_OPEN_STORES | WTCI_OPEN_ONLY_ROOT)))
return NULL;
memset(&Config, 0, sizeof(Config));
Config.cbSize = sizeof(Config);
if (NULL == (hStore = CertOpenStore(
CERT_STORE_PROV_MEMORY,
0, // dwEncodingType
0, // hCryptProv
0, // dwFlags
NULL // pvPara
)))
goto OpenMemoryStoreError;
if (pProvData->pWintrustData->pCert->dwFlags & WTCI_DONT_OPEN_STORES)
Config.hRestrictedRoot = hStore;
Config.hRestrictedTrust = hStore;
Config.hRestrictedOther = hStore;
if (!CertCreateCertificateChainEngine(
&Config,
&hChainEngine
))
goto CreateChainEngineError;
CommonReturn:
CertCloseStore(hStore, 0);
return hChainEngine;
ErrorReturn:
hChainEngine = NULL;
goto CommonReturn;
TRACE_ERROR_EX(DBG_SS, OpenMemoryStoreError)
TRACE_ERROR_EX(DBG_SS, CreateChainEngineError)
}
HCERTSTORE GetChainAdditionalStore(
IN CRYPT_PROVIDER_DATA *pProvData
)
{
HCERTSTORE hStore = NULL;
if (0 == pProvData->chStores)
return NULL;
if (1 < pProvData->chStores) {
if (hStore = CertOpenStore(
CERT_STORE_PROV_COLLECTION,
0, // dwEncodingType
0, // hCryptProv
0, // dwFlags
NULL // pvPara
)) {
DWORD i;
for (i = 0; i < pProvData->chStores; i++)
CertAddStoreToCollection(
hStore,
pProvData->pahStores[i],
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
0 // dwPriority
);
}
} else
hStore = CertDuplicateStore(pProvData->pahStores[0]);
#if 0
CertSaveStore(
hStore,
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
CERT_STORE_SAVE_AS_STORE,
CERT_STORE_SAVE_TO_FILENAME_A,
(void *) "C:\\temp\\wintrust.sto",
0 // dwFlags
);
#endif
return hStore;
}
BOOL UpdateCertProvChain(
IN OUT PCRYPT_PROVIDER_DATA pProvData,
IN DWORD idxSigner,
OUT DWORD *pdwError,
IN BOOL fCounterSigner,
IN DWORD idxCounterSigner,
IN PCRYPT_PROVIDER_SGNR pSgnr,
IN PCCERT_CHAIN_CONTEXT pChainContext
)
{
BOOL fTestCert = FALSE;
DWORD dwSgnrError = 0;
DWORD i;
// The chain better have at least the certificate we passed in
assert(0 < pChainContext->cChain &&
0 < pChainContext->rgpChain[0]->cElement);
for (i = 0; i < pChainContext->cChain; i++) {
DWORD j;
PCERT_SIMPLE_CHAIN pChain = pChainContext->rgpChain[i];
for (j = 0; j < pChain->cElement; j++) {
PCERT_CHAIN_ELEMENT pEle = pChain->rgpElement[j];
DWORD dwEleError = pEle->TrustStatus.dwErrorStatus;
DWORD dwEleInfo = pEle->TrustStatus.dwInfoStatus;
PCRYPT_PROVIDER_CERT pProvCert;
if (0 != i || 0 != j) {
if (!(pProvData->psPfns->pfnAddCert2Chain(
pProvData, idxSigner, fCounterSigner,
idxCounterSigner, pEle->pCertContext)))
{
pProvData->dwError = GetLastError();
dwSgnrError = TRUST_E_SYSTEM_ERROR;
goto CommonReturn;
}
}
// else
// Signer cert has already been added
pProvCert = &pSgnr->pasCertChain[pSgnr->csCertChain -1];
pProvCert->fSelfSigned =
0 != (dwEleInfo & CERT_TRUST_IS_SELF_SIGNED) &&
0 == (dwEleError & CERT_TRUST_IS_NOT_SIGNATURE_VALID);
pProvCert->fTrustedRoot =
pProvCert->fSelfSigned &&
i == pChainContext->cChain - 1 &&
j == pChain->cElement - 1 &&
0 == (dwEleError & CERT_TRUST_IS_UNTRUSTED_ROOT);
if (pProvCert->fSelfSigned) {
// Check if one of the "test" roots
DWORD k;
for (k = 0; k < NTESTROOTS; k++)
{
if (CertComparePublicKeyInfo(
pProvData->dwEncoding,
&pProvCert->pCert->pCertInfo->SubjectPublicKeyInfo,
&rgTestRootPublicKeyInfo[k]))
{
pProvCert->fTestCert = TRUE;
fTestCert = TRUE;
if (pProvData->dwRegPolicySettings & WTPF_TRUSTTEST)
pProvCert->fTrustedRoot = TRUE;
break;
}
}
}
// First Element in all but the first simple chain
pProvCert->fTrustListSignerCert = (0 < i && 0 == j);
pProvCert->fIsCyclic = (0 != (dwEleError & CERT_TRUST_IS_CYCLIC));
// Map to IE4Trust confidence
if (0 == (dwEleError & CERT_TRUST_IS_NOT_SIGNATURE_VALID))
pProvCert->dwConfidence |= CERT_CONFIDENCE_SIG;
if (0 == (dwEleError & CERT_TRUST_IS_NOT_TIME_VALID))
pProvCert->dwConfidence |= CERT_CONFIDENCE_TIME;
// On Sep 10, 1998 Trevor/Brian wanted time nesting checks to
// be disabled
// if (0 == (dwEleError & CERT_TRUST_IS_NOT_TIME_NESTED))
pProvCert->dwConfidence |= CERT_CONFIDENCE_TIMENEST;
if (0 != (dwEleInfo & CERT_TRUST_HAS_EXACT_MATCH_ISSUER))
pProvCert->dwConfidence |= CERT_CONFIDENCE_AUTHIDEXT;
if (0 == (dwEleError & CERT_TRUST_IS_NOT_SIGNATURE_VALID) &&
0 != (dwEleInfo & CERT_TRUST_HAS_EXACT_MATCH_ISSUER))
pProvCert->dwConfidence |= CERT_CONFIDENCE_HYGIENE;
if (pEle->pRevocationInfo) {
assert(dwEleError & (CERT_TRUST_IS_REVOKED |
CERT_TRUST_REVOCATION_STATUS_UNKNOWN));
pProvCert->dwRevokedReason =
pEle->pRevocationInfo->dwRevocationResult;
}
// Update any signature or revocations errors
if (dwEleError & CERT_TRUST_IS_NOT_SIGNATURE_VALID) {
pProvCert->dwError = TRUST_E_CERT_SIGNATURE;
assert(pChainContext->TrustStatus.dwErrorStatus &
CERT_TRUST_IS_NOT_SIGNATURE_VALID);
dwSgnrError = TRUST_E_CERT_SIGNATURE;
} else if (dwEleError & CERT_TRUST_IS_REVOKED) {
pProvCert->dwError = CERT_E_REVOKED;
assert(pChainContext->TrustStatus.dwErrorStatus &
CERT_TRUST_IS_REVOKED);
if (0 == dwSgnrError ||
CERT_E_REVOCATION_FAILURE == dwSgnrError)
dwSgnrError = CERT_E_REVOKED;
} else if (dwEleError & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) {
pProvCert->dwError = CERT_E_REVOCATION_FAILURE;
assert(pChainContext->TrustStatus.dwErrorStatus &
CERT_TRUST_REVOCATION_STATUS_UNKNOWN);
if (0 == dwSgnrError)
dwSgnrError = CERT_E_REVOCATION_FAILURE;
}
// If last element in simple chain, check if it was in a
// CTL and update CryptProvData if it was.
if (j == pChain->cElement - 1 && pChain->pTrustListInfo &&
pChain->pTrustListInfo->pCtlContext) {
DWORD dwChainError = pChain->TrustStatus.dwErrorStatus;
// Note, don't need to AddRef since we already hold an
// AddRef on the ChainContext.
pProvCert->pCtlContext = pChain->pTrustListInfo->pCtlContext;
if (dwChainError & CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID) {
pProvCert->dwCtlError = TRUST_E_CERT_SIGNATURE;
dwSgnrError = TRUST_E_CERT_SIGNATURE;
} else if (dwChainError & CERT_TRUST_CTL_IS_NOT_TIME_VALID) {
if (0 == (pProvData->dwRegPolicySettings &
WTPF_IGNOREEXPIRATION))
pProvCert->dwCtlError = CERT_E_EXPIRED;
} else if (dwChainError &
CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE) {
pProvCert->dwCtlError = CERT_E_WRONG_USAGE;
}
}
if (pProvData->psPfns->pfnCertCheckPolicy) {
if (! (*pProvData->psPfns->pfnCertCheckPolicy)(
pProvData, idxSigner, fCounterSigner, idxCounterSigner))
goto CommonReturn;
}
}
}
CommonReturn:
if (fTestCert) {
if (CERT_TRUST_IS_REVOKED == dwSgnrError ||
CERT_E_REVOCATION_FAILURE == dwSgnrError) {
// No revocation errors for "test" roots
dwSgnrError = 0;
// Loop through certs and remove any revocation error status
for (i = 0; i < pSgnr->csCertChain; i++) {
PCRYPT_PROVIDER_CERT pProvCert = &pSgnr->pasCertChain[i];
pProvCert->dwError = 0;
pProvCert->dwRevokedReason = 0;
}
}
}
if (CERT_E_REVOCATION_FAILURE == dwSgnrError &&
pProvData->pWintrustData->fdwRevocationChecks !=
WTD_REVOKE_WHOLECHAIN)
// Will check during Final Policy
dwSgnrError = 0;
if (dwSgnrError) {
pSgnr->dwError = dwSgnrError;
pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] =
dwSgnrError;
*pdwError = S_FALSE;
return FALSE;
} else
return TRUE;
}
BOOL _WalkChain(
CRYPT_PROVIDER_DATA *pProvData,
DWORD idxSigner,
DWORD *pdwError,
BOOL fCounterSigner,
DWORD idxCounterSigner
)
{
BOOL fResult;
DWORD dwCreateChainFlags;
DWORD dwSgnrError = 0;
CRYPT_PROVIDER_SGNR *pSgnr; // not allocated
PCCERT_CONTEXT pCertContext; // not allocated
CERT_CHAIN_PARA ChainPara;
HCERTCHAINENGINE hChainEngine = NULL;
HCERTSTORE hAdditionalStore = NULL;
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
LPSTR pszUsage = NULL;
if (fCounterSigner)
pSgnr = &pProvData->pasSigners[idxSigner].pasCounterSigners[
idxCounterSigner];
else
pSgnr = &pProvData->pasSigners[idxSigner];
assert(pSgnr);
// at this stage, the last cert in the chain "should be" the signers cert.
// eg: there should only be one cert in the chain from the Signature
// Provider
if (1 != pSgnr->csCertChain ||
(NULL == (pCertContext =
pSgnr->pasCertChain[pSgnr->csCertChain - 1].pCert))) {
dwSgnrError = TRUST_E_NO_SIGNER_CERT;
goto NoSignerCertError;
}
memset(&ChainPara, 0, sizeof(ChainPara));
ChainPara.cbSize = sizeof(ChainPara);
if (fCounterSigner && SGNR_TYPE_TIMESTAMP == pSgnr->dwSignerType) {
pszUsage = szOID_PKIX_KP_TIMESTAMP_SIGNING;
} else if(NULL != pProvData->pRequestUsage) {
ChainPara.RequestedUsage = *pProvData->pRequestUsage;
} else {
pszUsage = pProvData->pszUsageOID;
}
if ( (0 == (pProvData->dwProvFlags & WTD_NO_POLICY_USAGE_FLAG)) && pszUsage) {
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
ChainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = &pszUsage;
}
hChainEngine = GetChainEngine(pProvData);
hAdditionalStore = GetChainAdditionalStore(pProvData);
dwCreateChainFlags = 0;
if (pProvData->dwProvFlags & CPD_REVOCATION_CHECK_NONE) {
;
} else if (pProvData->dwProvFlags & CPD_REVOCATION_CHECK_END_CERT) {
dwCreateChainFlags = CERT_CHAIN_REVOCATION_CHECK_END_CERT;
} else if (pProvData->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN) {
dwCreateChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN;
} else if (pProvData->dwProvFlags &
CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT) {
dwCreateChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
} else if (pProvData->dwProvFlags & WTD_REVOCATION_CHECK_NONE) {
;
} else if (pProvData->dwProvFlags & WTD_REVOCATION_CHECK_END_CERT) {
dwCreateChainFlags = CERT_CHAIN_REVOCATION_CHECK_END_CERT;
} else if (pProvData->dwProvFlags & WTD_REVOCATION_CHECK_CHAIN) {
dwCreateChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN;
} else if (pProvData->dwProvFlags &
WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT) {
dwCreateChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
} else if (pProvData->pWintrustData->fdwRevocationChecks ==
WTD_REVOKE_WHOLECHAIN) {
dwCreateChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN;
} else if (fCounterSigner && SGNR_TYPE_TIMESTAMP == pSgnr->dwSignerType) {
if (0 == (pProvData->dwRegPolicySettings & WTPF_IGNOREREVOCATIONONTS))
dwCreateChainFlags = CERT_CHAIN_REVOCATION_CHECK_END_CERT;
} else if (0 == (pProvData->dwRegPolicySettings & WTPF_IGNOREREVOKATION))
dwCreateChainFlags = CERT_CHAIN_REVOCATION_CHECK_END_CERT;
if (!(pProvData->pWintrustData->dwUnionChoice == WTD_CHOICE_CERT ||
pProvData->pWintrustData->dwUnionChoice == WTD_CHOICE_SIGNER))
// Certificate was obtained from either the message store, or one
// of our known stores
dwCreateChainFlags |= CERT_CHAIN_CACHE_END_CERT;
// else
// Can't implicitly cache a context passed to us
#if 0
{
HCERTSTORE hDebugStore;
if (hDebugStore = CertOpenSystemStoreA(0, "wintrust")) {
CertAddCertificateContextToStore(
hDebugStore,
pCertContext,
CERT_STORE_ADD_ALWAYS,
NULL
);
CertCloseStore(hDebugStore, 0);
}
}
#endif
FILETIME fileTime;
memset(&fileTime, 0, sizeof(fileTime));
if (!CertGetCertificateChain (
hChainEngine,
pCertContext,
(memcmp(&pSgnr->sftVerifyAsOf, &fileTime, sizeof(fileTime)) == 0) ?
NULL : &pSgnr->sftVerifyAsOf,
hAdditionalStore,
&ChainPara,
dwCreateChainFlags,
NULL, // pvReserved,
&pChainContext
)) {
pProvData->dwError = GetLastError();
dwSgnrError = TRUST_E_SYSTEM_ERROR;
goto GetChainError;
}
pSgnr->pChainContext = pChainContext;
if (pProvData->dwProvFlags & WTD_NO_IE4_CHAIN_FLAG) {
pProvData->dwProvFlags |= CPD_USE_NT5_CHAIN_FLAG;
fResult = TRUE;
} else
fResult = UpdateCertProvChain(
pProvData,
idxSigner,
pdwError,
fCounterSigner,
idxCounterSigner,
pSgnr,
pChainContext
);
CommonReturn:
if (hChainEngine)
CertFreeCertificateChainEngine(hChainEngine);
if (hAdditionalStore)
CertCloseStore(hAdditionalStore, 0);
return fResult;
ErrorReturn:
pSgnr->dwError = dwSgnrError;
pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] =
dwSgnrError;
*pdwError = S_FALSE;
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR_EX(DBG_SS, NoSignerCertError)
TRACE_ERROR_EX(DBG_SS, GetChainError)
}
BOOL _IE4TrustWalkChain(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, DWORD *pdwError,
BOOL fCounterSigner, DWORD idxCounterSigner)
{
CRYPT_PROVIDER_SGNR *pSgnr;
PCCERT_CONTEXT pCertContext;
DWORD cCertsOld;
DWORD dwSaveConfidence;
int cLoops;
FILETIME *psftCheckTime;
if (fCounterSigner)
{
pSgnr = &pProvData->pasSigners[idxSigner].pasCounterSigners[idxCounterSigner];
}
else
{
pSgnr = &pProvData->pasSigners[idxSigner];
}
// at this stage, the last cert in the chain "should be" the signers cert.
// eg: there should only be one cert in the chain from the Signature Provider
pCertContext = pSgnr->pasCertChain[pSgnr->csCertChain - 1].pCert;
if (!(pCertContext))
{
pSgnr->dwError = TRUST_E_NO_SIGNER_CERT;
pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = TRUST_E_NO_SIGNER_CERT;
*pdwError = S_FALSE;
return(FALSE);
}
psftCheckTime = &pSgnr->sftVerifyAsOf;
pSgnr->pasCertChain[pSgnr->csCertChain - 1].dwConfidence = 0;
if (CertVerifyTimeValidity(&pSgnr->sftVerifyAsOf, pCertContext->pCertInfo) == 0)
{
pSgnr->pasCertChain[pSgnr->csCertChain - 1].dwConfidence = CERT_CONFIDENCE_TIME;
}
// start getting issuers
cLoops = 0;
for EVER
{
// we could be in an infinite loop!
if (++cLoops > MAX_CERT_CHAIN)
{
pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = CERT_E_CHAINING;
*pdwError = S_FALSE;
return(FALSE);
}
// set if self-signed
if (TrustIsCertificateSelfSigned(pSgnr->pasCertChain[pSgnr->csCertChain - 1].pCert,
pProvData->dwEncoding,
0))
{
pSgnr->pasCertChain[pSgnr->csCertChain - 1].fSelfSigned = TRUE;
}
// is in root store
if (WTHelperIsInRootStore(pProvData, pCertContext))
{
pSgnr->pasCertChain[pSgnr->csCertChain - 1].fTrustedRoot = TRUE;
}
else
{
pSgnr->pasCertChain[pSgnr->csCertChain - 1].fTrustedRoot = FALSE;
}
// is one of our "test" certs?
for (int i = 0; i < NTESTROOTS; i++)
{
if (CertComparePublicKeyInfo(pProvData->dwEncoding,
&pCertContext->pCertInfo->SubjectPublicKeyInfo,
&rgTestRootPublicKeyInfo[i]))
{
pSgnr->pasCertChain[pSgnr->csCertChain - 1].fTestCert = TRUE;
break;
}
}
//
// call the Certificate Check Provider if applicable.
if (pProvData->psPfns->pfnCertCheckPolicy)
{
cCertsOld = pSgnr->csCertChain;
if (!(*pProvData->psPfns->pfnCertCheckPolicy)(pProvData, idxSigner,
fCounterSigner, idxCounterSigner))
{
// certificate policy says "quit"!
break;
}
if (cCertsOld != pSgnr->csCertChain)
{
// the Certificate Check Provider added a certificate. back to the
// top!
continue;
}
else if (pSgnr->pasCertChain[pSgnr->csCertChain - 1].fSelfSigned)
{
// we've called the cert policy and it said to keep going. However
// this can't be done on a self-signed cert!
break;
}
pCertContext = pSgnr->pasCertChain[pSgnr->csCertChain - 1].pCert;
}
else if (pSgnr->pasCertChain[pSgnr->csCertChain - 1].fSelfSigned)
{
// no cert check policy, and we're self-signed... get out!
break;
}
// save this one and put selected bits back later that really pertain to
// the child cert.
dwSaveConfidence = pSgnr->pasCertChain[pSgnr->csCertChain - 1].dwConfidence;
if (pSgnr->pasCertChain[pSgnr->csCertChain - 1].fTrustListSignerCert)
{
// the trust list chain must be verified using the system time.
psftCheckTime = &pProvData->sftSystemTime;
}
// find the issuer
pCertContext = TrustFindIssuerCertificate(pCertContext,
pProvData->dwEncoding,
pProvData->chStores,
pProvData->pahStores,
psftCheckTime,
&pSgnr->pasCertChain[pSgnr->csCertChain - 1].dwConfidence,
pdwError,
0);
if (!(pCertContext))
{
// no more... get out!
break;
}
if (*pdwError != ERROR_SUCCESS)
{
pSgnr->pasCertChain[pSgnr->csCertChain - 1].dwError = *pdwError;
pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = *pdwError;
}
// add to our chain...
if (!(pProvData->psPfns->pfnAddCert2Chain(pProvData, idxSigner, fCounterSigner,
idxCounterSigner, pCertContext)))
{
pProvData->dwError = GetLastError();
pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = TRUST_E_SYSTEM_ERROR;
CertFreeCertificateContext(pCertContext);
*pdwError = S_FALSE;
return(FALSE);
}
CertFreeCertificateContext(pCertContext);
// assign the bits from the child (csCertChain - 2) that
// pertain to the issuer (csCertChain = 1)
if (pSgnr->pasCertChain[pSgnr->csCertChain - 2].dwConfidence & CERT_CONFIDENCE_TIME)
{
pSgnr->pasCertChain[pSgnr->csCertChain - 1].dwConfidence |= CERT_CONFIDENCE_TIME;
}
else
{
pSgnr->pasCertChain[pSgnr->csCertChain - 1].dwConfidence &= ~(CERT_CONFIDENCE_TIME);
}
// reset the bits that we saved of the childs (csCertChain - 2)
if (dwSaveConfidence & CERT_CONFIDENCE_TIME)
{
pSgnr->pasCertChain[pSgnr->csCertChain - 2].dwConfidence |= CERT_CONFIDENCE_TIME;
}
else
{
pSgnr->pasCertChain[pSgnr->csCertChain - 2].dwConfidence &= ~(CERT_CONFIDENCE_TIME);
}
// assign it again... because the addcert2chain does a dup and the cert check policy
// could have added another....
pCertContext = pSgnr->pasCertChain[pSgnr->csCertChain - 1].pCert;
} // end of for EVER.
// check application requested revocation checks....
if (pProvData->pWintrustData->fdwRevocationChecks != WTD_REVOKE_WHOLECHAIN)
{
return(TRUE);
}
// no revokation checking on test certs!
for (int i2 = 0; i2 < (int)pSgnr->csCertChain; i2++)
{
if (pSgnr->pasCertChain[i2].fTestCert)
{
return(TRUE);
}
}
CERT_REVOCATION_PARA sRevPara;
CERT_REVOCATION_STATUS sRevStatus;
PCERT_CONTEXT *papsCertContext;
if (!(papsCertContext = (PCERT_CONTEXT *)pProvData->psPfns->pfnAlloc(sizeof(PCERT_CONTEXT) *
pSgnr->csCertChain)))
{
pProvData->dwError = GetLastError();
pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = TRUST_E_SYSTEM_ERROR;
*pdwError = S_FALSE;
return(FALSE);
}
for (int i = 0; i < (int)pSgnr->csCertChain; i++)
{
papsCertContext[i] = (PCERT_CONTEXT)pSgnr->pasCertChain[i].pCert;
}
memset(&sRevPara, 0x00, sizeof(CERT_REVOCATION_PARA));
sRevPara.cbSize = sizeof(CERT_REVOCATION_PARA);
memset(&sRevStatus, 0x00, sizeof(CERT_REVOCATION_STATUS));
sRevStatus.cbSize = sizeof(CERT_REVOCATION_STATUS);
if (!(CertVerifyRevocation(pProvData->dwEncoding,
CERT_CONTEXT_REVOCATION_TYPE,
pSgnr->csCertChain,
(void **)papsCertContext,
CERT_VERIFY_REV_CHAIN_FLAG,
&sRevPara,
&sRevStatus)))
{
pProvData->psPfns->pfnFree(papsCertContext);
pSgnr->pasCertChain[sRevStatus.dwIndex].dwRevokedReason = sRevStatus.dwReason;
switch(sRevStatus.dwError)
{
case CRYPT_E_REVOKED:
pSgnr->pasCertChain[sRevStatus.dwIndex].dwError = CERT_E_REVOKED;
pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = CERT_E_REVOKED;
return(FALSE);
}
pSgnr->pasCertChain[sRevStatus.dwIndex].dwError = CERT_E_REVOCATION_FAILURE;
pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = CERT_E_REVOCATION_FAILURE;
return(FALSE);
}
pProvData->psPfns->pfnFree(papsCertContext);
return(TRUE);
}