|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 2001 - 2001
//
// File: wxptrust.cpp
//
// Contents: Windows XP version of the Outlook WinVerify Trust Provider
//
// Functions: WXP_CertTrustDllMain
// CertTrustInit
// CertTrustCertPolicy - shouldn't be called
// CertTrustFinalPolicy
// CertTrustCleanup - shouldn't be called
//
// CertModifyCertificatesToTrust
// FModifyTrust
// FreeWVTHandle
// HrDoTrustWork
// FormatValidityFailures
//
// History: 11-Feb-2001 philh created (rewrite to use chain APIs)
//
//--------------------------------------------------------------------------
#include "pch.hxx"
#include <wintrust.h>
#include "demand.h"
#include <stdio.h>
// The following should be moved to cryptdlg.h
#define CERT_VALIDITY_POLICY_FAILURE 0x00001000
#define CERT_VALIDITY_BASIC_CONSTRAINTS_FAILURE 0x00002000
const char SzPolicyKey[] = "SOFTWARE\\Microsoft\\Cryptography\\" szCERT_CERTIFICATE_ACTION_VERIFY; const char SzPolicyData[] = "PolicyFlags"; const char SzUrlRetrievalTimeoutData[] = "UrlRetrievalTimeout"; // milliseconds
#define EXPLICIT_TRUST_NONE 0
#define EXPLICIT_TRUST_YES 1
#define EXPLICIT_TRUST_NO 2
#define MAX_HASH_LEN 20
#define MIN_HASH_LEN 16
// ExplictTrust is encoded as a SEQUENCE OF Attribues. We are only
// interested in encoding one attribute with one value. We will only change
// the last byte. It contains the trust value. It can be: 0-NONE, 1-YES, 2-NO.
const BYTE rgbEncodedExplictTrust[] = { 0x30, 0x13, // SEQUENCE OF
0x30, 0x11, // SEQUENCE
0x06, 0x0a, // OID: 1.3.6.1.4.1.311.10.4.1
0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0A, 0x04, 0x01, 0x31, 0x03, // SET OF
0x02, 0x01, 0x00 // INTEGER: 0-NONE, 1-YES, 2-NO
};
HINSTANCE g_hCertTrustInst; HCERTSTORE g_hStoreTrustedPeople; HCERTSTORE g_hStoreDisallowed;
// Cached Chain. We remember the last built chain context and try to re-use.
// Outlook calls us 2 or 3 times to build a chain for the same certificate
// context.
CRITICAL_SECTION g_CachedChainCriticalSection; DWORD g_dwCachedCreateChainFlags; PCCERT_CHAIN_CONTEXT g_pCachedChainContext; FILETIME g_ftCachedChain;
#define CACHED_CHAIN_SECONDS_DURATION 30
BOOL WINAPI WXP_CertTrustDllMain( HINSTANCE hInst, ULONG ulReason, LPVOID ) { BOOL fResult = TRUE;
switch (ulReason) { case DLL_PROCESS_ATTACH: g_hCertTrustInst = hInst;
__try { InitializeCriticalSection(&g_CachedChainCriticalSection); } __except(EXCEPTION_EXECUTE_HANDLER) { SetLastError(GetExceptionCode()); fResult = FALSE; } break;
case DLL_PROCESS_DETACH: if (g_hStoreTrustedPeople) CertCloseStore(g_hStoreTrustedPeople, 0); if (g_hStoreDisallowed) CertCloseStore(g_hStoreDisallowed, 0);
if (g_pCachedChainContext) CertFreeCertificateChain(g_pCachedChainContext); DeleteCriticalSection(&g_CachedChainCriticalSection); break; case DLL_THREAD_DETACH: default: break; } return fResult; }
HCERTSTORE I_OpenCachedHKCUStore( IN OUT HCERTSTORE *phStoreCache, IN LPCWSTR pwszStore ) { HCERTSTORE hStore;
hStore = *phStoreCache; if (NULL == hStore) { hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_MAXIMUM_ALLOWED_FLAG | CERT_STORE_SHARE_CONTEXT_FLAG, (const void *) pwszStore );
if (hStore) { HCERTSTORE hPrevStore;
CertControlStore( hStore, 0, // dwFlags
CERT_STORE_CTRL_AUTO_RESYNC, NULL // pvCtrlPara
);
hPrevStore = InterlockedCompareExchangePointer( phStoreCache, hStore, NULL);
if (hPrevStore) { CertCloseStore(hStore, 0); hStore = hPrevStore; } } }
if (hStore) hStore = CertDuplicateStore(hStore);
return hStore; }
HCERTSTORE I_OpenTrustedPeopleStore() { return I_OpenCachedHKCUStore(&g_hStoreTrustedPeople, L"TrustedPeople"); }
HCERTSTORE I_OpenDisallowedStore() { return I_OpenCachedHKCUStore(&g_hStoreDisallowed, L"Disallowed"); }
// We use signature hash. For untrusted, this will find certificates with
// altered signature content.
PCCERT_CONTEXT I_FindCertificateInOtherStore( IN HCERTSTORE hOtherStore, IN PCCERT_CONTEXT pCert ) { BYTE rgbHash[MAX_HASH_LEN]; CRYPT_DATA_BLOB HashBlob;
HashBlob.pbData = rgbHash; HashBlob.cbData = MAX_HASH_LEN; if (!CertGetCertificateContextProperty( pCert, CERT_SIGNATURE_HASH_PROP_ID, rgbHash, &HashBlob.cbData ) || MIN_HASH_LEN > HashBlob.cbData) return NULL;
return CertFindCertificateInStore( hOtherStore, 0, // dwCertEncodingType
0, // dwFindFlags
CERT_FIND_SIGNATURE_HASH, (const void *) &HashBlob, NULL //pPrevCertContext
); }
// Returns:
// +1 - Cert was successfully deleted
// 0 - Cert wasn't found
// -1 - Delete failed (GetLastError() for failure reason)
//
LONG I_DeleteCertificateFromOtherStore( IN HCERTSTORE hOtherStore, IN PCCERT_CONTEXT pCert ) { LONG lDelete; PCCERT_CONTEXT pOtherCert; BYTE rgbHash[MAX_HASH_LEN]; CRYPT_DATA_BLOB HashBlob;
HashBlob.pbData = rgbHash; HashBlob.cbData = MAX_HASH_LEN; if (!CertGetCertificateContextProperty( pCert, CERT_SIGNATURE_HASH_PROP_ID, rgbHash, &HashBlob.cbData ) || MIN_HASH_LEN > HashBlob.cbData) return 0;
// Note, there is a possibility that multiple certs can have
// the same signature hash. For example, the signature algorithm
// parameters may have been altered. Change empty NULL : {0x05, 0x00} to
// empty OCTET : {0x04, 0x00}.
lDelete = 0; pOtherCert = NULL; while (pOtherCert = CertFindCertificateInStore( hOtherStore, 0, // dwCertEncodingType
0, // dwFindFlags
CERT_FIND_SIGNATURE_HASH, (const void *) &HashBlob, pOtherCert )) { CertDuplicateCertificateContext(pOtherCert); if (CertDeleteCertificateFromStore(pOtherCert)) { if (0 == lDelete) lDelete = 1; } else lDelete = -1; }
return lDelete; }
HRESULT I_CheckExplicitTrust( IN PCCERT_CONTEXT pCert, IN LPFILETIME pftCurrent, OUT BYTE *pbExplicitTrust ) { HRESULT hr; BYTE bExplicitTrust = EXPLICIT_TRUST_NONE; HCERTSTORE hStoreDisallowed = NULL; HCERTSTORE hStoreTrustedPeople = NULL; PCCERT_CONTEXT pFindCert = NULL;
hStoreDisallowed = I_OpenDisallowedStore(); if (NULL == hStoreDisallowed) goto OpenDisallowedStoreError;
pFindCert = I_FindCertificateInOtherStore(hStoreDisallowed, pCert); if (pFindCert) { bExplicitTrust = EXPLICIT_TRUST_NO; goto SuccessReturn; }
hStoreTrustedPeople = I_OpenTrustedPeopleStore(); if (NULL == hStoreTrustedPeople) goto SuccessReturn;
pFindCert = I_FindCertificateInOtherStore(hStoreTrustedPeople, pCert); if (pFindCert) { // Must be time valid to trust
if (0 == CertVerifyTimeValidity(pftCurrent, pCert->pCertInfo)) bExplicitTrust = EXPLICIT_TRUST_YES; else // Remove the expired cert. Just in case there are
// altered certificates having the same signature hash, do
// the following delete.
I_DeleteCertificateFromOtherStore(hStoreTrustedPeople, pFindCert); }
SuccessReturn: hr = S_OK; CommonReturn: if (pFindCert) CertFreeCertificateContext(pFindCert); if (hStoreDisallowed) CertCloseStore(hStoreDisallowed, 0); if (hStoreTrustedPeople) CertCloseStore(hStoreTrustedPeople, 0);
*pbExplicitTrust = bExplicitTrust; return hr;
OpenDisallowedStoreError: // Most likely unable to access
hr = E_ACCESSDENIED; goto CommonReturn; }
//+-------------------------------------------------------------------------
// Subtract two filetimes and return the number of seconds.
//
// The second filetime is subtracted from the first. If the first filetime
// is before the second, then, 0 seconds is returned.
//
// Filetime is in units of 100 nanoseconds. Each second has
// 10**7 100 nanoseconds.
//--------------------------------------------------------------------------
__inline DWORD WINAPI I_SubtractFileTimes( IN LPFILETIME pftFirst, IN LPFILETIME pftSecond ) { DWORDLONG qwDiff;
if (0 >= CompareFileTime(pftFirst, pftSecond)) return 0;
qwDiff = *(((DWORDLONG UNALIGNED *) pftFirst)) - *(((DWORDLONG UNALIGNED *) pftSecond));
return (DWORD) (qwDiff / 10000000i64); }
PCCERT_CHAIN_CONTEXT I_CheckCachedChain( IN PCCERT_CONTEXT pCert, IN DWORD dwCreateChainFlags ) { PCCERT_CHAIN_CONTEXT pChainContext = NULL; FILETIME ftCurrent;
EnterCriticalSection(&g_CachedChainCriticalSection);
if (NULL == g_pCachedChainContext) goto CommonReturn;
if (g_pCachedChainContext->rgpChain[0]->rgpElement[0]->pCertContext != pCert) goto CommonReturn;
if (dwCreateChainFlags == g_dwCachedCreateChainFlags) ; else { if ((dwCreateChainFlags & g_dwCachedCreateChainFlags) != dwCreateChainFlags) goto CommonReturn;
if (g_pCachedChainContext->TrustStatus.dwErrorStatus & (CERT_TRUST_IS_REVOKED | CERT_TRUST_REVOCATION_STATUS_UNKNOWN)) goto CommonReturn; }
GetSystemTimeAsFileTime(&ftCurrent); if (CACHED_CHAIN_SECONDS_DURATION < I_SubtractFileTimes(&ftCurrent, &g_ftCachedChain)) { CertFreeCertificateChain(g_pCachedChainContext); g_pCachedChainContext = NULL; goto CommonReturn; }
pChainContext = CertDuplicateCertificateChain(g_pCachedChainContext);
CommonReturn: LeaveCriticalSection(&g_CachedChainCriticalSection); return pChainContext; }
void I_SetCachedChain( IN PCCERT_CHAIN_CONTEXT pChainContext, IN DWORD dwCreateChainFlags ) { if (pChainContext->TrustStatus.dwErrorStatus & (CERT_TRUST_IS_NOT_SIGNATURE_VALID | CERT_TRUST_IS_PARTIAL_CHAIN)) return;
EnterCriticalSection(&g_CachedChainCriticalSection);
if (g_pCachedChainContext) CertFreeCertificateChain(g_pCachedChainContext);
g_pCachedChainContext = CertDuplicateCertificateChain(pChainContext); g_dwCachedCreateChainFlags = dwCreateChainFlags; GetSystemTimeAsFileTime(&g_ftCachedChain);
LeaveCriticalSection(&g_CachedChainCriticalSection); }
// Assumption: the message store is included in the rghstoreCAs array.
// Will ignore the rghstoreRoots and rghstoreTrust store arrays. These
// certs should already be opened and cached in the chain engine.
HCERTSTORE I_GetChainAdditionalStore( IN PCERT_VERIFY_CERTIFICATE_TRUST pCertTrust ) { if (0 == pCertTrust->cStores) return NULL;
if (1 < pCertTrust->cStores) { HCERTSTORE hCollectionStore;
if (hCollectionStore = CertOpenStore( CERT_STORE_PROV_COLLECTION, 0, // dwEncodingType
0, // hCryptProv
0, // dwFlags
NULL // pvPara
)) { DWORD i; for (i = 0; i < pCertTrust->cStores; i++) CertAddStoreToCollection( hCollectionStore, pCertTrust->rghstoreCAs[i], CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0 // dwPriority
); } return hCollectionStore; } else return CertDuplicateStore(pCertTrust->rghstoreCAs[0]); }
HRESULT I_BuildChain( IN PCERT_VERIFY_CERTIFICATE_TRUST pCertTrust, IN LPFILETIME pftCurrent, IN DWORD dwPolicy, IN DWORD dwUrlRetrievalTimeout, OUT PCCERT_CHAIN_CONTEXT* ppChainContext ) { HRESULT hr; PCCERT_CHAIN_CONTEXT pChainContext = NULL; DWORD dwCreateChainFlags = 0; CERT_CHAIN_PARA ChainPara; HCERTSTORE hAdditionalStore = NULL; HCRYPTDEFAULTCONTEXT hDefaultContext = NULL;
// Update the revocation flags to be used for chain building
if (pCertTrust->dwFlags & CRYPTDLG_REVOCATION_ONLINE) { // Allow full online revocation checking
dwCreateChainFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN; } else if (pCertTrust->dwFlags & CRYPTDLG_REVOCATION_CACHE) { // Allow local revocation checks only, do not hit the network.
dwCreateChainFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY; } else if (pCertTrust->dwFlags & CRYPTDLG_REVOCATION_NONE) { ; } else if (dwPolicy & ACTION_REVOCATION_DEFAULT_ONLINE) { // Allow full online revocation checking
dwCreateChainFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN; } else if (dwPolicy & ACTION_REVOCATION_DEFAULT_CACHE) { // Allow local revocation checks only, do not hit the network
dwCreateChainFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY; }
// Enable LRU caching of the end certificate. Also, set an upper limit
// for all CRL URL fetches.
dwCreateChainFlags |= CERT_CHAIN_CACHE_END_CERT | CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT;
pChainContext = I_CheckCachedChain( pCertTrust->pccert, dwCreateChainFlags ); if (NULL != pChainContext) goto SuccessReturn; if (pCertTrust->hprov != NULL) { // Set the default crypt provider so we can make sure that ours is used
if (!CryptInstallDefaultContext(pCertTrust->hprov, CRYPT_DEFAULT_CONTEXT_CERT_SIGN_OID, szOID_OIWSEC_md5RSA, 0, NULL, &hDefaultContext)) goto InstallDefaultContextError; }
memset(&ChainPara, 0, sizeof(ChainPara)); ChainPara.cbSize = sizeof(ChainPara); if (pCertTrust->pszUsageOid && '\0' != pCertTrust->pszUsageOid[0]) { ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND; ChainPara.RequestedUsage.Usage.cUsageIdentifier = 1; ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = &pCertTrust->pszUsageOid; } ChainPara.dwUrlRetrievalTimeout = dwUrlRetrievalTimeout;
hAdditionalStore = I_GetChainAdditionalStore(pCertTrust);
if (!CertGetCertificateChain ( HCCE_CURRENT_USER, pCertTrust->pccert, pftCurrent, hAdditionalStore, &ChainPara, dwCreateChainFlags, NULL, // pvReserved,
&pChainContext )) goto GetChainError;
I_SetCachedChain(pChainContext, dwCreateChainFlags);
SuccessReturn: hr = S_OK; CommonReturn: if (hDefaultContext) CryptUninstallDefaultContext(hDefaultContext, 0, NULL); if (hAdditionalStore) CertCloseStore(hAdditionalStore, 0);
*ppChainContext = pChainContext;
return hr;
GetChainError: InstallDefaultContextError: pChainContext = NULL; hr = TRUST_E_SYSTEM_ERROR; goto CommonReturn; }
DWORD I_MapValidityErrorsToTrustError( IN DWORD dwErrors ) { DWORD dwTrustError = S_OK;
// Look at them in decreasing order of importance
if (dwErrors) { if (dwErrors & CERT_VALIDITY_EXPLICITLY_DISTRUSTED) { dwTrustError = TRUST_E_EXPLICIT_DISTRUST; } else if (dwErrors & CERT_VALIDITY_SIGNATURE_FAILS) { dwTrustError = TRUST_E_CERT_SIGNATURE; } else if (dwErrors & CERT_VALIDITY_NO_ISSUER_CERT_FOUND) { dwTrustError = CERT_E_CHAINING; } else if (dwErrors & CERT_VALIDITY_NO_TRUST_DATA) { dwTrustError = CERT_E_UNTRUSTEDROOT; } else if (dwErrors & CERT_VALIDITY_CERTIFICATE_REVOKED) { dwTrustError = CERT_E_REVOKED; } else if (dwErrors & CERT_VALIDITY_EXTENDED_USAGE_FAILURE) { dwTrustError = CERT_E_WRONG_USAGE; } else if (dwErrors & (CERT_VALIDITY_BEFORE_START | CERT_VALIDITY_AFTER_END)) { dwTrustError = CERT_E_EXPIRED; } else if (dwErrors & CERT_VALIDITY_NAME_CONSTRAINTS_FAILURE) { dwTrustError = CERT_E_INVALID_NAME; } else if (dwErrors & CERT_VALIDITY_POLICY_FAILURE) { dwTrustError = CERT_E_INVALID_POLICY; } else if (dwErrors & CERT_VALIDITY_BASIC_CONSTRAINTS_FAILURE) { dwTrustError = TRUST_E_BASIC_CONSTRAINTS; } else if (dwErrors & CERT_VALIDITY_NO_CRL_FOUND) { dwTrustError = CERT_E_REVOCATION_FAILURE; } else if (dwErrors & (CERT_VALIDITY_ISSUER_INVALID | CERT_VALIDITY_ISSUER_DISTRUST)) { dwTrustError = CERT_E_UNTRUSTEDROOT; } else { dwTrustError = TRUST_E_FAIL; } }
return dwTrustError; }
HRESULT I_UpdateCertProvFromExplicitTrust( IN OUT PCRYPT_PROVIDER_DATA pProvData, IN PCCERT_CONTEXT pCert, IN DWORD dwAllErrors ) { CRYPT_PROVIDER_SGNR Sgnr; PCRYPT_PROVIDER_SGNR pSgnr; PCRYPT_PROVIDER_CERT pProvCert;
memset(&Sgnr, 0, sizeof(Sgnr)); Sgnr.cbStruct = sizeof(Sgnr);
if (!pProvData->psPfns->pfnAddSgnr2Chain( pProvData, FALSE, // fCounterSigner
0, // idwSigner
&Sgnr )) return TRUST_E_SYSTEM_ERROR;
if (!pProvData->psPfns->pfnAddCert2Chain( pProvData, 0, // idxSigner
FALSE, // fCounterSigner
0, // idxCounterSigner
pCert )) return TRUST_E_SYSTEM_ERROR;
pSgnr = WTHelperGetProvSignerFromChain( pProvData, 0, // idxSigner
FALSE, // fCounterSigner
0 // idxCounterSigner
); if (NULL == pSgnr) return TRUST_E_SYSTEM_ERROR;
pProvCert = WTHelperGetProvCertFromChain( pSgnr, 0 // idxCert
); if (NULL == pProvCert) return TRUST_E_SYSTEM_ERROR;
pSgnr->dwError = pProvCert->dwError = I_MapValidityErrorsToTrustError(dwAllErrors);
// Map to IE4Trust confidence
pProvCert->dwConfidence |= CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST | CERT_CONFIDENCE_AUTHIDEXT | CERT_CONFIDENCE_HYGIENE ;
if (!(dwAllErrors & (CERT_VALIDITY_BEFORE_START | CERT_VALIDITY_AFTER_END))) pProvCert->dwConfidence |= CERT_CONFIDENCE_TIME;
return S_OK; }
HRESULT I_UpdateCertProvChain( IN OUT PCRYPT_PROVIDER_DATA pProvData, IN PCCERT_CHAIN_CONTEXT pChainContext, IN DWORD cTrustCert, IN DWORD rgdwErrors[], IN DWORD dwAllErrors ) { CRYPT_PROVIDER_SGNR Sgnr; PCRYPT_PROVIDER_SGNR pSgnr; DWORD iTrustCert; DWORD i;
memset(&Sgnr, 0, sizeof(Sgnr)); Sgnr.cbStruct = sizeof(Sgnr);
if (!pProvData->psPfns->pfnAddSgnr2Chain( pProvData, FALSE, // fCounterSigner
0, // idwSigner
&Sgnr )) return TRUST_E_SYSTEM_ERROR;
pSgnr = WTHelperGetProvSignerFromChain( pProvData, 0, // idxSigner
FALSE, // fCounterSigner
0 // idxCounterSigner
); if (NULL == pSgnr) return TRUST_E_SYSTEM_ERROR;
pSgnr->pChainContext = CertDuplicateCertificateChain(pChainContext); pSgnr->dwError = I_MapValidityErrorsToTrustError(dwAllErrors);
iTrustCert = 0; 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 (iTrustCert >= cTrustCert) return TRUST_E_SYSTEM_ERROR;
if (!pProvData->psPfns->pfnAddCert2Chain( pProvData, 0, // idxSigner
FALSE, // fCounterSigner
0, // idxCounterSigner
pEle->pCertContext )) return TRUST_E_SYSTEM_ERROR;
pProvCert = WTHelperGetProvCertFromChain( pSgnr, iTrustCert ); if (NULL == pProvCert) return TRUST_E_SYSTEM_ERROR;
//DSIE: 12-Oct-2000 added pChainElement to CRYPT_PROVIDER_CERT.
if (WVT_ISINSTRUCT(CRYPT_PROVIDER_CERT, pProvCert->cbStruct, 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);
// 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; }
pProvCert->dwError = I_MapValidityErrorsToTrustError( rgdwErrors[iTrustCert]);
// 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; } else if (dwChainError & CERT_TRUST_CTL_IS_NOT_TIME_VALID) { pProvCert->dwCtlError = CERT_E_EXPIRED; } else if (dwChainError & CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE) { pProvCert->dwCtlError = CERT_E_WRONG_USAGE; } }
iTrustCert++; } }
return S_OK; }
HRESULT CertTrustFinalPolicy( IN OUT PCRYPT_PROVIDER_DATA pProvData ) { HRESULT hr; PCERT_VERIFY_CERTIFICATE_TRUST pCertTrust; DWORD dwPolicy = 0; DWORD dwUrlRetrievalTimeout = 0; FILETIME ftCurrent; BYTE bExplicitTrust = EXPLICIT_TRUST_NONE; PCCERT_CHAIN_CONTEXT pChainContext = NULL; DWORD cTrustCert = 0; PCCERT_CONTEXT *rgpTrustCert = NULL; DWORD *rgdwErrors = NULL; DATA_BLOB *rgBlobTrustInfo = NULL; DWORD dwAllErrors = 0;
// Verify we are called by a version of WVT having all of the fields we will
// be using.
if (!WVT_ISINSTRUCT(CRYPT_PROVIDER_DATA, pProvData->cbStruct, dwFinalError)) return E_INVALIDARG;
// Continue checking that we have everything we need.
if (pProvData->pWintrustData->pBlob->cbStruct < sizeof(WINTRUST_BLOB_INFO)) goto InvalidProvData;
pCertTrust = (PCERT_VERIFY_CERTIFICATE_TRUST) pProvData->pWintrustData->pBlob->pbMemObject; if ((pCertTrust == NULL) || (pCertTrust->cbSize < sizeof(*pCertTrust))) goto InvalidProvData;
// If present, retrieve policy flags and URL retrieval timeout from
// the registry
{ HKEY hKeyPolicy;
if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_LOCAL_MACHINE, SzPolicyKey, 0, KEY_READ, &hKeyPolicy)) { DWORD dwType; DWORD cbSize;
cbSize = sizeof(dwPolicy); if (ERROR_SUCCESS != RegQueryValueExA(hKeyPolicy, SzPolicyData, 0, &dwType, (LPBYTE) &dwPolicy, &cbSize) || REG_DWORD != dwType) dwPolicy = 0;
cbSize = sizeof(dwUrlRetrievalTimeout); if (ERROR_SUCCESS != RegQueryValueExA( hKeyPolicy, SzUrlRetrievalTimeoutData, 0, &dwType, (LPBYTE) &dwUrlRetrievalTimeout, &cbSize) || REG_DWORD != dwType) dwUrlRetrievalTimeout = 0;
RegCloseKey(hKeyPolicy); } }
// Get current time to be used
GetSystemTimeAsFileTime(&ftCurrent);
hr = I_CheckExplicitTrust( pCertTrust->pccert, &ftCurrent, &bExplicitTrust ); if (S_OK != hr) goto CheckExplicitTrustError;
if (EXPLICIT_TRUST_NONE != bExplicitTrust) { // No need to build the chain, the trust decision has already been
// made
cTrustCert = 1; } else { DWORD i;
hr = I_BuildChain( pCertTrust, &ftCurrent, dwPolicy, dwUrlRetrievalTimeout, &pChainContext ); if (S_OK != hr) goto BuildChainError;
cTrustCert = 0; for (i = 0; i < pChainContext->cChain; i++) cTrustCert += pChainContext->rgpChain[i]->cElement;
if (0 == cTrustCert) goto InvalidChainContext; }
// Allocate the memory to contain the errors for each cert in the chain
rgdwErrors = (DWORD *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, cTrustCert * sizeof(DWORD)); if (NULL == rgdwErrors) goto OutOfMemory;
// If the caller requests the chain certs and/or the encoded trust
// information, then, allocate the arrays
if (pCertTrust->prgChain) { rgpTrustCert = (PCCERT_CONTEXT *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, cTrustCert * sizeof(PCCERT_CONTEXT)); if (NULL == rgpTrustCert) goto OutOfMemory; }
if (pCertTrust->prgpbTrustInfo) { rgBlobTrustInfo = (DATA_BLOB *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, cTrustCert * sizeof(DATA_BLOB)); if (NULL == rgBlobTrustInfo) goto OutOfMemory; }
if (EXPLICIT_TRUST_NONE != bExplicitTrust) { // We have a single cert without a chain
if (rgpTrustCert) rgpTrustCert[0] = CertDuplicateCertificateContext(pCertTrust->pccert);
if (rgBlobTrustInfo) { // Update the returned encoded trust info
const DWORD cb = sizeof(rgbEncodedExplictTrust); BYTE *pb;
pb = (BYTE *) LocalAlloc(LMEM_FIXED, cb); if (NULL == pb) goto OutOfMemory; memcpy(pb, rgbEncodedExplictTrust, cb); pb[cb-1] = bExplicitTrust; rgBlobTrustInfo[0].cbData = cb; rgBlobTrustInfo[0].pbData = pb; }
if (EXPLICIT_TRUST_YES != bExplicitTrust) { LONG lValidity;
dwAllErrors |= CERT_VALIDITY_EXPLICITLY_DISTRUSTED;
lValidity = CertVerifyTimeValidity(&ftCurrent, pCertTrust->pccert->pCertInfo); if (0 > lValidity) dwAllErrors |= CERT_VALIDITY_BEFORE_START; else if (0 < lValidity) dwAllErrors |= CERT_VALIDITY_AFTER_END; }
dwAllErrors &= ~pCertTrust->dwIgnoreErr; rgdwErrors[0] = dwAllErrors;
if (WTD_STATEACTION_VERIFY == pProvData->pWintrustData->dwStateAction) { hr = I_UpdateCertProvFromExplicitTrust( pProvData, pCertTrust->pccert, dwAllErrors ); if (S_OK != hr) goto UpdateCertProvFromExplicitTrustError; }
} else { DWORD i; DWORD iTrustCert = 0;
// Get the cert trust info from the chain context elements
for (i = 0; i < pChainContext->cChain; i++) { DWORD j; PCERT_SIMPLE_CHAIN pChain = pChainContext->rgpChain[i]; DWORD dwChainError = pChain->TrustStatus.dwErrorStatus;
for (j = 0; j < pChain->cElement; j++) { PCERT_CHAIN_ELEMENT pEle = pChain->rgpElement[j]; DWORD dwEleError = pEle->TrustStatus.dwErrorStatus; DWORD dwErrors = 0;
if (iTrustCert >= cTrustCert) goto InvalidChainContext;
if (0 != dwEleError) { if (dwEleError & CERT_TRUST_IS_NOT_TIME_VALID) { // Check if after or before
if (0 > CertVerifyTimeValidity(&ftCurrent, pEle->pCertContext->pCertInfo)) dwErrors |= CERT_VALIDITY_BEFORE_START; else dwErrors |= CERT_VALIDITY_AFTER_END; }
if (dwEleError & CERT_TRUST_IS_NOT_SIGNATURE_VALID) dwErrors |= CERT_VALIDITY_SIGNATURE_FAILS;
if (dwEleError & CERT_TRUST_IS_REVOKED) { dwErrors |= CERT_VALIDITY_CERTIFICATE_REVOKED; } else if (dwEleError & CERT_TRUST_IS_OFFLINE_REVOCATION) dwErrors |= CERT_VALIDITY_NO_CRL_FOUND;
if (dwEleError & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) dwErrors |= CERT_VALIDITY_EXTENDED_USAGE_FAILURE;
if (dwEleError & (CERT_TRUST_INVALID_POLICY_CONSTRAINTS | CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY)) // We added POLICY_FAILURE on 02-13-01
dwErrors |= CERT_VALIDITY_POLICY_FAILURE | CERT_VALIDITY_OTHER_EXTENSION_FAILURE;
if (dwEleError & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) { BOOL fEnableBasicConstraints = TRUE;
if (dwPolicy & POLICY_IGNORE_NON_CRITICAL_BC) { // Disable if we don't have a critical extension
PCERT_EXTENSION pExt; pExt = CertFindExtension( szOID_BASIC_CONSTRAINTS2, pEle->pCertContext->pCertInfo->cExtension, pEle->pCertContext->pCertInfo->rgExtension ); if (NULL == pExt || !pExt->fCritical) fEnableBasicConstraints = FALSE; }
if (fEnableBasicConstraints) // We added BASIC_CONSTRAINTS_FAILURE on 02-13-01
dwErrors |= CERT_VALIDITY_BASIC_CONSTRAINTS_FAILURE | CERT_VALIDITY_OTHER_EXTENSION_FAILURE; }
if (dwEleError & CERT_TRUST_INVALID_EXTENSION) dwErrors |= CERT_VALIDITY_OTHER_EXTENSION_FAILURE;
if (dwEleError & (CERT_TRUST_INVALID_NAME_CONSTRAINTS | CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT | CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT | CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT)) dwErrors |= CERT_VALIDITY_NAME_CONSTRAINTS_FAILURE | CERT_VALIDITY_OTHER_EXTENSION_FAILURE; }
if (0 == j) { // End cert
if (dwChainError & CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY) // We added POLICY_FAILURE on 02-13-01
dwErrors |= CERT_VALIDITY_POLICY_FAILURE | CERT_VALIDITY_OTHER_EXTENSION_FAILURE; }
if (iTrustCert == cTrustCert - 1) { // Top cert. Should be the root.
if (dwChainError & (CERT_TRUST_IS_PARTIAL_CHAIN | CERT_TRUST_IS_CYCLIC)) dwErrors |= CERT_VALIDITY_NO_ISSUER_CERT_FOUND | CERT_VALIDITY_NO_TRUST_DATA; else if (dwEleError & CERT_TRUST_IS_UNTRUSTED_ROOT) dwErrors |= CERT_VALIDITY_NO_TRUST_DATA; else if (NULL != rgBlobTrustInfo) rgBlobTrustInfo[iTrustCert].pbData = (BYTE *) 1; }
dwErrors &= ~pCertTrust->dwIgnoreErr; dwAllErrors |= dwErrors;
rgdwErrors[iTrustCert] = dwErrors; if (rgpTrustCert) rgpTrustCert[iTrustCert] = CertDuplicateCertificateContext(pEle->pCertContext); iTrustCert++; }
// CTL chain errors
if (dwChainError & (CERT_TRUST_CTL_IS_NOT_TIME_VALID | CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID | CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE)) { if (dwChainError & CERT_TRUST_CTL_IS_NOT_TIME_VALID) dwAllErrors |= CERT_VALIDITY_AFTER_END; if (dwChainError & CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID) dwAllErrors |= CERT_VALIDITY_SIGNATURE_FAILS; if (dwChainError & CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE) dwAllErrors |= CERT_VALIDITY_EXTENDED_USAGE_FAILURE;
dwAllErrors &= ~pCertTrust->dwIgnoreErr; } }
if (dwAllErrors) { // If the issuer has errors, set an issuer error on the subject
for (iTrustCert = cTrustCert - 1; iTrustCert > 0; iTrustCert--) { if (rgdwErrors[iTrustCert] & CERT_VALIDITY_MASK_VALIDITY) rgdwErrors[iTrustCert - 1] |= CERT_VALIDITY_ISSUER_INVALID; if (rgdwErrors[iTrustCert] & CERT_VALIDITY_MASK_TRUST) rgdwErrors[iTrustCert - 1] |= CERT_VALIDITY_ISSUER_DISTRUST;
rgdwErrors[iTrustCert - 1] &= ~pCertTrust->dwIgnoreErr; dwAllErrors |= rgdwErrors[iTrustCert - 1]; } }
if (WTD_STATEACTION_VERIFY == pProvData->pWintrustData->dwStateAction) { hr = I_UpdateCertProvChain( pProvData, pChainContext, cTrustCert, rgdwErrors, dwAllErrors ); if (S_OK != hr) goto UpdateCertProvChainError; }
}
pProvData->dwFinalError = I_MapValidityErrorsToTrustError(dwAllErrors);
switch (pProvData->dwFinalError) { // For backwards compatibility, only the following HRESULTs are
// returned.
case S_OK: // case TRUST_E_CERT_SIGNATURE:
// case CERT_E_REVOKED:
// case CERT_E_REVOCATION_FAILURE:
hr = pProvData->dwFinalError; break; default: hr = S_FALSE; }
// Update the returned cert trust info
if (NULL != pCertTrust->pdwErrors) { *pCertTrust->pdwErrors = dwAllErrors; }
if (NULL != pCertTrust->pcChain) { *pCertTrust->pcChain = cTrustCert; } if (NULL != pCertTrust->prgChain) { *pCertTrust->prgChain = rgpTrustCert; rgpTrustCert = NULL; } if (NULL != pCertTrust->prgdwErrors) { *pCertTrust->prgdwErrors = rgdwErrors; rgdwErrors = NULL; } if (NULL != pCertTrust->prgpbTrustInfo) { *pCertTrust->prgpbTrustInfo = rgBlobTrustInfo; rgBlobTrustInfo = NULL; }
CommonReturn: if (pChainContext) CertFreeCertificateChain(pChainContext);
if (NULL != rgpTrustCert) { DWORD i;
for (i = 0; i < cTrustCert; i++) { if (NULL != rgpTrustCert[i]) CertFreeCertificateContext(rgpTrustCert[i]); } LocalFree(rgpTrustCert); }
if (NULL != rgBlobTrustInfo) { DWORD i;
for (i = 0; i < cTrustCert; i++) { if (0 < rgBlobTrustInfo[i].cbData) LocalFree(rgBlobTrustInfo[i].pbData); } LocalFree(rgBlobTrustInfo); }
if (NULL != rgdwErrors) LocalFree(rgdwErrors);
return hr;
CheckExplicitTrustError: BuildChainError: UpdateCertProvFromExplicitTrustError: UpdateCertProvChainError: ErrorReturn: if (SUCCEEDED(hr)) hr = TRUST_E_SYSTEM_ERROR; goto CommonReturn;
InvalidProvData: hr = E_INVALIDARG; goto ErrorReturn;
OutOfMemory: hr = E_OUTOFMEMORY; goto ErrorReturn;
InvalidChainContext: hr = TRUST_E_SYSTEM_ERROR; goto ErrorReturn; }
HRESULT CertTrustInit( IN OUT PCRYPT_PROVIDER_DATA pProvData ) { // Verify we are called by a version of WVT having all of the fields we will
// be using.
if (!WVT_ISINSTRUCT(CRYPT_PROVIDER_DATA, pProvData->cbStruct, dwFinalError)) return E_INVALIDARG;
// We are going to do all of our stuff in the pfFinalPolicy
// callback. NULL all of the remaining provider callbacks to
// inhibit them from being called.
if (!WVT_ISINSTRUCT(CRYPT_PROVIDER_FUNCTIONS, pProvData->psPfns->cbStruct, pfnCleanupPolicy)) return E_INVALIDARG;
pProvData->psPfns->pfnObjectTrust = NULL; pProvData->psPfns->pfnSignatureTrust = NULL; pProvData->psPfns->pfnCertificateTrust = NULL; pProvData->psPfns->pfnFinalPolicy = CertTrustFinalPolicy; pProvData->psPfns->pfnCertCheckPolicy = NULL; pProvData->psPfns->pfnTestFinalPolicy = NULL; pProvData->psPfns->pfnCleanupPolicy = NULL;
return S_OK; }
// The following function should never be called.
BOOL CertTrustCertPolicy(PCRYPT_PROVIDER_DATA, DWORD, BOOL, DWORD) { return FALSE; }
// The following function should never be called.
HRESULT CertTrustCleanup(PCRYPT_PROVIDER_DATA) { return TRUST_E_FAIL; }
// In WXP this API was changed not to use CTLs. Instead, the "TrustedPeople" and
// "Disallowed" certificate stores are used.
HRESULT CertModifyCertificatesToTrust(int cCertsToModify, PCTL_MODIFY_REQUEST rgCertMods, LPCSTR szPurpose, HWND hwnd, HCERTSTORE hcertstorTrust, PCCERT_CONTEXT pccertSigner) { HRESULT hr = S_OK; HCERTSTORE hStoreDisallowed = NULL; HCERTSTORE hStoreTrustedPeople = NULL; int i;
hStoreDisallowed = I_OpenDisallowedStore(); if (NULL == hStoreDisallowed) goto OpenDisallowedStoreError; hStoreTrustedPeople = I_OpenTrustedPeopleStore(); if (NULL == hStoreTrustedPeople) goto OpenTrustedPeopleStoreError;
for (i = 0; i < cCertsToModify; i++) { PCCERT_CONTEXT pCert = rgCertMods[i].pccert; DWORD dwError = S_OK;
switch(rgCertMods[i].dwOperation) { case CTL_MODIFY_REQUEST_ADD_NOT_TRUSTED: if (0 > I_DeleteCertificateFromOtherStore( hStoreTrustedPeople, pCert)) dwError = GetLastError(); if (!CertAddCertificateContextToStore( hStoreDisallowed, pCert, CERT_STORE_ADD_USE_EXISTING, NULL )) dwError = GetLastError(); break;
case CTL_MODIFY_REQUEST_REMOVE: if (0 > I_DeleteCertificateFromOtherStore( hStoreDisallowed, pCert)) dwError = GetLastError(); if (0 > I_DeleteCertificateFromOtherStore( hStoreTrustedPeople, pCert)) dwError = GetLastError(); break;
case CTL_MODIFY_REQUEST_ADD_TRUSTED: if (0 > I_DeleteCertificateFromOtherStore( hStoreDisallowed, pCert)) dwError = GetLastError(); if (!CertAddCertificateContextToStore( hStoreTrustedPeople, pCert, CERT_STORE_ADD_USE_EXISTING, NULL )) dwError = GetLastError(); break;
default: dwError = E_INVALIDARG; }
dwError = HRESULT_FROM_WIN32(dwError); rgCertMods[i].dwError = dwError; if (FAILED(dwError)) hr = S_FALSE; }
CommonReturn: if (hStoreDisallowed) CertCloseStore(hStoreDisallowed, 0); if (hStoreTrustedPeople) CertCloseStore(hStoreTrustedPeople, 0);
return hr;
OpenDisallowedStoreError: OpenTrustedPeopleStoreError: // Most likely unable to access
hr = E_ACCESSDENIED; goto CommonReturn; }
BOOL FModifyTrust(HWND hwnd, PCCERT_CONTEXT pccert, DWORD dwNewTrust, LPSTR szPurpose) { HRESULT hr; CTL_MODIFY_REQUEST certmod;
certmod.pccert = pccert; certmod.dwOperation = dwNewTrust;
hr = CertModifyCertificatesToTrust(1, &certmod, szPurpose, hwnd, NULL, NULL); return (hr == S_OK) && (certmod.dwError == 0); }
void FreeWVTHandle(HANDLE hWVTState) { if (hWVTState) { HRESULT hr; WINTRUST_DATA data = {0};
data.cbStruct = sizeof(WINTRUST_DATA); data.pPolicyCallbackData = NULL; data.pSIPClientData = NULL; data.dwUIChoice = WTD_UI_NONE; data.fdwRevocationChecks = WTD_REVOKE_NONE; data.dwUnionChoice = WTD_CHOICE_BLOB; data.pBlob = NULL; // &blob;
data.dwStateAction = WTD_STATEACTION_CLOSE; data.hWVTStateData = hWVTState; hr = WinVerifyTrust(NULL, (GUID *)&GuidCertValidate, &data); } }
HRESULT HrDoTrustWork(PCCERT_CONTEXT pccertToCheck, DWORD dwControl, DWORD dwValidityMask, DWORD /*cPurposes*/, LPSTR * rgszPurposes, HCRYPTPROV hprov, DWORD cRoots, HCERTSTORE * rgRoots, DWORD cCAs, HCERTSTORE * rgCAs, DWORD cTrust, HCERTSTORE * rgTrust, PFNTRUSTHELPER pfn, DWORD lCustData, PCCertFrame * /*ppcf*/, DWORD * pcNodes, PCCertFrame * rgpcfResult, HANDLE * phReturnStateData) // optional: return WinVerifyTrust state handle here
{ DWORD cbData; DWORD cCerts = 0; WINTRUST_BLOB_INFO blob = {0}; WINTRUST_DATA data = {0}; DWORD dwErrors; BOOL f; HRESULT hr; int i; DWORD j; PCCERT_CONTEXT * rgCerts = NULL; DWORD * rgdwErrors = NULL; DATA_BLOB * rgblobTrust = NULL; CERT_VERIFY_CERTIFICATE_TRUST trust; UNALIGNED CRYPT_ATTR_BLOB *pVal = NULL;
FILETIME ftCurrent;
data.cbStruct = sizeof(WINTRUST_DATA); data.pPolicyCallbackData = NULL; data.pSIPClientData = NULL; data.dwUIChoice = WTD_UI_NONE; data.fdwRevocationChecks = WTD_REVOKE_NONE; data.dwUnionChoice = WTD_CHOICE_BLOB; data.pBlob = &blob; if (phReturnStateData) { data.dwStateAction = WTD_STATEACTION_VERIFY; }
blob.cbStruct = sizeof(WINTRUST_BLOB_INFO); blob.pcwszDisplayName = NULL; blob.cbMemObject = sizeof(trust); blob.pbMemObject = (LPBYTE) &trust;
trust.cbSize = sizeof(trust); trust.pccert = pccertToCheck; trust.dwFlags = (CERT_TRUST_DO_FULL_SEARCH | CERT_TRUST_PERMIT_MISSING_CRLS | CERT_TRUST_DO_FULL_TRUST | dwControl); trust.dwIgnoreErr = dwValidityMask; trust.pdwErrors = &dwErrors; // Assert(cPurposes == 1);
if (rgszPurposes != NULL) { trust.pszUsageOid = rgszPurposes[0]; } else { trust.pszUsageOid = NULL; } trust.hprov = hprov; trust.cRootStores = cRoots; trust.rghstoreRoots = rgRoots; trust.cStores = cCAs; trust.rghstoreCAs = rgCAs; trust.cTrustStores = cTrust; trust.rghstoreTrust = rgTrust; trust.lCustData = lCustData; trust.pfnTrustHelper = pfn; trust.pcChain = &cCerts; trust.prgChain = &rgCerts; trust.prgdwErrors = &rgdwErrors; trust.prgpbTrustInfo = &rgblobTrust;
hr = WinVerifyTrust(NULL, (GUID *) &GuidCertValidate, &data); if ((TRUST_E_CERT_SIGNATURE == hr) || (CERT_E_REVOKED == hr) || (CERT_E_REVOCATION_FAILURE == hr)) { hr = S_OK; } else if (FAILED(hr)) { return hr; } if (cCerts == 0) { return(E_INVALIDARG); }
if (phReturnStateData) { *phReturnStateData = data.hWVTStateData; // Caller must use WinVerifyTrust to free
}
GetSystemTimeAsFileTime(&ftCurrent);
//Assert( cCerts <= 20);
*pcNodes = cCerts; for (i=cCerts-1; i >= 0; i--) { rgpcfResult[i] = new CCertFrame(rgCerts[i]);
if(!rgpcfResult[i]) { hr=E_OUTOFMEMORY; goto ExitHere; }
rgpcfResult[i]->m_dwFlags = rgdwErrors[i]; if (rgszPurposes == NULL) { continue; } rgpcfResult[i]->m_cTrust = 1; rgpcfResult[i]->m_rgTrust = new STrustDesc[1]; memset(rgpcfResult[i]->m_rgTrust, 0, sizeof(STrustDesc));
if (0 == i) rgpcfResult[i]->m_fLeaf = TRUE; else rgpcfResult[i]->m_fLeaf = FALSE;
if (0 == CertVerifyTimeValidity(&ftCurrent, rgCerts[i]->pCertInfo)) rgpcfResult[i]->m_fExpired = FALSE; else rgpcfResult[i]->m_fExpired = TRUE;
//
// We are going to fill in the trust information which we use
// to fill in the fields of the dialog box.
//
// Start with the question of the cert being self signed
//
rgpcfResult[i]->m_fSelfSign = WTHelperCertIsSelfSigned(X509_ASN_ENCODING, rgCerts[i]->pCertInfo);
//
// We may or may not have trust data information returned, we now
// build up the trust info for a single cert
//
// If we don't have any explicit data, then we just chain the data
// down from the next level up.
//
if (rgblobTrust[i].cbData == 0) { // chain:
rgpcfResult[i]->m_rgTrust[0].fExplicitTrust = FALSE; rgpcfResult[i]->m_rgTrust[0].fExplicitDistrust = FALSE;
//
// We return a special code to say that we found it in the root store
//
rgpcfResult[i]->m_rgTrust[0].fRootStore = rgpcfResult[i]->m_fRootStore = (rgblobTrust[i].pbData == (LPBYTE) 1);
if (i != (int) (cCerts-1)) { rgpcfResult[i]->m_rgTrust[0].fTrust = rgpcfResult[i+1]->m_rgTrust[0].fTrust; rgpcfResult[i]->m_rgTrust[0].fDistrust= rgpcfResult[i+1]->m_rgTrust[0].fDistrust; } else { // Oops -- there is no level up one, so just make some
// good defaults
//
rgpcfResult[i]->m_rgTrust[0].fTrust = rgpcfResult[i]->m_fRootStore; rgpcfResult[i]->m_rgTrust[0].fDistrust= FALSE; } } else { // Explicit trust is contained in the last byte
if (EXPLICIT_TRUST_YES == rgblobTrust[i].pbData[rgblobTrust[i].cbData - 1]) { rgpcfResult[i]->m_rgTrust[0].fExplicitTrust = TRUE; rgpcfResult[i]->m_rgTrust[0].fTrust = TRUE; } else { rgpcfResult[i]->m_rgTrust[0].fExplicitDistrust = TRUE; rgpcfResult[i]->m_rgTrust[0].fDistrust= TRUE; } } }
//
// Clean up all returned values
//
ExitHere: if (rgCerts != NULL) { //bobn If the loop has been broken because "new" failed, free what we allocated so far...
for ((hr==E_OUTOFMEMORY?i++:i=0); i< (int) cCerts; i++) { CertFreeCertificateContext(rgCerts[i]); } LocalFree(rgCerts); } if (rgdwErrors != NULL) LocalFree(rgdwErrors); if (rgblobTrust != NULL) { for (i=0; i<(int) cCerts; i++) { if (rgblobTrust[i].cbData > 0) { LocalFree(rgblobTrust[i].pbData); } } LocalFree(rgblobTrust); }
return hr; }
LPWSTR FormatValidityFailures(DWORD dwFlags) { DWORD cch = 0; LPWSTR pwsz = NULL; LPWSTR pwszT; WCHAR rgwch[200];
if (dwFlags == 0) { return NULL; }
cch = 100; pwsz = (LPWSTR) malloc(cch*sizeof(WCHAR)); if (pwsz == NULL) { return NULL; } if (dwFlags & CERT_VALIDITY_BEFORE_START) { LoadString(g_hCertTrustInst, IDS_WHY_NOT_YET, rgwch, sizeof(rgwch)/sizeof(WCHAR)); StrCpyNW(pwsz, rgwch, cch); } else { StrCpyNW(pwsz, L"",cch); }
if (dwFlags & CERT_VALIDITY_AFTER_END) { LoadString(g_hCertTrustInst, IDS_WHY_EXPIRED, rgwch, sizeof(rgwch)/sizeof(WCHAR)); if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) { cch += 200; pwszT = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR)); if (pwszT == NULL) { free(pwsz); return NULL; } pwsz = pwszT; } if (wcslen(pwsz) > 0) StrCatBuffW(pwsz, wszCRLF, cch); StrCatBuffW(pwsz, rgwch, cch); }
if (dwFlags & CERT_VALIDITY_SIGNATURE_FAILS) { LoadString(g_hCertTrustInst, IDS_WHY_CERT_SIG, rgwch, sizeof(rgwch)/sizeof(WCHAR)); if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) { cch += 200; pwszT = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR)); if (pwszT == NULL) { free(pwsz); return NULL; } pwsz = pwszT; } if (wcslen(pwsz) > 0) StrCatBuffW(pwsz, wszCRLF, cch); StrCatBuffW(pwsz, rgwch, cch); }
if (dwFlags & CERT_VALIDITY_NO_ISSUER_CERT_FOUND) { LoadString(g_hCertTrustInst, IDS_WHY_NO_PARENT, rgwch, sizeof(rgwch)/sizeof(WCHAR)); if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) { cch += 200; pwszT = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR)); if (pwszT == NULL) { free(pwsz); return NULL; } pwsz = pwszT; } if (wcslen(pwsz) > 0) StrCatBuffW(pwsz, wszCRLF, cch); StrCatBuffW(pwsz, rgwch, cch); }
if (dwFlags & CERT_VALIDITY_NO_CRL_FOUND) { LoadString(g_hCertTrustInst, IDS_WHY_NO_CRL, rgwch, sizeof(rgwch)/sizeof(WCHAR)); if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) { cch += 200; pwszT = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR)); if (pwszT == NULL) { free(pwsz); return NULL; } pwsz = pwszT; } if (wcslen(pwsz) > 0) StrCatBuffW(pwsz, wszCRLF, cch); StrCatBuffW(pwsz, rgwch, cch); }
if (dwFlags & CERT_VALIDITY_CERTIFICATE_REVOKED) { LoadString(g_hCertTrustInst, IDS_WHY_REVOKED, rgwch, sizeof(rgwch)/sizeof(WCHAR)); if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) { cch += 200; pwszT = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR)); if (pwszT == NULL) { free(pwsz); return NULL; } pwsz = pwszT; } if (wcslen(pwsz) > 0) StrCatBuffW(pwsz, wszCRLF, cch); StrCatBuffW(pwsz, rgwch, cch); }
if (dwFlags & CERT_VALIDITY_CRL_OUT_OF_DATE) { LoadString(g_hCertTrustInst, IDS_WHY_CRL_EXPIRED, rgwch, sizeof(rgwch)/sizeof(WCHAR)); if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) { cch += 200; pwszT = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR)); if (pwszT == NULL) { free(pwsz); return NULL; } pwsz = pwszT; } if (wcslen(pwsz) > 0) StrCatBuffW(pwsz, wszCRLF, cch); StrCatBuffW(pwsz, rgwch, cch); }
if (dwFlags & CERT_VALIDITY_EXTENDED_USAGE_FAILURE) { LoadString(g_hCertTrustInst, IDS_WHY_EXTEND_USE, rgwch, sizeof(rgwch)/sizeof(WCHAR)); if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) { cch += 200; pwszT = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR)); if (pwszT == NULL) { free(pwsz); return NULL; } pwsz = pwszT; } if (wcslen(pwsz) > 0) StrCatBuffW(pwsz, wszCRLF, cch); StrCatBuffW(pwsz, rgwch, cch); }
if (dwFlags & CERT_VALIDITY_NAME_CONSTRAINTS_FAILURE) { LoadString(g_hCertTrustInst, IDS_WHY_NAME_CONST, rgwch, sizeof(rgwch)/sizeof(WCHAR)); if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) { cch += 200; pwszT = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR)); if (pwszT == NULL) { free(pwsz); return NULL; } pwsz = pwszT; } if (wcslen(pwsz) > 0) StrCatBuffW(pwsz, wszCRLF, cch); StrCatBuffW(pwsz, rgwch, cch); }
if (dwFlags & CERT_VALIDITY_POLICY_FAILURE) { LoadString(g_hCertTrustInst, IDS_WHY_POLICY, rgwch, sizeof(rgwch)/sizeof(WCHAR)); if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) { cch += 200; pwszT = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR)); if (pwszT == NULL) { free(pwsz); return NULL; } pwsz = pwszT; } if (wcslen(pwsz) > 0) StrCatBuffW(pwsz, wszCRLF, cch); StrCatBuffW(pwsz, rgwch, cch); }
if (dwFlags & CERT_VALIDITY_BASIC_CONSTRAINTS_FAILURE) { LoadString(g_hCertTrustInst, IDS_WHY_BASIC_CONS, rgwch, sizeof(rgwch)/sizeof(WCHAR)); if (wcslen(pwsz) + wcslen(rgwch) + 2 > cch) { cch += 200; pwszT = (LPWSTR) realloc(pwsz, cch*sizeof(WCHAR)); if (pwszT == NULL) { free(pwsz); return NULL; } pwsz = pwszT; } if (wcslen(pwsz) > 0) StrCatBuffW(pwsz, wszCRLF, cch); StrCatBuffW(pwsz, rgwch, cch); }
return pwsz; }
|