|
|
//*******************************************************************
//
// Copyright(c) Microsoft Corporation, 1996
//
// FILE: CERT.C
//
// PURPOSE: Certificate functions for WAB.
//
// HISTORY:
// 96/09/23 vikramm Created.
// 96/11/14 markdu BUG 10132 Updated to post-SDR CAPI.
// 96/11/14 markdu BUG 10267 Remove static link to functions in advapi32.dll
// 96/11/14 markdu BUG 10741 Call DeinitCryptoLib in DLL_PROCESS_DETACH
// only, so don't bother ref counting.
// 96/11/20 markdu Set a global flag if we fail to load the crypto library.
// Then, check this flag before we try to load again, and if the flag
// is set, skip the load.
// Also, now we only zero the APIFCN arrays if the associated library
// was just freed.
// 96/12/14 markdu Clean up for code review.
// 96/12/19 markdu Post- code review clean up.
// 96/12/20 markdu Allow BuildCertSBinaryData to do MAPIAllocateMore
// on a passed-in object instead of LocalAlloc if desired.
// 96/12/20 markdu Move some strings into resource.
// 96/12/21 markdu Added support for getting UNICODE strings from certs.
// 97/02/07 t-erikne Updated to new CAPI functions and fixed bugs.
// 97/02/15 t-erikne Moved trust from MAPI to PStore
// 97/07/02 t-erikne Moved trust from PSTore to CTLs
//
//*******************************************************************
#include "_apipch.h"
#define _WIN32_OE 0x0501
#undef CHARFORMAT
#undef GetProp
#undef SetProp
#include <mimeole.h>
#define CHARFORMAT CHARFORMATW
#define GetProp GetPropW
#define SetProp SetPropW
// Global handles for Crypto DLLs
HINSTANCE ghCryptoDLLInst = NULL; HINSTANCE ghAdvApiDLLInst = NULL; BOOL gfPrevCryptoLoadFailed = FALSE;
// Name of cert stores
static const LPTSTR cszWABCertStore = TEXT("AddressBook"); static const LPTSTR cszCACertStore = TEXT("CA"); static const LPTSTR cszROOTCertStore = TEXT("ROOT");
// Crypto function names
static const LPTSTR cszCryptoDLL = TEXT("CRYPT32.DLL"); static const LPTSTR cszAdvApiDLL = TEXT("ADVAPI32.DLL"); static const char cszCertAddEncodedCertificateToStore[] = "CertAddEncodedCertificateToStore"; static const char cszCertCreateCertificateContext[] = "CertCreateCertificateContext"; static const char cszCertDeleteCertificateFromStore[] = "CertDeleteCertificateFromStore"; static const char cszCertFindCertificateInStore[] = "CertFindCertificateInStore"; static const char cszCertFreeCertificateContext[] = "CertFreeCertificateContext"; static const char cszCertGetCertificateContextProperty[] = "CertGetCertificateContextProperty"; static const char cszCertGetIssuerCertificateFromStore[] = "CertGetIssuerCertificateFromStore"; static const char cszCertOpenSystemStore[] = "CertOpenSystemStoreW"; static const char cszCryptDecodeObject[] = "CryptDecodeObject"; static const char cszCryptMsgClose[] = "CryptMsgClose"; static const char cszCryptMsgGetParam[] = "CryptMsgGetParam"; static const char cszCryptMsgOpenToDecode[] = "CryptMsgOpenToDecode"; static const char cszCryptMsgUpdate[] = "CryptMsgUpdate"; static const char cszCertNameToStr[] = "CertNameToStrW"; static const char cszCertFindRDNAttr[] = "CertFindRDNAttr"; static const char cszCertEnumCertificatesInStore[] = "CertEnumCertificatesInStore"; static const char cszCertCompareCertificate[] = "CertCompareCertificate"; static const char cszCertRDNValueToStr[] = "CertRDNValueToStrW"; static const char cszCertVerifyTimeValidity[] = "CertVerifyTimeValidity";
// Global function pointers for Crypto API
LPCERTADDENCODEDCERTIFICATETOSTORE gpfnCertAddEncodedCertificateToStore = NULL; LPCERTCREATECERTIFICATECONTEXT gpfnCertCreateCertificateContext = NULL; LPCERTDELETECERTIFICATEFROMSTORE gpfnCertDeleteCertificateFromStore = NULL; LPCERTFINDCERTIFICATEINSTORE gpfnCertFindCertificateInStore = NULL; LPCERTFREECERTIFICATECONTEXT gpfnCertFreeCertificateContext = NULL; LPCERTGETCERTIFICATECONTEXTPROPERTY gpfnCertGetCertificateContextProperty = NULL; LPCERTGETISSUERCERTIFICATEFROMSTORE gpfnCertGetIssuerCertificateFromStore = NULL; LPCERTOPENSYSTEMSTORE gpfnCertOpenSystemStore = NULL; LPCRYPTDECODEOBJECT gpfnCryptDecodeObject = NULL; LPCERTNAMETOSTR gpfnCertNameToStr = NULL; LPCRYPTMSGCLOSE gpfnCryptMsgClose = NULL; LPCRYPTMSGGETPARAM gpfnCryptMsgGetParam = NULL; LPCRYPTMSGOPENTODECODE gpfnCryptMsgOpenToDecode = NULL; LPCRYPTMSGUPDATE gpfnCryptMsgUpdate = NULL; LPCERTFINDRDNATTR gpfnCertFindRDNAttr = NULL; LPCERTRDNVALUETOSTR gpfnCertRDNValueToStr = NULL; LPCERTENUMCERTIFICATESINSTORE gpfnCertEnumCertificatesInStore = NULL; LPCERTCOMPARECERTIFICATE gpfnCertCompareCertificate = NULL; LPCERTVERIFYTIMEVALIDITY gpfnCertVerifyTimeValidity = NULL;
// API table for Crypto function addresses in crypt32.dll
// BUGBUG this global array should go away
#define NUM_CRYPT32_CRYPTOAPI_PROCS 19
APIFCN Crypt32CryptoAPIList[NUM_CRYPT32_CRYPTOAPI_PROCS] = { { (PVOID *) &gpfnCertAddEncodedCertificateToStore, cszCertAddEncodedCertificateToStore }, { (PVOID *) &gpfnCertCreateCertificateContext, cszCertCreateCertificateContext }, { (PVOID *) &gpfnCertDeleteCertificateFromStore, cszCertDeleteCertificateFromStore }, { (PVOID *) &gpfnCertFindCertificateInStore, cszCertFindCertificateInStore }, { (PVOID *) &gpfnCertFreeCertificateContext, cszCertFreeCertificateContext }, { (PVOID *) &gpfnCertGetCertificateContextProperty, cszCertGetCertificateContextProperty }, { (PVOID *) &gpfnCertGetIssuerCertificateFromStore, cszCertGetIssuerCertificateFromStore }, { (PVOID *) &gpfnCertOpenSystemStore, cszCertOpenSystemStore }, { (PVOID *) &gpfnCryptDecodeObject, cszCryptDecodeObject }, { (PVOID *) &gpfnCertNameToStr, cszCertNameToStr }, { (PVOID *) &gpfnCryptMsgClose, cszCryptMsgClose }, { (PVOID *) &gpfnCryptMsgGetParam, cszCryptMsgGetParam }, { (PVOID *) &gpfnCryptMsgOpenToDecode, cszCryptMsgOpenToDecode }, { (PVOID *) &gpfnCryptMsgUpdate, cszCryptMsgUpdate }, { (PVOID *) &gpfnCertFindRDNAttr, cszCertFindRDNAttr }, { (PVOID *) &gpfnCertRDNValueToStr, cszCertRDNValueToStr }, { (PVOID *) &gpfnCertEnumCertificatesInStore, cszCertEnumCertificatesInStore }, { (PVOID *) &gpfnCertCompareCertificate, cszCertCompareCertificate }, { (PVOID *) &gpfnCertVerifyTimeValidity, cszCertVerifyTimeValidity }, };
// Local function prototypes
HRESULT OpenSysCertStore( HCERTSTORE* phcsSysCertStore, HCRYPTPROV* phCryptProvider, LPTSTR lpszCertStore);
HRESULT CloseCertStore( HCERTSTORE hcsWABCertStore, HCRYPTPROV hCryptProvider);
HRESULT FileTimeToDateTimeString( IN LPFILETIME lpft, IN LPTSTR FAR* lplpszBuf);
HRESULT GetNameString( LPTSTR FAR * lplpszName, DWORD dwEncoding, PCERT_NAME_BLOB pNameBlob, DWORD dwType);
HRESULT GetIssuerName( LPTSTR FAR * lplpszIssuerName, PCERT_INFO pCertInfo);
HRESULT GetAttributeString( LPTSTR FAR * lplpszDisplayName, BYTE *pbEncoded, DWORD cbEncoded, LPSTR lpszObjID);
HRESULT GetCertsDisplayInfoFromContext( HWND hwndParent, PCCERT_CONTEXT pccCertContext, LPCERT_DISPLAY_INFO lpCDI);
HRESULT ReadMessageFromFile( LPTSTR lpszFileName, HCRYPTPROV hCryptProvider, PBYTE* ppbEncoded, PDWORD pcbEncoded);
HRESULT WriteDERToFile( LPTSTR lpszFileName, PBYTE pbEncoded, DWORD cbEncoded);
HRESULT GetCertThumbPrint( PCCERT_CONTEXT pccCertContext, PCRYPT_DIGEST_BLOB pblobCertThumbPrint);
HRESULT GetIssuerContextAndStore( PCCERT_CONTEXT pccCertContext, PCCERT_CONTEXT* ppccIssuerCertContext, HCRYPTPROV hCryptProvider, HCERTSTORE* phcsIssuerStore);
HRESULT HrBuildCertSBinaryData( BOOL bIsDefault, BOOL fIsThumbprint, PCRYPT_DIGEST_BLOB pPrint, BLOB * pSymCaps, FILETIME ftSigningTime, LPVOID lpObject, LPBYTE FAR* lplpbData, ULONG FAR* lpcbData);
HRESULT IsCertExpired( PCERT_INFO pCertInfo);
HRESULT IsCertRevoked( PCERT_INFO pCertInfo);
HRESULT ReadDataFromFile( LPTSTR lpszFileName, PBYTE* ppbData, PDWORD pcbData);
HRESULT HrGetTrustState(HWND hwndParent, PCCERT_CONTEXT pcCert, DWORD *pdwTrust);
LPTSTR SzConvertRDNString(PCERT_RDN_ATTR pRdnAttr);
/* HrGetLastError
** ** Purpose: ** Convert a GetLastError value to an HRESULT ** A failure HRESULT must have the high bit set. ** ** Takes: ** none ** ** Returns: ** HRESULT */ HRESULT HrGetLastError(void) { DWORD error; HRESULT hr;
error = GetLastError();
if (error && ! (error & 0x80000000)) { hr = error | 0x80070000; // system error
} else { hr = (HRESULT)error; }
return(hr); }
//*******************************************************************
//
// FUNCTION: HrUserSMimeToCDI
//
// PURPOSE: Convert the data contained in a CMS message for the userSMimeCertificate
// property and place into the display info structure.
//
// PARAMETERS: pbIn - data bytes for the CMS message
// cbIn - size of pbIn
// lpCDI - structure to receive the cert data.
//
// RETURNS: HRESULT.
//
// HISTORY:
// 98/10/23 jimsch Created.
//
//*******************************************************************
HRESULT HrUserSMimeToCDI(LPBYTE pbIn, DWORD cbIn, LPCERT_DISPLAY_INFO lpCDI) { DWORD cb; DWORD cbCert; DWORD cbMax; DWORD cbSMimeCaps; DWORD cCerts; CERT_INFO certInfo; DWORD cSigners; DWORD cval; DWORD dwDefaults; DWORD dwNortelAlg; BOOL f; BOOL fSMime = TRUE; HCRYPTMSG hmsg = NULL; HRESULT hr = S_OK; ULONG i; DWORD ival; PCRYPT_ATTRIBUTE pattr; LPBYTE pbCert; LPBYTE pbData; LPBYTE pbSMimeCaps; PCCERT_CONTEXT pccert; PCMSG_SIGNER_INFO pinfo = NULL; PCRYPT_RECIPIENT_ID prid = NULL;
// Parse out and verify the signature on the message. If that operation fails, then
// this is a bad record
hmsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); if (hmsg == 0) { goto CryptError; }
if (!CryptMsgUpdate(hmsg, pbIn, cbIn, TRUE)) { goto CryptError; }
cb = sizeof(cSigners); if (!CryptMsgGetParam(hmsg, CMSG_SIGNER_COUNT_PARAM, 0, &cSigners, &cb) || (cSigners == 0)) { goto CryptError; } Assert(cSigners == 1);
if (!CryptMsgGetParam(hmsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &cb)) { goto CryptError; }
pinfo = (PCMSG_SIGNER_INFO) LocalAlloc(0, cb); if (!pinfo) { hr = E_OUTOFMEMORY; goto Exit; } f = CryptMsgGetParam(hmsg, CMSG_SIGNER_INFO_PARAM, 0, pinfo, &cb); Assert(f);
// M00BUG -- verify signature on message
for (i=0; i<pinfo->AuthAttrs.cAttr; i++) { pattr = &pinfo->AuthAttrs.rgAttr[i]; if (strcmp(pattr->pszObjId, szOID_RSA_SMIMECapabilities) == 0) { Assert(pattr->cValue == 1); lpCDI->blobSymCaps.pBlobData = LocalAlloc(LMEM_ZEROINIT, pattr->rgValue[0].cbData); if (NULL == lpCDI->blobSymCaps.pBlobData) { hr = E_OUTOFMEMORY; goto Exit; } lpCDI->blobSymCaps.cbSize = pattr->rgValue[0].cbData; memcpy(lpCDI->blobSymCaps.pBlobData, pattr->rgValue[0].pbData, pattr->rgValue[0].cbData); } // else if (strcmp(pattr->pszObjId, szOID_Microsoft_Encryption_Cert) == 0) {
// Assert(pattr->cValue == 1);
// Assert(pattr->rgValue[0].cbData == 3);
// lpCDI->bIsDefault = pattr->rgValue[0].pbData[2];
// }
else if (strcmp(pattr->pszObjId, szOID_Microsoft_Encryption_Cert) == 0) { Assert(pattr->cValue == 1); f = CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_Microsoft_Encryption_Cert, pattr->rgValue[0].pbData, pattr->rgValue[0].cbData, CRYPT_DECODE_ALLOC_FLAG, 0, (LPVOID *) &prid, &cb); Assert(f); } }
//
if (prid == NULL) goto Exit; certInfo.SerialNumber = prid->SerialNumber; certInfo.Issuer = prid->Issuer;
// Enumerate all certs and pack into the structure
cbCert = sizeof(cCerts); if (!CryptMsgGetParam(hmsg, CMSG_CERT_COUNT_PARAM, 0, &cCerts, &cbCert)) { goto CryptError; }
for (i=0, cbMax = 0; i<cCerts; i++) { if (!CryptMsgGetParam(hmsg, CMSG_CERT_PARAM, i, NULL, &cbCert)) goto CryptError;
if (cbMax < cbCert) cbMax = cbCert; }
pbCert = (LPBYTE) LocalAlloc(0, cbCert); for (i=0; i<cCerts; i++) { cbCert = cbMax; if (!CryptMsgGetParam(hmsg, CMSG_CERT_PARAM, i, pbCert, &cbCert)) goto CryptError;
pccert = gpfnCertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert); if (pccert == NULL) continue;
if (CertCompareCertificate(X509_ASN_ENCODING, pccert->pCertInfo, &certInfo)) { lpCDI->pccert = CertDuplicateCertificateContext(pccert); } }
hr = S_OK;
Exit: if (prid != NULL) LocalFree(prid); if (pinfo != NULL) LocalFree(pinfo); if (hmsg != NULL) CryptMsgClose(hmsg); return hr;
CryptError: hr = E_FAIL; goto Exit; }
//*******************************************************************
//
// FUNCTION: HrGetCertsDisplayInfo
//
// PURPOSE: Takes an input array of certs in a SPropValue structure
// and outputs a list of cert data structures by parsing through
// the array and looking up the cert data in the store.
//
// PARAMETERS: lpPropValue - PR_USER_X509_CERTIFICATE property array
// lppCDI - recieves an allocated structure containing
// the cert data. Must be freed by calling FreeCertdisplayinfo.
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/09/24 markdu Created.
//
//*******************************************************************
HRESULT HrGetCertsDisplayInfo( IN HWND hwndParent, IN LPSPropValue lpPropValue, OUT LPCERT_DISPLAY_INFO * lppCDI) { CRYPT_HASH_BLOB blob; HRESULT hr = hrSuccess; HRESULT hrOut = hrSuccess; ULONG i; ULONG ulcCerts; LPCERTTAGS lpCurrentTag; LPCERT_DISPLAY_INFO lpHead=NULL; LPCERT_DISPLAY_INFO lpTemp=NULL; HCERTSTORE hcsWABCertStore = NULL; HCRYPTPROV hCryptProvider = 0; LPBYTE lpbTagEnd;
#ifdef PARAMETER_VALIDATION
if (IsBadReadPtr(lpPropValue, sizeof(SPropValue))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } if (IsBadWritePtr(lppCDI, sizeof(LPCERT_DISPLAY_INFO))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } #endif // PARAMETER_VALIDATION
// Make sure we have the right kind of proparray.
if ((NULL == lpPropValue) || (PR_USER_X509_CERTIFICATE != lpPropValue->ulPropTag)) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
// See if we really have any certs
ulcCerts = lpPropValue->Value.MVbin.cValues; if (0 == ulcCerts) { goto out; }
// Load the crypto functions
if (FALSE == InitCryptoLib()) { hr = ResultFromScode(MAPI_E_UNCONFIGURED); return hr; }
// Open the store since we need to lookup certs
hr = OpenSysCertStore(&hcsWABCertStore, &hCryptProvider, cszWABCertStore); if (hrSuccess != hr) { goto out; }
// Create a structure for each certificate in the array.
for (i=0;i<ulcCerts;i++) { // Allocate memory for the structure, and initialize pointers
LPCERT_DISPLAY_INFO lpCDI = LocalAlloc(LMEM_ZEROINIT, sizeof(CERT_DISPLAY_INFO)); if (NULL == lpCDI) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto out; }
if(NULL == lpHead) { lpHead = lpCDI; }
lpCDI->lpPrev = lpTemp; lpCDI->lpNext = NULL; if(NULL != lpTemp) { lpTemp->lpNext = lpCDI; } lpTemp = lpCDI;
if (CERT_TAG_SMIMECERT == lpPropValue->Value.MVbin.lpbin[i].lpb[0]) { hr = HrUserSMimeToCDI(lpPropValue->Value.MVbin.lpbin[i].lpb, lpPropValue->Value.MVbin.lpbin[i].cb, lpCDI); if (FAILED(hr)) goto out; } else { // Loop through the tags for this certificate and extract the data we want
lpCurrentTag = (LPCERTTAGS)lpPropValue->Value.MVbin.lpbin[i].lpb; lpbTagEnd = (LPBYTE)lpCurrentTag + lpPropValue->Value.MVbin.lpbin[i].cb; while ((LPBYTE)lpCurrentTag < lpbTagEnd) { LPCERTTAGS lpTempTag = lpCurrentTag;
// Check if this is the tag that indicates whether this is the default cert
if (CERT_TAG_DEFAULT == lpCurrentTag->tag) { memcpy((void*)&lpCDI->bIsDefault, &lpCurrentTag->rgbData, sizeof(lpCDI->bIsDefault)); }
// Check if this is just the raw cert itself
else if (CERT_TAG_BINCERT == lpCurrentTag->tag) { AssertSz(lpCDI->pccert == NULL, TEXT("Two certs in a single record")); lpCDI->pccert = gpfnCertCreateCertificateContext( X509_ASN_ENCODING, lpCurrentTag->rgbData, lpCurrentTag->cbData); }
// Check if this is the tag that contains the thumbprint
else if (CERT_TAG_THUMBPRINT == lpCurrentTag->tag) { AssertSz(lpCDI->pccert == NULL, TEXT("Two certs in a single record")); blob.cbData = lpCurrentTag->cbData - sizeof(DWORD); blob.pbData = lpCurrentTag->rgbData;
// Get the certificate from the WAB store using the thumbprint
lpCDI->pccert = CertFindCertificateInStore( hcsWABCertStore, X509_ASN_ENCODING, 0, CERT_FIND_HASH, (void *)&blob, NULL); }
// Check if this is the tag that contains the symcaps
else if (CERT_TAG_SYMCAPS == lpCurrentTag->tag) { lpCDI->blobSymCaps.pBlobData = LocalAlloc(LMEM_ZEROINIT, lpCurrentTag->cbData - SIZE_CERTTAGS); if (NULL == lpCDI->blobSymCaps.pBlobData) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto out; }
lpCDI->blobSymCaps.cbSize = lpCurrentTag->cbData - SIZE_CERTTAGS; memcpy(lpCDI->blobSymCaps.pBlobData, &lpCurrentTag->rgbData, lpCurrentTag->cbData - SIZE_CERTTAGS); }
// Check if this is the tag that contains the signing time
else if (CERT_TAG_SIGNING_TIME == lpCurrentTag->tag) { memcpy(&lpCDI->ftSigningTime, &lpCurrentTag->rgbData, min(lpCurrentTag->cbData - SIZE_CERTTAGS, sizeof(FILETIME))); }
lpCurrentTag = (LPCERTTAGS)((BYTE*)lpCurrentTag + LcbAlignLcb(lpCurrentTag->cbData)); if (lpCurrentTag == lpTempTag) { AssertSz(FALSE, TEXT("Bad CertTag in PR_USER_X509_CERTIFICATE\n")); break; // Safety valve, prevent infinite loop if bad data
} } }
// If we can't get the cert, delete this node of the linked list.
if (NULL == lpCDI->pccert) { if(lpHead == lpCDI) { lpHead = NULL; }
lpTemp = lpCDI->lpPrev; if (NULL != lpTemp) { lpTemp->lpNext = NULL; }
FreeCertdisplayinfo(lpCDI); } else { // Get the context-specific display info from the cert.
hr = GetCertsDisplayInfoFromContext(hwndParent, lpCDI->pccert, lpCDI); if (hrSuccess != hr) { goto out; } } }
out: // Close the cert store.
hrOut = CloseCertStore(hcsWABCertStore, hCryptProvider);
// If an error occurred in the function body, return that instead of
// any errors that occurred here in cleanup.
if (hrSuccess == hr) { hr = hrOut; }
if ((hrSuccess == hr) && (NULL != lppCDI)) { *lppCDI = lpHead; } else { // Free the list of structures we allocated.
while (NULL != lpHead) { lpTemp = lpHead->lpNext; FreeCertdisplayinfo(lpHead); lpHead = lpTemp; } }
return hr; }
//*******************************************************************
//
// FUNCTION: HrSetCertsFromDisplayInfo
//
// PURPOSE: Takes a linked list of cert data structures and outputs
// an SPropValue array of PR_USER_X509_CERTIFICATE properties.
//
// PARAMETERS: lpCDI - linked list of input structures to convert to
// SPropValue array
// lpulcPropCount - receives the number of SPropValue's returned
// Note that this will always be one.
// lppPropValue - receives a MAPI-allocated SPropValue structure
// containing an X509_USER_CERTIFICATE property
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/09/24 markdu Created.
//
//*******************************************************************
HRESULT HrSetCertsFromDisplayInfo( IN LPCERT_ITEM lpCItem, OUT ULONG * lpulcPropCount, OUT LPSPropValue * lppPropValue) { CRYPT_DIGEST_BLOB blob; HRESULT hr = hrSuccess; HCERTSTORE hcertstore = NULL; LPCERT_ITEM lpTemp; LPSPropValue lpPropValue = NULL; ULONG ulcCerts = 0; ULONG ulCert = 0; ULONG cbData = 0; LPBYTE lpbData; SCODE sc;
#ifdef PARAMETER_VALIDATION
if (IsBadReadPtr(lpCItem, sizeof(CERT_ITEM))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } if (IsBadWritePtr(lpulcPropCount, sizeof(ULONG))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } if (IsBadWritePtr(lppPropValue, sizeof(LPSPropValue))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } #endif // PARAMETER_VALIDATION
// Find out how many certs there are in the list
lpTemp = lpCItem; while (NULL != lpTemp) { ulcCerts++; lpTemp = lpTemp->lpNext; } Assert(ulcCerts);
// Allocate a new buffer for the MAPI property structure
sc = MAPIAllocateBuffer(sizeof(SPropValue), (LPVOID *)&lpPropValue); if (sc) { hr = ResultFromScode(sc); goto out; } lpPropValue->ulPropTag = PR_USER_X509_CERTIFICATE; lpPropValue->dwAlignPad = 0;
// Allocate more space for the SBinaryArray. We need SBinary's for
// each of the certs
lpPropValue->Value.MVbin.cValues = ulcCerts; sc = MAPIAllocateMore(ulcCerts * sizeof(SBinary), lpPropValue, (LPVOID *)&(lpPropValue->Value.MVbin.lpbin)); if (sc) { hr = ResultFromScode(sc); goto out; }
hr = OpenSysCertStore(&hcertstore, NULL, cszWABCertStore); if (hrSuccess != hr) goto out;
// Create the SPropValue entries by walking the list
while (NULL != lpCItem) { hr = GetCertThumbPrint(lpCItem->lpCDI->pccert, &blob); if (hr != hrSuccess) goto out;
if (!CertAddCertificateContextToStore(hcertstore, lpCItem->lpCDI->pccert, CERT_STORE_ADD_USE_EXISTING, NULL)) { hr = E_FAIL; goto out; }
// Pack up all the cert data and stuff it in the property
hr = HrBuildCertSBinaryData( lpCItem->lpCDI->bIsDefault, TRUE, (PCRYPT_DIGEST_BLOB ) &blob, (BLOB * ) &(lpCItem->lpCDI->blobSymCaps), lpCItem->lpCDI->ftSigningTime, lpPropValue, (LPBYTE FAR*) &(lpPropValue->Value.MVbin.lpbin[ulCert].lpb), (ULONG FAR* ) &(lpPropValue->Value.MVbin.lpbin[ulCert].cb));
LocalFree(blob.pbData); if (hrSuccess != hr) { goto out; }
// Next certificate
ulCert++; lpCItem = lpCItem->lpNext; }
out: if (hcertstore != NULL) CloseCertStore(hcertstore, 0); if ((hrSuccess == hr) && (NULL != lppPropValue) && (NULL != lpulcPropCount)) { *lppPropValue = lpPropValue; *lpulcPropCount = 1; } else { // Free the list of structures we allocated.
MAPIFreeBuffer(lpPropValue); }
return hr; }
//*******************************************************************
//
// FUNCTION: HrImportCertFromFile
//
// PURPOSE: Import a cert from a file.
//
// PARAMETERS: lpszFileName - name of file containing the cert.
// lppCDI - recieves an allocated structure containing
// the cert data. Must be freed by calling FreeCertdisplayinfo.
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/09/24 markdu Created.
//
//*******************************************************************
HRESULT HrImportCertFromFile( IN LPTSTR lpszFileName, OUT LPCERT_DISPLAY_INFO * lppCDI) { HRESULT hr = hrSuccess; HRESULT hrOut = hrSuccess; HCERTSTORE hcsWABCertStore = NULL; HCRYPTPROV hCryptProvider = 0; PCCERT_CONTEXT pccCertContext = NULL; LPCERT_DISPLAY_INFO lpCDI=NULL; BYTE* pbEncoded = NULL; DWORD cbEncoded = 0; BOOL fRet;
#ifdef PARAMETER_VALIDATION
if (IsBadReadPtr(lpszFileName, sizeof(TCHAR))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } if (IsBadWritePtr(lppCDI, sizeof(CERT_DISPLAY_INFO))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } #endif // PARAMETER_VALIDATION
// Load the crypto functions
if (FALSE == InitCryptoLib()) { hr = ResultFromScode(MAPI_E_UNCONFIGURED); return hr; }
// Open the store
hr = OpenSysCertStore(&hcsWABCertStore, &hCryptProvider, cszWABCertStore); if (hrSuccess != hr) { DebugTrace(TEXT("OpenSysCertStore -> 0x%08x\n"), GetScode(hr)); goto out; }
// Import the cert into a CERT_CONTEXT structure
#ifndef WIN16
hr = ReadMessageFromFile( lpszFileName, hCryptProvider, &pbEncoded, &cbEncoded); #else // !WIN16
hr = ReadMessageFromFile( lpszFileName, hCryptProvider, (PBYTE *)&pbEncoded, (PDWORD)&cbEncoded); #endif // !WIN16
if (hrSuccess != hr) { // Try reading it as just a DER encoded blob
#ifndef WIN16
hr = ReadDataFromFile( lpszFileName, &pbEncoded, &cbEncoded); #else // !WIN16
hr = ReadDataFromFile( lpszFileName, (PBYTE *)&pbEncoded, (PDWORD)&cbEncoded); #endif // !WIN16
if (hrSuccess != hr) { goto out; } }
// Add the cert to the store
fRet = gpfnCertAddEncodedCertificateToStore( hcsWABCertStore, X509_ASN_ENCODING, pbEncoded, cbEncoded, CERT_STORE_ADD_USE_EXISTING, &pccCertContext); if (FALSE == fRet) { hr = HrGetLastError(); DebugTrace(TEXT("CertAddEncodedCertificateToStore -> 0x%08x\n"), GetScode(hr)); goto out; }
// Allocate memory for the structure, and initialize pointers
// Since we read only one cert, there are no more entries in the linked list
lpCDI = LocalAlloc(LMEM_ZEROINIT, sizeof(CERT_DISPLAY_INFO)); if (NULL == lpCDI) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto out; } lpCDI->lpNext = NULL; lpCDI->lpPrev = NULL;
// Fill in the defaults for info we don't know
lpCDI->bIsDefault = FALSE;
// Get the certificate
lpCDI->pccert = CertDuplicateCertificateContext(pccCertContext);
// Get the context-specific display info from the cert.
hr = GetCertsDisplayInfoFromContext(GetDesktopWindow(), pccCertContext, lpCDI); if (hrSuccess != hr) { DebugTrace(TEXT("GetCertsDisplayInfoFromContext -> 0x%08x\n"), GetScode(hr)); goto out; }
out: // Free the cert context. Ignore errors since there is nothing we can do.
if (NULL != pccCertContext) { gpfnCertFreeCertificateContext(pccCertContext); }
// Close the cert store if we were able to free the cert context.
if (hrSuccess == hrOut) { hrOut = CloseCertStore(hcsWABCertStore, hCryptProvider); }
// If an error occurred in the function body, return that instead of
// any errors that occurred here in cleanup.
if (hrSuccess == hr) { hr = hrOut; }
if ((hrSuccess == hr) && (NULL != lppCDI)) { *lppCDI = lpCDI; } else { LocalFreeAndNull(&lpCDI); }
LocalFreeAndNull(&pbEncoded);
return hr; }
//*******************************************************************
//
// FUNCTION: HrExportCertToFile
//
// PURPOSE: Export a cert to a file.
//
// PARAMETERS: lpszFileName - name of file in which to store the cert.
// If the file exists, it will be overwritten, so the caller
// must verify that this is OK first if so desired.
// pblobCertThumbPrint - thumb print of certificate to export.
// lpCertDataBuffer - needs to be freed by caller, data is
// filled here when flag is true.
// lpcbBufLen - how long the buffer is
// fWriteDataToBuffer - flag indicating where to write data
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/09/24 markdu Created.
// 98/07/22 t-jstaj updated to take 3 add'l parameters, a data buffer, its length
// and flag which will indicate whether or not to
// write data to buffer or file. The memory allocated to
// to the buffer needs to be freed by caller.
//
//
//*******************************************************************
HRESULT HrExportCertToFile( IN LPTSTR lpszFileName, IN PCCERT_CONTEXT pccert, OUT LPBYTE *lppCertDataBuffer, OUT PULONG lpcbBufLen, IN BOOL fWriteDataToBuffer) { HRESULT hr = hrSuccess; HRESULT hrOut = hrSuccess;
#ifdef PARAMETER_VALIDATION
if( !fWriteDataToBuffer ) { if (IsBadReadPtr(lpszFileName, sizeof(TCHAR))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } } if (IsBadReadPtr(pccert, sizeof(*pccert))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } #endif // PARAMETER_VALIDATION
// Load the crypto functions
if (FALSE == InitCryptoLib()) { hr = ResultFromScode(MAPI_E_UNCONFIGURED); return hr; }
// Export the cert to the file
if( !fWriteDataToBuffer ) { hr = WriteDERToFile( lpszFileName, (PBYTE)pccert->pbCertEncoded, pccert->cbCertEncoded); if (hrSuccess != hr) { goto out; } } // write cert to buffer
else { *lppCertDataBuffer = LocalAlloc( LMEM_ZEROINIT, /*sizeof( BYTE ) **/ pccert->cbCertEncoded); if( *lppCertDataBuffer ) CopyMemory( *lppCertDataBuffer, pccert->pbCertEncoded, pccert->cbCertEncoded); else { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } *lpcbBufLen = pccert->cbCertEncoded; } out: // If an error occurred in the function body, return that instead of
// any errors that occurred here in cleanup.
if (hrSuccess == hr) { hr = hrOut; }
return hr; }
//*******************************************************************
//
// FUNCTION: FreeCertdisplayinfo
//
// PURPOSE: Release memory allocated for a CERT_DISPLAY_INFO structure.
// Assumes all info in the structure was LocalAlloced
//
// PARAMETERS: lpCDI - structure to free.
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/09/24 markdu Created.
//
//*******************************************************************
void FreeCertdisplayinfo(LPCERT_DISPLAY_INFO lpCDI) { if (lpCDI) { if (lpCDI->lpszDisplayString != lpCDI->lpszEmailAddress) { LocalFreeAndNull(&lpCDI->lpszDisplayString); } if (lpCDI->pccert != NULL) { CertFreeCertificateContext(lpCDI->pccert); lpCDI->pccert = NULL; } LocalFreeAndNull(&lpCDI->lpszEmailAddress); LocalFreeAndNull(&lpCDI->blobSymCaps.pBlobData); LocalFreeAndNull(&lpCDI); } }
//*******************************************************************
//
// FUNCTION: InitCryptoLib
//
// PURPOSE: Load the Crypto API libray and get the proc addrs.
//
// PARAMETERS: None.
//
// RETURNS: TRUE if successful, FALSE otherwise.
//
// HISTORY:
// 96/10/01 markdu Created.
// 96/11/19 markdu No longer keep a ref count, just use the global
// library handles.
//
//*******************************************************************
BOOL InitCryptoLib(void) {
#ifndef WIN16 // Disable until we get crypt16.dll
// See if we already tried to load and failed.
if (TRUE == gfPrevCryptoLoadFailed) { return FALSE; }
// See if we already initialized.
if ((NULL == ghCryptoDLLInst) && (NULL == ghAdvApiDLLInst)) { // open Crypto API library
ghCryptoDLLInst = LoadLibrary(cszCryptoDLL); if (!ghCryptoDLLInst) { DebugTrace(TEXT("InitCryptoLib: Failed to LoadLibrary CRYPT32.DLL.\n")); goto error; }
// cycle through the API table and get proc addresses for all the APIs we
// need
if (!GetApiProcAddresses(ghCryptoDLLInst,Crypt32CryptoAPIList,NUM_CRYPT32_CRYPTOAPI_PROCS)) { DebugTrace(TEXT("InitCryptoLib: Failed to load Crypto API from CRYPT32.DLL.\n")); goto error; }
// open AdvApi32 library
ghAdvApiDLLInst = LoadLibrary(cszAdvApiDLL); if (!ghAdvApiDLLInst) { DebugTrace(TEXT("InitCryptoLib: Failed to LoadLibrary ADVAPI32.DLL.\n")); goto error; } }
// Make sure both libraries are loaded
if ((NULL != ghCryptoDLLInst) && (NULL != ghAdvApiDLLInst)) { return TRUE; }
error: // Unload the libraries we just loaded and indicate that we should not try to
// load again this session.
gfPrevCryptoLoadFailed = TRUE; DeinitCryptoLib(); #endif // !WIN16
return FALSE; }
//*******************************************************************
//
// FUNCTION: DeinitCryptoLib
//
// PURPOSE: Release the Crypto API libraries.
//
// PARAMETERS: None.
//
// RETURNS: None.
//
// HISTORY:
// 96/10/01 markdu Created.
// 96/11/19 markdu No longer keep a ref count, just call this in
// DLL_PROCESS_DETACH.
//
//*******************************************************************
void DeinitCryptoLib(void) { UINT nIndex;
// No clients using the Crypto API library. Release it.
if (ghCryptoDLLInst) { FreeLibrary(ghCryptoDLLInst); ghCryptoDLLInst = NULL;
// cycle through the API table and NULL proc addresses for all the APIs
for (nIndex = 0; nIndex < NUM_CRYPT32_CRYPTOAPI_PROCS; nIndex++) { *Crypt32CryptoAPIList[nIndex].ppFcnPtr = NULL; } }
// Now releaes the crypto functions in advapi32.dll
if (ghAdvApiDLLInst) { FreeLibrary(ghAdvApiDLLInst); ghAdvApiDLLInst = NULL; }
return; }
//*******************************************************************
//
// FUNCTION: FileTimeToDateTimeString
//
// PURPOSE: Convert a filetime structure to displayable text.
//
// PARAMETERS: lpft - FILETIME to convert to a string
// lplpszBuf - receives buffer to hold the string
//
// RETURNS: HRESULT
//
// HISTORY:
// 96/10/02 markdu Copied from shdocvw code
// 96/12/16 markdu Made more robust, and LocalAlloc the buffer here
//
//*******************************************************************
HRESULT FileTimeToDateTimeString( IN LPFILETIME lpft, IN LPTSTR FAR* lplpszBuf) { HRESULT hr = hrSuccess; SYSTEMTIME st; LPTSTR szBuf; int cbBuf = 0; int cb = 0;
FileTimeToLocalFileTime(lpft, lpft); FileTimeToSystemTime(lpft, &st);
// Figure out how much space we need, then allocate 2 times that just
// in case it's DBCS.
cbBuf += GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, NULL, 0); cbBuf += GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, NULL, 0); cbBuf *= 2;
szBuf = LocalAlloc(LMEM_ZEROINIT, cbBuf); if (NULL == szBuf) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto out; } *lplpszBuf = szBuf;
// First fill in the date portion.
GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, szBuf, cbBuf); cb = lstrlen(szBuf); szBuf += cb; cbBuf -= cb;
// Separate the time and date with a space. and null terminate this
// (in case GetTimeFormat doesn't add anything).
*szBuf = TEXT(' '); szBuf = CharNext(szBuf); *szBuf = TEXT('\0'); cbBuf-=2;
GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, szBuf, cbBuf);
out: return hr; }
//*******************************************************************
//
// FUNCTION: OpenSysCertStore
//
// PURPOSE: Open the specified system cert store.
//
// PARAMETERS: phcsSysCertStore - receives handle to the cert store
// phCryptProvider - If this points to a valid handle,
// this handle is used as the provider to open the store.
// otherwise, it receives a handle to the store provider
// lpszCertStore - name of the store to open
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/10/03 markdu Created.
//
//*******************************************************************
HRESULT OpenSysCertStore( HCERTSTORE* phcsSysCertStore, HCRYPTPROV* phCryptProvider, LPTSTR lpszCertStore) { HRESULT hr = hrSuccess; BOOL fRet; BOOL fWeAcquiredContext = FALSE;
if (phCryptProvider != NULL) { // Get a handle to the crypto provider if we need one
if (0 == *phCryptProvider) { fRet = CryptAcquireContextWrapW( phCryptProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); if (FALSE == fRet) { hr = HrGetLastError(); goto out; } fWeAcquiredContext = TRUE; } }
// Open the store
*phcsSysCertStore = gpfnCertOpenSystemStore( ((phCryptProvider == NULL) ? (HCRYPTPROV) NULL : (*phCryptProvider)), lpszCertStore); if (NULL == *phcsSysCertStore) { hr = HrGetLastError();
// Release the crypto provider if we were unable to open the store.
if (TRUE == fWeAcquiredContext) { CryptReleaseContext(*phCryptProvider, 0); *phCryptProvider = 0; }
goto out; }
out: return hr; }
//*******************************************************************
//
// FUNCTION: CloseCertStore
//
// PURPOSE: Close the specified cert store.
//
// PARAMETERS: hcsCertStore - handle to the cert store
// hCryptProvider - handle to the store provider. The
// provider will be closed as well, unless 0 is passed.
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/10/03 markdu Created.
//
//*******************************************************************
HRESULT CloseCertStore( HCERTSTORE hcsCertStore, HCRYPTPROV hCryptProvider) { HRESULT hr = hrSuccess; BOOL fRet;
if (NULL != hcsCertStore) { fRet = CertCloseStore(hcsCertStore, 0); if (FALSE == fRet) { hr = HrGetLastError(); } }
// Release the crypto provider if we were able to close the store.
if ((0 != hCryptProvider) && (hrSuccess == hr)) { fRet = CryptReleaseContext(hCryptProvider, 0); if (FALSE == fRet) { hr = HrGetLastError(); } }
return hr; }
//*******************************************************************
//
// FUNCTION: GetNameString
//
// PURPOSE: Get the string associated with the given attribute
//
// PARAMETERS: lplpszName - pointer that will be
// allocated to hold the string
// dwEncoding - certificate's encoding
// pNameBlob - the encoded blob
// dwType - type of string, e.g. CERT_SIMPLE_NAME_STR
//
// RETURNS: HRESULT.
//
// HISTORY:
// 97/02/03 t-erikne Copied and revamped from GetAttributeString
// 96/10/03 markdu Created.
//
//*******************************************************************
HRESULT GetNameString( LPTSTR FAR * lplpszName, DWORD dwEncoding, PCERT_NAME_BLOB pNameBlob, DWORD dwType) { DWORD cch; HRESULT hr = hrSuccess;
Assert(lplpszName && pNameBlob);
// Initialize so we know if any data was copied in.
*lplpszName = NULL;
cch = gpfnCertNameToStr( dwEncoding, // indicates X509 encoding
pNameBlob, // name_blob to decode
dwType, // style for output
NULL, // NULL used when just getting length
0); // length of buffer
*lplpszName = (LPTSTR) LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cch); if (NULL == lplpszName) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto out; }
gpfnCertNameToStr(dwEncoding, pNameBlob, dwType, *lplpszName, cch);
out: return hr; }
//*******************************************************************
//
// FUNCTION: GetAttributeString
//
// PURPOSE: Get the string associated with the given attribute
// by parsing through the relative
// distinguished names in the object.
//
// PARAMETERS: lplpszAttributeString - pointer that will be allocated to
// hold the string
// pbEncoded - the encoded blob
// cbEncoded - size of the encoded blob
// lpszObjID - object ID of attribute to retrieve
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/10/03 markdu Created.
//
//*******************************************************************
HRESULT GetAttributeString( LPTSTR FAR * lplpszAttributeString, BYTE *pbEncoded, DWORD cbEncoded, LPSTR lpszObjID) { HRESULT hr = hrSuccess; BOOL fRet; PCERT_RDN_ATTR pRdnAttr; PCERT_NAME_INFO pNameInfo = NULL; DWORD cbInfo; DWORD cbData; //N need both?
// Initialize so we know if any data was copied in.
*lplpszAttributeString = NULL;
// Get the size of the subject name data
cbInfo = 0; gpfnCryptDecodeObject( X509_ASN_ENCODING, // indicates X509 encoding
(LPCSTR)X509_NAME, // flag indicating a name blob is to be decoded
pbEncoded, // pointer to a buffer holding the encoded name
cbEncoded, // length in bytes of the encoded name
//N maybe can use nocopy flag
0, // flags
NULL, // NULL used when just geting length
&cbInfo); // length in bytes of the decoded name
if (0 == cbInfo) { hr = HrGetLastError(); goto out; }
// Allocate space for the decoded name
pNameInfo = (PCERT_NAME_INFO) LocalAlloc(LMEM_ZEROINIT, cbInfo); if (NULL == pNameInfo) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto out; }
// Get the subject name
fRet = gpfnCryptDecodeObject( X509_ASN_ENCODING, // indicates X509 encoding
(LPCSTR)X509_NAME, // flag indicating a name blob is to be decoded
pbEncoded, // pointer to a buffer holding the encoded name
cbEncoded, // length in bytes of the encoded name
0, // flags
pNameInfo, // the buffer where the decoded name is written to
&cbInfo); // length in bytes of the decoded name
if (FALSE == fRet) { hr = HrGetLastError(); goto out; }
// Now we have a decoded name RDN array, so find the oid we want
pRdnAttr = gpfnCertFindRDNAttr(lpszObjID, pNameInfo);
if (!pRdnAttr) { hr = MAPI_E_NOT_FOUND; goto out; }
*lplpszAttributeString = SzConvertRDNString(pRdnAttr);
out: if (NULL != pNameInfo) { LocalFreeAndNull(&pNameInfo); } return hr; }
//*******************************************************************
//
// FUNCTION: GetCertThumbPrint
//
// PURPOSE: Gets the thumbprint of the cert.
//
// PARAMETERS: pccCertContext - cert whose thumbprint to get
// pblobCertThumbPrint - receives thumb print
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/10/13 markdu Created.
//
//*******************************************************************
HRESULT GetCertThumbPrint( PCCERT_CONTEXT pccCertContext, PCRYPT_DIGEST_BLOB pblobCertThumbPrint) { HRESULT hr = hrSuccess; BOOL fRet;
// Get the size of the thumbprint data
pblobCertThumbPrint->cbData = 0; fRet = gpfnCertGetCertificateContextProperty( pccCertContext, CERT_HASH_PROP_ID, NULL, &pblobCertThumbPrint->cbData); if (FALSE == fRet) { hr = HrGetLastError(); goto out; }
// Allocate memory for the thumbprint data
pblobCertThumbPrint->pbData = LocalAlloc(LMEM_ZEROINIT, pblobCertThumbPrint->cbData); if (NULL == pblobCertThumbPrint->pbData) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto out; }
// Get the thumbprint
fRet = gpfnCertGetCertificateContextProperty( pccCertContext, CERT_HASH_PROP_ID, pblobCertThumbPrint->pbData, &pblobCertThumbPrint->cbData); if (FALSE == fRet) { hr = HrGetLastError(); goto out; }
out: return hr; }
/* SzConvertRDNString
** ** Purpose: ** Figure out what kind of string data is in the RDN, allocate ** a buffer and convert the string data to DBCS/ANSI. ** ** Takes: ** IN pRdnAttr - Certificate RDN atteribute ** Returns: ** A LocalAlloc'd buffer containing the string. */ LPTSTR SzConvertRDNString(PCERT_RDN_ATTR pRdnAttr) { LPTSTR szRet = NULL; ULONG cbData = 0;
// We only handle certain types
//N look to see if we should have a stack var for the ->
if ((CERT_RDN_NUMERIC_STRING != pRdnAttr->dwValueType) && (CERT_RDN_PRINTABLE_STRING != pRdnAttr->dwValueType) && (CERT_RDN_IA5_STRING != pRdnAttr->dwValueType) && (CERT_RDN_VISIBLE_STRING != pRdnAttr->dwValueType) && (CERT_RDN_ISO646_STRING != pRdnAttr->dwValueType) && (CERT_RDN_UNIVERSAL_STRING != pRdnAttr->dwValueType) && (CERT_RDN_TELETEX_STRING != pRdnAttr->dwValueType) && (CERT_RDN_UNICODE_STRING != pRdnAttr->dwValueType)) { Assert((CERT_RDN_NUMERIC_STRING == pRdnAttr->dwValueType) || (CERT_RDN_PRINTABLE_STRING == pRdnAttr->dwValueType) || (CERT_RDN_IA5_STRING == pRdnAttr->dwValueType) || (CERT_RDN_VISIBLE_STRING == pRdnAttr->dwValueType) || (CERT_RDN_ISO646_STRING == pRdnAttr->dwValueType) || (CERT_RDN_UNIVERSAL_STRING == pRdnAttr->dwValueType) || (CERT_RDN_TELETEX_STRING == pRdnAttr->dwValueType) || (CERT_RDN_UNICODE_STRING == pRdnAttr->dwValueType)); return(NULL); }
// Find out how much space to allocate.
switch (pRdnAttr->dwValueType) { case CERT_RDN_UNICODE_STRING: cbData = WideCharToMultiByte( CP_ACP, 0, (LPWSTR)pRdnAttr->Value.pbData, -1, NULL, 0, NULL, NULL); break;
case CERT_RDN_UNIVERSAL_STRING: case CERT_RDN_TELETEX_STRING: cbData = gpfnCertRDNValueToStr(pRdnAttr->dwValueType, (PCERT_RDN_VALUE_BLOB)&(pRdnAttr->Value), NULL, 0); break;
default: cbData = pRdnAttr->Value.cbData + 1; break; }
// Allocate the space for the string.
if (! (szRet = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cbData))) { Assert(szRet); return(NULL); }
// Copy the string
switch (pRdnAttr->dwValueType) { case CERT_RDN_UNICODE_STRING: StrCpyN(szRet, (LPWSTR)pRdnAttr->Value.pbData, cbData); break;
case CERT_RDN_UNIVERSAL_STRING: case CERT_RDN_TELETEX_STRING: gpfnCertRDNValueToStr(pRdnAttr->dwValueType, (PCERT_RDN_VALUE_BLOB)&(pRdnAttr->Value), szRet, cbData); break;
default: ScAnsiToWCMore(NULL, NULL, pRdnAttr->Value.pbData, &szRet); szRet[cbData - 1] = '\0'; break; } return(szRet); }
/* PVDecodeObject:
** ** Purpose: ** Combine the "how big? okay, here." double question to decode an ** object. Give it a thing to get and it will alloc the mem. ** Takes: ** IN pbEncoded - encoded data ** IN cbEncoded - size of data in pbData ** IN item - X509_* ... the thing to get ** OUT OPTIONAL cbOut - (def value of NULL) size of the return ** Notes: ** pbEncoded can't be freed until return is freed. ** Returns: ** data that was obtained, NULL if failed. Caller must LocalFree buffer. */ LPVOID PVDecodeObject( BYTE *pbEncoded, DWORD cbEncoded, LPCSTR item, DWORD *cbOut) { DWORD cbData; void *pvData = NULL;
if (!(pbEncoded && cbEncoded)) { SetLastError((DWORD)E_INVALIDARG); goto ErrorReturn; }
cbData = 0; gpfnCryptDecodeObject( X509_ASN_ENCODING, // indicates X509 encoding
item, // flag indicating type to be decoded
pbEncoded, // pointer to a buffer holding the encoded data
cbEncoded, // length in bytes of the encoded data
CRYPT_DECODE_NOCOPY_FLAG, NULL, // NULL used when just geting length
&cbData); // length in bytes of the decoded data
if (!cbData || ! (pvData = LocalAlloc(LPTR, cbData))) { goto ErrorReturn; }
if (!gpfnCryptDecodeObject( X509_ASN_ENCODING, // indicates X509 encoding
item, // flag indicating type is to be decoded
pbEncoded, // pointer to a buffer holding the encoded data
cbEncoded, // length in bytes of the encoded name
CRYPT_DECODE_NOCOPY_FLAG, pvData, // out buffer
&cbData)) // length in bytes of the decoded data
goto ErrorReturn;
exit: if (cbOut) *cbOut = cbData; return pvData;
ErrorReturn: if (pvData) { IF_WIN32(LocalFree(pvData);) IF_WIN16(LocalFree((HLOCAL)pvData);) pvData = NULL; } cbData = 0; goto exit; }
/* SzGetAltNameEmail:
** ** Input: ** pCert -> certificate context ** lpszOID -> OID or predefined id of alt name to look in. ie, OID_SUBJECT_ALT_NAME or ** X509_ALTERNATE_NAME. ** ** Returns: ** Buffer containing email name or NULL if not found. ** Caller must LocalFree the buffer. */ LPTSTR SzGetAltNameEmail( const PCCERT_CONTEXT pCert, LPSTR lpszOID) { PCERT_INFO pCertInfo = pCert->pCertInfo; PCERT_ALT_NAME_ENTRY pAltNameEntry = NULL; PCERT_ALT_NAME_INFO pAltNameInfo = NULL; ULONG i, j, cbData; LPSTR szRet = NULL; LPTSTR sz = NULL;
if (lpszOID == (LPCSTR)X509_ALTERNATE_NAME) { lpszOID = szOID_SUBJECT_ALT_NAME; }
for (i = 0; i < pCertInfo->cExtension; i++) { if (! lstrcmpA(pCertInfo->rgExtension[i].pszObjId, lpszOID)) { // Found the OID. Look for the email tag
if (pAltNameInfo = (PCERT_ALT_NAME_INFO)PVDecodeObject( pCertInfo->rgExtension[i].Value.pbData, pCertInfo->rgExtension[i].Value.cbData, lpszOID, NULL)) { // Cycle through the alt name entries
for (j = 0; j < pAltNameInfo->cAltEntry; j++) { if (pAltNameEntry = &pAltNameInfo->rgAltEntry[j]) { if (pAltNameEntry->dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME) { // This is it, copy it out to a new allocation
if (pAltNameEntry->pwszRfc822Name) { DWORD cchSize = (lstrlen(pAltNameEntry->pwszRfc822Name)+1); if (sz = LocalAlloc(LPTR, sizeof(TCHAR)*cchSize)) { StrCpyN(sz, pAltNameEntry->pwszRfc822Name, cchSize); break; } } } } } IF_WIN32(LocalFree(pAltNameInfo);) IF_WIN16(LocalFree((HLOCAL)pAltNameInfo);) pAltNameInfo = NULL; }
} } LocalFreeAndNull(&pAltNameInfo); return(sz); }
/* SzGetCertificateEmailAddress:
** ** Returns: ** NULL if there is no email address */ LPTSTR SzGetCertificateEmailAddress( const PCCERT_CONTEXT pCert) { PCERT_NAME_INFO pNameInfo; PCERT_ALT_NAME_INFO pAltNameInfo = NULL; PCERT_RDN_ATTR pRDNAttr; LPTSTR szRet = NULL;
Assert(pCert && pCert->pCertInfo);
pNameInfo = (PCERT_NAME_INFO)PVDecodeObject(pCert->pCertInfo->Subject.pbData, pCert->pCertInfo->Subject.cbData, X509_NAME, 0); if (pNameInfo) { pRDNAttr = gpfnCertFindRDNAttr(szOID_RSA_emailAddr, pNameInfo); if (pRDNAttr) { Assert(0 == lstrcmpA(szOID_RSA_emailAddr, pRDNAttr->pszObjId)); szRet = SzConvertRDNString(pRDNAttr); } IF_WIN32(LocalFree(pNameInfo);) IF_WIN16(LocalFree((HLOCAL)pNameInfo);) }
if (! szRet) { if (! (szRet = SzGetAltNameEmail(pCert, szOID_SUBJECT_ALT_NAME))) { szRet = SzGetAltNameEmail(pCert, szOID_SUBJECT_ALT_NAME2); } }
return(szRet); }
//*******************************************************************
//
// FUNCTION: GetCertsDisplayInfoFromContext
//
// PURPOSE: Gets the display info that is available in the cert
// context structure.
//
// PARAMETERS: pccCertContext - cert data
// lpCDI - structure to receive the cert data
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/10/04 markdu Created.
//
//*******************************************************************
HRESULT GetCertsDisplayInfoFromContext( HWND hwndParent, PCCERT_CONTEXT pccCertContext, LPCERT_DISPLAY_INFO lpCDI) { HRESULT hr = hrSuccess; PCERT_INFO pCertInfo;
pCertInfo = pccCertContext->pCertInfo; lpCDI->lpszDisplayString = NULL, lpCDI->lpszEmailAddress = NULL;
hr = GetAttributeString( &lpCDI->lpszDisplayString, pCertInfo->Subject.pbData, pCertInfo->Subject.cbData, szOID_COMMON_NAME); if (hrSuccess != hr) { DebugTrace(TEXT("Cert has no common name\n")); }
lpCDI->lpszEmailAddress = SzGetCertificateEmailAddress(pccCertContext);
// In case there is no common name (weird, but true)
if (! lpCDI->lpszDisplayString) { lpCDI->lpszDisplayString = lpCDI->lpszEmailAddress; } if (! lpCDI->lpszDisplayString) { DebugTrace(TEXT("Certificate had no name or email! What a pathetic cert!\n")); }
// Some certificates won't have email addresses in them which means that
// Failure is not a (valid) option.
// just set it to empty
if (hrSuccess != hr) { hr = S_OK; }
DebugTrace(TEXT("Certificate for '%s'. Email: '%s'\n"), lpCDI->lpszDisplayString ? lpCDI->lpszDisplayString : NULL, (lpCDI->lpszEmailAddress ? lpCDI->lpszEmailAddress : szEmpty));
// Determine if cert has expired
lpCDI->bIsExpired = IsCertExpired(pCertInfo);
// Determine if cert has been revoked
lpCDI->bIsRevoked = IsCertRevoked(pCertInfo);
// Determine if this certificate is trusted or not
if (FAILED(HrGetTrustState(hwndParent, pccCertContext, &lpCDI->dwTrust))) { lpCDI->dwTrust = CERT_VALIDITY_NO_TRUST_DATA; hr = S_OK; // we handled this
}
if (0 == lpCDI->dwTrust) lpCDI->bIsTrusted = TRUE; else lpCDI->bIsTrusted = FALSE;
return hr; }
//*******************************************************************
//
// FUNCTION: DebugTraceCertContextName
//
// PURPOSE: Dump the subject name of a cert context
//
// PARAMETERS: pcCertContext = cert context to dump
// lpDescription = description text
//
// RETURNS: none
//
//*******************************************************************
void DebugTraceCertContextName(PCCERT_CONTEXT pcCertContext, LPTSTR lpDescription) { #ifdef DEBUG
LPTSTR lpName = NULL; PCERT_INFO pCertInfo = pcCertContext->pCertInfo; GetAttributeString( &lpName, pCertInfo->Subject.pbData, pCertInfo->Subject.cbData, szOID_COMMON_NAME); if (! lpName) { GetAttributeString( &lpName, pCertInfo->Subject.pbData, pCertInfo->Subject.cbData, szOID_ORGANIZATION_NAME); }
DebugTrace(TEXT("%s %s\n"), lpDescription, lpName ? lpName : TEXT("<unknown>")); if (lpName) { IF_WIN32(LocalFree(lpName);) IF_WIN16(LocalFree((HLOCAL)lpName);) } #endif
}
//*******************************************************************
//
// FUNCTION: ReadMessageFromFile
//
// PURPOSE: Reads a single cert from a PKCS7 message file
//
// PARAMETERS: lpszFileName - name of file containing the PKCS7 encoded
// message
// hCryptProvider - handle to the store provider
// ppbEncoded - receives the encoded cert blob
// pcbEncoded - receives the size of the encoded cert blob
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/10/06 markdu Created.
//
//*******************************************************************
HRESULT ReadMessageFromFile( LPTSTR lpszFileName, HCRYPTPROV hCryptProvider, PBYTE* ppbEncoded, PDWORD pcbEncoded) { HRESULT hr = hrSuccess; BOOL fRet; DWORD cCert, cbData; HCRYPTMSG hMsg = NULL; PBYTE lpBuf = 0; ULONG i, j; DWORD dwIssuerFlags = 0; BOOL fFound = FALSE, fIssuer; PCERT_CONTEXT * rgpcCertContext = NULL; HCERTSTORE hCertStoreMsg = NULL; PCCERT_CONTEXT pcCertContextTarget = NULL, pcCertContextIssuer; PCERT_INFO pCertInfoTarget = NULL;
if ((NULL == ppbEncoded) || (NULL == pcbEncoded)) { return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } *ppbEncoded = 0; *pcbEncoded = 0;
// Read the data from the file.
if (hr = ReadDataFromFile(lpszFileName, &lpBuf, (PDWORD)&cbData)) { goto out; }
hMsg = gpfnCryptMsgOpenToDecode( PKCS_7_ASN_ENCODING, 0, // dwFlags
0, // dwMsgType
hCryptProvider, NULL, // pRecipientInfo (not supported)
NULL); // pStreamInfo (not supported)
if (NULL == hMsg) { hr = HrGetLastError(); DebugTrace(TEXT("CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING) -> 0x%08x\n"), GetScode(hr)); goto error; }
fRet = gpfnCryptMsgUpdate(hMsg, lpBuf, cbData, TRUE); if (FALSE == fRet) { hr = HrGetLastError(); DebugTrace(TEXT("CryptMsgUpdate -> 0x%08x\n"), GetScode(hr)); goto error; }
cbData = sizeof(cCert); fRet = gpfnCryptMsgGetParam( hMsg, CMSG_CERT_COUNT_PARAM, // dwParamType
0, // dwIndex
(void *)&cCert, &cbData); // pcbData
if (FALSE == fRet) { hr = HrGetLastError(); DebugTrace(TEXT("CryptMsgGetParam(CMSG_CERT_COUNT_PARAM) -> 0x%08x\n"), GetScode(hr)); goto error; } if (cbData != sizeof(cCert)) { hr = ResultFromScode(MAPI_E_CALL_FAILED); goto error; }
if (cCert == 1) { // Just one cert. No decisions to make.
cbData = 0; fRet = gpfnCryptMsgGetParam( hMsg, CMSG_CERT_PARAM, 0, // dwIndex
NULL, // pvData
&cbData ); if ((!fRet) || (0 == cbData)) { hr = ResultFromScode(MAPI_E_CALL_FAILED); DebugTrace(TEXT("CryptMsgGetParam(CMSG_CERT_PARAM) -> 0x%08x\n"), GetScode(hr)); goto error; }
IF_WIN32(*ppbEncoded = (BYTE *)LocalAlloc(LMEM_ZEROINIT, cbData);) IF_WIN16(*ppbEncoded = (PBYTE)LocalAlloc(LMEM_ZEROINIT, cbData);) if (NULL == *ppbEncoded) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto error; }
fRet = gpfnCryptMsgGetParam( hMsg, CMSG_CERT_PARAM, 0, *ppbEncoded, &cbData ); if (FALSE == fRet) { hr = HrGetLastError(); DebugTrace(TEXT("CryptMsgGetParam(CMSG_CERT_PARAM) -> 0x%08x\n"), GetScode(hr)); IF_WIN32(LocalFreeAndNull(ppbEncoded);) IF_WIN16(LocalFreeAndNull((LPVOID *)ppbEncoded);) goto error; } *pcbEncoded = cbData; } else { // More than one cert in the message. Which one is it?
//
// Look for one that's a "Leaf" node.
// Unfortunately, there is no easy way to tell, so we'll have
// to loop through each cert, checking to see if it is an issuer of any other cert
// in the message. If it is not an issuer of any other cert, it must be the leaf cert.
//
hCertStoreMsg = CertOpenStore( CERT_STORE_PROV_MSG, X509_ASN_ENCODING, hCryptProvider, CERT_STORE_NO_CRYPT_RELEASE_FLAG, hMsg);
if (hCertStoreMsg == NULL) { hr = HrGetLastError(); DebugTrace(TEXT("CertOpenStore(msg) -> %u\n"), hr); } else { if (! (rgpcCertContext = LocalAlloc(LPTR, cCert * sizeof(PCERT_CONTEXT)))) { DebugTrace(TEXT("LocalAlloc of cert table -> %u\n"), HrGetLastError()); hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto error; }
// Enumerate all certs on this message
i = 0; while (pcCertContextTarget = gpfnCertEnumCertificatesInStore(hCertStoreMsg, pcCertContextTarget)) {
if (! (rgpcCertContext[i] = (PCERT_CONTEXT)CertDuplicateCertificateContext( pcCertContextTarget))) { DebugTrace(TEXT("CertCertificateContext -> %x\n"), HrGetLastError()); }
#ifdef DEBUG
DebugTraceCertContextName(rgpcCertContext[i], TEXT("Found Cert:")); #endif
i++; };
// Now we've got a table full of certs
for (i = 0; i < cCert; i++) { pCertInfoTarget = rgpcCertContext[i]->pCertInfo; fIssuer = FALSE;
for (j = 0; j < cCert; j++) { if (i != j) { dwIssuerFlags = 0;
if (pcCertContextIssuer = gpfnCertGetIssuerCertificateFromStore(hCertStoreMsg, rgpcCertContext[j], NULL, &dwIssuerFlags)) {
// Found an issuer
// Is it the same as the target?
fIssuer = gpfnCertCompareCertificate(X509_ASN_ENCODING, pCertInfoTarget, // target
pcCertContextIssuer->pCertInfo); // test issuer
gpfnCertFreeCertificateContext(pcCertContextIssuer);
if (fIssuer) { // This test cert is issued by the target, so
// we know that Target is NOT a leaf cert
break; } // else, loop back to the enumerate where the test cert context will be freed.
} } }
if (! fIssuer) { DebugTrace(TEXT("Found a Cert which is not an issuer.\n")); #ifdef DEBUG
DebugTraceCertContextName(rgpcCertContext[i], TEXT("Non-issuer cert:")); #endif
// Copy the cert encoded data to a seperate allocation
cbData = rgpcCertContext[i]->cbCertEncoded; #ifndef WIN16
if (! (*ppbEncoded = (BYTE *)LocalAlloc(LPTR, cbData))) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto error; } #else
if (! (*ppbEncoded = (PBYTE)LocalAlloc(LPTR, cbData))) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto error; } #endif
CopyMemory(*ppbEncoded, rgpcCertContext[i]->pbCertEncoded, cbData); *pcbEncoded = cbData; fFound = TRUE; break; // done with loop
} }
// Free the table of certs
for (i = 0; i < cCert; i++) { gpfnCertFreeCertificateContext(rgpcCertContext[i]); } IF_WIN32(LocalFree((LPVOID)rgpcCertContext);) IF_WIN16(LocalFree((HLOCAL)rgpcCertContext);)
if (! fFound) { // Didn't find a cert that isn't an issuer. Fail.
hr = ResultFromScode(MAPI_E_NOT_FOUND); goto error; } } }
out: if (hCertStoreMsg) { CertCloseStore(hCertStoreMsg, 0); }
if (hMsg) { gpfnCryptMsgClose(hMsg); }
if (lpBuf) { IF_WIN32(LocalFreeAndNull(&lpBuf);) IF_WIN16(LocalFreeAndNull((LPVOID *)&lpBuf);) }
return(hr);
error: // some of the GetLastError calls above may not have worked.
if (hrSuccess == hr) { hr = ResultFromScode(MAPI_E_CALL_FAILED); }
goto out; }
//*******************************************************************
//
// FUNCTION: WriteDERToFile
//
// PURPOSE: Writes a single cert to a file as a DER encoded blob
//
// PARAMETERS: lpszFileName - name of file to hold the encoded blob
// pccCertContext - the cert to be written
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/10/29 markdu Created.
//
//*******************************************************************
HRESULT WriteDERToFile( LPTSTR lpszFileName, PBYTE pbEncoded, DWORD cbEncoded) { HRESULT hr = hrSuccess; BOOL fRet; HANDLE hFile = 0; DWORD cbFile;
// Open the file
hFile = CreateFile( lpszFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if(INVALID_HANDLE_VALUE == hFile) { hr = ResultFromScode(MAPI_E_DISK_ERROR); goto out; }
// Write the data to the file
fRet = WriteFile( hFile, // handle of file to write
pbEncoded, // address of buffer to write
cbEncoded, // number of bytes to write
&cbFile, // address of number of bytes written
NULL // address of structure for data
); if (FALSE == fRet) { hr = ResultFromScode(MAPI_E_DISK_ERROR); goto out; } if (cbEncoded != cbFile) { hr = ResultFromScode(MAPI_E_CALL_FAILED); goto out; }
out: if (hFile) { IF_WIN32(CloseHandle(hFile);) IF_WIN16(CloseFile(hFile);) }
return hr; }
//*******************************************************************
//
// FUNCTION: GetIssuerContextAndStore
//
// PURPOSE: Get the context of the issuer by first looking in the
// CA store, then the root store.
//
// PARAMETERS: pccCertContext - cert whose issuer to find
// ppccIssuerCertContext - receives context of issuer,
// or NULL if no issuer cert found.
// phcsIssuerStore - receives handle of store containing cert.
// hCryptProvider - must be a valid provider
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/10/14 markdu Created.
//
//*******************************************************************
HRESULT GetIssuerContextAndStore( PCCERT_CONTEXT pccCertContext, PCCERT_CONTEXT* ppccIssuerCertContext, HCRYPTPROV hCryptProvider, HCERTSTORE* phcsIssuerStore) { HRESULT hr = hrSuccess; DWORD dwFlags;
// Open the CA store to get the issuer data.
hr = OpenSysCertStore(phcsIssuerStore, &hCryptProvider, cszCACertStore); if (hrSuccess == hr) { // Get the issuer cert context
dwFlags = 0; *ppccIssuerCertContext = gpfnCertGetIssuerCertificateFromStore( *phcsIssuerStore, pccCertContext, NULL, &dwFlags); if (NULL != *ppccIssuerCertContext) { goto out; } else { // Close the store, but don't goto error, becuase we want to try again.
CloseCertStore(*phcsIssuerStore, 0); *phcsIssuerStore = NULL; hr = ResultFromScode(MAPI_E_NOT_FOUND); } }
// We didn't find the issuer, so try the root store
hr = OpenSysCertStore(phcsIssuerStore, &hCryptProvider, cszROOTCertStore); if (hrSuccess == hr) { // Get the issuer cert context
dwFlags = 0; *ppccIssuerCertContext = gpfnCertGetIssuerCertificateFromStore( *phcsIssuerStore, pccCertContext, NULL, &dwFlags); if (NULL != *ppccIssuerCertContext) { goto out; } else { goto error; } }
out: // Make sure we didn't get back the same cert (ie it was self-signed).
if (hrSuccess == hr) { // First compare sizes since that is faster.
if (pccCertContext->cbCertEncoded == (*ppccIssuerCertContext)->cbCertEncoded) { // Sizes are the same, now compare the encoded cert blobs
if (0 == memcmp( pccCertContext->pbCertEncoded, (*ppccIssuerCertContext)->pbCertEncoded, pccCertContext->cbCertEncoded)) { // Certs are identical. There is no issuer.
goto error; } } }
return hr;
error: CloseCertStore(*phcsIssuerStore, 0); *phcsIssuerStore = NULL; return ResultFromScode(MAPI_E_NOT_FOUND); }
/***************************************************************************
Name : HrBuildCertSBinaryData
Purpose : Takes as input all the data needed for a cert entry in PR_USER_X509_CERTIFICATE and returns a pointer to memory that contains all the input data in the correct format to be plugged in to the lpb member of an SBinary structure. This memory should be Freed by the caller.
Parameters: bIsDefault - TRUE if this is the default cert pblobCertThumbPrint - The actual certificate thumbprint pblobSymCaps - symcaps blob ftSigningTime - Signing time lpObject - object to alloc more onto, or NULL to LocalAlloc lplpbData - receives the buffer with the data lpcbData - receives size of the data
Returns : HRESULT
Comment :
***************************************************************************/ HRESULT HrBuildCertSBinaryData( BOOL bIsDefault, BOOL fIsThumbprint, PCRYPT_DIGEST_BLOB pPrint, BLOB * pSymCaps, FILETIME ftSigningTime, LPVOID lpObject, LPBYTE FAR* lplpbData, ULONG FAR* lpcbData) { WORD cbDefault, cbPrint; DWORD cbSymCaps; HRESULT hr = S_OK; LPCERTTAGS lpCurrentTag; ULONG cbSize, cProps; LPBYTE lpb = NULL;
cbDefault = sizeof(bIsDefault); cbPrint = (WORD) pPrint->cbData; cbSymCaps = pSymCaps ? pSymCaps->cbSize : 0; cProps = 2; cbSize = cbDefault + cbPrint; if (cbSymCaps) { cProps++; cbSize += cbSymCaps; } if (ftSigningTime.dwLowDateTime || ftSigningTime.dwHighDateTime) { cProps++; cbSize += sizeof(FILETIME); } cbSize += (cProps * SIZE_CERTTAGS);
if (NULL == lpObject) { lpb = LocalAlloc(LMEM_ZEROINIT, cbSize); if (NULL == lpb) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto exit; } } else { SCODE sc; sc = MAPIAllocateMore(cbSize, lpObject, (LPVOID *)&lpb); if (sc) { hr = ResultFromScode(sc); goto exit; } }
// Set the default property
lpCurrentTag = (LPCERTTAGS)lpb; lpCurrentTag->tag = CERT_TAG_DEFAULT; lpCurrentTag->cbData = SIZE_CERTTAGS + cbDefault; memcpy(&lpCurrentTag->rgbData, &bIsDefault, cbDefault);
// Set the thumbprint property
lpCurrentTag = (LPCERTTAGS)((BYTE*)lpCurrentTag + lpCurrentTag->cbData); lpCurrentTag->tag = fIsThumbprint ? CERT_TAG_THUMBPRINT : CERT_TAG_BINCERT; lpCurrentTag->cbData = SIZE_CERTTAGS + cbPrint; memcpy(&lpCurrentTag->rgbData, pPrint->pbData, cbPrint);
// Set the SymCaps property
if (cbSymCaps) { lpCurrentTag = (LPCERTTAGS)((BYTE*)lpCurrentTag + lpCurrentTag->cbData); lpCurrentTag->tag = CERT_TAG_SYMCAPS; lpCurrentTag->cbData = (WORD) (SIZE_CERTTAGS + pSymCaps->cbSize); memcpy(&lpCurrentTag->rgbData, pSymCaps->pBlobData, cbSymCaps); }
// Signing time property
if (ftSigningTime.dwLowDateTime || ftSigningTime.dwHighDateTime) { lpCurrentTag = (LPCERTTAGS)((BYTE*)lpCurrentTag + lpCurrentTag->cbData); lpCurrentTag->tag = CERT_TAG_SIGNING_TIME; lpCurrentTag->cbData = SIZE_CERTTAGS + sizeof(FILETIME); memcpy(&lpCurrentTag->rgbData, &ftSigningTime, sizeof(FILETIME)); }
*lpcbData = cbSize; *lplpbData = lpb; exit: return(hr); }
//*******************************************************************
//
// FUNCTION: HrLDAPCertToMAPICert
//
// PURPOSE: Convert cert(s) returned from LDAP server to MAPI props.
// Two properties are required. The certs are placed in the
// WAB store, and all necessary indexing data is placed in
// PR_USER_X509_CERTIFICATE property. If this certificate
// didn't already exist in the WAB store, it's thumbprint is
// added to PR_WAB_TEMP_CERT_HASH so that these certs can
// be deleted from the store if the user cancels the add.
//
// PARAMETERS: lpPropArray - the prop array where the 2 props are stored
// ulX509Index - the index to the PR_USER_X509_CERTIFICATE prop
// ulTempCertIndex - the index to the PR_WAB_TEMP_CERT_HASH prop
// cbCert, lpCert - encoded cert data from the LDAP ppberval struct
// ulcCerts - the number of certs from the LDAP server
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/12/12 markdu Created.
//
//*******************************************************************
HRESULT HrLDAPCertToMAPICert( LPSPropValue lpPropArray, ULONG ulX509Index, ULONG ulTempCertIndex, ULONG cbCert, PBYTE lpCert, ULONG ulcCerts) { HRESULT hr = hrSuccess; HRESULT hrOut = hrSuccess; CRYPT_DIGEST_BLOB blobCertThumbPrint = {0}; PCCERT_CONTEXT pccCertToAdd; PCCERT_CONTEXT pccCertFromStore; HCERTSTORE hcsWABCertStore = NULL; HCRYPTPROV hCryptProvider = 0; PBYTE pbEncoded; DWORD cbEncoded; ULONG i; ULONG cbData = 0; LPBYTE lpbData = NULL; FILETIME ftNull = {0, 0}; #ifdef PARAMETER_VALIDATION
ULONG ulcProps = max(ulX509Index, ulTempCertIndex); if (ulcProps && IsBadReadPtr(lpPropArray, ulcProps * sizeof(SPropValue))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } /* if (ulcCerts && IsBadReadPtr(ppberval, ulcCerts * sizeof(struct berval)))
{ return ResultFromScode(MAPI_E_INVALID_PARAMETER); } */ #endif // PARAMETER_VALIDATION
// Make sure we have the right kind of proparray.
if ((NULL == lpPropArray) || (PR_USER_X509_CERTIFICATE != lpPropArray[ulX509Index].ulPropTag) || (PR_WAB_TEMP_CERT_HASH != lpPropArray[ulTempCertIndex].ulPropTag)) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } // Load the crypto functions
if (FALSE == InitCryptoLib()) { hr = ResultFromScode(MAPI_E_UNCONFIGURED); return hr; } // Open the store since we need to lookup certs
hr = OpenSysCertStore(&hcsWABCertStore, &hCryptProvider, cszWABCertStore); if (hrSuccess != hr) { goto out; } // Add each cert to the props, unless it is a duplicate.
for (i=0;i<ulcCerts;i++) { // Convert the cert into a form we can deal with.
// BUGBUG this assumes the cert is DER encoded.
pbEncoded = lpCert; //(PBYTE)ppberval[i]->bv_val;
cbEncoded = cbCert; //(DWORD)ppberval[i]->bv_len;
// Get a context for the cert so we can get the thumbprint
pccCertToAdd = gpfnCertCreateCertificateContext( X509_ASN_ENCODING, pbEncoded, cbEncoded); if (NULL == pccCertToAdd) { hr = GetLastError(); goto out; } // Get the thumbprint for this cert.
hr = GetCertThumbPrint( pccCertToAdd, &blobCertThumbPrint); if (hrSuccess != hr) { goto out; } // See if this cert is in the store already. If it is, we don't want to
// add it to the temp property for deletion later.
pccCertFromStore = gpfnCertFindCertificateInStore( hcsWABCertStore, X509_ASN_ENCODING, 0, CERT_FIND_HASH, (void *)&blobCertThumbPrint, NULL); if (NULL == pccCertFromStore) { BOOL fRet; // Add the cert to the store
fRet = gpfnCertAddEncodedCertificateToStore( hcsWABCertStore, X509_ASN_ENCODING, pbEncoded, cbEncoded, CERT_STORE_ADD_NEW, NULL); if (FALSE == fRet) { hr = GetLastError(); goto out; } // Add the thumbprint to the temp prop so we can delete it later if the user cancels.
hr = AddPropToMVPBin( lpPropArray, ulTempCertIndex, blobCertThumbPrint.pbData, blobCertThumbPrint.cbData, TRUE); if (hrSuccess != hr) { goto out; } } else { // We don't need to add this one to the store.
gpfnCertFreeCertificateContext(pccCertFromStore); } // Pack up all the cert data
cbData = 0; hr = HrBuildCertSBinaryData( FALSE, TRUE, &blobCertThumbPrint, NULL, // SymCaps blob
ftNull, // Signing time
NULL, // This NULL means lpbData is allocated with LocalAlloc()
&lpbData, &cbData); if ((hrSuccess != hr) || (0 == cbData)) { goto out; } // Add the cert data to the real cert prop.
hr = AddPropToMVPBin( lpPropArray, ulX509Index, lpbData, cbData, TRUE); if (hrSuccess != hr) { goto out; } // Add the trust for this LDAP cert to the pstore
// (doesn't have to be done because we won't trust this
// certificate by default)
// This is the way it was, wonder if that is correct
// (t-erikne)
// Free the cert context so we can do the next one.
gpfnCertFreeCertificateContext(pccCertToAdd); pccCertToAdd = NULL; LocalFreeAndNull(&lpbData); cbData = 0;
// Also free the blobCertThumbPrint.pbData which is allocated with LocalAlloc()
LocalFreeAndNull(&(blobCertThumbPrint.pbData)); blobCertThumbPrint.cbData = 0; } out: // Both blobCertThumbPrint.pbData and lpbData above are allocated using LocalAlloc()
// Be sure and free this memory.
LocalFreeAndNull(&lpbData); LocalFreeAndNull(&(blobCertThumbPrint.pbData));
// Destroy any data we created if the function failed.
if (hrSuccess != hr) { lpPropArray[ulX509Index].ulPropTag = PR_NULL; lpPropArray[ulTempCertIndex].ulPropTag = PR_NULL; } // Free the cert context. Ignore errors since there is nothing we can do.
if (NULL != pccCertToAdd) { gpfnCertFreeCertificateContext(pccCertToAdd); } // Close the cert store.
hrOut = CloseCertStore(hcsWABCertStore, hCryptProvider); // If an error occurred in the function body, return that instead of
// any errors that occurred here in cleanup.
if (hrSuccess == hr) { hr = hrOut; } return hr; }
//*******************************************************************
//
// FUNCTION: HrRemoveCertsFromWABStore
//
// PURPOSE: Remove the certs whose thumbprints are in the supplied
// PR_WAB_TEMP_CERT_HASH property.
//
// PARAMETERS: lpPropValue - the PR_WAB_TEMP_CERT_HASH property
//
// RETURNS: HRESULT.
//
// HISTORY:
// 96/12/13 markdu Created.
//
//*******************************************************************
HRESULT HrRemoveCertsFromWABStore( LPSPropValue lpPropValue) { HRESULT hr = hrSuccess; HRESULT hrOut = hrSuccess; CRYPT_DIGEST_BLOB blobCertThumbPrint; PCCERT_CONTEXT pccCertContext; HCERTSTORE hcsWABCertStore = NULL; HCRYPTPROV hCryptProvider = 0; ULONG i; ULONG ulcCerts; BOOL fRet;
#ifdef PARAMETER_VALIDATION
if (IsBadReadPtr(lpPropValue, sizeof(SPropValue))) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); } #endif // PARAMETER_VALIDATION
// Make sure we have the right kind of proparray.
if ((NULL == lpPropValue) || (PR_WAB_TEMP_CERT_HASH != lpPropValue->ulPropTag)) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
// Count the number of certs in the input.
ulcCerts = lpPropValue->Value.MVbin.cValues; if (0 == ulcCerts) { return hr; }
// Load the crypto functions
if (FALSE == InitCryptoLib()) { hr = ResultFromScode(MAPI_E_UNCONFIGURED); return hr; }
// Open the store since we need to delete certs
hr = OpenSysCertStore(&hcsWABCertStore, &hCryptProvider, cszWABCertStore); if (hrSuccess != hr) { return hr; }
// Delete each cert.
for (i=0;i<ulcCerts;i++) { // Get the thumbprint from the propval.
blobCertThumbPrint.cbData = lpPropValue->Value.MVbin.lpbin[i].cb; blobCertThumbPrint.pbData = lpPropValue->Value.MVbin.lpbin[i].lpb;
// Get the certificate from the WAB store using the thumbprint
// If we don't find the cert, ignore it and go on to the next one.
pccCertContext = gpfnCertFindCertificateInStore( hcsWABCertStore, X509_ASN_ENCODING, 0, CERT_FIND_HASH, (void *)&blobCertThumbPrint, NULL); if (NULL != pccCertContext) { // Delete the cert
fRet = gpfnCertDeleteCertificateFromStore(pccCertContext); if (FALSE == fRet) { hr = HrGetLastError(); goto out; } } }
out: // Close the cert store.
hrOut = CloseCertStore(hcsWABCertStore, hCryptProvider);
// If an error occurred in the function body, return that instead of
// any errors that occurred here in cleanup.
if (hrSuccess == hr) { hr = hrOut; }
return hr; }
//*******************************************************************
//
// FUNCTION: IsCertExpired
//
// PURPOSE: Check the cert info to see if it is expired or not yet valid.
//
// PARAMETERS: pCertInfo - Cert to verify
//
// RETURNS: TRUE if cert is expired, FALSE otherwise.
//
// HISTORY:
// 96/12/16 markdu Created.
// 98/03/225 brucek Use CAPI fn and be a little lenient on the start time.
//
//*******************************************************************
#define TIME_DELTA_SECONDS 600 // 10 minutes in seconds
#define FILETIME_SECOND 10000000 // 100ns intervals per second
HRESULT IsCertExpired( PCERT_INFO pCertInfo) { LONG lRet; FILETIME ftDelta; __int64 i64Delta; __int64 i64Offset; FILETIME ftNow;
Assert(pCertInfo);
lRet = gpfnCertVerifyTimeValidity(NULL, pCertInfo);
if (lRet < 0) { // Get the current time in filetime format so we can add the offset
GetSystemTimeAsFileTime(&ftNow);
i64Delta = ftNow.dwHighDateTime; i64Delta = i64Delta << 32; i64Delta += ftNow.dwLowDateTime;
// Add the offset into the original time to get us a new time to check
i64Offset = FILETIME_SECOND; i64Offset *= TIME_DELTA_SECONDS; i64Delta += i64Offset;
ftDelta.dwLowDateTime = (ULONG)i64Delta & 0xFFFFFFFF; ftDelta.dwHighDateTime = (ULONG)(i64Delta >> 32);
lRet = gpfnCertVerifyTimeValidity(&ftDelta, pCertInfo); }
return(lRet != 0); }
//*******************************************************************
//
// FUNCTION: IsCertRevoked
//
// PURPOSE: Check the cert info to see if it is revoked.
//
// PARAMETERS: pCertInfo - Cert to verify
//
// RETURNS: TRUE if cert is revoked, FALSE otherwise.
//
// HISTORY:
// 96/12/16 markdu Created.
//
//*******************************************************************
HRESULT IsCertRevoked( PCERT_INFO pCertInfo) { Assert(pCertInfo);
// Determine if cert has been revoked
// BUGBUG How to do this?
return FALSE; }
//*******************************************************************
//
// FUNCTION: ReadDataFromFile
//
// PURPOSE: Read data from a file.
//
// PARAMETERS: lpszFileName - name of file containing the data to be read
// ppbData - receives the data that is read
// pcbData - receives the size of the data that is read
//
// RETURNS: HRESULT
//
// HISTORY:
// 96/12/16 markdu Created.
//
//*******************************************************************
HRESULT ReadDataFromFile( LPTSTR lpszFileName, PBYTE* ppbData, PDWORD pcbData) { HRESULT hr = hrSuccess; BOOL fRet; HANDLE hFile = 0; DWORD cbFile; DWORD cbData; PBYTE pbData = 0;
if ((NULL == ppbData) || (NULL == pcbData)) { return ResultFromScode(MAPI_E_INVALID_PARAMETER); }
// Open the file and find out how big it is
hFile = CreateFile( lpszFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(INVALID_HANDLE_VALUE == hFile) { hr = ResultFromScode(MAPI_E_DISK_ERROR); goto error; }
cbData = GetFileSize(hFile, NULL); if (0xFFFFFFFF == cbData) { hr = ResultFromScode(MAPI_E_DISK_ERROR); goto error; }
IF_WIN32(pbData = (BYTE *)LocalAlloc(LMEM_ZEROINIT, cbData);) IF_WIN16(pbData = (PBYTE)LocalAlloc(LMEM_ZEROINIT, cbData);) if (NULL == pbData) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto error; }
fRet = ReadFile( hFile, // handle of file to read
pbData, // address of buffer that receives data
cbData, // number of bytes to read
&cbFile, // address of number of bytes read
NULL // address of structure for data
); if (FALSE == fRet) { hr = ResultFromScode(MAPI_E_DISK_ERROR); goto error; } if (cbData != cbFile) { hr = ResultFromScode(MAPI_E_CALL_FAILED); goto error; }
*ppbData = pbData; *pcbData = cbData;
out: if (hFile) { IF_WIN32(CloseHandle(hFile);) IF_WIN16(CloseFile(hFile);) }
return hr;
error: // BUGBUG some of the GetLastError calls above may not have worked.
if (hrSuccess == hr) { hr = ResultFromScode(MAPI_E_CALL_FAILED); }
goto out; }
//*******************************************************************
//
// FUNCTION: GetIssuerName
//
// PURPOSE: Wraps the several calls that one can make to try to
// get a usable name from a certificate. Esp in the
// case of self-signed certs, the issuer may just have a
// common name.
//
// PARAMETERS: lplpszIssuerName - OUT, for the name, NULL on err
// pCertInfo - IN, place from which to retrieve the data
//
// RETURNS: HRESULT.
//
// HISTORY:
// 97/02/04 t-erikne Created.
//
//*******************************************************************
HRESULT GetIssuerName( LPTSTR FAR * lplpszIssuerName, PCERT_INFO pCertInfo) { HRESULT hr;
Assert(lplpszIssuerName);
*lplpszIssuerName = '\000';
hr = GetAttributeString( lplpszIssuerName, pCertInfo->Issuer.pbData, pCertInfo->Issuer.cbData, szOID_ORGANIZATION_NAME);
if (hrSuccess != hr) if (MAPI_E_NOT_FOUND == hr) hr = GetAttributeString( lplpszIssuerName, pCertInfo->Issuer.pbData, pCertInfo->Issuer.cbData, szOID_COMMON_NAME);
return hr; }
//*******************************************************************
//
// FUNCTION: HrGetTrustState
//
// PURPOSE: For newly imported certs, need to determine if an
// issuer exists for this cert or not ...
//
// HISTORY:
// 2/17/97 t-erikne created
// 7/02/97 t-erikne updated to WinTrust
//
//*******************************************************************
HRESULT HrGetTrustState( HWND hwndParent, PCCERT_CONTEXT pcCert, DWORD * pdwTrust) { HRESULT hr; DWORD dwErr; GUID guidAction = CERT_CERTIFICATE_ACTION_VERIFY; // CERT_VERIFY_CERTIFICATE_TRUST cvct = {0};
CERT_VERIFY_CERTIFICATE_TRUST trust = {0}; WINTRUST_BLOB_INFO blob = {0}; WINTRUST_DATA data = {0};
if (!(pcCert || pdwTrust)) return E_INVALIDARG;
data.cbStruct = sizeof(WINTRUST_DATA); data.pPolicyCallbackData = NULL; data.pSIPClientData = NULL; data.dwUIChoice = WTD_UI_NONE; data.fdwRevocationChecks = WTD_REVOKE_NONE; data.dwUnionChoice = WTD_CHOICE_BLOB; data.pBlob = &blob;
blob.cbStruct = sizeof(WINTRUST_BLOB_INFO); blob.pcwszDisplayName = NULL; blob.cbMemObject = sizeof(trust); blob.pbMemObject = (LPBYTE)&trust;
trust.cbSize = sizeof(trust); trust.pccert = pcCert; trust.pdwErrors = pdwTrust; trust.pszUsageOid = szOID_PKIX_KP_EMAIL_PROTECTION; trust.dwIgnoreErr = CERT_VALIDITY_NO_CRL_FOUND | CERT_VALIDITY_UNKNOWN_CRITICAL_EXTENSION;
return (0 <= WinVerifyTrust(hwndParent, &guidAction, &data)) ? S_OK : E_FAIL; }
HRESULT DeleteCertStuff(LPADRBOOK lpAdrBook, LPENTRYID lpEntryID, ULONG cbEntryID) { SizedSPropTagArray(1, ptaCert)= { 1, {PR_USER_X509_CERTIFICATE} }; LPMAPIPROP lpMailUser = NULL; HRESULT hr = E_FAIL; LPSPropValue ppv = NULL; ULONG ul; BLOB thumbprint; LPWSTR szW = NULL;
//N2 not sure what to do yet about trust removal
goto out;
if (HR_FAILED(hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook, cbEntryID, // cbEntryID
lpEntryID, // entryid
NULL, // interface
0, // ulFlags
&ul, // returned object type
(LPUNKNOWN *)&lpMailUser))) { // Failed! Hmmm.
DebugTraceResult( TEXT("DeleteCertStuff: IAB->OpenEntry:"), hr); goto out; }
Assert(lpMailUser);
if(MAPI_DISTLIST == ul) { hr = S_OK; goto out; }
if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(lpMailUser, (LPSPropTagArray)&ptaCert, // lpPropTagArray
MAPI_UNICODE, // ulFlags
&ul, // how many properties were there?
&ppv))) { DebugTraceResult( TEXT("DeleteCertStuff: IAB->GetProps:"), hr); goto out; }
if (MAPI_W_ERRORS_RETURNED == hr) { if (PROP_TYPE(ppv->ulPropTag) == PT_ERROR) // the property doesn't exist, so we have no certs
// for this entry
hr = S_OK; // cool
goto out; } else if (1 != ul) { hr = E_FAIL; goto out; } else if (FAILED(hr)) goto out;
// Now need to loop over the SBinary structures to look at each cert
for (ul = 0; ul < ppv->Value.MVbin.cValues; ul++) { LPCERTTAGS lpCurrentTag, lpTempTag; LPBYTE lpbTagEnd;
lpCurrentTag = (LPCERTTAGS)ppv->Value.MVbin.lpbin[ul].lpb; lpbTagEnd = (LPBYTE)lpCurrentTag + ppv->Value.MVbin.lpbin[ul].cb;
// either this is the last cert or it is the default, so get the data
// scan for "thumbprint" tag
while ((LPBYTE)lpCurrentTag < lpbTagEnd && (CERT_TAG_THUMBPRINT != lpCurrentTag->tag)) { lpTempTag = lpCurrentTag; lpCurrentTag = (LPCERTTAGS)((BYTE*)lpCurrentTag + lpCurrentTag->cbData); if (lpCurrentTag == lpTempTag) { AssertSz(FALSE, TEXT("Bad CertTag in PR_USER_X509_CERTIFICATE\n")); break; // Safety valve, prevent infinite loop if bad data
} } if (CERT_TAG_THUMBPRINT == lpCurrentTag->tag) { // we need to remove the trust blob
#ifdef DEBUG
if (SUCCEEDED(hr)) DebugTraceResult( TEXT("DeleteCertStuff: trust blob deleted -- "), hr); else DebugTraceResult( TEXT("DeleteCertStuff: FAILED trust blob delete --"), hr); #endif
} else { // no data, so go to next cert
DebugTrace(TEXT("DeleteCertStuff: odd... no data for the cert\n")); continue; } } // for loop over certs
out: if (ppv) MAPIFreeBuffer(ppv); if (lpMailUser) lpMailUser->lpVtbl->Release(lpMailUser); return hr; }
PCCERT_CONTEXT WabGetCertFromThumbprint(CRYPT_DIGEST_BLOB thumbprint) { HCERTSTORE hcWAB; PCCERT_CONTEXT pcRet;
hcWAB = CertOpenStore( #ifdef UNICODE
CERT_STORE_PROV_SYSTEM_W, #else
CERT_STORE_PROV_SYSTEM_A, #endif
X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, cszWABCertStore);
if (hcWAB) { pcRet = CertFindCertificateInStore( hcWAB, X509_ASN_ENCODING, 0, //dwFindFlags
CERT_FIND_HASH, (void *)&thumbprint, NULL); CertCloseStore(hcWAB, 0); } else { pcRet = NULL; }
return pcRet; }
|