|
|
/*-----------------------------------------
//
// CertProp.C -- Displays Certificate File
// Properties and Allows
/// Add Cert to WAB
//
//-----------------------------------------*/
#include <windows.h>
#include <wab.h>
#include <wabguid.h>
#include "..\wab32res\resrc2.h"
#include <wincrypt.h>
#include <cryptdlg.h>
#include <cryptui.h>
#include "wabexe.h"
const UCHAR cszOID_PKIX_KP_EMAIL_PROTECTION[] = szOID_PKIX_KP_EMAIL_PROTECTION; const UCHAR szRoot[] = "ROOT"; const UCHAR szCA[] = "CA"; const UCHAR szAB[] = "AddressBook";
#define iAddToWAB 0
// Test for PT_ERROR property tag
// #define PROP_ERROR(prop) (prop.ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(prop.ulPropTag)))
#define PROP_ERROR(prop) (PROP_TYPE(prop.ulPropTag) == PT_ERROR)
#define GET_PROC_ADDR(h, fn) \
VAR_##fn = (TYP_##fn) GetProcAddress(h, #fn); \ Assert(VAR_##fn != NULL); \ if(NULL == VAR_##fn ) { \ VAR_##fn = LOADER_##fn; \ }
#define GET_PROC_ADDR_FLAG(h, fn, pflag) \
VAR_##fn = (TYP_##fn) GetProcAddress(h, #fn); \ *pflag = (VAR_##fn != NULL);
#undef LOADER_FUNCTION
#define LOADER_FUNCTION(ret, name, args1, args2, err, dll) \
typedef ret (WINAPI * TYP_##name) args1; \ extern TYP_##name VAR_##name; \ ret LOADER_##name args1 \ { \ if (!DemandLoad##dll()) return err; \ return VAR_##name args2; \ } \ TYP_##name VAR_##name = LOADER_##name;
#ifdef DEBUG
void DebugTraceCertContextName(PCCERT_CONTEXT pcCertContext, LPTSTR lpDescription); #endif
// *****************************************************************************************
// CRYPTDLG.DLL
// *****************************************************************************************
BOOL DemandLoadCryptDlg(void); static HMODULE s_hCryptDlg = 0;
LOADER_FUNCTION( DWORD, GetFriendlyNameOfCertA, (PCCERT_CONTEXT pccert, LPSTR pchBuffer, DWORD cchBuffer), (pccert, pchBuffer, cchBuffer), 0, CryptDlg) #define GetFriendlyNameOfCertA VAR_GetFriendlyNameOfCertA
LOADER_FUNCTION( BOOL, CertViewPropertiesA, (PCERT_VIEWPROPERTIES_STRUCT_A pCertViewInfo), (pCertViewInfo), FALSE, CryptDlg) #define CertViewPropertiesA VAR_CertViewPropertiesA
// *****************************************************************************************
// CRYPT32.DLL
// *****************************************************************************************
BOOL DemandLoadCrypt32(void); static HMODULE s_hCrypt32 = 0;
LOADER_FUNCTION( BOOL, CertFreeCertificateContext, (PCCERT_CONTEXT pCertContext), (pCertContext), FALSE, Crypt32) #define CertFreeCertificateContext VAR_CertFreeCertificateContext
LOADER_FUNCTION( PCCERT_CONTEXT, CertDuplicateCertificateContext, (PCCERT_CONTEXT pCertContext), (pCertContext), NULL, Crypt32) #define CertDuplicateCertificateContext VAR_CertDuplicateCertificateContext
LOADER_FUNCTION( BOOL, CertCloseStore, (HCERTSTORE hCertStore, DWORD dwFlags), (hCertStore, dwFlags), FALSE, Crypt32) #define CertCloseStore VAR_CertCloseStore
LOADER_FUNCTION( HCERTSTORE, CertOpenSystemStoreA, (HCRYPTPROV hProv, LPCSTR szSubsystemProtocol), (hProv, szSubsystemProtocol), NULL, Crypt32) #define CertOpenSystemStoreA VAR_CertOpenSystemStoreA
LOADER_FUNCTION( BOOL, CertGetCertificateContextProperty, (PCCERT_CONTEXT pCertContext, DWORD dwPropId, void *pvData, DWORD *pcbData), (pCertContext, dwPropId, pvData, pcbData), FALSE, Crypt32) #define CertGetCertificateContextProperty VAR_CertGetCertificateContextProperty
LOADER_FUNCTION( HCERTSTORE, CertOpenStore, (LPCSTR lpszStoreProvider, DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara), (lpszStoreProvider, dwEncodingType, hCryptProv, dwFlags, pvPara), NULL, Crypt32) #define CertOpenStore VAR_CertOpenStore
LOADER_FUNCTION( PCCERT_CONTEXT, CertEnumCertificatesInStore, (HCERTSTORE hCertStore, PCCERT_CONTEXT pPrevCertContext), (hCertStore, pPrevCertContext), NULL, Crypt32) #define CertEnumCertificatesInStore VAR_CertEnumCertificatesInStore
LOADER_FUNCTION( PCCERT_CONTEXT, CertGetIssuerCertificateFromStore, (HCERTSTORE hCertStore, PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext, DWORD *pdwFlags), (hCertStore, pSubjectContext, pPrevIssuerContext, pdwFlags), NULL, Crypt32) #define CertGetIssuerCertificateFromStore VAR_CertGetIssuerCertificateFromStore
LOADER_FUNCTION( BOOL, CertCompareCertificate, (DWORD dwCertEncodingType, PCERT_INFO pCertId1, PCERT_INFO pCertId2), (dwCertEncodingType, pCertId1, pCertId2), FALSE, Crypt32) #define CertCompareCertificate VAR_CertCompareCertificate
LOADER_FUNCTION( BOOL, CryptMsgClose, (HCRYPTMSG hCryptMsg), (hCryptMsg), FALSE, Crypt32) #define CryptMsgClose VAR_CryptMsgClose
LOADER_FUNCTION( BOOL, CryptMsgGetParam, (HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex, void *pvData, DWORD *pcbData), (hCryptMsg, dwParamType, dwIndex, pvData, pcbData), FALSE, Crypt32) #define CryptMsgGetParam VAR_CryptMsgGetParam
LOADER_FUNCTION( BOOL, CryptMsgUpdate, (HCRYPTMSG hCryptMsg, const BYTE *pbData, DWORD cbData, BOOL fFinal), (hCryptMsg, pbData, cbData, fFinal), FALSE, Crypt32) #define CryptMsgUpdate VAR_CryptMsgUpdate
LOADER_FUNCTION( HCRYPTMSG, CryptMsgOpenToDecode, (DWORD dwMsgEncodingType, DWORD dwFlags, DWORD dwMsgType, HCRYPTPROV hCryptProv, PCERT_INFO pRecipientInfo, PCMSG_STREAM_INFO pStreamInfo), (dwMsgEncodingType, dwFlags, dwMsgType, hCryptProv, pRecipientInfo, pStreamInfo), NULL, Crypt32) #define CryptMsgOpenToDecode VAR_CryptMsgOpenToDecode
LOADER_FUNCTION( DWORD, CertRDNValueToStrA, (DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue, LPTSTR pszValueString, DWORD cszValueString), (dwValueType, pValue, pszValueString, cszValueString), 0, Crypt32) #define CertRDNValueToStrA VAR_CertRDNValueToStrA
LOADER_FUNCTION( PCERT_RDN_ATTR, CertFindRDNAttr, (LPCSTR pszObjId, PCERT_NAME_INFO pName), (pszObjId, pName), NULL, Crypt32) #define CertFindRDNAttr VAR_CertFindRDNAttr
LOADER_FUNCTION( BOOL, CryptDecodeObject, (DWORD dwEncodingType, LPCSTR lpszStructType, const BYTE * pbEncoded, DWORD cbEncoded, DWORD dwFlags, void * pvStructInfo, DWORD * pcbStructInfo), (dwEncodingType, lpszStructType, pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo), FALSE, Crypt32) #define CryptDecodeObject VAR_CryptDecodeObject
LOADER_FUNCTION( BOOL, CertAddCertificateContextToStore, (HCERTSTORE hCertStore, PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition, PCCERT_CONTEXT * ppStoreContext), (hCertStore, pCertContext, dwAddDisposition, ppStoreContext), FALSE, Crypt32) #define CertAddCertificateContextToStore VAR_CertAddCertificateContextToStore
LOADER_FUNCTION( BOOL, CertAddEncodedCertificateToStore, (HCERTSTORE hCertStore, DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded, DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext), (hCertStore, dwCertEncodingType, pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext), FALSE, Crypt32) #define CertAddEncodedCertificateToStore VAR_CertAddEncodedCertificateToStore
// *****************************************************************************************
// ADVAPI.DLL
// *****************************************************************************************
BOOL DemandLoadAdvApi32(void); static HMODULE s_hAdvApi = 0;
LOADER_FUNCTION(BOOL, CryptAcquireContextA, (HCRYPTPROV * phProv, LPCTSTR pszContainer, LPCTSTR pszProvider, DWORD dwProvType, DWORD dwFlags), (phProv, pszContainer, pszProvider, dwProvType, dwFlags), FALSE, AdvApi32) #define CryptAcquireContextA VAR_CryptAcquireContextA
LOADER_FUNCTION( BOOL, CryptReleaseContext, (HCRYPTPROV hProv, DWORD dwFlags), (hProv, dwFlags), FALSE, AdvApi32) #define CryptReleaseContext VAR_CryptReleaseContext
// *****************************************************************************************
// Various Structures and typdefs
// *****************************************************************************************
typedef BLOB THUMBBLOB;
// This struct and tags will be published by the exchange group -- this is temporary.
#define NUM_CERT_TAGS 2
#define CERT_TAG_DEFAULT 0x20
#define CERT_TAG_THUMBPRINT 0x22
// SIZE_CERTTAGS is the size of the structure excluding the byte array.
#define SIZE_CERTTAGS (2 * sizeof(WORD))
//N warnings, should probably just remove the []
#pragma warning (disable:4200)
typedef struct _CertTag { WORD tag; WORD cbData; BYTE rgbData[]; } CERTTAGS, FAR * LPCERTTAGS; #pragma warning (default:4200)
#define LPARAM_SENTRY 0x424A4800
typedef struct _AB_DIALOG_PANE_PARAMS { DWORD dwSentry; // Must be set to value of LPARAM_SENTRY
LPWABOBJECT lpWABObject; LPADRBOOK lpAdrBook; PCERT_CONTEXT * rgCertContext; // array of cert context pointers
ULONG cCertContexts; // how many cert in rgCertContext
ULONG iLeafCert; // index in array of the leaf cert
LPTSTR lpDisplayName; LPTSTR lpEmailAddress; HCRYPTPROV hCryptProv; } AB_DIALOG_PANE_PARAMS, *LPAB_DIALOG_PANE_PARAMS;
static BOOL s_fCertViewPropertiesCryptUIA = FALSE; BOOL DemandLoadCryptDlg(void) { BOOL fRet = TRUE;
if (0 == s_hCryptDlg) { s_hCryptDlg = LoadLibrary("CRYPTDLG.DLL");
if (0 == s_hCryptDlg) { DebugTrace("LoadLibrary of CRYPTDLG.DLL failed\n"); fRet = FALSE; } else { GET_PROC_ADDR(s_hCryptDlg, GetFriendlyNameOfCertA) GET_PROC_ADDR(s_hCryptDlg, CertViewPropertiesA) } } return(fRet); }
BOOL CryptUIAvailable(void) { DemandLoadCryptDlg(); return(s_fCertViewPropertiesCryptUIA); }
BOOL DemandLoadCrypt32(void) { BOOL fRet = TRUE;
if (0 == s_hCrypt32) { s_hCrypt32 = LoadLibrary("CRYPT32.DLL");
if (0 == s_hCrypt32) { DebugTrace("LoadLibrary of CRYPT32.DLL failed\n"); fRet = FALSE; } else { GET_PROC_ADDR(s_hCrypt32, CertFreeCertificateContext) GET_PROC_ADDR(s_hCrypt32, CertDuplicateCertificateContext) GET_PROC_ADDR(s_hCrypt32, CertCloseStore) GET_PROC_ADDR(s_hCrypt32, CertOpenSystemStoreA) GET_PROC_ADDR(s_hCrypt32, CertGetCertificateContextProperty) GET_PROC_ADDR(s_hCrypt32, CertOpenStore) GET_PROC_ADDR(s_hCrypt32, CertEnumCertificatesInStore) GET_PROC_ADDR(s_hCrypt32, CertGetIssuerCertificateFromStore) GET_PROC_ADDR(s_hCrypt32, CertCompareCertificate) GET_PROC_ADDR(s_hCrypt32, CryptMsgClose) GET_PROC_ADDR(s_hCrypt32, CryptMsgGetParam) GET_PROC_ADDR(s_hCrypt32, CryptMsgUpdate) GET_PROC_ADDR(s_hCrypt32, CryptMsgOpenToDecode) GET_PROC_ADDR(s_hCrypt32, CertRDNValueToStrA) GET_PROC_ADDR(s_hCrypt32, CertFindRDNAttr) GET_PROC_ADDR(s_hCrypt32, CryptDecodeObject) GET_PROC_ADDR(s_hCrypt32, CertAddCertificateContextToStore) GET_PROC_ADDR(s_hCrypt32, CertAddEncodedCertificateToStore) } } return(fRet); }
BOOL DemandLoadAdvApi32(void) { BOOL fRet = TRUE;
if (0 == s_hAdvApi) { s_hAdvApi = LoadLibrary("ADVAPI32.DLL");
if (0 == s_hAdvApi) { DebugTrace("LoadLibrary of ADVAPI32.DLL failed\n"); fRet = FALSE; } else { GET_PROC_ADDR(s_hAdvApi, CryptAcquireContextA) GET_PROC_ADDR(s_hAdvApi, CryptReleaseContext) } } return(fRet); }
/***************************************************************************
Name : IsThumbprintInMVPBin
Purpose : Check the PR_USER_X509_CERTIFICATE prop for this vsthumbprint
Parameters: spv = prop value structure of PR_USER_X509_CERTIFICATE lpThumbprint -> THUMBBLOB structure to find
Returns : TRUE if found
Comment :
***************************************************************************/ BOOL IsThumbprintInMVPBin(SPropValue spv, THUMBBLOB * lpThumbprint) { ULONG cValues, i; LPSBinary lpsb = NULL; LPCERTTAGS lpCurrentTag; LPBYTE lpbTagEnd;
if (! PROP_ERROR((spv))) { lpsb = spv.Value.MVbin.lpbin; cValues = spv.Value.MVbin.cValues;
// Check for duplicates
for (i = 0; i < cValues; i++) { lpCurrentTag = (LPCERTTAGS)lpsb[i].lpb; lpbTagEnd = (LPBYTE)lpCurrentTag + lpsb[i].cb;
while ((LPBYTE)lpCurrentTag < lpbTagEnd) { // Check if this is the tag that contains the thumbprint
if (CERT_TAG_THUMBPRINT == lpCurrentTag->tag) { if ((lpThumbprint->cbSize == lpCurrentTag->cbData - SIZE_CERTTAGS) && ! memcmp(lpThumbprint->pBlobData, &lpCurrentTag->rgbData, lpThumbprint->cbSize)) { return(TRUE); } }
lpCurrentTag = (LPCERTTAGS)((BYTE*)lpCurrentTag + lpCurrentTag->cbData); } } } return(FALSE); }
/***************************************************************************
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 lplpbData - receives the buffer with the data lpcbData - receives size of the data
Returns : HRESULT
Comment :
***************************************************************************/ HRESULT HrBuildCertSBinaryData( BOOL bIsDefault, THUMBBLOB* pPrint, LPBYTE FAR* lplpbData, ULONG FAR* lpcbData) { WORD cbDefault, cbPrint; HRESULT hr = S_OK; LPCERTTAGS lpCurrentTag; ULONG cbSize, cProps; LPBYTE lpb = NULL;
cbDefault = sizeof(bIsDefault); cbPrint = (WORD) pPrint->cbSize; cProps = 2; cbSize = cbDefault + cbPrint; cbSize += (cProps * SIZE_CERTTAGS);
if (! (lpb = LocalAlloc(LPTR, cbSize))) { hr = E_OUTOFMEMORY; 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 = CERT_TAG_THUMBPRINT; lpCurrentTag->cbData = SIZE_CERTTAGS + cbPrint; memcpy(&lpCurrentTag->rgbData, pPrint->pBlobData, cbPrint);
*lpcbData = cbSize; *lplpbData = lpb; exit: return(hr); }
/* PVGetCertificateParam:
** ** Purpose: ** Combine the "how big? okay, here." double question to get a parameter ** from a certificate. Give it a thing to get and it will alloc the mem. ** Takes: ** IN pCert - CAPI certificate to query ** IN dwParam - parameter to find, ex: CERT_SHA1_HASH_PROP_ID ** OUT OPTIONAL cbOut - (def value of NULL) size of the returned PVOID ** Returns: ** data that was obtained, NULL if failed */ LPVOID PVGetCertificateParam( PCCERT_CONTEXT pCert, DWORD dwParam, DWORD *cbOut) { DWORD cbData; void *pvData = NULL;
if (!pCert) { SetLastError((DWORD)E_INVALIDARG); goto ErrorReturn; }
cbData = 0; CertGetCertificateContextProperty(pCert, dwParam, NULL, &cbData); if (! cbData || (! (pvData = LocalAlloc(LPTR, cbData)))) { DebugTrace("CertGetCertificateContextProperty -> %x\n", GetLastError()); goto ErrorReturn; }
if (! CertGetCertificateContextProperty(pCert, dwParam, pvData, &cbData)) { DebugTrace("CertGetCertificateContextProperty -> %x\n", GetLastError()); goto ErrorReturn; }
exit: if (cbOut) { *cbOut = cbData; } return(pvData);
ErrorReturn: if (pvData) { LocalFree(pvData); pvData = NULL; } cbData = 0; goto exit; }
/*
** ** FUNCTION: GetAttributeString ** ** PURPOSE: Get the string associated with the given attribute ** ** PARAMETERS: lplpszAttributeString - pointer that will be LocalAlloc'ed ** to hold the string. Caller must LocalFree this! ** 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 for WAB ** */ HRESULT GetAttributeString(LPTSTR FAR * lplpszAttributeString, BYTE *pbEncoded, DWORD cbEncoded, LPCSTR 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; CryptDecodeObject( 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 = GetLastError(); goto exit; }
// Allocate space for the decoded name
if (! (pNameInfo = LocalAlloc(LPTR, cbInfo))) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto exit; }
// Get the subject name
if (! CryptDecodeObject( 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
hr = GetLastError(); goto exit; }
// Now we have a decoded name RDN array, so find the oid we want
if (! (pRdnAttr = CertFindRDNAttr(lpszObjID, pNameInfo))) { hr = MAPI_E_NOT_FOUND; goto exit; }
// 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)) { hr = MAPI_E_INVALID_PARAMETER; goto exit; }
// 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 = CertRDNValueToStr(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 (! (*lplpszAttributeString = LocalAlloc(LPTR, cbData))) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto exit; }
// Copy the string
switch (pRdnAttr->dwValueType) { case CERT_RDN_UNICODE_STRING: if (FALSE == WideCharToMultiByte( CP_ACP, 0, (LPWSTR)pRdnAttr->Value.pbData, -1, *lplpszAttributeString, cbData, NULL, NULL)) { DWORD dwErr = GetLastError(); switch(dwErr) { case ERROR_INSUFFICIENT_BUFFER: hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); break; case ERROR_INVALID_PARAMETER: hr = ResultFromScode(MAPI_E_INVALID_PARAMETER); break; default: hr = ResultFromScode(MAPI_E_CALL_FAILED); break; } goto exit; } break;
case CERT_RDN_UNIVERSAL_STRING: case CERT_RDN_TELETEX_STRING: CertRDNValueToStr(pRdnAttr->dwValueType, (PCERT_RDN_VALUE_BLOB)&(pRdnAttr->Value), *lplpszAttributeString, cbData); break;
default: lstrcpyn(*lplpszAttributeString, (LPCSTR)pRdnAttr->Value.pbData, cbData); (*lplpszAttributeString)[cbData - 1] = '\0'; break; }
exit: if (hr && *lplpszAttributeString) { LocalFree(*lplpszAttributeString); *lplpszAttributeString = NULL; }
if (NULL != pNameInfo) { LocalFree(pNameInfo); } return(hr); }
/***************************************************************************
Name : AddPropToMVPBin
Purpose : Add a property to a multi-valued binary property in a prop array
Parameters: lpWABObject -> WAB Object lpaProps -> array of properties uPropTag = property tag for MVP index = index in lpaProps of MVP lpNew -> new data cbNew = size of lpbNew fNoDuplicates = TRUE if we should not add duplicates
Returns : HRESULT
Comment : Find the size of the existing MVP Add in the size of the new entry allocate new space copy old to new free old copy new entry point prop array lpbin the new space increment cValues
Note: The new MVP memory is AllocMore'd onto the lpaProps allocation. We will unlink the pointer to the old MVP array, but this will be cleaned up when the prop array is freed.
***************************************************************************/ HRESULT AddPropToMVPBin(LPWABOBJECT lpWABObject, LPSPropValue lpaProps, DWORD index, LPVOID lpNew, ULONG cbNew, BOOL fNoDuplicates) { UNALIGNED SBinaryArray * lprgsbOld = NULL; SBinaryArray * lprgsbNew = NULL; LPSBinary lpsbOld = NULL; LPSBinary lpsbNew = NULL; ULONG cbMVP = 0; ULONG cExisting = 0; LPBYTE lpNewTemp = NULL; HRESULT hResult = hrSuccess; SCODE sc = SUCCESS_SUCCESS; ULONG i;
// Find the size of any existing MVP entries
if (PT_ERROR == PROP_TYPE(lpaProps[index].ulPropTag)) { // Un-ERROR the property tag
lpaProps[index].ulPropTag = PROP_TAG(PT_MV_BINARY, PROP_ID(lpaProps[index].ulPropTag)); } else { // point to the structure in the prop array.
lprgsbOld = &(lpaProps[index].Value.MVbin); lpsbOld = lprgsbOld->lpbin;
cExisting = lprgsbOld->cValues;
// Check for duplicates
if (fNoDuplicates) { for (i = 0; i < cExisting; i++) { if (cbNew == lpsbOld[i].cb && ! memcmp(lpNew, lpsbOld[i].lpb, cbNew)) { DebugTrace("AddPropToMVPBin found duplicate.\n"); return(hrSuccess); } } }
cbMVP = cExisting * sizeof(SBinary); }
// cbMVP now contains the current size of the MVP
cbMVP += sizeof(SBinary); // room in the MVP for another Sbin
// Allocate room for new MVP
if (sc = lpWABObject->lpVtbl->AllocateMore(lpWABObject, cbMVP, lpaProps, (LPVOID*)&lpsbNew)) { DebugTrace("AddPropToMVPBin allocation (%u) failed %x\n", cbMVP, sc); hResult = ResultFromScode(sc); return(hResult); }
// If there are properties there already, copy them to our new MVP
for (i = 0; i < cExisting; i++) { // Copy this property value to the MVP
lpsbNew[i].cb = lpsbOld[i].cb; lpsbNew[i].lpb = lpsbOld[i].lpb; }
// Add the new property value
// Allocate room for it
if (sc = lpWABObject->lpVtbl->AllocateMore(lpWABObject, cbNew, lpaProps, (LPVOID*)&(lpsbNew[i].lpb))) { DebugTrace("AddPropToMVPBin allocation (%u) failed %x\n", cbNew, sc); hResult = ResultFromScode(sc); return(hResult); }
lpsbNew[i].cb = cbNew; CopyMemory(lpsbNew[i].lpb, lpNew, cbNew);
lpaProps[index].Value.MVbin.lpbin = lpsbNew; lpaProps[index].Value.MVbin.cValues = cExisting + 1;
return(hResult); }
// enum for ADRENTRY props
enum { irnPR_ENTRYID = 0, irnPR_DISPLAY_NAME, irnPR_EMAIL_ADDRESS, irnPR_OBJECT_TYPE, irnMax };
// enum for getting the entryid of an entry
enum { itbdPR_USER_X509_CERTIFICATE, itbMax }; static const SizedSPropTagArray(itbMax, ptaCert) = { itbMax, { PR_USER_X509_CERTIFICATE, } };
enum { iconPR_DEF_CREATE_MAILUSER = 0, iconMax }; static const SizedSPropTagArray(iconMax, ptaCon)= { iconMax, { PR_DEF_CREATE_MAILUSER, } };
// enum for setting the created properties
enum { imuPR_DISPLAY_NAME = 0, // must be first so DL's can use same enum
imuPR_EMAIL_ADDRESS, imuPR_ADDRTYPE, imuMax }; static const SizedSPropTagArray(imuMax, ptag)= { imuMax, { PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_ADDRTYPE, } };
// enum for getting the entryid of an entry
enum { ieidPR_ENTRYID, ieidMax }; static const SizedSPropTagArray(ieidMax, ptaEID)= { ieidMax, { PR_ENTRYID, } };
HRESULT HrAddCertsToWAB(HWND hwnd, LPWABOBJECT lpWABObject, LPADRBOOK lpAdrBook, HCRYPTPROV hCryptProv, PCERT_CONTEXT * rgCertContext, ULONG cCertContexts, ULONG iLeaf, LPTSTR lpDisplayName, LPTSTR lpEmailAddress) { HRESULT hr; SCODE sc; BOOL fFound; ULONG cCerts; LPSPropValue ppv = NULL; LPSPropValue ppvEID = NULL; BOOL fAlreadyHasCert; ULONG ul; LPADRLIST lpAdrList = NULL; LPMAILUSER lpMailUser = NULL; ULONG ulObjectType; LPBYTE lpCertProp; ULONG cbCertProp; LPSPropValue ppvUndo = NULL; HCERTSTORE hcAB = 0, hcCA = 0; PCCERT_CONTEXT pccLeaf = NULL; THUMBBLOB Thumbprint = {0}; ULONG i, iEntry; BOOL fShowUI = TRUE; HCRYPTPROV hProv = 0; SPropValue spv[imuMax]; ULONG cbEIDWAB; LPENTRYID lpEIDWAB = NULL; ULONG cProps; LPSPropValue lpCreateEIDs = NULL; LPABCONT lpContainer = NULL; BOOL fCreateNew = FALSE;
if (! rgCertContext || ! lpAdrBook || ! lpWABObject) { return(ResultFromScode(E_FAIL)); }
DebugTrace("Certificate for '%s'. Email: '%s'\n", lpDisplayName, lpEmailAddress ? lpEmailAddress : szEmpty);
if (! (hcCA = CertOpenSystemStoreA(hCryptProv, szCA))) { hr = GetLastError(); goto exit; }
if (! (hcAB = CertOpenSystemStore(hCryptProv, szAB))) { hr = GetLastError(); goto exit; }
// Add all the certs to the cert stores
// Leaf goes in WAB store, others go in CA
for (i = 0; i < cCertContexts; i++) { if (i == iLeaf) { if (CertAddCertificateContextToStore(hcAB, rgCertContext[i], CERT_STORE_ADD_REPLACE_EXISTING, &pccLeaf)) { // Get it's thumbprint
if (! (Thumbprint.pBlobData = (BYTE *)PVGetCertificateParam( pccLeaf, CERT_HASH_PROP_ID, &Thumbprint.cbSize))) { goto exit; } } else { hr = GetLastError(); DebugTrace("CertAddCertificateContextToStore -> %x\n", hr); goto exit; } } else {
if (! CertAddCertificateContextToStore(hcCA, rgCertContext[i], CERT_STORE_ADD_REPLACE_EXISTING, NULL)) { DebugTrace("CertAddCertificateContextToStore -> %x\n", GetLastError()); // Don't fail, just go on
} } }
if (sc = lpWABObject->lpVtbl->AllocateBuffer(lpWABObject, sizeof(ADRLIST) + 1 * sizeof(ADRENTRY), (LPVOID*)&lpAdrList)) { hr = ResultFromScode(sc); goto exit; }
lpAdrList->cEntries = 1; lpAdrList->aEntries[0].ulReserved1 = 0; lpAdrList->aEntries[0].cValues = irnMax;
// Allocate the prop array for the ADRENTRY
if (sc = lpWABObject->lpVtbl->AllocateBuffer(lpWABObject, lpAdrList->aEntries[0].cValues * sizeof(SPropValue), (LPVOID*)&lpAdrList->aEntries[0].rgPropVals)) { hr = ResultFromScode(sc); goto exit; }
lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].ulPropTag = PR_ENTRYID; lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin.cb = 0; lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin.lpb = NULL;
lpAdrList->aEntries[0].rgPropVals[irnPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE; lpAdrList->aEntries[0].rgPropVals[irnPR_OBJECT_TYPE].Value.l = MAPI_MAILUSER;
if (lpDisplayName) { lpAdrList->aEntries[0].rgPropVals[irnPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME; lpAdrList->aEntries[0].rgPropVals[irnPR_DISPLAY_NAME].Value.LPSZ = lpDisplayName; } else { lpAdrList->aEntries[0].rgPropVals[irnPR_DISPLAY_NAME].ulPropTag = PR_NULL; } if (lpEmailAddress) { lpAdrList->aEntries[0].rgPropVals[irnPR_EMAIL_ADDRESS].ulPropTag = PR_EMAIL_ADDRESS; lpAdrList->aEntries[0].rgPropVals[irnPR_EMAIL_ADDRESS].Value.LPSZ = lpEmailAddress; } else { lpAdrList->aEntries[0].rgPropVals[irnPR_EMAIL_ADDRESS].ulPropTag = PR_NULL; }
hr = lpAdrBook->lpVtbl->ResolveName(lpAdrBook, (ULONG_PTR)hwnd, MAPI_DIALOG | WAB_RESOLVE_LOCAL_ONLY | WAB_RESOLVE_ALL_EMAILS | WAB_RESOLVE_NO_ONE_OFFS | WAB_RESOLVE_NO_NOT_FOUND_UI, NULL, // BUGBUG: name for NewEntry dialog?
lpAdrList);
switch (GetScode(hr)) { case SUCCESS_SUCCESS: // Should be a resolved entry now
// Should have PR_ENTRYID in rgPropVals[irnPR_ENTRYID]
if (lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].ulPropTag == PR_ENTRYID) { if (HR_FAILED(hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook, lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin.cb, (LPENTRYID)lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin.lpb, NULL, MAPI_MODIFY, // ulFlags
&ulObjectType, (LPUNKNOWN *)&lpMailUser))) { DebugTrace("OpenEntry -> %x\n", GetScode(hr)); goto exit; } } break;
case MAPI_E_NOT_FOUND: // no match, create one
// Get the PAB object
if (HR_FAILED(hr = lpAdrBook->lpVtbl->GetPAB(lpAdrBook, &cbEIDWAB, &lpEIDWAB))) { goto exit; // Bad stuff here!
}
if (HR_FAILED(hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook, cbEIDWAB, // size of EntryID to open
lpEIDWAB, // EntryID to open
NULL, // interface
0, // flags
&ulObjectType, (LPUNKNOWN *)&lpContainer))) { goto exit; }
// Get us the creation entryids
if (hr = lpContainer->lpVtbl->GetProps(lpContainer, (LPSPropTagArray)&ptaCon, 0, &cProps, &lpCreateEIDs)) { goto exit; // Bad stuff here!
}
if (HR_FAILED(hr = lpContainer->lpVtbl->CreateEntry(lpContainer, lpCreateEIDs[iconPR_DEF_CREATE_MAILUSER].Value.bin.cb, (LPENTRYID)lpCreateEIDs[iconPR_DEF_CREATE_MAILUSER].Value.bin.lpb, 0, //CREATE_CHECK_DUP_STRICT
(LPMAPIPROP *)&lpMailUser))) { goto exit; }
// Successful creation of new entry. Fill in email and displayname
spv[imuPR_EMAIL_ADDRESS].ulPropTag = PR_EMAIL_ADDRESS; spv[imuPR_EMAIL_ADDRESS].Value.lpszA = lpEmailAddress;
spv[imuPR_ADDRTYPE].ulPropTag = PR_ADDRTYPE; spv[imuPR_ADDRTYPE].Value.lpszA = "SMTP"; spv[imuPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME; spv[imuPR_DISPLAY_NAME].Value.lpszA = lpDisplayName;
if (HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(lpMailUser, // this
imuMax, // cValues
spv, // property array
NULL))) { // problems array
DebugTrace("SetProps -> %x\n", GetScode(hr)); } // Need to save so we can get an entryid later
if (HR_FAILED(hr = lpMailUser->lpVtbl->SaveChanges(lpMailUser, KEEP_OPEN_READWRITE))) { goto exit; }
if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(lpMailUser, (LPSPropTagArray)&ptaEID, 0, &ul, &ppvEID))) { goto exit; }
lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].ulPropTag = PR_ENTRYID; lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin.cb = ppvEID[ieidPR_ENTRYID].Value.bin.cb; lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin.lpb = ppvEID[ieidPR_ENTRYID].Value.bin.lpb;
fCreateNew = TRUE; break;
case MAPI_E_USER_CANCEL: // cancel, don't update
default: break; }
if (lpMailUser) { // Got the entry, Set the cert property
if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(lpMailUser, (LPSPropTagArray)&ptaCert, 0, &ul, &ppv))) { // Shouldn't happen, but if it does, we don't have a lpPropArray
goto exit; }
if (! IsThumbprintInMVPBin(ppv[0], &Thumbprint)) { if (HR_FAILED(hr = HrBuildCertSBinaryData(PROP_ERROR(ppv[0]), // Default if there is no current value
&Thumbprint, &lpCertProp, &cbCertProp))) { goto exit; }
// Add the new thumbprint to PR_USER_X509_CERTIFICATE
if (HR_FAILED(hr = AddPropToMVPBin(lpWABObject, ppv, // prop array
0, // index of PR_USER_X509_CERTIFICATE in ppv
lpCertProp, cbCertProp, TRUE))) { // fNoDuplicates
goto exit; }
if (fShowUI) { // Save undo information
if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(lpMailUser, (LPSPropTagArray)&ptaCert, 0, &ul, &ppvUndo))) { ppvUndo = NULL; } }
if (HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(lpMailUser, 1, ppv, NULL))) { goto exit; } if (HR_FAILED(hr = lpMailUser->lpVtbl->SaveChanges(lpMailUser, KEEP_OPEN_READWRITE))) { goto exit; } }
if (fShowUI) { hr = lpAdrBook->lpVtbl->Details(lpAdrBook, (PULONG_PTR)&hwnd, NULL, NULL, lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin.cb, (LPENTRYID)lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin.lpb, NULL, NULL, NULL, 0); if (ResultFromScode(hr) == MAPI_E_USER_CANCEL && (ppvUndo || fCreateNew)) { // Undo
if (fCreateNew && lpContainer) { ENTRYLIST EntryList;
EntryList.cValues = 1; EntryList.lpbin = &lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin;
// Now, delete the entry found.
if (hr = lpContainer->lpVtbl->DeleteEntries(lpContainer, &EntryList, 0)) { goto exit; } } else { // Not a new entry, restore the original cert props
if (HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(lpMailUser, 1, ppvUndo, NULL))) { goto exit; } if (HR_FAILED(hr = lpMailUser->lpVtbl->SaveChanges(lpMailUser, 0))) { goto exit; } } } } }
exit: if (lpAdrList) { for (iEntry = 0; iEntry < lpAdrList->cEntries; ++iEntry) { if(lpAdrList->aEntries[iEntry].rgPropVals) lpWABObject->lpVtbl->FreeBuffer(lpWABObject, lpAdrList->aEntries[iEntry].rgPropVals); } lpWABObject->lpVtbl->FreeBuffer(lpWABObject, lpAdrList); lpAdrList = NULL; }
if (lpCreateEIDs) { lpWABObject->lpVtbl->FreeBuffer(lpWABObject, lpCreateEIDs); }
if (ppvEID) { lpWABObject->lpVtbl->FreeBuffer(lpWABObject, ppvEID); }
if (lpEIDWAB) { lpWABObject->lpVtbl->FreeBuffer(lpWABObject, lpEIDWAB); }
if (lpContainer) { lpContainer->lpVtbl->Release(lpContainer); }
if (lpMailUser) { lpMailUser->lpVtbl->Release(lpMailUser); }
if (ppv) { lpWABObject->lpVtbl->FreeBuffer(lpWABObject, ppv); }
if (ppvUndo) { lpWABObject->lpVtbl->FreeBuffer(lpWABObject, ppvUndo); }
if (Thumbprint.pBlobData) { LocalFree(Thumbprint.pBlobData); }
if (pccLeaf) { CertFreeCertificateContext(pccLeaf); }
if (hcAB) { CertCloseStore(hcAB, 0); }
if (hcCA) { CertCloseStore(hcCA, 0); }
return(hr); }
//*******************************************************************
//
// 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( LPCSTR 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
if (INVALID_HANDLE_VALUE == (hFile = CreateFile( lpszFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL))) { hr = ResultFromScode(MAPI_E_DISK_ERROR); goto error; }
cbData = GetFileSize(hFile, NULL); if (0xFFFFFFFF == cbData) { hr = ResultFromScode(MAPI_E_DISK_ERROR); goto error; }
if (NULL == (pbData = (BYTE *)LocalAlloc(LMEM_ZEROINIT, cbData))) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto error; }
if (! 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
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) { CloseHandle(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; }
LPAB_DIALOG_PANE_PARAMS GetLParamFromPropSheetPage(PROPSHEETPAGE *ps) { LONG lparam; LPAB_DIALOG_PANE_PARAMS lpABDialogPaneParams; ULONG i;
lpABDialogPaneParams = (LPAB_DIALOG_PANE_PARAMS)(ps->lParam); if (lpABDialogPaneParams->dwSentry != LPARAM_SENTRY) { // Assume that CryptUI has passed us a wrapped lparam/cert pair
// typedef struct tagCRYPTUI_INITDIALOG_STRUCT {
// LPARAM lParam;
// PCCERT_CONTEXT pCertContext;
// } CRYPTUI_INITDIALOG_STRUCT, *PCRYPTUI_INITDIALOG_STRUCT;
PCRYPTUI_INITDIALOG_STRUCT pCryptUIInitDialog = (PCRYPTUI_INITDIALOG_STRUCT)lpABDialogPaneParams; lpABDialogPaneParams = (LPAB_DIALOG_PANE_PARAMS )pCryptUIInitDialog->lParam; if (lpABDialogPaneParams->dwSentry != LPARAM_SENTRY) { // Bad lparam
return(NULL); } } return(lpABDialogPaneParams); }
INT_PTR CALLBACK ViewPageAddressBook(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { BOOL fTrust; HANDLE hGraphic; DWORD i; PCCERT_CONTEXT pccert; PROPSHEETPAGE * ps; WCHAR rgwch[200]; UINT rguiStrings[7]; LPAB_DIALOG_PANE_PARAMS lpABDialogPaneParams; PROPSHEETPAGE * lpps;
switch ( msg ) { case WM_INITDIALOG: // Get access to the parameters
lpps = (PROPSHEETPAGE *)lParam; lpABDialogPaneParams = GetLParamFromPropSheetPage(lpps); if (! lpABDialogPaneParams) { return(FALSE); } SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lpABDialogPaneParams);
return TRUE;
case WM_NOTIFY: switch (((NMHDR FAR *) lParam)->code) { case PSN_SETACTIVE: break;
case PSN_APPLY: SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); break;
case PSN_KILLACTIVE: SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); return TRUE;
case PSN_RESET: SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); break; }
case WM_COMMAND: if (LOWORD(wParam) == IDC_ADD_TO_ADDRESS_BOOK) { HRESULT hr = ResultFromScode(MAPI_E_CALL_FAILED); lpABDialogPaneParams = (LPAB_DIALOG_PANE_PARAMS)GetWindowLongPtr(hwndDlg, DWLP_USER);
if (lpABDialogPaneParams) { hr = HrAddCertsToWAB(hwndDlg, lpABDialogPaneParams->lpWABObject, lpABDialogPaneParams->lpAdrBook, lpABDialogPaneParams->hCryptProv, lpABDialogPaneParams->rgCertContext, lpABDialogPaneParams->cCertContexts, lpABDialogPaneParams->iLeafCert, lpABDialogPaneParams->lpDisplayName, lpABDialogPaneParams->lpEmailAddress); }
return TRUE; } else if (LOWORD(wParam) == IDHELP) { return TRUE; } break; } return FALSE; }
//*******************************************************************
//
// FUNCTION: CertFileDisplay
//
// PURPOSE: Display the certificate properties of a pkcs7 file
//
// PARAMETERS: hwnd = parent window handle
// lpWABObject -> wab object
// lpAdrBook -> Adrbook object
// lpFileName -> Cert filename
//
// RETURNS: HRESULT
//
//*******************************************************************
HRESULT CertFileDisplay(HWND hwnd, LPWABOBJECT lpWABObject, LPADRBOOK lpAdrBook, LPTSTR lpFileName) { HCRYPTPROV hCryptProvider = 0; HRESULT hr; CERT_CONTEXT CertContext; LPBYTE lpBuf = NULL; ULONG cbData = 0, cCert; HCRYPTMSG hMsg = NULL; PCERT_CONTEXT * rgCertContext = NULL; DWORD dwIssuerFlags = 0; ULONG i, j; PCCERT_CONTEXT pcCertContextTarget = NULL, pcCertContextIssuer; PCERT_INFO pCertInfoTarget = NULL; HCERTSTORE hCertStoreMsg = NULL; BOOL fFound = FALSE, fIssuer; PROPSHEETPAGE PSPage; TCHAR szTitle[MAX_RESOURCE_STRING + 1]; TCHAR szABPaneTitle[MAX_RESOURCE_STRING + 1]; AB_DIALOG_PANE_PARAMS ABDialogPaneParams; PCERT_INFO pCertInfo; LPTSTR lpDisplayName = NULL, lpEmailAddress = NULL; LPTSTR rgPurposes[1] = {(LPTSTR)&cszOID_PKIX_KP_EMAIL_PROTECTION};
// Get the crypt provider context
if (! CryptAcquireContext( &hCryptProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { hr = GetLastError(); goto exit; }
// Read the data from the file.
if (hr = ReadDataFromFile(lpFileName, &lpBuf, &cbData)) { goto exit; }
if (! (hMsg = CryptMsgOpenToDecode( PKCS_7_ASN_ENCODING, 0, // dwFlags
0, // dwMsgType
hCryptProvider, NULL, // pRecipientInfo (not supported)
NULL))) { // pStreamInfo (not supported)
hr = GetLastError(); DebugTrace("CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING) -> 0x%08x\n", GetScode(hr)); goto exit; }
if (! CryptMsgUpdate(hMsg, lpBuf, cbData, TRUE)) { hr = GetLastError(); DebugTrace("CryptMsgUpdate -> 0x%08x\n", GetScode(hr)); goto exit; }
cbData = sizeof(cCert); if (! CryptMsgGetParam( hMsg, CMSG_CERT_COUNT_PARAM, // dwParamType
0, // dwIndex
(void *)&cCert, &cbData)) { // pcbData
hr = GetLastError(); DebugTrace("CryptMsgGetParam(CMSG_CERT_COUNT_PARAM) -> 0x%08x\n", GetScode(hr)); goto exit; } if (cbData != sizeof(cCert)) { hr = ResultFromScode(MAPI_E_CALL_FAILED); goto exit; }
// Look for cert 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.
//
if (! (hCertStoreMsg = CertOpenStore( CERT_STORE_PROV_MSG, X509_ASN_ENCODING, hCryptProvider, CERT_STORE_NO_CRYPT_RELEASE_FLAG, hMsg))) { hr = GetLastError(); DebugTrace("CertOpenStore(msg) -> %x\n", hr); goto exit; } else { if (! (rgCertContext = LocalAlloc(LPTR, cCert * sizeof(PCERT_CONTEXT)))) { DebugTrace("LocalAlloc of cert table -> %u\n", GetLastError()); hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto exit; }
// Enumerate all certs on this message
i = 0; while (pcCertContextTarget = CertEnumCertificatesInStore(hCertStoreMsg, pcCertContextTarget)) {
rgCertContext[i] = (PCERT_CONTEXT)CertDuplicateCertificateContext( pcCertContextTarget);
#ifdef DEBUG
DebugTraceCertContextName(rgCertContext[i], "Found Cert:"); #endif
i++; };
// Now we've got a table full of certs
for (i = 0; i < cCert; i++) { pCertInfoTarget = rgCertContext[i]->pCertInfo; fIssuer = FALSE;
for (j = 0; j < cCert; j++) { if (i != j) { dwIssuerFlags = 0;
if (pcCertContextIssuer = CertGetIssuerCertificateFromStore(hCertStoreMsg, rgCertContext[j], NULL, &dwIssuerFlags)) {
// Found an issuer
// Is it the same as the target?
fIssuer = CertCompareCertificate(X509_ASN_ENCODING, pCertInfoTarget, // target
pcCertContextIssuer->pCertInfo); // test issuer
CertFreeCertificateContext(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("Found a Cert which is not an issuer.\n"); #ifdef DEBUG
DebugTraceCertContextName(rgCertContext[i], "Non-issuer cert:"); #endif
// What is the email and display name of the leaf cert?
pCertInfo = rgCertContext[i]->pCertInfo;
GetAttributeString(&ABDialogPaneParams.lpDisplayName, pCertInfo->Subject.pbData, pCertInfo->Subject.cbData, szOID_COMMON_NAME);
GetAttributeString(&ABDialogPaneParams.lpEmailAddress, pCertInfo->Subject.pbData, pCertInfo->Subject.cbData, szOID_RSA_emailAddr);
ABDialogPaneParams.lpWABObject = lpWABObject; ABDialogPaneParams.lpAdrBook = lpAdrBook; ABDialogPaneParams.hCryptProv = hCryptProvider; ABDialogPaneParams.rgCertContext = rgCertContext; ABDialogPaneParams.cCertContexts = cCert; ABDialogPaneParams.iLeafCert = i; ABDialogPaneParams.dwSentry = LPARAM_SENTRY;
memset(&PSPage, 0, sizeof(PROPSHEETPAGE));
PSPage.dwSize = sizeof(PSPage); PSPage.dwFlags = 0; // PSP_HASHELP;
PSPage.hInstance = hInst; PSPage.pszTemplate = MAKEINTRESOURCE(IDD_CERTPROP_ADDRESS_BOOK); PSPage.hIcon = 0; LoadString(hInst, idsAddToABPaneTitle, szABPaneTitle, sizeof(szABPaneTitle)); PSPage.pszTitle = szABPaneTitle; PSPage.pfnDlgProc = ViewPageAddressBook; PSPage.lParam = (LPARAM)&ABDialogPaneParams; // (DWORD) &viewhelp;
PSPage.pfnCallback = 0; PSPage.pcRefParent = NULL;
{ CERT_VIEWPROPERTIES_STRUCT_A cvps = {0};
// Fill in the cert view struct
cvps.dwSize = sizeof(CERT_VIEWPROPERTIES_STRUCT); cvps.hwndParent = hwnd; cvps.hInstance = hInst; cvps.dwFlags = CM_ADD_CERT_STORES; // Look in rghstoreCAs
LoadString(hInst, idsCertificateViewTitle, szTitle, sizeof(szTitle)); cvps.szTitle = szTitle; cvps.pCertContext = rgCertContext[i]; cvps.nStartPage = iAddToWAB; // show add to WAB page first
cvps.arrayPurposes = rgPurposes; cvps.cArrayPurposes = 1; cvps.cStores = 1; // Count of other stores to search
cvps.rghstoreCAs = &hCertStoreMsg; // Array of other stores to search
cvps.hprov = hCryptProvider; // Provider to use for verification
cvps.cArrayPropSheetPages = 1; cvps.arrayPropSheetPages = &PSPage;
if (! CertViewPropertiesA(&cvps)) { hr = GetLastError(); } }
fFound = TRUE; break; // done with loop
} }
// Free the table of certs
for (i = 0; i < cCert; i++) { if (rgCertContext[i]) { CertFreeCertificateContext(rgCertContext[i]); } } LocalFree((LPVOID)rgCertContext);
if (! fFound) { // Didn't find a cert that isn't an issuer. Fail.
hr = ResultFromScode(MAPI_E_NOT_FOUND); goto exit; } }
exit: if (hCryptProvider) { CryptReleaseContext(hCryptProvider, 0); }
return(hr); }
/* DebugTrapFn -------------------------------------------------------------- */ #ifdef DEBUG
#if defined(WIN32) && !defined(_MAC)
typedef struct { char * sz1; char * sz2; UINT rgf; int iResult; } MBContext;
DWORD WINAPI MessageBoxFnThreadMain(MBContext *pmbc) { pmbc->iResult = MessageBoxA(NULL, pmbc->sz1, pmbc->sz2, pmbc->rgf | MB_SETFOREGROUND);
return(0); }
int MessageBoxFn(char *sz1, char *sz2, UINT rgf) { HANDLE hThread; DWORD dwThreadId; MBContext mbc;
mbc.sz1 = sz1; mbc.sz2 = sz2; mbc.rgf = rgf; mbc.iResult = IDRETRY;
MessageBoxFnThreadMain(&mbc); return(mbc.iResult); } #else
#define MessageBoxFn(sz1, sz2, rgf) MessageBoxA(NULL, sz1, sz2, rgf)
#endif
void FAR CDECL DebugTrapFn(int fFatal, char *pszFile, int iLine, char *pszFormat, ...) { char sz[512]; va_list vl;
#if defined(WIN16) || defined(WIN32)
int id; #endif
lstrcpyA(sz, "++++ WAB Debug Trap ("); // _strdate(sz + lstrlenA(sz));
// lstrcatA(sz, " ");
// _strtime(sz + lstrlenA(sz));
lstrcatA(sz, ")\n"); DebugTrace(sz);
va_start(vl, pszFormat); wvsprintfA(sz, pszFormat, vl); va_end(vl);
wsprintfA(sz + lstrlenA(sz), "\n[File %s, Line %d]\n\n", pszFile, iLine);
DebugTrace(sz);
#if defined(DOS)
_asm { int 3 } #endif
#if defined(WIN16) || defined(WIN32)
/* Hold down control key to prevent MessageBox */ if ( GetAsyncKeyState(VK_CONTROL) >= 0 ) { UINT uiFlags = MB_ABORTRETRYIGNORE;
if (fFatal) uiFlags |= MB_DEFBUTTON1; else uiFlags |= MB_DEFBUTTON3;
#ifdef WIN16
uiFlags |= MB_ICONEXCLAMATION | MB_SYSTEMMODAL; #else
uiFlags |= MB_ICONSTOP | MB_TASKMODAL; #endif
#ifndef MAC
id = MessageBoxFn(sz, "WAB Debug Trap", uiFlags);
if (id == IDABORT) *((LPBYTE)NULL) = 0; else if (id == IDRETRY) DebugBreak(); #endif // MAC
} #endif
} #endif
/*
* DebugTrace -- printf to the debugger console or debug output file * Takes printf style arguments. * Expects newline characters at the end of the string. */ #ifdef DEBUG
VOID FAR CDECL DebugTrace(LPSTR lpszFmt, ...) { va_list marker; TCHAR String[1100];
va_start(marker, lpszFmt); wvsprintf(String, lpszFmt, marker); OutputDebugString(String); } #endif
#ifdef DEBUG
//*******************************************************************
void DebugTraceCertContextName(PCCERT_CONTEXT pcCertContext, LPTSTR lpDescription) { LPTSTR lpName = NULL; PCERT_INFO pCertInfo = pcCertContext->pCertInfo; #ifdef OLD_STUFF
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("%s %s\n", lpDescription, lpName ? lpName : "<unknown>"); if (lpName) { LocalFree(lpName); } #endif // OLD_STUFF
} #endif
|