|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: certtrst.cpp
//
// Contents: Microsoft Internet Security Provider
//
// Functions: WintrustCertificateTrust
//
// *** local functions ***
// _WalkChain
// _IsLifetimeSigningCert
//
// 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} };
BOOL _WalkChain( CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, DWORD *pdwError, BOOL fCounterSigner, DWORD idxCounterSigner, BOOL fTimeStamped, BOOL *pfLifetimeSigning // IN OUT, only accessed for fTimeStamped
);
BOOL WINAPI _IsLifetimeSigningCert( PCCERT_CONTEXT pCertContext );
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); }
//
// loop through all signers
//
for (int i = 0; i < (int)pProvData->csSigners; i++) { BOOL fTimeStamped = FALSE; BOOL fLifetimeSigning = FALSE;
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; }
// Check if timestamped.
if (0 < pProvData->pasSigners[i].csCounterSigners && (pProvData->pasSigners[i].pasCounterSigners[0].dwSignerType & SGNR_TYPE_TIMESTAMP)) { fTimeStamped = TRUE;
// See if LifeTime Signing has been enabled
if (pProvData->dwProvFlags & WTD_LIFETIME_SIGNING_FLAG) { fLifetimeSigning = TRUE; } else { // Check if the signer certificate has the LIFETIME_SIGNING
// EKU.
fLifetimeSigning = _IsLifetimeSigningCert( pProvData->pasSigners[i].pasCertChain[0].pCert); } }
_WalkChain(pProvData, i, &dwError, FALSE, 0, fTimeStamped, &fLifetimeSigning);
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 lifetime signing has been enabled, use current time instead
// of timestamp time.
if (fLifetimeSigning) { memcpy(&pProvData->pasSigners[i].pasCounterSigners[i2].sftVerifyAsOf, &pProvData->sftSystemTime, sizeof(FILETIME)); }
_WalkChain(pProvData, i, &dwError, TRUE, i2, FALSE, NULL); } }
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; }
// Following is in ..\softpub\callui.cpp
extern HRESULT _CheckTrustedCodeHash(CRYPT_PROVIDER_DATA *pProvData);
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];
//DSIE: 12-Oct-2000 added to get pChainElement.
pProvCert->pChainElement = pEle;
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) { 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; #if 0
// On 8-April-2002 removed the following. Revocation checking
// is no longer done for partial chains.
//
// Also, this was only set for WTD_REVOKE_WHOLECHAIN.
} else if (dwEleError & CERT_TRUST_IS_OFFLINE_REVOCATION) { // Ignore NO_CHECK errors
if (pProvData->pWintrustData->fdwRevocationChecks == WTD_REVOKE_WHOLECHAIN) { pProvCert->dwError = CERT_E_REVOCATION_FAILURE; assert(pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_REVOCATION_STATUS_UNKNOWN); if (0 == dwSgnrError) dwSgnrError = CERT_E_REVOCATION_FAILURE; } #endif
}
// 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 (CERT_E_REVOKED == dwSgnrError) { if (S_OK == _CheckTrustedCodeHash(pProvData)) { // The code was explicitly trusted.
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 fTimeStamped, BOOL *pfLifetimeSigning // IN OUT, only accessed for fTimeStamped
) { 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)) // On 4-12-01 changed from END_CERT to EXCLUDE_ROOT
dwCreateChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; } else if (0 == (pProvData->dwRegPolicySettings & WTPF_IGNOREREVOKATION)) // On 4-12-01 changed from END_CERT to EXCLUDE_ROOT
dwCreateChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
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 (pProvData->dwProvFlags & WTD_CACHE_ONLY_URL_RETRIEVAL) { dwCreateChainFlags |= CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL | CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY; }
#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 (fTimeStamped && *pfLifetimeSigning) dwCreateChainFlags |= CERT_CHAIN_TIMESTAMP_TIME;
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; }
if (fTimeStamped && !*pfLifetimeSigning) { // See if resultant application policy has the LIFETIME_SIGNING OID
PCERT_ENHKEY_USAGE pAppUsage = pChainContext->rgpChain[0]->rgpElement[0]->pApplicationUsage;
if (pAppUsage) { DWORD i;
for (i = 0; i < pAppUsage->cUsageIdentifier; i++) { if (0 == strcmp(pAppUsage->rgpszUsageIdentifier[i], szOID_KP_LIFETIME_SIGNING)) { *pfLifetimeSigning = TRUE; break; } } }
if (*pfLifetimeSigning) { CertFreeCertificateChain(pChainContext); pChainContext = NULL; dwCreateChainFlags |= CERT_CHAIN_TIMESTAMP_TIME;
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 WINAPI _IsLifetimeSigningCert( PCCERT_CONTEXT pCertContext ) { DWORD cbSize; PCERT_ENHKEY_USAGE pCertEKU;
//
// see if the certificate has the proper enhanced key usage OID
//
cbSize = 0;
CertGetEnhancedKeyUsage(pCertContext, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &cbSize);
if (cbSize == 0) { return(FALSE); }
if (!(pCertEKU = (PCERT_ENHKEY_USAGE)new BYTE[cbSize])) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(FALSE); }
if (!(CertGetEnhancedKeyUsage(pCertContext, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pCertEKU, &cbSize))) { delete pCertEKU; return(FALSE); }
for (int i = 0; i < (int)pCertEKU->cUsageIdentifier; i++) { if (strcmp(pCertEKU->rgpszUsageIdentifier[i], szOID_KP_LIFETIME_SIGNING) == 0) { delete pCertEKU; return(TRUE); } }
delete pCertEKU;
return(FALSE); }
|