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.
1762 lines
58 KiB
1762 lines
58 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|