//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: CCert.cpp // // Contents: Microsoft Internet Security Certificate Class // // History: 14-Aug-1997 pberkman created // //-------------------------------------------------------------------------- #include "global.hxx" #include "signer.h" extern "C" { extern BOOL WINAPI GetCryptProvFromCert(HWND hwnd, PCCERT_CONTEXT pCert, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec, BOOL *pfDidCryptAcquire, LPWSTR *ppwszTmpContainer, LPWSTR *ppwszProviderName, DWORD *pdwProviderType); extern void WINAPI FreeCryptProvFromCert(BOOL fAcquired, HCRYPTPROV hProv, LPWSTR pwszCapiProvider, DWORD dwProviderType, LPWSTR pwszTmpContainer); }; #include "ccert.hxx" CCert_::CCert_(PCCERT_CONTEXT pCertContext) { m_pCertContext = CertDuplicateCertificateContext(pCertContext); m_pCCert_Issuer = NULL; m_pwszPublisherName = NULL; m_pwszAgencyName = NULL; m_pwszProvider = NULL; m_pwszKeyContainer = NULL; m_dwProviderType = 0; m_chStores = 0; m_fTriedPrivateKey = FALSE; memset(m_pahStores, 0x00, sizeof(HCERTSTORE) * CCERT_MAXSTORES); } CCert_::~CCert_(void) { CertFreeCertificateContext(m_pCertContext); DELETE_OBJECT(m_pCCert_Issuer); DELETE_OBJECT(m_pwszPublisherName); DELETE_OBJECT(m_pwszAgencyName); DELETE_OBJECT(m_pwszProvider); DELETE_OBJECT(m_pwszKeyContainer); for (int i = 0; i < (int)m_chStores; i++) { if (m_pahStores[i]) { CertCloseStore(m_pahStores[i], 0); } } } WCHAR *CCert_::PublisherName(void) { if (m_pwszPublisherName) { return(m_pwszPublisherName); } if (!(this->ExtractCommonNameExt(&m_pwszPublisherName))) { if (!(this->ExtractCommonNameAttr(&m_pwszPublisherName))) { m_pwszPublisherName = this->GetRDNAttr(szOID_COMMON_NAME, &m_pCertContext->pCertInfo->Subject); } } return(m_pwszPublisherName); } WCHAR *CCert_::AgencyName(void) { if (m_pwszAgencyName) { return(m_pwszAgencyName); } if (!(m_pCertContext)) { return(NULL); } m_pwszAgencyName = this->GetRDNAttr(szOID_ORGANIZATIONAL_UNIT_NAME, &m_pCertContext->pCertInfo->Subject); if (!(m_pwszAgencyName)) { m_pwszAgencyName = this->GetRDNAttr(szOID_ORGANIZATION_NAME, &m_pCertContext->pCertInfo->Subject); if (!(m_pwszAgencyName)) { m_pwszAgencyName = this->GetRDNAttr(szOID_COMMON_NAME, &m_pCertContext->pCertInfo->Subject); } } return(m_pwszAgencyName); } WCHAR *CCert_::ProviderName(void) { if (m_pwszProvider) { return(m_pwszProvider); } if (!(m_pCertContext)) { return(NULL); } this->FindPrivateKey(); return(m_pwszProvider); } DWORD CCert_::ProviderType(void) { if (m_pwszProvider) { return(m_dwProviderType); } this->FindPrivateKey(); return(m_dwProviderType); } WCHAR *CCert_::PrivateKeyContainer(void) { if (m_pwszKeyContainer) { return(m_pwszKeyContainer); } this->FindPrivateKey(); return(m_pwszKeyContainer); } BOOL CCert_::BuildChain(FILETIME *psftVerifyAsOf) { FILETIME sft; if (!(m_pCertContext)) { return(FALSE); } if (m_pCCert_Issuer) { return(TRUE); } if (!(psftVerifyAsOf)) { GetSystemTimeAsFileTime(&sft); psftVerifyAsOf = &sft; } this->OpenStores(); return(this->BuildChainPrivate(m_chStores, m_pahStores, psftVerifyAsOf)); } ////////////////////////////////////////////////////////////////////////// //// //// protected //// BOOL CCert_::ExtractCommonNameExt(WCHAR **ppwszRet) { *ppwszRet = NULL; if (!(m_pCertContext)) { return(FALSE); } PCERT_NAME_VALUE pNameValue; PCERT_EXTENSION pExt; pNameValue = NULL; pExt = CertFindExtension(SPC_COMMON_NAME_OBJID, m_pCertContext->pCertInfo->cExtension, m_pCertContext->pCertInfo->rgExtension); if (pExt) { DWORD cbInfo; PCERT_RDN_VALUE_BLOB pValue; DWORD dwValueType; DWORD cwsz; cbInfo = 0; CryptDecodeObject( X509_ASN_ENCODING, X509_NAME_VALUE, pExt->Value.pbData, pExt->Value.cbData, 0, NULL, &cbInfo); if (cbInfo == 0) { return(FALSE); } if (!(pNameValue = (PCERT_NAME_VALUE)new BYTE[cbInfo])) { return(FALSE); } if (!(CryptDecodeObject(X509_ASN_ENCODING, X509_NAME_VALUE, pExt->Value.pbData, pExt->Value.cbData, 0, pNameValue, &cbInfo))) { delete pNameValue; return(FALSE); } dwValueType = pNameValue->dwValueType; pValue = &pNameValue->Value; cwsz = CertRDNValueToStrW(dwValueType, pValue, NULL, 0); if (cwsz > 1) { if (!(*ppwszRet = new WCHAR[cwsz])) { delete pNameValue; SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(FALSE); } CertRDNValueToStrW(dwValueType, pValue, *ppwszRet, cwsz); delete pNameValue; return(TRUE); } } DELETE_OBJECT(pNameValue); return(FALSE); } BOOL CCert_::ExtractCommonNameAttr(WCHAR **ppwszRet) { *ppwszRet = GetRDNAttr(szOID_COMMON_NAME, &m_pCertContext->pCertInfo->Subject); if (*ppwszRet) { return(TRUE); } return(FALSE); } WCHAR *CCert_::GetRDNAttr(char *pszObjId, PCERT_NAME_BLOB pNameBlob) { LPWSTR pwsz; PCERT_NAME_INFO pNameInfo; PCERT_RDN_ATTR pRDNAttr; DWORD cbInfo; pwsz = NULL; pNameInfo = NULL; cbInfo = 0; CryptDecodeObject( X509_ASN_ENCODING, X509_NAME, pNameBlob->pbData, pNameBlob->cbData, 0, NULL, &cbInfo); if (cbInfo == 0) { return(NULL); } if (!(pNameInfo = (PCERT_NAME_INFO)new BYTE[cbInfo])) { return(NULL); } if (!(CryptDecodeObject(X509_ASN_ENCODING, X509_NAME, pNameBlob->pbData, pNameBlob->cbData, 0, pNameInfo, &cbInfo))) { delete pNameInfo; return(NULL); } pRDNAttr = CertFindRDNAttr(pszObjId, pNameInfo); if (pRDNAttr) { PCERT_RDN_VALUE_BLOB pValue = &pRDNAttr->Value; DWORD dwValueType = pRDNAttr->dwValueType; DWORD cwsz; pValue = &pRDNAttr->Value; dwValueType = pRDNAttr->dwValueType; cwsz = CertRDNValueToStrW(dwValueType, pValue, NULL, 0); if (cwsz > 1) { if (!(pwsz = new WCHAR[cwsz])) { delete pNameInfo; SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(NULL); } CertRDNValueToStrW(dwValueType, pValue, pwsz, cwsz); } } DELETE_OBJECT(pNameInfo); return(pwsz); } ////////////////////////////////////////////////////////////////////////// //// //// private //// BOOL CCert_::BuildChainPrivate(DWORD chStores, HCERTSTORE *pahStores, FILETIME *psftVerifyAsOf) { DWORD dwError; PCCERT_CONTEXT pIssuerCertContext; DELETE_OBJECT(m_pCCert_Issuer); if (TrustIsCertificateSelfSigned(m_pCertContext, m_pCertContext->dwCertEncodingType, 0)) { return(TRUE); } pIssuerCertContext = TrustFindIssuerCertificate(m_pCertContext, m_pCertContext->dwCertEncodingType, chStores, pahStores, psftVerifyAsOf, &m_dwConfidence, &dwError, 0); if (!(pIssuerCertContext)) { SetLastError(dwError); return(FALSE); } m_pCCert_Issuer = new CCert_(pIssuerCertContext); CertFreeCertificateContext(pIssuerCertContext); if (!(m_pCCert_Issuer)) { return(FALSE); } return(m_pCCert_Issuer->BuildChainPrivate(chStores, pahStores, psftVerifyAsOf)); } // // warning: if you add a store, make sure to add one to the CCERT_MAXSTORES in ccert.hxx!!! // void CCert_::OpenStores(void) { HCERTSTORE hStore; m_chStores = 0; if (hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG | CERT_STORE_NO_CRYPT_RELEASE_FLAG, "ROOT")) { m_pahStores[m_chStores] = hStore; m_chStores++; } else { return; // if we can't find the root, FAIL! } // // open the Trust List store // if (hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG | CERT_STORE_NO_CRYPT_RELEASE_FLAG, "TRUST")) { m_pahStores[m_chStores] = hStore; m_chStores++; } // // CA Store // if (hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG | CERT_STORE_NO_CRYPT_RELEASE_FLAG, "CA")) { m_pahStores[m_chStores] = hStore; m_chStores++; } // // MY Store // if (hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG | CERT_STORE_NO_CRYPT_RELEASE_FLAG, "MY")) { m_pahStores[m_chStores] = hStore; m_chStores++; } // // SPC Store (historic reasons!) // if (hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_A, 0, NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG | CERT_STORE_NO_CRYPT_RELEASE_FLAG, "SPC")) { m_pahStores[m_chStores] = hStore; m_chStores++; } } BOOL CCert_::FindPrivateKey(void) { if ((m_pwszProvider) || (m_pwszKeyContainer)) { return(TRUE); } if (m_fTriedPrivateKey) { return(FALSE); } m_fTriedPrivateKey = TRUE; DELETE_OBJECT(m_pwszProvider); DELETE_OBJECT(m_pwszKeyContainer); // // try mssign32.dll first // HCRYPTPROV signer_hProv; WCHAR *signer_pwszTmpContainer; WCHAR *signer_pwszProviderName; DWORD signer_dwKeySpec; DWORD signer_dwProviderType; BOOL signer_fDidCryptAcquire; signer_hProv = NULL; signer_pwszTmpContainer = NULL; signer_pwszProviderName = NULL; if (GetCryptProvFromCert(NULL, m_pCertContext, &signer_hProv, &signer_dwKeySpec, &signer_fDidCryptAcquire, &signer_pwszTmpContainer, &signer_pwszProviderName, &signer_dwProviderType)) { if (signer_pwszProviderName) { if (!(m_pwszProvider = new WCHAR[wcslen(signer_pwszProviderName) + 1])) { return(FALSE); } wcscpy(m_pwszProvider, signer_pwszProviderName); if (signer_pwszTmpContainer) { if (!(m_pwszKeyContainer = new WCHAR[wcslen(signer_pwszTmpContainer) + 1])) { return(FALSE); } wcscpy(m_pwszKeyContainer, signer_pwszTmpContainer); } m_dwProviderType = signer_dwProviderType; FreeCryptProvFromCert(signer_fDidCryptAcquire, signer_hProv, signer_pwszProviderName, signer_dwProviderType, signer_pwszTmpContainer); return(TRUE); } FreeCryptProvFromCert(signer_fDidCryptAcquire, signer_hProv, signer_pwszProviderName, signer_dwProviderType, signer_pwszTmpContainer); } DWORD dwIndexProv; DWORD dwIndexContainer; DWORD dwProvType; DWORD cbSize; WCHAR wszProv[MAX_PATH + 1]; WCHAR *pwszContainer; HCRYPTPROV hProvEnum; pwszContainer = NULL; dwIndexProv = 0; for EVER { cbSize = MAX_PATH; if (!(CryptEnumProvidersU(dwIndexProv, NULL, 0, &dwProvType, &wszProv[0], &cbSize))) { break; } wszProv[cbSize] = NULL; dwIndexContainer = 0; hProvEnum = NULL; for EVER { if (!(this->EnumContainer(&hProvEnum, dwIndexContainer, dwProvType, &wszProv[0], &pwszContainer))) { break; } if (this->CheckContainerForKey(&wszProv[0], dwProvType, pwszContainer)) { m_dwProviderType = dwProvType; m_pwszKeyContainer = pwszContainer; if (m_pwszProvider = new WCHAR[wcslen(&wszProv[0]) + 1]) { wcscpy(m_pwszProvider, &wszProv[0]); } CryptReleaseContext(hProvEnum, 0); return(TRUE); } DELETE_OBJECT(pwszContainer); dwIndexContainer++; } if (hProvEnum) { CryptReleaseContext(hProvEnum, 0); } dwIndexProv++; // for our enum at the top! } return(FALSE); } BOOL CCert_::EnumContainer(HCRYPTPROV *phProv, DWORD dwIndex, DWORD dwProvType, WCHAR *pwszProv, WCHAR **ppwszContainer) { DWORD i; DWORD cbSize; char *psz; *ppwszContainer = NULL; if (!(*phProv)) { if (!(CryptAcquireContextU(phProv, NULL, pwszProv, dwProvType, CRYPT_VERIFYCONTEXT))) { return(FALSE); } } cbSize = 0; CryptGetProvParam(*phProv, PP_ENUMCONTAINERS, NULL, &cbSize, CRYPT_FIRST); if (cbSize > 0) { if (!(psz = new char[cbSize])) { return(FALSE); } memset(psz, 0x00, cbSize); CryptGetProvParam(*phProv, PP_ENUMCONTAINERS, (BYTE *)psz, &cbSize, CRYPT_FIRST); for (i = 1; i <= dwIndex; i++) { if (!(CryptGetProvParam(*phProv, PP_ENUMCONTAINERS, (BYTE *)psz, &cbSize, 0))) { delete psz; return(FALSE); } } if (!(*ppwszContainer = new WCHAR[strlen(psz) + 1])) { delete psz; SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(FALSE); } MultiByteToWideChar(0, 0, psz, -1, *ppwszContainer, (strlen(psz) + 1) * sizeof(WCHAR)); delete psz; return(TRUE); } return(FALSE); } BOOL CCert_::CheckContainerForKey(WCHAR *pwszProv, DWORD dwProvType, WCHAR *pwszContainer) { HCRYPTPROV hProv; DWORD cbSize; PCERT_PUBLIC_KEY_INFO pContInfo; if (CryptAcquireContextU(&hProv, pwszContainer, pwszProv, dwProvType, 0)) { if (!(CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, NULL, &cbSize))) { CryptReleaseContext(hProv, 0); return(FALSE); } if (!(pContInfo = (PCERT_PUBLIC_KEY_INFO)new BYTE[cbSize])) { CryptReleaseContext(hProv, 0); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(FALSE); } if (!(CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, pContInfo, &cbSize))) { delete pContInfo; CryptReleaseContext(hProv, 0); return(FALSE); } CryptReleaseContext(hProv, 0); if (CertComparePublicKeyInfo(X509_ASN_ENCODING, &m_pCertContext->pCertInfo->SubjectPublicKeyInfo, pContInfo)) { delete pContInfo; return(TRUE); } delete pContInfo; } return(FALSE); }