|
|
//+-------------------------------------------------------------------------
//
// 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); }
|