Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

620 lines
18 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: usagutil.cpp
//
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
extern HINSTANCE HinstDll;
//BOOL CertifiateValidForEnhancedKeyUsage(LPCSTR szEku, PCCERT_CONTEXT pCert);
//BOOL CertifiateValidForEnhancedKeyUsageWithChain(LPCSTR szEku, PCCERT_CONTEXT pCert);
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
BOOL OIDinArray(LPCSTR pszOID, LPSTR *rgszOIDArray, DWORD cOIDs)
{
DWORD i;
for (i=0; i<cOIDs; i++)
{
if (strcmp(pszOID, rgszOIDArray[i]) == 0)
{
return TRUE;
}
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
BOOL OIDInUsages(PCERT_ENHKEY_USAGE pUsage, LPCSTR pszOID)
{
DWORD i;
// check every extension
for(i=0; i<pUsage->cUsageIdentifier; i++)
{
if(!strcmp(pUsage->rgpszUsageIdentifier[i], pszOID))
break;
}
return (i < pUsage->cUsageIdentifier);
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
static BOOL UsageExists(PCCRYPT_OID_INFO *pCryptOIDInfo, LPSTR pszOID)
{
int i = 0;
while (pCryptOIDInfo[i] != NULL)
{
if (strcmp(pCryptOIDInfo[i]->pszOID, pszOID) == 0)
{
return TRUE;
}
i++;
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
static BOOL WINAPI AddNewOIDToArray(IN LPTSTR pNewOID, IN LPTSTR ** pppOIDs, IN DWORD * pdwOIDs)
{
LPTSTR * ppNewOIDs;
DWORD cNumOIDs = *pdwOIDs;
for (DWORD i = 0; i < cNumOIDs; i++)
{
if (0 == strcmp(pNewOID, (*pppOIDs)[i]))
{
return TRUE;
}
}
if (0 == cNumOIDs)
ppNewOIDs = (LPTSTR *) malloc(sizeof(LPSTR));
else
ppNewOIDs = (LPTSTR *) realloc(*pppOIDs, (cNumOIDs + 1) * sizeof(LPSTR));
if (ppNewOIDs)
{
if (NULL == (ppNewOIDs[cNumOIDs] = (LPSTR) malloc(strlen(pNewOID) + 1)))
{
free(ppNewOIDs);
return FALSE;
}
strcpy(ppNewOIDs[cNumOIDs], pNewOID);
*pppOIDs = ppNewOIDs;
*pdwOIDs = cNumOIDs + 1;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
BOOL AllocAndReturnKeyUsageList(PCRYPT_PROVIDER_CERT pCryptProviderCert, LPSTR **pKeyUsageOIDs, DWORD *numOIDs)
{
BOOL fRet = TRUE;
DWORD i, j = 0;
PCERT_CHAIN_ELEMENT pChainElement = pCryptProviderCert->pChainElement;
*numOIDs = 0;
*pKeyUsageOIDs = NULL;
if (!pChainElement)
{
goto ErrorCleanUp;
}
//
// For NULL usages, use
//
// szOID_ANY_CERT_POLICY = good for all issuance usages (maps to "All issuance purposes")
// szOID_ANY_APPLICATION_POLICY = good for all application usages (maps to "All application purposes")
//
if (!pChainElement->pIssuanceUsage)
{
//
// Good for all issuance usages.
//
if (!AddNewOIDToArray(szOID_ANY_CERT_POLICY, pKeyUsageOIDs, numOIDs))
{
goto ErrorCleanUp;
}
}
else
{
for (i = 0; i < pChainElement->pIssuanceUsage->cUsageIdentifier; i++)
{
if (!AddNewOIDToArray(pChainElement->pIssuanceUsage->rgpszUsageIdentifier[i], pKeyUsageOIDs, numOIDs))
{
goto ErrorCleanUp;
}
}
}
if (!pChainElement->pApplicationUsage)
{
//
// Good for all application usages.
//
if (!AddNewOIDToArray(szOID_ANY_APPLICATION_POLICY, pKeyUsageOIDs, numOIDs))
{
goto ErrorCleanUp;
}
}
else
{
for (i = 0; i < pChainElement->pApplicationUsage->cUsageIdentifier; i++)
{
if (!AddNewOIDToArray(pChainElement->pApplicationUsage->rgpszUsageIdentifier[i], pKeyUsageOIDs, numOIDs))
{
goto ErrorCleanUp;
}
}
}
CleanUp:
return(fRet);
ErrorCleanUp:
if (*pKeyUsageOIDs != NULL)
{
for (i = 0; i < *numOIDs; i++)
{
if ((*pKeyUsageOIDs)[i])
free((*pKeyUsageOIDs)[i]);
}
*numOIDs = 0;
free(*pKeyUsageOIDs);
*pKeyUsageOIDs = NULL;
}
fRet = FALSE;
goto CleanUp;
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
BOOL AllocAndReturnEKUList(PCCERT_CONTEXT pCert, LPSTR **pKeyUsageOIDs, DWORD *numOIDs)
{
BOOL fRet = TRUE;
DWORD cbExtensionUsage = 0;
PCERT_ENHKEY_USAGE pExtensionUsage = NULL;
DWORD cbPropertyUsage = 0;
PCERT_ENHKEY_USAGE pPropertyUsage = NULL;
DWORD i;
DWORD numPropUsages = 0;
//
// get all of the usages from extensions
//
if(!CertGetEnhancedKeyUsage (
pCert,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
NULL,
&cbExtensionUsage
) ||
(pExtensionUsage = (PCERT_ENHKEY_USAGE) malloc(cbExtensionUsage)) == NULL ||
!CertGetEnhancedKeyUsage (
pCert,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
pExtensionUsage,
&cbExtensionUsage
) ) {
// if not found, then we mean everything is OK
if( GetLastError() == CRYPT_E_NOT_FOUND) {
if(pExtensionUsage != NULL)
free(pExtensionUsage);
pExtensionUsage = NULL;
}
else
goto ErrorCleanUp;
}
//
// get all of the usages from properties
//
if(!CertGetEnhancedKeyUsage (
pCert,
CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
NULL,
&cbPropertyUsage
) ||
(pPropertyUsage = (PCERT_ENHKEY_USAGE) malloc(cbPropertyUsage)) == NULL ||
!CertGetEnhancedKeyUsage (
pCert,
CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
pPropertyUsage,
&cbPropertyUsage
) ) {
// if not found, then we mean everything is OK
if( GetLastError() == CRYPT_E_NOT_FOUND) {
if(pPropertyUsage != NULL)
free(pPropertyUsage);
pPropertyUsage = NULL;
}
else
goto ErrorCleanUp;
}
*numOIDs = 0;
//
// if there are usages in the extensions, then that is the
// available list, otherwise get the global list and add the properties
//
if (pExtensionUsage != NULL)
{
*pKeyUsageOIDs = (LPSTR *) malloc(pExtensionUsage->cUsageIdentifier * sizeof(LPSTR));
if (*pKeyUsageOIDs == NULL)
{
goto ErrorCleanUp;
}
for(i=0; i<pExtensionUsage->cUsageIdentifier; i++)
{
(*pKeyUsageOIDs)[*numOIDs] =
(LPSTR) malloc(strlen(pExtensionUsage->rgpszUsageIdentifier[i])+1);
if ((*pKeyUsageOIDs)[*numOIDs] == NULL)
{
goto ErrorCleanUp;
}
strcpy((*pKeyUsageOIDs)[(*numOIDs)++], pExtensionUsage->rgpszUsageIdentifier[i]);
}
}
else
{
PCCRYPT_OID_INFO *pCryptOIDInfo;
DWORD numUsages = 0;
//
// use WTHelperGetKnownUsages to get the default list
//
if (!WTHelperGetKnownUsages(WTH_ALLOC, &pCryptOIDInfo))
{
goto ErrorCleanUp;
}
//
// count the number of oids
//
i = 0;
while (pCryptOIDInfo[i] != NULL)
{
numUsages++;
i++;
}
//
// if there are properties, then count how many there are that
// are not already in the global list
//
if (pPropertyUsage)
{
for(i=0; i<pPropertyUsage->cUsageIdentifier; i++)
{
if (!UsageExists(pCryptOIDInfo, pPropertyUsage->rgpszUsageIdentifier[i]))
{
numPropUsages++;
}
}
}
*pKeyUsageOIDs = (LPSTR *) malloc((numUsages + numPropUsages) * sizeof(LPSTR));
if (*pKeyUsageOIDs == NULL)
{
goto ErrorCleanUp;
}
i = 0;
while (pCryptOIDInfo[i] != NULL)
{
(*pKeyUsageOIDs)[*numOIDs] =
(LPSTR) malloc(strlen(pCryptOIDInfo[i]->pszOID)+1);
if ((*pKeyUsageOIDs)[*numOIDs] == NULL)
{
WTHelperGetKnownUsages(WTH_FREE, &pCryptOIDInfo);
goto ErrorCleanUp;
}
strcpy((*pKeyUsageOIDs)[(*numOIDs)++], pCryptOIDInfo[i]->pszOID);
i++;
}
//
// add the property usages
//
if (pPropertyUsage)
{
for(i=0; i<pPropertyUsage->cUsageIdentifier; i++)
{
if (!UsageExists(pCryptOIDInfo, pPropertyUsage->rgpszUsageIdentifier[i]))
{
(*pKeyUsageOIDs)[*numOIDs] =
(LPSTR) malloc(strlen(pPropertyUsage->rgpszUsageIdentifier[i])+1);
if ((*pKeyUsageOIDs)[*numOIDs] == NULL)
{
WTHelperGetKnownUsages(WTH_FREE, &pCryptOIDInfo);
goto ErrorCleanUp;
}
strcpy((*pKeyUsageOIDs)[(*numOIDs)++], pPropertyUsage->rgpszUsageIdentifier[i]);
}
}
}
WTHelperGetKnownUsages(WTH_FREE, &pCryptOIDInfo);
}
CleanUp:
if(pExtensionUsage != NULL)
free(pExtensionUsage);
if(pPropertyUsage != NULL)
free(pPropertyUsage);
if ((*numOIDs == 0) && (*pKeyUsageOIDs != NULL))
{
free(*pKeyUsageOIDs);
}
return(fRet);
ErrorCleanUp:
if (*pKeyUsageOIDs != NULL)
{
for(i=0; i<*numOIDs; i++)
{
free(*pKeyUsageOIDs[i]);
}
*numOIDs = 0;
}
fRet = FALSE;
goto CleanUp;
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
void FreeEKUList(LPSTR *pKeyUsageOIDs, DWORD numOIDs)
{
DWORD i;
if (*pKeyUsageOIDs != NULL)
{
for(i=0; i<numOIDs; i++)
{
free(pKeyUsageOIDs[i]);
}
free(pKeyUsageOIDs);
}
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
BOOL MyGetOIDInfo(LPWSTR string, DWORD stringSize, LPSTR pszObjId)
{
PCCRYPT_OID_INFO pOIDInfo;
pOIDInfo = CryptFindOIDInfo(
CRYPT_OID_INFO_OID_KEY,
pszObjId,
0);
if (pOIDInfo != NULL)
{
if ((DWORD)wcslen(pOIDInfo->pwszName)+1 <= stringSize)
{
wcscpy(string, pOIDInfo->pwszName);
}
else
{
return FALSE;
}
}
else
{
return (MultiByteToWideChar(CP_ACP, 0, pszObjId, -1, string, stringSize) != 0);
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
BOOL fPropertiesDisabled(PCERT_ENHKEY_USAGE pPropertyUsage)
{
if (pPropertyUsage == NULL)
{
return FALSE;
}
else if (pPropertyUsage->cUsageIdentifier == 0)
{
return TRUE;
}
else
{
return ((pPropertyUsage->cUsageIdentifier == 1) &&
(strcmp(szOID_YESNO_TRUST_ATTR, pPropertyUsage->rgpszUsageIdentifier[0]) == 0));
}
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
BOOL CertHasEmptyEKUProp(PCCERT_CONTEXT pCertContext)
{
DWORD cbPropertyUsage = 0;
PCERT_ENHKEY_USAGE pPropertyUsage = NULL;
BOOL fRet = FALSE;
// get the extension usages that are in the cert
if(!CertGetEnhancedKeyUsage (
pCertContext,
CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
NULL,
&cbPropertyUsage
) ||
(pPropertyUsage = (PCERT_ENHKEY_USAGE) malloc(cbPropertyUsage)) == NULL ||
!CertGetEnhancedKeyUsage (
pCertContext,
CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
pPropertyUsage,
&cbPropertyUsage
) )
{
if(GetLastError() == CRYPT_E_NOT_FOUND)
{
return FALSE;
}
}
if (pPropertyUsage == NULL)
{
return FALSE;
}
if ((pPropertyUsage->cUsageIdentifier == 0) ||
((pPropertyUsage->cUsageIdentifier == 1) && (strcmp(szOID_YESNO_TRUST_ATTR, pPropertyUsage->rgpszUsageIdentifier[0]) == 0)))
{
fRet = TRUE;
}
if (pPropertyUsage != NULL)
{
free(pPropertyUsage);
}
return fRet;
}
//////////////////////////////////////////////////////////////////////////////////////
// This function will validate the cert for the given oid
//////////////////////////////////////////////////////////////////////////////////////
BOOL ValidateCertForUsage(
PCCERT_CONTEXT pCertContext,
FILETIME *psftVerifyAsOf,
DWORD cStores,
HCERTSTORE * rghStores,
HCERTSTORE hExtraStore,
LPCSTR pszOID)
{
WINTRUST_DATA WTD;
WINTRUST_CERT_INFO WTCI;
CRYPT_PROVIDER_DEFUSAGE cryptProviderDefUsage;
GUID defaultProviderGUID = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
BOOL fUseDefaultProvider;
BOOL fRet = FALSE;
HCERTSTORE *rghLocalStoreArray;
DWORD i;
//
// make one array out of the array of hCertStores plus the extra hCertStore
//
if (NULL == (rghLocalStoreArray = (HCERTSTORE *) malloc(sizeof(HCERTSTORE) * (cStores+1))))
{
return FALSE;
}
i=0;
while (i<cStores)
{
rghLocalStoreArray[i] = rghStores[i];
i++;
}
rghLocalStoreArray[i] = hExtraStore;
//
// initialize structs that are used with WinVerifyTrust()
//
memset(&WTD, 0x00, sizeof(WINTRUST_DATA));
WTD.cbStruct = sizeof(WINTRUST_DATA);
WTD.dwUIChoice = WTD_UI_NONE;
WTD.dwUnionChoice = WTD_CHOICE_CERT;
WTD.pCert = &WTCI;
memset(&WTCI, 0x00, sizeof(WINTRUST_CERT_INFO));
WTCI.cbStruct = sizeof(WINTRUST_CERT_INFO);
WTCI.pcwszDisplayName = L"CryptUI";
WTCI.psCertContext = (CERT_CONTEXT *)pCertContext;
WTCI.chStores = cStores+1;
WTCI.pahStores = rghLocalStoreArray;
WTCI.psftVerifyAsOf = psftVerifyAsOf;
fUseDefaultProvider = FALSE;
if (pszOID != NULL)
{
memset(&cryptProviderDefUsage, 0, sizeof(cryptProviderDefUsage));
cryptProviderDefUsage.cbStruct = sizeof(cryptProviderDefUsage);
if (!(WintrustGetDefaultForUsage(DWACTION_ALLOCANDFILL, pszOID, &cryptProviderDefUsage)))
{
// if we can't get a provider to check trust for this usage, then use the default
// provider to check usage
fUseDefaultProvider = TRUE;
}
}
//
// this call to WVT will verify the chain and return the data in sWTD.hWVTStateData
//
if (fUseDefaultProvider)
{
// the default default provider requires the policycallback data to point
// to the usage oid you are validating for, if usage is "all" then wintrust ignores
// usage checks
WTD.pPolicyCallbackData = (pszOID != NULL) ? (void *) pszOID : "all";
WTD.pSIPClientData = NULL;
if (SUCCEEDED(WinVerifyTrustEx(NULL, &defaultProviderGUID, &WTD)))
{
fRet = TRUE;
}
}
else
{
WTD.pPolicyCallbackData = cryptProviderDefUsage.pDefPolicyCallbackData;
WTD.pSIPClientData = cryptProviderDefUsage.pDefSIPClientData;
if (SUCCEEDED(WinVerifyTrustEx(NULL, &cryptProviderDefUsage.gActionID, &WTD)))
{
fRet = TRUE;
}
WintrustGetDefaultForUsage(DWACTION_FREE, szOID_KP_CTL_USAGE_SIGNING, &cryptProviderDefUsage);
}
free(rghLocalStoreArray);
return fRet;
}