Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

747 lines
24 KiB

//+-------------------------------------------------------------------------
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1999 - 1999
//
// File: rootlist.cpp
//
// Contents: Signed List of Trusted Roots Helper Functions
//
//
// Functions: I_CertVerifySignedListOfTrustedRoots
//
// History: 01-Aug-99 philh created
//--------------------------------------------------------------------------
#include <windows.h>
#include <assert.h>
#include "wincrypt.h"
#include "wintrust.h"
#include "softpub.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <time.h>
#include "dbgdef.h"
#include "rootlist.h"
#ifdef STATIC
#undef STATIC
#endif
#define STATIC
#define SHA1_HASH_LEN 20
//+-------------------------------------------------------------------------
// SHA1 Key Identifier of the signer's root
//--------------------------------------------------------------------------
STATIC BYTE rgbSignerRootKeyId[SHA1_HASH_LEN] = {
#if 1
// The following is the sha1 key identifier for the Microsoft root
0x4A, 0x5C, 0x75, 0x22, 0xAA, 0x46, 0xBF, 0xA4, 0x08, 0x9D,
0x39, 0x97, 0x4E, 0xBD, 0xB4, 0xA3, 0x60, 0xF7, 0xA0, 0x1D
#else
// The following is the sha1 key identifier for the test root
0x9A, 0xA6, 0x58, 0x7F, 0x94, 0xDD, 0x91, 0xD9, 0x1E, 0x63,
0xDF, 0xD3, 0xF0, 0xCE, 0x5F, 0xAE, 0x18, 0x93, 0xAA, 0xB7
#endif
};
//+-------------------------------------------------------------------------
// If the certificate has an EKU extension, returns an allocated and
// decoded EKU. Otherwise, returns NULL.
//
// LocalFree() must be called to free the returned EKU.
//--------------------------------------------------------------------------
STATIC
PCERT_ENHKEY_USAGE
WINAPI
GetAndAllocCertEKUExt(
IN PCCERT_CONTEXT pCert
)
{
PCERT_ENHKEY_USAGE pUsage = NULL;
DWORD cbUsage;
cbUsage = 0;
if (!CertGetEnhancedKeyUsage(
pCert,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
NULL, // pUsage
&cbUsage) || 0 == cbUsage)
goto GetEnhancedKeyUsageError;
if (NULL == (pUsage = (PCERT_ENHKEY_USAGE) LocalAlloc(LPTR, cbUsage)))
goto OutOfMemory;
if (!CertGetEnhancedKeyUsage(
pCert,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
pUsage,
&cbUsage))
goto GetEnhancedKeyUsageError;
CommonReturn:
return pUsage;
ErrorReturn:
if (pUsage) {
LocalFree(pUsage);
pUsage = NULL;
}
goto CommonReturn;
SET_ERROR(GetEnhancedKeyUsageError, CERT_E_WRONG_USAGE)
SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
}
//+-------------------------------------------------------------------------
// The signature of the CTL is verified. The signer of the CTL is verified
// up to a trusted root containing the predefined Microsoft public key.
// The signer and intermediate certificates must have the
// szOID_ROOT_LIST_SIGNER enhanced key usage extension.
//
// For success, *ppSignerCert is updated with certificate context of the
// signer.
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
GetAndVerifyTrustedRootsSigner(
IN HCRYPTMSG hCryptMsg,
IN HCERTSTORE hMsgStore,
OUT PCCERT_CONTEXT *ppSignerCert
)
{
BOOL fResult;
LONG lStatus;
PCCERT_CONTEXT pSignerCert = NULL;
GUID wvtCertActionID = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
WINTRUST_CERT_INFO wvtCertInfo;
WINTRUST_DATA wvtData;
BOOL fCloseWVT = FALSE;
DWORD dwLastError = 0;
CRYPT_PROVIDER_DATA *pProvData; // not allocated
CRYPT_PROVIDER_SGNR *pProvSigner; // not allocated
CRYPT_PROVIDER_CERT *pProvCert; // not allocated
DWORD idxCert;
PCCERT_CONTEXT pCert; // not refCount'ed
PCERT_ENHKEY_USAGE pUsage = NULL;
BYTE rgbKeyId[SHA1_HASH_LEN];
DWORD cbKeyId;
if (!CryptMsgGetAndVerifySigner(
hCryptMsg,
0, // cSignerStore
NULL, // rghSignerStore
0, // dwFlags
&pSignerCert,
NULL // pdwSignerIndex
))
goto CryptMsgGetAndVerifySignerError;
memset(&wvtCertInfo, 0, sizeof(wvtCertInfo));
wvtCertInfo.cbStruct = sizeof(wvtCertInfo);
wvtCertInfo.psCertContext = (PCERT_CONTEXT) pSignerCert;
wvtCertInfo.chStores = 1;
wvtCertInfo.pahStores = &hMsgStore;
wvtCertInfo.dwFlags = 0;
wvtCertInfo.pcwszDisplayName = L"";
memset(&wvtData, 0, sizeof(wvtData));
wvtData.cbStruct = sizeof(wvtData);
wvtData.pPolicyCallbackData = (void *) szOID_ROOT_LIST_SIGNER;
wvtData.dwUIChoice = WTD_UI_NONE;
wvtData.fdwRevocationChecks = WTD_REVOKE_NONE;
wvtData.dwUnionChoice = WTD_CHOICE_CERT;
wvtData.pCert = &wvtCertInfo;
wvtData.dwStateAction = WTD_STATEACTION_VERIFY;
wvtData.hWVTStateData = NULL;
wvtData.dwProvFlags = 0;
lStatus = WinVerifyTrust(
NULL, // hwnd
&wvtCertActionID,
&wvtData
);
#if (0) // DSIE
if (ERROR_SUCCESS != lStatus)
goto WinVerifyTrustError;
else
fCloseWVT = TRUE;
#else
if (ERROR_SUCCESS != lStatus && CERT_E_REVOCATION_FAILURE != lStatus)
goto WinVerifyTrustError;
else
fCloseWVT = TRUE;
#endif
if (NULL == (pProvData = WTHelperProvDataFromStateData(
wvtData.hWVTStateData)))
goto NoProvDataError;
if (0 == pProvData->csSigners)
goto NoProvSignerError;
if (NULL == (pProvSigner = WTHelperGetProvSignerFromChain(
pProvData,
0, // idxSigner
FALSE, // fCounterSigner
0 // idxCounterSigner
)))
goto NoProvSignerError;
if (2 > pProvSigner->csCertChain)
goto MissingSignerCertsError;
// Check that the top level certificate contains the public
// key for the Microsoft root.
pProvCert = WTHelperGetProvCertFromChain(pProvSigner,
pProvSigner->csCertChain - 1);
if (NULL == pProvCert)
goto UnexpectedError;
pCert = pProvCert->pCert;
cbKeyId = SHA1_HASH_LEN;
if (!CryptHashPublicKeyInfo(
NULL, // hCryptProv
CALG_SHA1,
0, // dwFlags
X509_ASN_ENCODING,
&pCert->pCertInfo->SubjectPublicKeyInfo,
rgbKeyId,
&cbKeyId
))
goto HashPublicKeyInfoError;
if (SHA1_HASH_LEN != cbKeyId ||
0 != memcmp(rgbSignerRootKeyId, rgbKeyId, SHA1_HASH_LEN))
goto InvalidSignerRootError;
// Check that the signer and intermediate certs have the RootListSigner
// Usage extension
for (idxCert = 0; idxCert < pProvSigner->csCertChain - 1; idxCert++) {
DWORD i;
pProvCert = WTHelperGetProvCertFromChain(pProvSigner, idxCert);
if (NULL == pProvCert)
goto UnexpectedError;
pCert = pProvCert->pCert;
pUsage = GetAndAllocCertEKUExt(pCert);
if (NULL == pUsage)
goto GetAndAllocCertEKUExtError;
for (i = 0; i < pUsage->cUsageIdentifier; i++) {
if (0 == strcmp(szOID_ROOT_LIST_SIGNER,
pUsage->rgpszUsageIdentifier[i]))
break;
}
if (i == pUsage->cUsageIdentifier)
goto MissingTrustListSignerUsageError;
LocalFree(pUsage);
pUsage = NULL;
}
fResult = TRUE;
CommonReturn:
if (fCloseWVT) {
wvtData.dwStateAction = WTD_STATEACTION_CLOSE;
lStatus = WinVerifyTrust(
NULL, // hwnd
&wvtCertActionID,
&wvtData
);
}
if (pUsage)
LocalFree(pUsage);
SetLastError(dwLastError);
*ppSignerCert = pSignerCert;
return fResult;
ErrorReturn:
dwLastError = GetLastError();
if (pSignerCert) {
CertFreeCertificateContext(pSignerCert);
pSignerCert = NULL;
}
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(CryptMsgGetAndVerifySignerError)
SET_ERROR_VAR(WinVerifyTrustError, lStatus)
SET_ERROR(NoProvDataError, E_UNEXPECTED)
SET_ERROR(NoProvSignerError, TRUST_E_NO_SIGNER_CERT)
SET_ERROR(MissingSignerCertsError, CERT_E_CHAINING)
SET_ERROR(UnexpectedError, E_UNEXPECTED)
TRACE_ERROR(HashPublicKeyInfoError)
SET_ERROR(InvalidSignerRootError, CERT_E_UNTRUSTEDROOT)
TRACE_ERROR(GetAndAllocCertEKUExtError)
SET_ERROR(MissingTrustListSignerUsageError, CERT_E_WRONG_USAGE)
}
//+-------------------------------------------------------------------------
// Returns TRUE if all the CTL fields are valid. Checks for the following:
// - There is at least one SubjectUsage (really the roots enhanced key usage)
// - If NextUpdate isn't NULL, that the CTL is still time valid
// - Only allow roots identified by their sha1 hash
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
VerifyTrustedRootsCtlFields(
IN PCTL_INFO pCtlInfo
)
{
BOOL fResult;
// Must have a least one usage
if (0 == pCtlInfo->SubjectUsage.cUsageIdentifier)
goto NoSubjectUsageError;
// If NextUpdate is present, verify that the CTL hasn't expired.
if (pCtlInfo->NextUpdate.dwLowDateTime ||
pCtlInfo->NextUpdate.dwHighDateTime) {
SYSTEMTIME SystemTime;
FILETIME FileTime;
GetSystemTime(&SystemTime);
SystemTimeToFileTime(&SystemTime, &FileTime);
if (CompareFileTime(&FileTime, &pCtlInfo->NextUpdate) > 0)
goto ExpiredCtlError;
}
// Only allow roots identified by their sha1 hash
if (0 != strcmp(szOID_OIWSEC_sha1,
pCtlInfo->SubjectAlgorithm.pszObjId))
goto InvalidSubjectAlgorithm;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(NoSubjectUsageError, ERROR_INVALID_DATA)
SET_ERROR(ExpiredCtlError, CERT_E_EXPIRED)
SET_ERROR(InvalidSubjectAlgorithm, ERROR_INVALID_DATA)
}
//+-------------------------------------------------------------------------
// Returns TRUE if all the known extensions are valid and there aren't any
// unknown critical extensions.
//
// We know about the following extensions:
// - szOID_ENHANCED_KEY_USAGE - if present, must contain
// szOID_ROOT_LIST_SIGNER usage
// - szOID_REMOVE_CERTIFICATE - integer value, 0 => FALSE (add)
// 1 => TRUE (remove), all other values are invalid
// - szOID_CERT_POLICIES - ignored
//
// If szOID_REMOVE_CERTIFICATE is present, then, *pfRemoveRoots is updated.
// Otherwise, *pfRemoveRoots defaults to FALSE.
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
VerifyTrustedRootsCtlExtensions(
IN PCTL_INFO pCtlInfo,
OUT BOOL *pfRemoveRoots
)
{
BOOL fResult;
PCERT_EXTENSION pExt;
DWORD cExt;
PCERT_ENHKEY_USAGE pUsage = NULL;
DWORD cbRemoveRoots;
*pfRemoveRoots = FALSE;
// Verify the extensions
for (cExt = pCtlInfo->cExtension,
pExt = pCtlInfo->rgExtension; 0 < cExt; cExt--, pExt++) {
if (0 == strcmp(szOID_ENHANCED_KEY_USAGE, pExt->pszObjId)) {
DWORD cbUsage;
DWORD i;
// Check for szOID_ROOT_LIST_SIGNER usage
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_ENHANCED_KEY_USAGE,
pExt->Value.pbData,
pExt->Value.cbData,
0, // dwFlags
NULL, // pvStructInfo
&cbUsage
))
goto DecodeEnhancedKeyUsageExtError;
if (NULL == (pUsage = (PCERT_ENHKEY_USAGE) LocalAlloc(
LPTR, cbUsage)))
goto OutOfMemory;
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_ENHANCED_KEY_USAGE,
pExt->Value.pbData,
pExt->Value.cbData,
0, // dwFlags
pUsage,
&cbUsage
))
goto DecodeEnhancedKeyUsageExtError;
for (i = 0; i < pUsage->cUsageIdentifier; i++) {
if (0 == strcmp(szOID_ROOT_LIST_SIGNER,
pUsage->rgpszUsageIdentifier[i]))
break;
}
if (i == pUsage->cUsageIdentifier)
goto MissingTrustListSignerUsageInExtError;
LocalFree(pUsage);
pUsage = NULL;
} else if (0 == strcmp(szOID_REMOVE_CERTIFICATE, pExt->pszObjId)) {
int iVal;
DWORD cbVal;
cbVal = sizeof(iVal);
iVal = 0;
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_INTEGER,
pExt->Value.pbData,
pExt->Value.cbData,
0, // dwFlags
&iVal,
&cbVal
))
goto DecodeRemoveCertificateExtError;
switch(iVal) {
case 0:
*pfRemoveRoots = FALSE;
break;
case 1:
*pfRemoveRoots = TRUE;
break;
default:
goto InvalidRemoveCertificateExtValueError;
}
} else if (0 == strcmp(szOID_CERT_POLICIES, pExt->pszObjId)) {
;
} else if (pExt->fCritical) {
goto UnknownCriticalExtensionError;
}
}
fResult = TRUE;
CommonReturn:
if (pUsage)
LocalFree(pUsage);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(DecodeEnhancedKeyUsageExtError)
SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
SET_ERROR(MissingTrustListSignerUsageInExtError, ERROR_INVALID_DATA)
TRACE_ERROR(DecodeRemoveCertificateExtError)
SET_ERROR(InvalidRemoveCertificateExtValueError, ERROR_INVALID_DATA)
SET_ERROR(UnknownCriticalExtensionError, ERROR_INVALID_DATA)
}
//+-------------------------------------------------------------------------
// Returns TRUE, if a sha1 entry exists in the CTL for the certificate
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
IsTrustedRoot(
IN PCTL_INFO pCtlInfo,
IN PCCERT_CONTEXT pCert
)
{
BOOL fResult = FALSE;
BYTE rgbSha1Hash[SHA1_HASH_LEN];
DWORD cbSha1Hash;
DWORD cEntry;
PCTL_ENTRY pEntry; // not allocated
cbSha1Hash = SHA1_HASH_LEN;
if (!CertGetCertificateContextProperty(
pCert,
CERT_SHA1_HASH_PROP_ID,
rgbSha1Hash,
&cbSha1Hash
))
goto GetSha1HashError;
for (cEntry = pCtlInfo->cCTLEntry,
pEntry = pCtlInfo->rgCTLEntry; 0 < cEntry; cEntry--, pEntry++) {
if (SHA1_HASH_LEN == pEntry->SubjectIdentifier.cbData &&
0 == memcmp(rgbSha1Hash, pEntry->SubjectIdentifier.pbData,
SHA1_HASH_LEN)) {
fResult = TRUE;
break;
}
}
CommonReturn:
return fResult;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(GetSha1HashError)
}
//+-------------------------------------------------------------------------
// Checks if the certificate has an EKU extension and if all of the
// cert's usages are within the specified list of usages.
//
// Returns TRUE if the above two conditions are satisfied.
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
IsValidCertEKUExtSubset(
IN PCCERT_CONTEXT pCert,
PCERT_ENHKEY_USAGE pValidUsage
)
{
PCERT_ENHKEY_USAGE pCertUsage = NULL;
BOOL fResult = FALSE;
DWORD i, j;
pCertUsage = GetAndAllocCertEKUExt(pCert);
if (NULL == pCertUsage || 0 == pCertUsage->cUsageIdentifier)
goto CommonReturn;
for (i = 0; i < pCertUsage->cUsageIdentifier; i++) {
for (j = 0; j < pValidUsage->cUsageIdentifier; j++) {
if (0 == strcmp(pCertUsage->rgpszUsageIdentifier[i],
pValidUsage->rgpszUsageIdentifier[j]))
break;
}
if (j == pValidUsage->cUsageIdentifier)
// No Match
goto CommonReturn;
}
fResult = TRUE;
CommonReturn:
if (pCertUsage)
LocalFree(pCertUsage);
return fResult;
}
//+-------------------------------------------------------------------------
// Removes all certificates from the store not having a sha1 hash
// entry in the CTL.
//
// For added certificates, sets the CERT_ENHKEY_USAGE_PROP_ID
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
FilterAndUpdateTrustedRootsInStore(
IN PCTL_INFO pCtlInfo,
IN BOOL fRemoveRoots,
IN OUT HCERTSTORE hMsgStore
)
{
BOOL fResult;
PCCERT_CONTEXT pCert = NULL;
CRYPT_DATA_BLOB EncodedUsage = {0, NULL}; // pbData is allocated
if (!fRemoveRoots) {
// Re-encode the decoded SubjectUsage field. It will be added as
// a CERT_ENHKEY_USAGE_PROP_ID to each of the certs in the list
if (!CryptEncodeObject(
X509_ASN_ENCODING,
X509_ENHANCED_KEY_USAGE,
&pCtlInfo->SubjectUsage,
NULL, // pbEncoded
&EncodedUsage.cbData
))
goto EncodeUsageError;
if (NULL == (EncodedUsage.pbData = (BYTE *) LocalAlloc(
LPTR, EncodedUsage.cbData)))
goto OutOfMemory;
if (!CryptEncodeObject(
X509_ASN_ENCODING,
X509_ENHANCED_KEY_USAGE,
&pCtlInfo->SubjectUsage,
EncodedUsage.pbData,
&EncodedUsage.cbData
))
goto EncodeUsageError;
}
// Iterate through the certificates in the message store.
// Remove certificates not in the signed CTL entry list
pCert = NULL;
while (pCert = CertEnumCertificatesInStore(hMsgStore, pCert)) {
if (IsTrustedRoot(pCtlInfo, pCert)) {
// Add the enhanced key usage property if the certificate
// doesn't already have an EKU extension that's a subset
// of the SubjectUsage
if (!fRemoveRoots && !IsValidCertEKUExtSubset(
pCert, &pCtlInfo->SubjectUsage)) {
if (!CertSetCertificateContextProperty(
pCert,
CERT_ENHKEY_USAGE_PROP_ID,
0, // dwFlags
&EncodedUsage
))
goto SetEnhancedKeyUsagePropertyError;
}
} else {
PCCERT_CONTEXT pCertDup;
pCertDup = CertDuplicateCertificateContext(pCert);
CertDeleteCertificateFromStore(pCertDup);
}
}
fResult = TRUE;
CommonReturn:
if (EncodedUsage.pbData)
LocalFree(EncodedUsage.pbData);
if (pCert)
CertFreeCertificateContext(pCert);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(EncodeUsageError)
SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
TRACE_ERROR(SetEnhancedKeyUsagePropertyError)
}
//+-------------------------------------------------------------------------
// Verify that the encoded CTL contains a signed list of roots. For success,
// return certificate store containing the trusted roots to add or
// remove. Also for success, return certificate context of the signer.
//
// The signature of the CTL is verified. The signer of the CTL is verified
// up to a trusted root containing the predefined Microsoft public key.
// The signer and intermediate certificates must have the
// szOID_ROOT_LIST_SIGNER enhanced key usage extension.
//
// The CTL fields are validated as follows:
// - There is at least one SubjectUsage (really the roots enhanced key usage)
// - If NextUpdate isn't NULL, that the CTL is still time valid
// - Only allow roots identified by their sha1 hash
//
// The following CTL extensions are processed:
// - szOID_ENHANCED_KEY_USAGE - if present, must contain
// szOID_ROOT_LIST_SIGNER usage
// - szOID_REMOVE_CERTIFICATE - integer value, 0 => FALSE (add)
// 1 => TRUE (remove), all other values are invalid
// - szOID_CERT_POLICIES - ignored
//
// If the CTL contains any other critical extensions, then, the
// CTL verification fails.
//
// For a successfully verified CTL:
// - TRUE is returned
// - *pfRemoveRoots is set to FALSE to add roots and is set to TRUE to
// remove roots.
// - *phRootListStore is a certificate store containing only the roots to
// add or remove. *phRootListStore must be closed by calling
// CertCloseStore(). For added roots, the CTL's SubjectUsage field is
// set as CERT_ENHKEY_USAGE_PROP_ID on all of the certificates in the
// store.
// - *ppSignerCert is a pointer to the certificate context of the signer.
// *ppSignerCert must be freed by calling CertFreeCertificateContext().
//
// Otherwise, FALSE is returned with *phRootListStore and *ppSignerCert
// set to NULL.
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CertVerifySignedListOfTrustedRoots(
IN const BYTE *pbCtlEncoded,
IN DWORD cbCtlEncoded,
OUT BOOL *pfRemoveRoots, // FALSE: add, TRUE: remove
OUT HCERTSTORE *phRootListStore,
OUT PCCERT_CONTEXT *ppSignerCert
)
{
BOOL fResult;
PCCTL_CONTEXT pCtl = NULL;
HCERTSTORE hMsgStore = NULL;
PCCERT_CONTEXT pSignerCert = NULL;
BOOL fRemoveRoots = FALSE;
PCTL_INFO pCtlInfo; // not allocated
if (NULL == (pCtl = CertCreateCTLContext(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
pbCtlEncoded,
cbCtlEncoded)))
goto CreateCtlContextError;
if (NULL == (hMsgStore = CertOpenStore(
CERT_STORE_PROV_MSG,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0, // hCryptProv
0, // dwFlags
pCtl->hCryptMsg // pvPara
)))
goto OpenMsgStoreError;
if (!GetAndVerifyTrustedRootsSigner(
pCtl->hCryptMsg, hMsgStore, &pSignerCert))
goto GetAndVerifyTrustedRootsSignerError;
pCtlInfo = pCtl->pCtlInfo;
if (!VerifyTrustedRootsCtlFields(pCtlInfo))
goto VerifyCtlFieldsError;
if (!VerifyTrustedRootsCtlExtensions(pCtlInfo, &fRemoveRoots))
goto VerifyCtlExtensionsError;
if (!FilterAndUpdateTrustedRootsInStore(pCtlInfo, fRemoveRoots, hMsgStore))
goto FilterAndUpdateTrustedRootsError;
fResult = TRUE;
CommonReturn:
if (pCtl)
CertFreeCTLContext(pCtl);
*pfRemoveRoots = fRemoveRoots;
*phRootListStore = hMsgStore;
*ppSignerCert = pSignerCert;
return fResult;
ErrorReturn:
if (pSignerCert) {
CertFreeCertificateContext(pSignerCert);
pSignerCert = NULL;
}
if (hMsgStore) {
CertCloseStore(hMsgStore, 0);
hMsgStore = NULL;
}
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(CreateCtlContextError)
TRACE_ERROR(OpenMsgStoreError)
TRACE_ERROR(GetAndVerifyTrustedRootsSignerError)
TRACE_ERROR(VerifyCtlFieldsError)
TRACE_ERROR(VerifyCtlExtensionsError)
TRACE_ERROR(FilterAndUpdateTrustedRootsError)
}