//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: trustapi.cpp // // Contents: Microsoft Internet Security Trust APIs // // Functions: TrustFindIssuerCertificate // TrustOpenStores // TrustDecode // TrustFreeDecode // // *** local functions *** // _CompareAuthKeyId // _CompareAuthKeyId2 // _SetCertErrorAndHygiene // _GetExternalIssuerCert // // History: 20-Nov-1997 pberkman created // //-------------------------------------------------------------------------- #include "global.hxx" BOOL _CompareAuthKeyId(DWORD dwEncoding, PCCERT_CONTEXT pChildContext, PCCERT_CONTEXT pParentContext); BOOL _CompareAuthKeyId2(DWORD dwEncoding, PCCERT_CONTEXT pChildContext, PCCERT_CONTEXT pParentContext); BOOL _SetCertErrorAndHygiene(PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pIssuerContext, DWORD dwCurrentConfidence, DWORD *pdwError); PCCERT_CONTEXT _GetExternalIssuerCert(PCCERT_CONTEXT pContext, DWORD dwEncoding, DWORD *pdwRetError, DWORD *pdwConfidence, FILETIME *psftVerifyAsOf); void _SetConfidenceOnIssuer(DWORD dwEncoding, PCCERT_CONTEXT pChildCert, PCCERT_CONTEXT pTestIssuerCert, DWORD dwVerificationFlag, FILETIME *psftVerifyAsOf, DWORD *pdwConfidence, DWORD *pdwError); PCCERT_CONTEXT WINAPI TrustFindIssuerCertificate(PCCERT_CONTEXT pChildContext, DWORD dwEncoding, DWORD chStores, HCERTSTORE *pahStores, FILETIME *psftVerifyAsOf, DWORD *pdwConfidence, DWORD *pdwError, DWORD dwFlags) { if (!(pChildContext) || !(pahStores) || !(psftVerifyAsOf) || (dwFlags != 0)) { SetLastError(ERROR_INVALID_PARAMETER); return(NULL); } PCCERT_CONTEXT pCertContext; DWORD fdwRetError; DWORD fdwWork; DWORD dwError; PCCERT_CONTEXT pCertWithHighestConfidence; DWORD dwHighestConfidence; DWORD dwConfidence; if (pdwError) { *pdwError = ERROR_SUCCESS; } dwConfidence = 0; dwHighestConfidence = 0; pCertWithHighestConfidence = NULL; fdwRetError = 0; fdwWork = 0; for (int i = 0; i < (int)chStores; i++) { fdwWork = CERT_STORE_SIGNATURE_FLAG; pCertContext = NULL; while (pCertContext = CertGetIssuerCertificateFromStore(pahStores[i], pChildContext, pCertContext, &fdwWork)) { _SetConfidenceOnIssuer(dwEncoding, pChildContext, pCertContext, fdwWork, psftVerifyAsOf, &dwConfidence, &dwError); if (dwConfidence > dwHighestConfidence) { if (pCertWithHighestConfidence) { CertFreeCertificateContext(pCertWithHighestConfidence); } dwHighestConfidence = dwConfidence; pCertWithHighestConfidence = CertDuplicateCertificateContext(pCertContext); fdwRetError = dwError; } if (dwConfidence >= CERT_CONFIDENCE_HIGHEST) { if (pdwError) { *pdwError = dwError; } if (pdwConfidence) { *pdwConfidence = dwConfidence; } CertFreeCertificateContext(pCertContext); return(pCertWithHighestConfidence); } fdwWork = CERT_STORE_SIGNATURE_FLAG; } } if (!(dwHighestConfidence & CERT_CONFIDENCE_HYGIENE)) { if (pCertContext = _GetExternalIssuerCert(pChildContext, dwEncoding, &fdwRetError, &dwConfidence, psftVerifyAsOf)) { if (dwHighestConfidence < dwConfidence) { CertFreeCertificateContext(pCertWithHighestConfidence); pCertWithHighestConfidence = pCertContext; dwHighestConfidence = dwConfidence; } } } if (pdwError) { *pdwError = fdwRetError; } if (pdwConfidence) { *pdwConfidence = dwHighestConfidence; } return(pCertWithHighestConfidence); } BOOL WINAPI TrustOpenStores(HCRYPTPROV hProv, OUT DWORD *pchStores, HCERTSTORE *pahStores, DWORD dwFlags) { BOOL fRet; DWORD cs = 0; HCERTSTORE pas[WVT_STOREID_MAX]; fRet = FALSE; if (!(pchStores) || (dwFlags != 0)) { goto ErrorInvalidParam; } // // ROOT store - ALWAYS #0 !!!! // if (!(pas[cs] = StoreProviderGetStore(hProv, WVT_STOREID_ROOT))) { goto ErrorNoRootStore; } cs++; if (pas[cs] = StoreProviderGetStore(hProv, WVT_STOREID_TRUST)) { cs++; } if (pas[cs] = StoreProviderGetStore(hProv, WVT_STOREID_CA)) { cs++; } if (pas[cs] = StoreProviderGetStore(hProv, WVT_STOREID_MY)) { cs++; } if ((pahStores) && (cs > *pchStores)) { *pchStores = cs; goto ErrorMoreData; } *pchStores = cs; fRet = TRUE; if (!(pahStores)) { goto ErrorMoreData; } DWORD i; for (i = 0; i < cs; i++) { pahStores[i] = pas[i]; } CommonReturn: return(fRet); ErrorReturn: while (cs > 0) { CertCloseStore(pas[cs - 1], 0); cs--; } goto CommonReturn; SET_ERROR_VAR_EX(DBG_SS, ErrorMoreData, ERROR_MORE_DATA); SET_ERROR_VAR_EX(DBG_SS, ErrorNoRootStore, TRUST_E_SYSTEM_ERROR); SET_ERROR_VAR_EX(DBG_SS, ErrorInvalidParam, ERROR_INVALID_PARAMETER); } BOOL WINAPI TrustIsCertificateSelfSigned(PCCERT_CONTEXT pContext, DWORD dwEncoding, DWORD dwFlags) { if (!(pContext) || (dwFlags != 0)) { SetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } if (!(CertCompareCertificateName(dwEncoding, &pContext->pCertInfo->Issuer, &pContext->pCertInfo->Subject))) { return(FALSE); } DWORD dwFlag; dwFlag = CERT_STORE_SIGNATURE_FLAG; if (!(CertVerifySubjectCertificateContext(pContext, pContext, &dwFlag)) || (dwFlag & CERT_STORE_SIGNATURE_FLAG)) { return(FALSE); } return(TRUE); } #define sz_CRYPTNET_DLL "cryptnet.dll" #define sz_CryptGetObjectUrl "CryptGetObjectUrl" #define sz_CryptRetrieveObjectByUrlW "CryptRetrieveObjectByUrlW" typedef BOOL (WINAPI *PFN_CRYPT_GET_OBJECT_URL)( IN LPCSTR pszUrlOid, IN LPVOID pvPara, IN DWORD dwFlags, OUT OPTIONAL PCRYPT_URL_ARRAY pUrlArray, IN OUT DWORD* pcbUrlArray, OUT OPTIONAL PCRYPT_URL_INFO pUrlInfo, IN OUT OPTIONAL DWORD* pcbUrlInfo, IN OPTIONAL LPVOID pvReserved ); typedef BOOL (WINAPI *PFN_CRYPT_RETRIEVE_OBJECT_BY_URLW)( IN LPCWSTR pszUrl, IN LPCSTR pszObjectOid, IN DWORD dwRetrievalFlags, IN DWORD dwTimeout, OUT LPVOID* ppvObject, IN HCRYPTASYNC hAsyncRetrieve, IN OPTIONAL PCRYPT_CREDENTIALS pCredentials, IN OPTIONAL LPVOID pvVerify, IN OPTIONAL LPVOID pvReserved ); PCCERT_CONTEXT _GetExternalIssuerCert(PCCERT_CONTEXT pContext, DWORD dwEncoding, DWORD *pdwRetError, DWORD *pdwConfidence, FILETIME *psftVerifyAsOf) { *pdwConfidence = 0; #if (USE_IEv4CRYPT32) return(NULL); #else DWORD cbUrlArray; CRYPT_URL_ARRAY *pUrlArray; PCCERT_CONTEXT pIssuer; PCCERT_CONTEXT pCertBestMatch; DWORD dwHighestConfidence; DWORD dwConfidence; DWORD dwStatus; DWORD dwError; DWORD i; pCertBestMatch = NULL; pIssuer = NULL; pUrlArray = NULL; cbUrlArray = 0; dwHighestConfidence = 0; HMODULE hDll = NULL; PFN_CRYPT_GET_OBJECT_URL pfnCryptGetObjectUrl; PFN_CRYPT_RETRIEVE_OBJECT_BY_URLW pfnCryptRetrieveObjectByUrlW; if (NULL == (hDll = LoadLibraryA(sz_CRYPTNET_DLL))) goto LoadCryptNetDllError; if (NULL == (pfnCryptGetObjectUrl = (PFN_CRYPT_GET_OBJECT_URL) GetProcAddress(hDll, sz_CryptGetObjectUrl))) goto CryptGetObjectUrlProcAddressError; if (NULL == (pfnCryptRetrieveObjectByUrlW = (PFN_CRYPT_RETRIEVE_OBJECT_BY_URLW) GetProcAddress(hDll, sz_CryptRetrieveObjectByUrlW))) goto CryptRetrieveObjectByUrlWProcAddressError; if (!(pfnCryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)pContext, 0, NULL, &cbUrlArray, NULL, NULL, NULL)) || (cbUrlArray < 1)) { goto GetObjectUrlFailed; } if (!(pUrlArray = (CRYPT_URL_ARRAY *) new BYTE[cbUrlArray])) { goto MemoryError; } memset(pUrlArray, 0x00, cbUrlArray); if (!(pfnCryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)pContext, 0, pUrlArray, &cbUrlArray, NULL, NULL, NULL))) { goto GetObjectUrlFailed; } for (i = 0; i < pUrlArray->cUrl; i++) { if (pIssuer) { CertFreeCertificateContext(pIssuer); pIssuer = NULL; } if (pfnCryptRetrieveObjectByUrlW(pUrlArray->rgwszUrl[i], CONTEXT_OID_CERTIFICATE, 0, 0, (void **)&pIssuer, NULL, NULL, NULL, NULL)) { if (!(CertCompareCertificateName(X509_ASN_ENCODING, &pContext->pCertInfo->Issuer, &pIssuer->pCertInfo->Subject))) { continue; } dwStatus = CERT_STORE_SIGNATURE_FLAG; if (!(CertVerifySubjectCertificateContext(pContext, pIssuer, &dwStatus))) { continue; } dwError = 0; _SetConfidenceOnIssuer(dwEncoding, pContext, pIssuer, dwStatus, psftVerifyAsOf, &dwConfidence, &dwError); if (dwError != 0) { continue; } if (dwConfidence > dwHighestConfidence) { if (pCertBestMatch) { CertFreeCertificateContext(pCertBestMatch); } dwHighestConfidence = dwConfidence; pCertBestMatch = CertDuplicateCertificateContext(pIssuer); } if (dwConfidence >= CERT_CONFIDENCE_HIGHEST) { goto CommonReturn; } } } goto RetrieveObjectFailed; CommonReturn: if (hDll) FreeLibrary(hDll); if (pIssuer) { CertFreeCertificateContext(pIssuer); } if (pUrlArray) { delete pUrlArray; } *pdwConfidence = dwHighestConfidence; return(pCertBestMatch); ErrorReturn: if (pCertBestMatch) { CertFreeCertificateContext(pCertBestMatch); pCertBestMatch = NULL; } goto CommonReturn; TRACE_ERROR_EX(DBG_SS, LoadCryptNetDllError) TRACE_ERROR_EX(DBG_SS, CryptGetObjectUrlProcAddressError) TRACE_ERROR_EX(DBG_SS, CryptRetrieveObjectByUrlWProcAddressError) TRACE_ERROR_EX(DBG_SS, GetObjectUrlFailed); TRACE_ERROR_EX(DBG_SS, RetrieveObjectFailed); SET_ERROR_VAR_EX(DBG_SS, MemoryError, ERROR_NOT_ENOUGH_MEMORY); #endif // USE_IEv4CRYPT32 } BOOL WINAPI TrustDecode(DWORD dwModuleId, BYTE **ppbRet, DWORD *pcbRet, DWORD cbHint, DWORD dwEncoding, const char *pcszOID, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwDecodeFlags) { if (!(*ppbRet = new BYTE[cbHint])) { goto MemoryError; } *pcbRet = cbHint; if (!(CryptDecodeObject(dwEncoding, pcszOID, pbEncoded, cbEncoded, dwDecodeFlags, *ppbRet, pcbRet))) { if (GetLastError() != ERROR_MORE_DATA) { goto DecodeError; } } if (cbHint < *pcbRet) { DBG_PRINTF((DBG_SS, "****** TrustDecode(0x%08.8lX): recalling due to bad size: hint: %lu actual: %lu\r\n", dwModuleId, cbHint, *pcbRet)); DELETE_OBJECT(*ppbRet); return(TrustDecode(dwModuleId, ppbRet, pcbRet, *pcbRet, dwEncoding, pcszOID, pbEncoded, cbEncoded, dwDecodeFlags)); } # if DBG if ((cbHint / 3) > *pcbRet) { DBG_PRINTF((DBG_SS, "TrustDecode(0x%08.8lX): hint too big. hint: %lu actual: %lu\r\n", dwModuleId, cbHint, *pcbRet)); } # endif return(TRUE); ErrorReturn: DELETE_OBJECT(*ppbRet); return(FALSE); TRACE_ERROR_EX(DBG_SS, DecodeError); SET_ERROR_VAR_EX(DBG_SS, MemoryError, ERROR_NOT_ENOUGH_MEMORY); } BOOL WINAPI TrustFreeDecode(DWORD dwModuleId, BYTE **pbAllocated) { DELETE_OBJECT(*pbAllocated); return(TRUE); } void _SetConfidenceOnIssuer(DWORD dwEncoding, PCCERT_CONTEXT pChildCert, PCCERT_CONTEXT pTestIssuerCert, DWORD dwVerificationFlag, FILETIME *psftVerifyAsOf, DWORD *pdwConfidence, DWORD *pdwError) { *pdwConfidence = 0; if (!(dwVerificationFlag & CERT_STORE_SIGNATURE_FLAG)) { *pdwConfidence |= CERT_CONFIDENCE_SIG; } if (CertVerifyTimeValidity(psftVerifyAsOf, pTestIssuerCert->pCertInfo) == 0) { *pdwConfidence |= CERT_CONFIDENCE_TIME; } if (CertVerifyValidityNesting(pChildCert->pCertInfo, pTestIssuerCert->pCertInfo)) { *pdwConfidence |= CERT_CONFIDENCE_TIMENEST; } if (_CompareAuthKeyId(dwEncoding, pChildCert, pTestIssuerCert)) { *pdwConfidence |= CERT_CONFIDENCE_AUTHIDEXT; } else if (_CompareAuthKeyId2(dwEncoding, pChildCert, pTestIssuerCert)) { *pdwConfidence |= CERT_CONFIDENCE_AUTHIDEXT; } if (_SetCertErrorAndHygiene(pChildCert, pTestIssuerCert, *pdwConfidence, pdwError)) { *pdwConfidence |= CERT_CONFIDENCE_HYGIENE; } } BOOL _SetCertErrorAndHygiene(PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pIssuerContext, DWORD dwCurrentConfidence, DWORD *pdwError) { *pdwError = ERROR_SUCCESS; if (!(dwCurrentConfidence & CERT_CONFIDENCE_SIG)) { *pdwError = TRUST_E_CERT_SIGNATURE; return(FALSE); } if ((dwCurrentConfidence & CERT_CONFIDENCE_SIG) && (dwCurrentConfidence & CERT_CONFIDENCE_TIME) && (dwCurrentConfidence & CERT_CONFIDENCE_TIMENEST) && (dwCurrentConfidence & CERT_CONFIDENCE_AUTHIDEXT)) { return(TRUE); } if (dwCurrentConfidence & CERT_CONFIDENCE_AUTHIDEXT) { return(TRUE); } return(FALSE); } BOOL _CompareAuthKeyId2(DWORD dwEncoding, PCCERT_CONTEXT pChildContext, PCCERT_CONTEXT pParentContext) { DWORD i; PCERT_EXTENSION pExt; DWORD cbIdInfo; PCERT_AUTHORITY_KEY_ID2_INFO pIdInfo; BOOL fRet; pIdInfo = NULL; if (pChildContext->pCertInfo->cExtension < 1) { goto NoExtensions; } if (!(pExt = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2, pChildContext->pCertInfo->cExtension, pChildContext->pCertInfo->rgExtension))) { goto NoExtensions; } if (!(TrustDecode(WVT_MODID_WINTRUST, (BYTE **)&pIdInfo, &cbIdInfo, 103, dwEncoding, X509_AUTHORITY_KEY_ID2, pExt->Value.pbData, pExt->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG))) { goto DecodeFailed; } for (i = 0; i < pIdInfo->AuthorityCertIssuer.cAltEntry; i++) { if (pIdInfo->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME) { break; } } if (i == pIdInfo->AuthorityCertIssuer.cAltEntry) { goto NoAltDirectoryName; } if (!(CertCompareCertificateName(dwEncoding, &pIdInfo->AuthorityCertIssuer.rgAltEntry[i].DirectoryName, &pParentContext->pCertInfo->Issuer))) { goto IncorrectIssuer; } // // issuer certificate's serial number must match // if (!(CertCompareIntegerBlob(&pIdInfo->AuthorityCertSerialNumber, &pParentContext->pCertInfo->SerialNumber))) { goto IncorrectIssuer; } fRet = TRUE; CommonReturn: if (pIdInfo) { TrustFreeDecode(WVT_MODID_WINTRUST, (BYTE **)&pIdInfo); } return(fRet); ErrorReturn: fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS, NoExtensions); TRACE_ERROR_EX(DBG_SS, DecodeFailed); TRACE_ERROR_EX(DBG_SS, IncorrectIssuer); TRACE_ERROR_EX(DBG_SS, NoAltDirectoryName); } BOOL _CompareAuthKeyId(DWORD dwEncoding, PCCERT_CONTEXT pChildContext, PCCERT_CONTEXT pParentContext) { PCERT_EXTENSION pExt; PCERT_AUTHORITY_KEY_ID_INFO pChildKeyIdInfo; DWORD cbKeyIdInfo; BOOL fRet; pChildKeyIdInfo = NULL; pExt = NULL; if (pChildContext->pCertInfo->cExtension < 1) { goto NoExtensions; } pChildKeyIdInfo = NULL; if (!(pExt = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER, pChildContext->pCertInfo->cExtension, pChildContext->pCertInfo->rgExtension))) { goto NoExtensions; } if (!(TrustDecode(WVT_MODID_WINTRUST, (BYTE **)&pChildKeyIdInfo, &cbKeyIdInfo, 104, dwEncoding, X509_AUTHORITY_KEY_ID, pExt->Value.pbData, pExt->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG))) { goto DecodeFailed; } if ((pChildKeyIdInfo->CertIssuer.cbData < 1) || (pChildKeyIdInfo->CertSerialNumber.cbData < 1)) { goto NoKeyId; } // // issuer certificate's issuer name must match // if (!(CertCompareCertificateName(dwEncoding, &pChildKeyIdInfo->CertIssuer, &pParentContext->pCertInfo->Issuer))) { goto IncorrectIssuer; } // // issuer certificate's serial number must match // if (!(CertCompareIntegerBlob(&pChildKeyIdInfo->CertSerialNumber, &pParentContext->pCertInfo->SerialNumber))) { goto IncorrectIssuer; } fRet = TRUE; CommonReturn: if (pChildKeyIdInfo) { TrustFreeDecode(WVT_MODID_WINTRUST, (BYTE **)&pChildKeyIdInfo); } return(fRet); ErrorReturn: fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS, NoExtensions); TRACE_ERROR_EX(DBG_SS, DecodeFailed); TRACE_ERROR_EX(DBG_SS, NoKeyId); TRACE_ERROR_EX(DBG_SS, IncorrectIssuer); }