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

506 lines
14 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: fndchain.cpp
//
// Contents: Find Certificate Chain in Store API
//
// Functions: CertFindChainInStore
// IFC_IsEndCertValidForUsage
//
// History: 28-Feb-98 philh created
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
BOOL IFC_IsEndCertValidForUsages(
IN PCCERT_CONTEXT pCert,
IN PCERT_ENHKEY_USAGE pUsage,
IN BOOL fOrUsage
)
{
BOOL fResult;
int cNumOIDs;
LPSTR *ppOIDs = NULL;
DWORD cbOIDs;
if (0 == pUsage->cUsageIdentifier)
goto SuccessReturn;
cbOIDs = 0;
if (!CertGetValidUsages(
1, // cCerts
&pCert,
&cNumOIDs,
NULL, // rghOIDs
&cbOIDs
)) goto CertGetValidUsagesError;
if (-1 == cNumOIDs)
// Cert doesn't have any EKU
goto SuccessReturn;
else if (0 == cNumOIDs)
// Intersection of usages in properties and extensions is NONE
goto NoMatch;
assert(cbOIDs);
if (NULL == (ppOIDs = (LPSTR *) PkiNonzeroAlloc(cbOIDs)))
goto OutOfMemory;
if (!CertGetValidUsages(
1, // cCerts
&pCert,
&cNumOIDs,
ppOIDs,
&cbOIDs
)) goto CertGetValidUsagesError;
if (0 >= cNumOIDs)
// We had a change from the first call
goto NoMatch;
{
DWORD cId1 = pUsage->cUsageIdentifier;
LPSTR *ppszId1 = pUsage->rgpszUsageIdentifier;
for ( ; cId1 > 0; cId1--, ppszId1++) {
DWORD cId2 = cNumOIDs;
LPSTR *ppszId2 = ppOIDs;
for ( ; cId2 > 0; cId2--, ppszId2++) {
if (0 == strcmp(*ppszId1, *ppszId2)) {
if (fOrUsage)
goto SuccessReturn;
else
break;
}
}
if (!fOrUsage && 0 == cId2)
goto NoMatch;
}
if (fOrUsage)
// For the "OR" option we're here without any match
goto NoMatch;
// else
// For the "AND" option we have matched all the specified
// identifiers
}
SuccessReturn:
fResult = TRUE;
CommonReturn:
PkiFree(ppOIDs);
return fResult;
NoMatch:
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(CertGetValidUsagesError)
TRACE_ERROR(OutOfMemory)
}
BOOL IFC_IsEndCertValidForUsage(
IN PCCERT_CONTEXT pCert,
IN LPCSTR pszUsageIdentifier
)
{
CERT_ENHKEY_USAGE Usage = { 1, (LPSTR *) &pszUsageIdentifier};
return IFC_IsEndCertValidForUsages(
pCert,
&Usage,
TRUE // fOrUsage
);
}
BOOL CompareChainIssuerNameBlobs(
IN DWORD dwCertEncodingType,
IN DWORD dwFindFlags,
IN PCERT_CHAIN_FIND_BY_ISSUER_PARA pPara,
IN OUT PCCERT_CHAIN_CONTEXT *ppChainContext
)
{
DWORD i;
DWORD cIssuer = pPara->cIssuer;
PCERT_NAME_BLOB pIssuer = pPara->rgIssuer;
PCCERT_CHAIN_CONTEXT pChainContext = *ppChainContext;
if (0 == cIssuer)
return TRUE;
for (i = 0; i < pChainContext->cChain; i++) {
DWORD j;
PCERT_SIMPLE_CHAIN pChain;
if (0 < i && 0 == (dwFindFlags &
CERT_CHAIN_FIND_BY_ISSUER_COMPLEX_CHAIN_FLAG))
break;
pChain = pChainContext->rgpChain[i];
for (j = 0; j < pChain->cElement; j++) {
DWORD k;
PCCERT_CONTEXT pCert = pChain->rgpElement[j]->pCertContext;
PCERT_NAME_BLOB pChainIssuer = &pCert->pCertInfo->Issuer;
for (k = 0; k < cIssuer; k++) {
if (CertCompareCertificateName(
dwCertEncodingType,
pChainIssuer,
&pIssuer[k]
)) {
if (STRUCT_CBSIZE(CERT_CHAIN_FIND_BY_ISSUER_PARA,
pdwIssuerElementIndex) <= pPara->cbSize) {
if (pPara->pdwIssuerChainIndex)
*pPara->pdwIssuerChainIndex = i;
if (pPara->pdwIssuerElementIndex)
*pPara->pdwIssuerElementIndex = j + 1;
}
return TRUE;
}
}
}
}
// See if we have a match in any of the lower quality chains
for (i = 0; i < pChainContext->cLowerQualityChainContext; i++) {
PCCERT_CHAIN_CONTEXT pLowerQualityChainContext =
pChainContext->rgpLowerQualityChainContext[i];
if (pLowerQualityChainContext->TrustStatus.dwErrorStatus &
CERT_TRUST_IS_NOT_SIGNATURE_VALID)
// Lower quality chains must at least have valid signatures
continue;
CertDuplicateCertificateChain(pLowerQualityChainContext);
if (CompareChainIssuerNameBlobs(
dwCertEncodingType,
dwFindFlags,
pPara,
&pLowerQualityChainContext
)) {
// Replace the input chain context with the lower quality
// chain context
CertFreeCertificateChain(pChainContext);
*ppChainContext = pLowerQualityChainContext;
return TRUE;
} else {
assert(pLowerQualityChainContext ==
pChainContext->rgpLowerQualityChainContext[i]);
CertFreeCertificateChain(pLowerQualityChainContext);
}
}
return FALSE;
}
static DWORD GetChainKeyIdentifierPropId(
IN PCCERT_CONTEXT pCert,
IN DWORD dwKeySpec
)
{
DWORD dwPropId;
PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
DWORD cbKeyProvInfo;
BYTE rgbKeyId[MAX_HASH_LEN];
DWORD cbKeyId;
CRYPT_HASH_BLOB KeyIdentifier;
cbKeyId = sizeof(rgbKeyId);
if (!CertGetCertificateContextProperty(
pCert,
CERT_KEY_IDENTIFIER_PROP_ID,
rgbKeyId,
&cbKeyId
))
return 0;
KeyIdentifier.pbData = rgbKeyId;
KeyIdentifier.cbData = cbKeyId;
if (!CryptGetKeyIdentifierProperty(
&KeyIdentifier,
CERT_KEY_PROV_INFO_PROP_ID,
CRYPT_KEYID_ALLOC_FLAG,
NULL, // pwszComputerName
NULL, // pvReserved
(void *) &pKeyProvInfo,
&cbKeyProvInfo
)) {
// Try again, searching LocalMachine
if (!CryptGetKeyIdentifierProperty(
&KeyIdentifier,
CERT_KEY_PROV_INFO_PROP_ID,
CRYPT_KEYID_ALLOC_FLAG | CRYPT_KEYID_MACHINE_FLAG,
NULL, // pwszComputerName
NULL, // pvReserved
(void *) &pKeyProvInfo,
&cbKeyProvInfo
))
return 0;
}
if (dwKeySpec && dwKeySpec != pKeyProvInfo->dwKeySpec)
dwPropId = 0;
else
dwPropId = CERT_KEY_PROV_INFO_PROP_ID;
PkiDefaultCryptFree(pKeyProvInfo);
return dwPropId;
}
DWORD GetChainPrivateKeyPropId(
IN PCCERT_CONTEXT pCert,
IN DWORD dwKeySpec
)
{
DWORD dwPropId;
CERT_KEY_CONTEXT KeyContext;
PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
DWORD cbProp;
cbProp = sizeof(KeyContext);
if (CertGetCertificateContextProperty(
pCert,
CERT_KEY_CONTEXT_PROP_ID,
&KeyContext,
&cbProp
)) {
assert(sizeof(KeyContext) <= cbProp);
if (dwKeySpec && dwKeySpec != KeyContext.dwKeySpec)
return 0;
else
return CERT_KEY_CONTEXT_PROP_ID;
}
if (!CertGetCertificateContextProperty(
pCert,
CERT_KEY_PROV_INFO_PROP_ID,
NULL, // pvData
&cbProp
))
return 0;
if (NULL == (pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) PkiNonzeroAlloc(
cbProp)))
goto OutOfMemory;
if (!CertGetCertificateContextProperty(
pCert,
CERT_KEY_PROV_INFO_PROP_ID,
pKeyProvInfo,
&cbProp
)) goto CertGetCertificateContextPropertyError;
if (dwKeySpec && dwKeySpec != pKeyProvInfo->dwKeySpec)
goto NoMatch;
dwPropId = CERT_KEY_PROV_INFO_PROP_ID;
CommonReturn:
PkiFree(pKeyProvInfo);
return dwPropId;
NoMatch:
ErrorReturn:
dwPropId = 0;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(CertGetCertificateContextPropertyError)
}
BOOL FindChainByIssuer(
IN DWORD dwCertEncodingType,
IN DWORD dwFindFlags,
IN PCERT_CHAIN_FIND_BY_ISSUER_PARA pPara,
IN PCCERT_CONTEXT pCert,
OUT PCCERT_CHAIN_CONTEXT *ppChainContext
)
{
BOOL fResult = TRUE;
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
DWORD dwPrivateKeyPropId;
CERT_CHAIN_PARA ChainPara;
DWORD dwCreateChainFlags;
if (NULL == pPara ||
offsetof(CERT_CHAIN_FIND_BY_ISSUER_PARA, pvFindArg) >
pPara->cbSize) {
fResult = FALSE;
goto InvalidArg;
}
if (dwFindFlags & CERT_CHAIN_FIND_BY_ISSUER_NO_KEY_FLAG)
dwPrivateKeyPropId = CERT_KEY_CONTEXT_PROP_ID;
else if (0 == (dwPrivateKeyPropId = GetChainPrivateKeyPropId(
pCert,
pPara->dwKeySpec
))) {
if (0 == (dwPrivateKeyPropId = GetChainKeyIdentifierPropId(
pCert,
pPara->dwKeySpec
)))
goto NoMatch;
}
if (pPara->pszUsageIdentifier) {
if (!IFC_IsEndCertValidForUsage(
pCert,
pPara->pszUsageIdentifier
)) goto NoMatch;
}
if (pPara->pfnFindCallback) {
if (!pPara->pfnFindCallback(
pCert,
pPara->pvFindArg
)) goto NoMatch;
}
memset(&ChainPara, 0, sizeof(ChainPara));
ChainPara.cbSize = sizeof(ChainPara);
if (pPara->pszUsageIdentifier) {
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
ChainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier =
(LPSTR *) &pPara->pszUsageIdentifier;
}
dwCreateChainFlags = 0;
if (0 != pPara->cIssuer) {
// For cross certs, might need to look at the lower quality chains
dwCreateChainFlags |= CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS;
}
if (dwFindFlags & CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG)
dwCreateChainFlags |= CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL;
if (dwFindFlags & CERT_CHAIN_FIND_BY_ISSUER_LOCAL_MACHINE_FLAG)
dwCreateChainFlags |= CERT_CHAIN_USE_LOCAL_MACHINE_STORE;
if (!CertGetCertificateChain(
NULL, // hChainEngine
pCert,
NULL, // pTime
dwFindFlags & CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG ?
0 : pCert->hCertStore,
&ChainPara,
dwCreateChainFlags,
NULL, // pvReserved
&pChainContext
)) goto CertGetCertificateChainError;
if (!CompareChainIssuerNameBlobs(
dwCertEncodingType,
dwFindFlags,
pPara,
&pChainContext
)) goto NoMatch;
if (dwFindFlags & CERT_CHAIN_FIND_BY_ISSUER_COMPARE_KEY_FLAG) {
if (CERT_KEY_CONTEXT_PROP_ID != dwPrivateKeyPropId) {
DWORD dwAcquireFlags = pPara->dwAcquirePrivateKeyFlags |
CRYPT_ACQUIRE_COMPARE_KEY_FLAG;
HCRYPTPROV hProv;
BOOL fCallerFreeProv;
if (!CryptAcquireCertificatePrivateKey(
pCert,
dwAcquireFlags,
NULL, // pvReserved
&hProv,
NULL, // pdwKeySpec
&fCallerFreeProv
)) goto CryptAcquireCertificatePrivateKeyError;
if (fCallerFreeProv)
CryptReleaseContext(hProv, 0);
}
}
CommonReturn:
*ppChainContext = pChainContext;
return fResult;
NoMatch:
ErrorReturn:
if (pChainContext) {
CertFreeCertificateChain(pChainContext);
pChainContext = NULL;
}
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(CertGetCertificateChainError)
TRACE_ERROR(CryptAcquireCertificatePrivateKeyError)
}
PCCERT_CHAIN_CONTEXT
WINAPI
CertFindChainInStore(
IN HCERTSTORE hCertStore,
IN DWORD dwCertEncodingType,
IN DWORD dwFindFlags,
IN DWORD dwFindType,
IN const void *pvFindPara,
IN PCCERT_CHAIN_CONTEXT pPrevChainContext
)
{
PCCERT_CONTEXT pCert = NULL;
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
if (0 == dwCertEncodingType)
dwCertEncodingType = X509_ASN_ENCODING;
if (pPrevChainContext) {
if (pPrevChainContext->cChain) {
PCERT_SIMPLE_CHAIN pChain = pPrevChainContext->rgpChain[0];
if (pChain->cElement)
pCert = CertDuplicateCertificateContext(
pChain->rgpElement[0]->pCertContext);
}
CertFreeCertificateChain(pPrevChainContext);
}
while (pCert = CertEnumCertificatesInStore(hCertStore, pCert)) {
switch (dwFindType) {
case CERT_CHAIN_FIND_BY_ISSUER:
if (!FindChainByIssuer(
dwCertEncodingType,
dwFindFlags,
(PCERT_CHAIN_FIND_BY_ISSUER_PARA) pvFindPara,
pCert,
&pChainContext
)) goto FindChainByIssuerError;
if (pChainContext)
goto CommonReturn;
break;
default:
goto InvalidArg;
}
}
SetLastError((DWORD) CRYPT_E_NOT_FOUND);
CommonReturn:
if (pCert)
CertFreeCertificateContext(pCert);
return pChainContext;
ErrorReturn:
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(FindChainByIssuerError)
}