Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3291 lines
99 KiB

  1. //*******************************************************************
  2. //
  3. // Copyright(c) Microsoft Corporation, 1996
  4. //
  5. // FILE: CERT.C
  6. //
  7. // PURPOSE: Certificate functions for WAB.
  8. //
  9. // HISTORY:
  10. // 96/09/23 vikramm Created.
  11. // 96/11/14 markdu BUG 10132 Updated to post-SDR CAPI.
  12. // 96/11/14 markdu BUG 10267 Remove static link to functions in advapi32.dll
  13. // 96/11/14 markdu BUG 10741 Call DeinitCryptoLib in DLL_PROCESS_DETACH
  14. // only, so don't bother ref counting.
  15. // 96/11/20 markdu Set a global flag if we fail to load the crypto library.
  16. // Then, check this flag before we try to load again, and if the flag
  17. // is set, skip the load.
  18. // Also, now we only zero the APIFCN arrays if the associated library
  19. // was just freed.
  20. // 96/12/14 markdu Clean up for code review.
  21. // 96/12/19 markdu Post- code review clean up.
  22. // 96/12/20 markdu Allow BuildCertSBinaryData to do MAPIAllocateMore
  23. // on a passed-in object instead of LocalAlloc if desired.
  24. // 96/12/20 markdu Move some strings into resource.
  25. // 96/12/21 markdu Added support for getting UNICODE strings from certs.
  26. // 97/02/07 t-erikne Updated to new CAPI functions and fixed bugs.
  27. // 97/02/15 t-erikne Moved trust from MAPI to PStore
  28. // 97/07/02 t-erikne Moved trust from PSTore to CTLs
  29. //
  30. //*******************************************************************
  31. #include "_apipch.h"
  32. #define _WIN32_OE 0x0501
  33. #undef CHARFORMAT
  34. #undef GetProp
  35. #undef SetProp
  36. #include <mimeole.h>
  37. #define CHARFORMAT CHARFORMATW
  38. #define GetProp GetPropW
  39. #define SetProp SetPropW
  40. // Global handles for Crypto DLLs
  41. HINSTANCE ghCryptoDLLInst = NULL;
  42. HINSTANCE ghAdvApiDLLInst = NULL;
  43. BOOL gfPrevCryptoLoadFailed = FALSE;
  44. // Name of cert stores
  45. static const LPTSTR cszWABCertStore = TEXT("AddressBook");
  46. static const LPTSTR cszCACertStore = TEXT("CA");
  47. static const LPTSTR cszROOTCertStore = TEXT("ROOT");
  48. // Crypto function names
  49. static const LPTSTR cszCryptoDLL = TEXT("CRYPT32.DLL");
  50. static const LPTSTR cszAdvApiDLL = TEXT("ADVAPI32.DLL");
  51. static const char cszCertAddEncodedCertificateToStore[] = "CertAddEncodedCertificateToStore";
  52. static const char cszCertCreateCertificateContext[] = "CertCreateCertificateContext";
  53. static const char cszCertDeleteCertificateFromStore[] = "CertDeleteCertificateFromStore";
  54. static const char cszCertFindCertificateInStore[] = "CertFindCertificateInStore";
  55. static const char cszCertFreeCertificateContext[] = "CertFreeCertificateContext";
  56. static const char cszCertGetCertificateContextProperty[] = "CertGetCertificateContextProperty";
  57. static const char cszCertGetIssuerCertificateFromStore[] = "CertGetIssuerCertificateFromStore";
  58. static const char cszCertOpenSystemStore[] = "CertOpenSystemStoreW";
  59. static const char cszCryptDecodeObject[] = "CryptDecodeObject";
  60. static const char cszCryptMsgClose[] = "CryptMsgClose";
  61. static const char cszCryptMsgGetParam[] = "CryptMsgGetParam";
  62. static const char cszCryptMsgOpenToDecode[] = "CryptMsgOpenToDecode";
  63. static const char cszCryptMsgUpdate[] = "CryptMsgUpdate";
  64. static const char cszCertNameToStr[] = "CertNameToStrW";
  65. static const char cszCertFindRDNAttr[] = "CertFindRDNAttr";
  66. static const char cszCertEnumCertificatesInStore[] = "CertEnumCertificatesInStore";
  67. static const char cszCertCompareCertificate[] = "CertCompareCertificate";
  68. static const char cszCertRDNValueToStr[] = "CertRDNValueToStrW";
  69. static const char cszCertVerifyTimeValidity[] = "CertVerifyTimeValidity";
  70. // Global function pointers for Crypto API
  71. LPCERTADDENCODEDCERTIFICATETOSTORE gpfnCertAddEncodedCertificateToStore = NULL;
  72. LPCERTCREATECERTIFICATECONTEXT gpfnCertCreateCertificateContext = NULL;
  73. LPCERTDELETECERTIFICATEFROMSTORE gpfnCertDeleteCertificateFromStore = NULL;
  74. LPCERTFINDCERTIFICATEINSTORE gpfnCertFindCertificateInStore = NULL;
  75. LPCERTFREECERTIFICATECONTEXT gpfnCertFreeCertificateContext = NULL;
  76. LPCERTGETCERTIFICATECONTEXTPROPERTY gpfnCertGetCertificateContextProperty = NULL;
  77. LPCERTGETISSUERCERTIFICATEFROMSTORE gpfnCertGetIssuerCertificateFromStore = NULL;
  78. LPCERTOPENSYSTEMSTORE gpfnCertOpenSystemStore = NULL;
  79. LPCRYPTDECODEOBJECT gpfnCryptDecodeObject = NULL;
  80. LPCERTNAMETOSTR gpfnCertNameToStr = NULL;
  81. LPCRYPTMSGCLOSE gpfnCryptMsgClose = NULL;
  82. LPCRYPTMSGGETPARAM gpfnCryptMsgGetParam = NULL;
  83. LPCRYPTMSGOPENTODECODE gpfnCryptMsgOpenToDecode = NULL;
  84. LPCRYPTMSGUPDATE gpfnCryptMsgUpdate = NULL;
  85. LPCERTFINDRDNATTR gpfnCertFindRDNAttr = NULL;
  86. LPCERTRDNVALUETOSTR gpfnCertRDNValueToStr = NULL;
  87. LPCERTENUMCERTIFICATESINSTORE gpfnCertEnumCertificatesInStore = NULL;
  88. LPCERTCOMPARECERTIFICATE gpfnCertCompareCertificate = NULL;
  89. LPCERTVERIFYTIMEVALIDITY gpfnCertVerifyTimeValidity = NULL;
  90. // API table for Crypto function addresses in crypt32.dll
  91. // BUGBUG this global array should go away
  92. #define NUM_CRYPT32_CRYPTOAPI_PROCS 19
  93. APIFCN Crypt32CryptoAPIList[NUM_CRYPT32_CRYPTOAPI_PROCS] =
  94. {
  95. { (PVOID *) &gpfnCertAddEncodedCertificateToStore, cszCertAddEncodedCertificateToStore },
  96. { (PVOID *) &gpfnCertCreateCertificateContext, cszCertCreateCertificateContext },
  97. { (PVOID *) &gpfnCertDeleteCertificateFromStore, cszCertDeleteCertificateFromStore },
  98. { (PVOID *) &gpfnCertFindCertificateInStore, cszCertFindCertificateInStore },
  99. { (PVOID *) &gpfnCertFreeCertificateContext, cszCertFreeCertificateContext },
  100. { (PVOID *) &gpfnCertGetCertificateContextProperty, cszCertGetCertificateContextProperty },
  101. { (PVOID *) &gpfnCertGetIssuerCertificateFromStore, cszCertGetIssuerCertificateFromStore },
  102. { (PVOID *) &gpfnCertOpenSystemStore, cszCertOpenSystemStore },
  103. { (PVOID *) &gpfnCryptDecodeObject, cszCryptDecodeObject },
  104. { (PVOID *) &gpfnCertNameToStr, cszCertNameToStr },
  105. { (PVOID *) &gpfnCryptMsgClose, cszCryptMsgClose },
  106. { (PVOID *) &gpfnCryptMsgGetParam, cszCryptMsgGetParam },
  107. { (PVOID *) &gpfnCryptMsgOpenToDecode, cszCryptMsgOpenToDecode },
  108. { (PVOID *) &gpfnCryptMsgUpdate, cszCryptMsgUpdate },
  109. { (PVOID *) &gpfnCertFindRDNAttr, cszCertFindRDNAttr },
  110. { (PVOID *) &gpfnCertRDNValueToStr, cszCertRDNValueToStr },
  111. { (PVOID *) &gpfnCertEnumCertificatesInStore, cszCertEnumCertificatesInStore },
  112. { (PVOID *) &gpfnCertCompareCertificate, cszCertCompareCertificate },
  113. { (PVOID *) &gpfnCertVerifyTimeValidity, cszCertVerifyTimeValidity },
  114. };
  115. // Local function prototypes
  116. HRESULT OpenSysCertStore(
  117. HCERTSTORE* phcsSysCertStore,
  118. HCRYPTPROV* phCryptProvider,
  119. LPTSTR lpszCertStore);
  120. HRESULT CloseCertStore(
  121. HCERTSTORE hcsWABCertStore,
  122. HCRYPTPROV hCryptProvider);
  123. HRESULT FileTimeToDateTimeString(
  124. IN LPFILETIME lpft,
  125. IN LPTSTR FAR* lplpszBuf);
  126. HRESULT GetNameString(
  127. LPTSTR FAR * lplpszName,
  128. DWORD dwEncoding,
  129. PCERT_NAME_BLOB pNameBlob,
  130. DWORD dwType);
  131. HRESULT GetIssuerName(
  132. LPTSTR FAR * lplpszIssuerName,
  133. PCERT_INFO pCertInfo);
  134. HRESULT GetAttributeString(
  135. LPTSTR FAR * lplpszDisplayName,
  136. BYTE *pbEncoded,
  137. DWORD cbEncoded,
  138. LPSTR lpszObjID);
  139. HRESULT GetCertsDisplayInfoFromContext(
  140. HWND hwndParent,
  141. PCCERT_CONTEXT pccCertContext,
  142. LPCERT_DISPLAY_INFO lpCDI);
  143. HRESULT ReadMessageFromFile(
  144. LPTSTR lpszFileName,
  145. HCRYPTPROV hCryptProvider,
  146. PBYTE* ppbEncoded,
  147. PDWORD pcbEncoded);
  148. HRESULT WriteDERToFile(
  149. LPTSTR lpszFileName,
  150. PBYTE pbEncoded,
  151. DWORD cbEncoded);
  152. HRESULT GetCertThumbPrint(
  153. PCCERT_CONTEXT pccCertContext,
  154. PCRYPT_DIGEST_BLOB pblobCertThumbPrint);
  155. HRESULT GetIssuerContextAndStore(
  156. PCCERT_CONTEXT pccCertContext,
  157. PCCERT_CONTEXT* ppccIssuerCertContext,
  158. HCRYPTPROV hCryptProvider,
  159. HCERTSTORE* phcsIssuerStore);
  160. HRESULT HrBuildCertSBinaryData(
  161. BOOL bIsDefault,
  162. BOOL fIsThumbprint,
  163. PCRYPT_DIGEST_BLOB pPrint,
  164. BLOB * pSymCaps,
  165. FILETIME ftSigningTime,
  166. LPVOID lpObject,
  167. LPBYTE FAR* lplpbData,
  168. ULONG FAR* lpcbData);
  169. HRESULT IsCertExpired(
  170. PCERT_INFO pCertInfo);
  171. HRESULT IsCertRevoked(
  172. PCERT_INFO pCertInfo);
  173. HRESULT ReadDataFromFile(
  174. LPTSTR lpszFileName,
  175. PBYTE* ppbData,
  176. PDWORD pcbData);
  177. HRESULT HrGetTrustState(HWND hwndParent, PCCERT_CONTEXT pcCert, DWORD *pdwTrust);
  178. LPTSTR SzConvertRDNString(PCERT_RDN_ATTR pRdnAttr);
  179. /* HrGetLastError
  180. **
  181. ** Purpose:
  182. ** Convert a GetLastError value to an HRESULT
  183. ** A failure HRESULT must have the high bit set.
  184. **
  185. ** Takes:
  186. ** none
  187. **
  188. ** Returns:
  189. ** HRESULT
  190. */
  191. HRESULT HrGetLastError(void)
  192. {
  193. DWORD error;
  194. HRESULT hr;
  195. error = GetLastError();
  196. if (error && ! (error & 0x80000000)) {
  197. hr = error | 0x80070000; // system error
  198. } else {
  199. hr = (HRESULT)error;
  200. }
  201. return(hr);
  202. }
  203. //*******************************************************************
  204. //
  205. // FUNCTION: HrUserSMimeToCDI
  206. //
  207. // PURPOSE: Convert the data contained in a CMS message for the userSMimeCertificate
  208. // property and place into the display info structure.
  209. //
  210. // PARAMETERS: pbIn - data bytes for the CMS message
  211. // cbIn - size of pbIn
  212. // lpCDI - structure to receive the cert data.
  213. //
  214. // RETURNS: HRESULT.
  215. //
  216. // HISTORY:
  217. // 98/10/23 jimsch Created.
  218. //
  219. //*******************************************************************
  220. HRESULT HrUserSMimeToCDI(LPBYTE pbIn, DWORD cbIn, LPCERT_DISPLAY_INFO lpCDI)
  221. {
  222. DWORD cb;
  223. DWORD cbCert;
  224. DWORD cbMax;
  225. DWORD cbSMimeCaps;
  226. DWORD cCerts;
  227. CERT_INFO certInfo;
  228. DWORD cSigners;
  229. DWORD cval;
  230. DWORD dwDefaults;
  231. DWORD dwNortelAlg;
  232. BOOL f;
  233. BOOL fSMime = TRUE;
  234. HCRYPTMSG hmsg = NULL;
  235. HRESULT hr = S_OK;
  236. ULONG i;
  237. DWORD ival;
  238. PCRYPT_ATTRIBUTE pattr;
  239. LPBYTE pbCert;
  240. LPBYTE pbData;
  241. LPBYTE pbSMimeCaps;
  242. PCCERT_CONTEXT pccert;
  243. PCMSG_SIGNER_INFO pinfo = NULL;
  244. PCRYPT_RECIPIENT_ID prid = NULL;
  245. // Parse out and verify the signature on the message. If that operation fails, then
  246. // this is a bad record
  247. hmsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0,
  248. NULL, NULL);
  249. if (hmsg == 0) {
  250. goto CryptError;
  251. }
  252. if (!CryptMsgUpdate(hmsg, pbIn, cbIn, TRUE)) {
  253. goto CryptError;
  254. }
  255. cb = sizeof(cSigners);
  256. if (!CryptMsgGetParam(hmsg, CMSG_SIGNER_COUNT_PARAM, 0, &cSigners, &cb) ||
  257. (cSigners == 0)) {
  258. goto CryptError;
  259. }
  260. Assert(cSigners == 1);
  261. if (!CryptMsgGetParam(hmsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &cb)) {
  262. goto CryptError;
  263. }
  264. pinfo = (PCMSG_SIGNER_INFO) LocalAlloc(0, cb);
  265. if (!pinfo) {
  266. hr = E_OUTOFMEMORY;
  267. goto Exit;
  268. }
  269. f = CryptMsgGetParam(hmsg, CMSG_SIGNER_INFO_PARAM, 0, pinfo, &cb);
  270. Assert(f);
  271. // M00BUG -- verify signature on message
  272. for (i=0; i<pinfo->AuthAttrs.cAttr; i++) {
  273. pattr = &pinfo->AuthAttrs.rgAttr[i];
  274. if (strcmp(pattr->pszObjId, szOID_RSA_SMIMECapabilities) == 0) {
  275. Assert(pattr->cValue == 1);
  276. lpCDI->blobSymCaps.pBlobData = LocalAlloc(LMEM_ZEROINIT,
  277. pattr->rgValue[0].cbData);
  278. if (NULL == lpCDI->blobSymCaps.pBlobData)
  279. {
  280. hr = E_OUTOFMEMORY;
  281. goto Exit;
  282. }
  283. lpCDI->blobSymCaps.cbSize = pattr->rgValue[0].cbData;
  284. memcpy(lpCDI->blobSymCaps.pBlobData, pattr->rgValue[0].pbData,
  285. pattr->rgValue[0].cbData);
  286. }
  287. // else if (strcmp(pattr->pszObjId, szOID_Microsoft_Encryption_Cert) == 0) {
  288. // Assert(pattr->cValue == 1);
  289. // Assert(pattr->rgValue[0].cbData == 3);
  290. // lpCDI->bIsDefault = pattr->rgValue[0].pbData[2];
  291. // }
  292. else if (strcmp(pattr->pszObjId, szOID_Microsoft_Encryption_Cert) == 0) {
  293. Assert(pattr->cValue == 1);
  294. f = CryptDecodeObjectEx(X509_ASN_ENCODING,
  295. szOID_Microsoft_Encryption_Cert,
  296. pattr->rgValue[0].pbData,
  297. pattr->rgValue[0].cbData, CRYPT_DECODE_ALLOC_FLAG, 0,
  298. (LPVOID *) &prid, &cb);
  299. Assert(f);
  300. }
  301. }
  302. //
  303. if (prid == NULL)
  304. goto Exit;
  305. certInfo.SerialNumber = prid->SerialNumber;
  306. certInfo.Issuer = prid->Issuer;
  307. // Enumerate all certs and pack into the structure
  308. cbCert = sizeof(cCerts);
  309. if (!CryptMsgGetParam(hmsg, CMSG_CERT_COUNT_PARAM, 0, &cCerts, &cbCert)) {
  310. goto CryptError;
  311. }
  312. for (i=0, cbMax = 0; i<cCerts; i++)
  313. {
  314. if (!CryptMsgGetParam(hmsg, CMSG_CERT_PARAM, i, NULL, &cbCert))
  315. goto CryptError;
  316. if (cbMax < cbCert)
  317. cbMax = cbCert;
  318. }
  319. pbCert = (LPBYTE) LocalAlloc(0, cbCert);
  320. for (i=0; i<cCerts; i++) {
  321. cbCert = cbMax;
  322. if (!CryptMsgGetParam(hmsg, CMSG_CERT_PARAM, i, pbCert, &cbCert))
  323. goto CryptError;
  324. pccert = gpfnCertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
  325. if (pccert == NULL)
  326. continue;
  327. if (CertCompareCertificate(X509_ASN_ENCODING, pccert->pCertInfo,
  328. &certInfo)) {
  329. lpCDI->pccert = CertDuplicateCertificateContext(pccert);
  330. }
  331. }
  332. hr = S_OK;
  333. Exit:
  334. if (prid != NULL) LocalFree(prid);
  335. if (pinfo != NULL) LocalFree(pinfo);
  336. if (hmsg != NULL) CryptMsgClose(hmsg);
  337. return hr;
  338. CryptError:
  339. hr = E_FAIL;
  340. goto Exit;
  341. }
  342. //*******************************************************************
  343. //
  344. // FUNCTION: HrGetCertsDisplayInfo
  345. //
  346. // PURPOSE: Takes an input array of certs in a SPropValue structure
  347. // and outputs a list of cert data structures by parsing through
  348. // the array and looking up the cert data in the store.
  349. //
  350. // PARAMETERS: lpPropValue - PR_USER_X509_CERTIFICATE property array
  351. // lppCDI - recieves an allocated structure containing
  352. // the cert data. Must be freed by calling FreeCertdisplayinfo.
  353. //
  354. // RETURNS: HRESULT.
  355. //
  356. // HISTORY:
  357. // 96/09/24 markdu Created.
  358. //
  359. //*******************************************************************
  360. HRESULT HrGetCertsDisplayInfo(
  361. IN HWND hwndParent,
  362. IN LPSPropValue lpPropValue,
  363. OUT LPCERT_DISPLAY_INFO * lppCDI)
  364. {
  365. CRYPT_HASH_BLOB blob;
  366. HRESULT hr = hrSuccess;
  367. HRESULT hrOut = hrSuccess;
  368. ULONG i;
  369. ULONG ulcCerts;
  370. LPCERTTAGS lpCurrentTag;
  371. LPCERT_DISPLAY_INFO lpHead=NULL;
  372. LPCERT_DISPLAY_INFO lpTemp=NULL;
  373. HCERTSTORE hcsWABCertStore = NULL;
  374. HCRYPTPROV hCryptProvider = 0;
  375. LPBYTE lpbTagEnd;
  376. #ifdef PARAMETER_VALIDATION
  377. if (IsBadReadPtr(lpPropValue, sizeof(SPropValue)))
  378. {
  379. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  380. }
  381. if (IsBadWritePtr(lppCDI, sizeof(LPCERT_DISPLAY_INFO)))
  382. {
  383. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  384. }
  385. #endif // PARAMETER_VALIDATION
  386. // Make sure we have the right kind of proparray.
  387. if ((NULL == lpPropValue) || (PR_USER_X509_CERTIFICATE != lpPropValue->ulPropTag))
  388. {
  389. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  390. }
  391. // See if we really have any certs
  392. ulcCerts = lpPropValue->Value.MVbin.cValues;
  393. if (0 == ulcCerts)
  394. {
  395. goto out;
  396. }
  397. // Load the crypto functions
  398. if (FALSE == InitCryptoLib())
  399. {
  400. hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  401. return hr;
  402. }
  403. // Open the store since we need to lookup certs
  404. hr = OpenSysCertStore(&hcsWABCertStore, &hCryptProvider, cszWABCertStore);
  405. if (hrSuccess != hr)
  406. {
  407. goto out;
  408. }
  409. // Create a structure for each certificate in the array.
  410. for (i=0;i<ulcCerts;i++)
  411. {
  412. // Allocate memory for the structure, and initialize pointers
  413. LPCERT_DISPLAY_INFO lpCDI = LocalAlloc(LMEM_ZEROINIT, sizeof(CERT_DISPLAY_INFO));
  414. if (NULL == lpCDI)
  415. {
  416. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  417. goto out;
  418. }
  419. if(NULL == lpHead)
  420. {
  421. lpHead = lpCDI;
  422. }
  423. lpCDI->lpPrev = lpTemp;
  424. lpCDI->lpNext = NULL;
  425. if(NULL != lpTemp)
  426. {
  427. lpTemp->lpNext = lpCDI;
  428. }
  429. lpTemp = lpCDI;
  430. if (CERT_TAG_SMIMECERT == lpPropValue->Value.MVbin.lpbin[i].lpb[0]) {
  431. hr = HrUserSMimeToCDI(lpPropValue->Value.MVbin.lpbin[i].lpb,
  432. lpPropValue->Value.MVbin.lpbin[i].cb,
  433. lpCDI);
  434. if (FAILED(hr))
  435. goto out;
  436. }
  437. else
  438. {
  439. // Loop through the tags for this certificate and extract the data we want
  440. lpCurrentTag = (LPCERTTAGS)lpPropValue->Value.MVbin.lpbin[i].lpb;
  441. lpbTagEnd = (LPBYTE)lpCurrentTag + lpPropValue->Value.MVbin.lpbin[i].cb;
  442. while ((LPBYTE)lpCurrentTag < lpbTagEnd)
  443. {
  444. LPCERTTAGS lpTempTag = lpCurrentTag;
  445. // Check if this is the tag that indicates whether this is the default cert
  446. if (CERT_TAG_DEFAULT == lpCurrentTag->tag)
  447. {
  448. memcpy((void*)&lpCDI->bIsDefault,
  449. &lpCurrentTag->rgbData,
  450. sizeof(lpCDI->bIsDefault));
  451. }
  452. // Check if this is just the raw cert itself
  453. else if (CERT_TAG_BINCERT == lpCurrentTag->tag)
  454. {
  455. AssertSz(lpCDI->pccert == NULL, TEXT("Two certs in a single record"));
  456. lpCDI->pccert = gpfnCertCreateCertificateContext(
  457. X509_ASN_ENCODING,
  458. lpCurrentTag->rgbData,
  459. lpCurrentTag->cbData);
  460. }
  461. // Check if this is the tag that contains the thumbprint
  462. else if (CERT_TAG_THUMBPRINT == lpCurrentTag->tag)
  463. {
  464. AssertSz(lpCDI->pccert == NULL, TEXT("Two certs in a single record"));
  465. blob.cbData = lpCurrentTag->cbData - sizeof(DWORD);
  466. blob.pbData = lpCurrentTag->rgbData;
  467. // Get the certificate from the WAB store using the thumbprint
  468. lpCDI->pccert = CertFindCertificateInStore(
  469. hcsWABCertStore,
  470. X509_ASN_ENCODING,
  471. 0,
  472. CERT_FIND_HASH,
  473. (void *)&blob,
  474. NULL);
  475. }
  476. // Check if this is the tag that contains the symcaps
  477. else if (CERT_TAG_SYMCAPS == lpCurrentTag->tag)
  478. {
  479. lpCDI->blobSymCaps.pBlobData = LocalAlloc(LMEM_ZEROINIT,
  480. lpCurrentTag->cbData - SIZE_CERTTAGS);
  481. if (NULL == lpCDI->blobSymCaps.pBlobData)
  482. {
  483. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  484. goto out;
  485. }
  486. lpCDI->blobSymCaps.cbSize = lpCurrentTag->cbData - SIZE_CERTTAGS;
  487. memcpy(lpCDI->blobSymCaps.pBlobData,
  488. &lpCurrentTag->rgbData,
  489. lpCurrentTag->cbData - SIZE_CERTTAGS);
  490. }
  491. // Check if this is the tag that contains the signing time
  492. else if (CERT_TAG_SIGNING_TIME == lpCurrentTag->tag)
  493. {
  494. memcpy(&lpCDI->ftSigningTime,
  495. &lpCurrentTag->rgbData,
  496. min(lpCurrentTag->cbData - SIZE_CERTTAGS, sizeof(FILETIME)));
  497. }
  498. lpCurrentTag = (LPCERTTAGS)((BYTE*)lpCurrentTag + LcbAlignLcb(lpCurrentTag->cbData));
  499. if (lpCurrentTag == lpTempTag) {
  500. AssertSz(FALSE, TEXT("Bad CertTag in PR_USER_X509_CERTIFICATE\n"));
  501. break; // Safety valve, prevent infinite loop if bad data
  502. }
  503. }
  504. }
  505. // If we can't get the cert, delete this node of the linked list.
  506. if (NULL == lpCDI->pccert)
  507. {
  508. if(lpHead == lpCDI)
  509. {
  510. lpHead = NULL;
  511. }
  512. lpTemp = lpCDI->lpPrev;
  513. if (NULL != lpTemp)
  514. {
  515. lpTemp->lpNext = NULL;
  516. }
  517. FreeCertdisplayinfo(lpCDI);
  518. }
  519. else
  520. {
  521. // Get the context-specific display info from the cert.
  522. hr = GetCertsDisplayInfoFromContext(hwndParent, lpCDI->pccert, lpCDI);
  523. if (hrSuccess != hr)
  524. {
  525. goto out;
  526. }
  527. }
  528. }
  529. out:
  530. // Close the cert store.
  531. hrOut = CloseCertStore(hcsWABCertStore, hCryptProvider);
  532. // If an error occurred in the function body, return that instead of
  533. // any errors that occurred here in cleanup.
  534. if (hrSuccess == hr)
  535. {
  536. hr = hrOut;
  537. }
  538. if ((hrSuccess == hr) && (NULL != lppCDI))
  539. {
  540. *lppCDI = lpHead;
  541. }
  542. else
  543. {
  544. // Free the list of structures we allocated.
  545. while (NULL != lpHead)
  546. {
  547. lpTemp = lpHead->lpNext;
  548. FreeCertdisplayinfo(lpHead);
  549. lpHead = lpTemp;
  550. }
  551. }
  552. return hr;
  553. }
  554. //*******************************************************************
  555. //
  556. // FUNCTION: HrSetCertsFromDisplayInfo
  557. //
  558. // PURPOSE: Takes a linked list of cert data structures and outputs
  559. // an SPropValue array of PR_USER_X509_CERTIFICATE properties.
  560. //
  561. // PARAMETERS: lpCDI - linked list of input structures to convert to
  562. // SPropValue array
  563. // lpulcPropCount - receives the number of SPropValue's returned
  564. // Note that this will always be one.
  565. // lppPropValue - receives a MAPI-allocated SPropValue structure
  566. // containing an X509_USER_CERTIFICATE property
  567. //
  568. // RETURNS: HRESULT.
  569. //
  570. // HISTORY:
  571. // 96/09/24 markdu Created.
  572. //
  573. //*******************************************************************
  574. HRESULT HrSetCertsFromDisplayInfo(
  575. IN LPCERT_ITEM lpCItem,
  576. OUT ULONG * lpulcPropCount,
  577. OUT LPSPropValue * lppPropValue)
  578. {
  579. CRYPT_DIGEST_BLOB blob;
  580. HRESULT hr = hrSuccess;
  581. HCERTSTORE hcertstore = NULL;
  582. LPCERT_ITEM lpTemp;
  583. LPSPropValue lpPropValue = NULL;
  584. ULONG ulcCerts = 0;
  585. ULONG ulCert = 0;
  586. ULONG cbData = 0;
  587. LPBYTE lpbData;
  588. SCODE sc;
  589. #ifdef PARAMETER_VALIDATION
  590. if (IsBadReadPtr(lpCItem, sizeof(CERT_ITEM)))
  591. {
  592. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  593. }
  594. if (IsBadWritePtr(lpulcPropCount, sizeof(ULONG)))
  595. {
  596. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  597. }
  598. if (IsBadWritePtr(lppPropValue, sizeof(LPSPropValue)))
  599. {
  600. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  601. }
  602. #endif // PARAMETER_VALIDATION
  603. // Find out how many certs there are in the list
  604. lpTemp = lpCItem;
  605. while (NULL != lpTemp)
  606. {
  607. ulcCerts++;
  608. lpTemp = lpTemp->lpNext;
  609. }
  610. Assert(ulcCerts);
  611. // Allocate a new buffer for the MAPI property structure
  612. sc = MAPIAllocateBuffer(sizeof(SPropValue),
  613. (LPVOID *)&lpPropValue);
  614. if (sc)
  615. {
  616. hr = ResultFromScode(sc);
  617. goto out;
  618. }
  619. lpPropValue->ulPropTag = PR_USER_X509_CERTIFICATE;
  620. lpPropValue->dwAlignPad = 0;
  621. // Allocate more space for the SBinaryArray. We need SBinary's for
  622. // each of the certs
  623. lpPropValue->Value.MVbin.cValues = ulcCerts;
  624. sc = MAPIAllocateMore(ulcCerts * sizeof(SBinary), lpPropValue,
  625. (LPVOID *)&(lpPropValue->Value.MVbin.lpbin));
  626. if (sc)
  627. {
  628. hr = ResultFromScode(sc);
  629. goto out;
  630. }
  631. hr = OpenSysCertStore(&hcertstore, NULL, cszWABCertStore);
  632. if (hrSuccess != hr)
  633. goto out;
  634. // Create the SPropValue entries by walking the list
  635. while (NULL != lpCItem)
  636. {
  637. hr = GetCertThumbPrint(lpCItem->lpCDI->pccert, &blob);
  638. if (hr != hrSuccess)
  639. goto out;
  640. if (!CertAddCertificateContextToStore(hcertstore, lpCItem->lpCDI->pccert,
  641. CERT_STORE_ADD_USE_EXISTING, NULL))
  642. {
  643. hr = E_FAIL;
  644. goto out;
  645. }
  646. // Pack up all the cert data and stuff it in the property
  647. hr = HrBuildCertSBinaryData(
  648. lpCItem->lpCDI->bIsDefault,
  649. TRUE,
  650. (PCRYPT_DIGEST_BLOB ) &blob,
  651. (BLOB * ) &(lpCItem->lpCDI->blobSymCaps),
  652. lpCItem->lpCDI->ftSigningTime,
  653. lpPropValue,
  654. (LPBYTE FAR*) &(lpPropValue->Value.MVbin.lpbin[ulCert].lpb),
  655. (ULONG FAR* ) &(lpPropValue->Value.MVbin.lpbin[ulCert].cb));
  656. LocalFree(blob.pbData);
  657. if (hrSuccess != hr)
  658. {
  659. goto out;
  660. }
  661. // Next certificate
  662. ulCert++;
  663. lpCItem = lpCItem->lpNext;
  664. }
  665. out:
  666. if (hcertstore != NULL)
  667. CloseCertStore(hcertstore, 0);
  668. if ((hrSuccess == hr) && (NULL != lppPropValue) && (NULL != lpulcPropCount))
  669. {
  670. *lppPropValue = lpPropValue;
  671. *lpulcPropCount = 1;
  672. }
  673. else
  674. {
  675. // Free the list of structures we allocated.
  676. MAPIFreeBuffer(lpPropValue);
  677. }
  678. return hr;
  679. }
  680. //*******************************************************************
  681. //
  682. // FUNCTION: HrImportCertFromFile
  683. //
  684. // PURPOSE: Import a cert from a file.
  685. //
  686. // PARAMETERS: lpszFileName - name of file containing the cert.
  687. // lppCDI - recieves an allocated structure containing
  688. // the cert data. Must be freed by calling FreeCertdisplayinfo.
  689. //
  690. // RETURNS: HRESULT.
  691. //
  692. // HISTORY:
  693. // 96/09/24 markdu Created.
  694. //
  695. //*******************************************************************
  696. HRESULT HrImportCertFromFile(
  697. IN LPTSTR lpszFileName,
  698. OUT LPCERT_DISPLAY_INFO * lppCDI)
  699. {
  700. HRESULT hr = hrSuccess;
  701. HRESULT hrOut = hrSuccess;
  702. HCERTSTORE hcsWABCertStore = NULL;
  703. HCRYPTPROV hCryptProvider = 0;
  704. PCCERT_CONTEXT pccCertContext = NULL;
  705. LPCERT_DISPLAY_INFO lpCDI=NULL;
  706. BYTE* pbEncoded = NULL;
  707. DWORD cbEncoded = 0;
  708. BOOL fRet;
  709. #ifdef PARAMETER_VALIDATION
  710. if (IsBadReadPtr(lpszFileName, sizeof(TCHAR)))
  711. {
  712. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  713. }
  714. if (IsBadWritePtr(lppCDI, sizeof(CERT_DISPLAY_INFO)))
  715. {
  716. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  717. }
  718. #endif // PARAMETER_VALIDATION
  719. // Load the crypto functions
  720. if (FALSE == InitCryptoLib())
  721. {
  722. hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  723. return hr;
  724. }
  725. // Open the store
  726. hr = OpenSysCertStore(&hcsWABCertStore, &hCryptProvider, cszWABCertStore);
  727. if (hrSuccess != hr)
  728. {
  729. DebugTrace(TEXT("OpenSysCertStore -> 0x%08x\n"), GetScode(hr));
  730. goto out;
  731. }
  732. // Import the cert into a CERT_CONTEXT structure
  733. #ifndef WIN16
  734. hr = ReadMessageFromFile(
  735. lpszFileName,
  736. hCryptProvider,
  737. &pbEncoded,
  738. &cbEncoded);
  739. #else // !WIN16
  740. hr = ReadMessageFromFile(
  741. lpszFileName,
  742. hCryptProvider,
  743. (PBYTE *)&pbEncoded,
  744. (PDWORD)&cbEncoded);
  745. #endif // !WIN16
  746. if (hrSuccess != hr)
  747. {
  748. // Try reading it as just a DER encoded blob
  749. #ifndef WIN16
  750. hr = ReadDataFromFile(
  751. lpszFileName,
  752. &pbEncoded,
  753. &cbEncoded);
  754. #else // !WIN16
  755. hr = ReadDataFromFile(
  756. lpszFileName,
  757. (PBYTE *)&pbEncoded,
  758. (PDWORD)&cbEncoded);
  759. #endif // !WIN16
  760. if (hrSuccess != hr)
  761. {
  762. goto out;
  763. }
  764. }
  765. // Add the cert to the store
  766. fRet = gpfnCertAddEncodedCertificateToStore(
  767. hcsWABCertStore,
  768. X509_ASN_ENCODING,
  769. pbEncoded,
  770. cbEncoded,
  771. CERT_STORE_ADD_USE_EXISTING,
  772. &pccCertContext);
  773. if (FALSE == fRet)
  774. {
  775. hr = HrGetLastError();
  776. DebugTrace(TEXT("CertAddEncodedCertificateToStore -> 0x%08x\n"), GetScode(hr));
  777. goto out;
  778. }
  779. // Allocate memory for the structure, and initialize pointers
  780. // Since we read only one cert, there are no more entries in the linked list
  781. lpCDI = LocalAlloc(LMEM_ZEROINIT, sizeof(CERT_DISPLAY_INFO));
  782. if (NULL == lpCDI)
  783. {
  784. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  785. goto out;
  786. }
  787. lpCDI->lpNext = NULL;
  788. lpCDI->lpPrev = NULL;
  789. // Fill in the defaults for info we don't know
  790. lpCDI->bIsDefault = FALSE;
  791. // Get the certificate
  792. lpCDI->pccert = CertDuplicateCertificateContext(pccCertContext);
  793. // Get the context-specific display info from the cert.
  794. hr = GetCertsDisplayInfoFromContext(GetDesktopWindow(), pccCertContext, lpCDI);
  795. if (hrSuccess != hr)
  796. {
  797. DebugTrace(TEXT("GetCertsDisplayInfoFromContext -> 0x%08x\n"), GetScode(hr));
  798. goto out;
  799. }
  800. out:
  801. // Free the cert context. Ignore errors since there is nothing we can do.
  802. if (NULL != pccCertContext)
  803. {
  804. gpfnCertFreeCertificateContext(pccCertContext);
  805. }
  806. // Close the cert store if we were able to free the cert context.
  807. if (hrSuccess == hrOut)
  808. {
  809. hrOut = CloseCertStore(hcsWABCertStore, hCryptProvider);
  810. }
  811. // If an error occurred in the function body, return that instead of
  812. // any errors that occurred here in cleanup.
  813. if (hrSuccess == hr)
  814. {
  815. hr = hrOut;
  816. }
  817. if ((hrSuccess == hr) && (NULL != lppCDI))
  818. {
  819. *lppCDI = lpCDI;
  820. }
  821. else
  822. {
  823. LocalFreeAndNull(&lpCDI);
  824. }
  825. LocalFreeAndNull(&pbEncoded);
  826. return hr;
  827. }
  828. //*******************************************************************
  829. //
  830. // FUNCTION: HrExportCertToFile
  831. //
  832. // PURPOSE: Export a cert to a file.
  833. //
  834. // PARAMETERS: lpszFileName - name of file in which to store the cert.
  835. // If the file exists, it will be overwritten, so the caller
  836. // must verify that this is OK first if so desired.
  837. // pblobCertThumbPrint - thumb print of certificate to export.
  838. // lpCertDataBuffer - needs to be freed by caller, data is
  839. // filled here when flag is true.
  840. // lpcbBufLen - how long the buffer is
  841. // fWriteDataToBuffer - flag indicating where to write data
  842. //
  843. // RETURNS: HRESULT.
  844. //
  845. // HISTORY:
  846. // 96/09/24 markdu Created.
  847. // 98/07/22 t-jstaj updated to take 3 add'l parameters, a data buffer, its length
  848. // and flag which will indicate whether or not to
  849. // write data to buffer or file. The memory allocated to
  850. // to the buffer needs to be freed by caller.
  851. //
  852. //
  853. //*******************************************************************
  854. HRESULT HrExportCertToFile(
  855. IN LPTSTR lpszFileName,
  856. IN PCCERT_CONTEXT pccert,
  857. OUT LPBYTE *lppCertDataBuffer,
  858. OUT PULONG lpcbBufLen,
  859. IN BOOL fWriteDataToBuffer)
  860. {
  861. HRESULT hr = hrSuccess;
  862. HRESULT hrOut = hrSuccess;
  863. #ifdef PARAMETER_VALIDATION
  864. if( !fWriteDataToBuffer )
  865. {
  866. if (IsBadReadPtr(lpszFileName, sizeof(TCHAR)))
  867. {
  868. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  869. }
  870. }
  871. if (IsBadReadPtr(pccert, sizeof(*pccert)))
  872. {
  873. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  874. }
  875. #endif // PARAMETER_VALIDATION
  876. // Load the crypto functions
  877. if (FALSE == InitCryptoLib())
  878. {
  879. hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  880. return hr;
  881. }
  882. // Export the cert to the file
  883. if( !fWriteDataToBuffer )
  884. {
  885. hr = WriteDERToFile(
  886. lpszFileName,
  887. (PBYTE)pccert->pbCertEncoded,
  888. pccert->cbCertEncoded);
  889. if (hrSuccess != hr)
  890. {
  891. goto out;
  892. }
  893. }
  894. // write cert to buffer
  895. else
  896. {
  897. *lppCertDataBuffer = LocalAlloc( LMEM_ZEROINIT, /*sizeof( BYTE ) **/ pccert->cbCertEncoded);
  898. if( *lppCertDataBuffer )
  899. CopyMemory( *lppCertDataBuffer, pccert->pbCertEncoded, pccert->cbCertEncoded);
  900. else
  901. {
  902. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  903. goto out;
  904. }
  905. *lpcbBufLen = pccert->cbCertEncoded;
  906. }
  907. out:
  908. // If an error occurred in the function body, return that instead of
  909. // any errors that occurred here in cleanup.
  910. if (hrSuccess == hr)
  911. {
  912. hr = hrOut;
  913. }
  914. return hr;
  915. }
  916. //*******************************************************************
  917. //
  918. // FUNCTION: FreeCertdisplayinfo
  919. //
  920. // PURPOSE: Release memory allocated for a CERT_DISPLAY_INFO structure.
  921. // Assumes all info in the structure was LocalAlloced
  922. //
  923. // PARAMETERS: lpCDI - structure to free.
  924. //
  925. // RETURNS: HRESULT.
  926. //
  927. // HISTORY:
  928. // 96/09/24 markdu Created.
  929. //
  930. //*******************************************************************
  931. void FreeCertdisplayinfo(LPCERT_DISPLAY_INFO lpCDI)
  932. {
  933. if (lpCDI)
  934. {
  935. if (lpCDI->lpszDisplayString != lpCDI->lpszEmailAddress)
  936. {
  937. LocalFreeAndNull(&lpCDI->lpszDisplayString);
  938. }
  939. if (lpCDI->pccert != NULL)
  940. {
  941. CertFreeCertificateContext(lpCDI->pccert);
  942. lpCDI->pccert = NULL;
  943. }
  944. LocalFreeAndNull(&lpCDI->lpszEmailAddress);
  945. LocalFreeAndNull(&lpCDI->blobSymCaps.pBlobData);
  946. LocalFreeAndNull(&lpCDI);
  947. }
  948. }
  949. //*******************************************************************
  950. //
  951. // FUNCTION: InitCryptoLib
  952. //
  953. // PURPOSE: Load the Crypto API libray and get the proc addrs.
  954. //
  955. // PARAMETERS: None.
  956. //
  957. // RETURNS: TRUE if successful, FALSE otherwise.
  958. //
  959. // HISTORY:
  960. // 96/10/01 markdu Created.
  961. // 96/11/19 markdu No longer keep a ref count, just use the global
  962. // library handles.
  963. //
  964. //*******************************************************************
  965. BOOL InitCryptoLib(void)
  966. {
  967. #ifndef WIN16 // Disable until we get crypt16.dll
  968. // See if we already tried to load and failed.
  969. if (TRUE == gfPrevCryptoLoadFailed)
  970. {
  971. return FALSE;
  972. }
  973. // See if we already initialized.
  974. if ((NULL == ghCryptoDLLInst) && (NULL == ghAdvApiDLLInst))
  975. {
  976. // open Crypto API library
  977. ghCryptoDLLInst = LoadLibrary(cszCryptoDLL);
  978. if (!ghCryptoDLLInst)
  979. {
  980. DebugTrace(TEXT("InitCryptoLib: Failed to LoadLibrary CRYPT32.DLL.\n"));
  981. goto error;
  982. }
  983. // cycle through the API table and get proc addresses for all the APIs we
  984. // need
  985. if (!GetApiProcAddresses(ghCryptoDLLInst,Crypt32CryptoAPIList,NUM_CRYPT32_CRYPTOAPI_PROCS))
  986. {
  987. DebugTrace(TEXT("InitCryptoLib: Failed to load Crypto API from CRYPT32.DLL.\n"));
  988. goto error;
  989. }
  990. // open AdvApi32 library
  991. ghAdvApiDLLInst = LoadLibrary(cszAdvApiDLL);
  992. if (!ghAdvApiDLLInst)
  993. {
  994. DebugTrace(TEXT("InitCryptoLib: Failed to LoadLibrary ADVAPI32.DLL.\n"));
  995. goto error;
  996. }
  997. }
  998. // Make sure both libraries are loaded
  999. if ((NULL != ghCryptoDLLInst) && (NULL != ghAdvApiDLLInst))
  1000. {
  1001. return TRUE;
  1002. }
  1003. error:
  1004. // Unload the libraries we just loaded and indicate that we should not try to
  1005. // load again this session.
  1006. gfPrevCryptoLoadFailed = TRUE;
  1007. DeinitCryptoLib();
  1008. #endif // !WIN16
  1009. return FALSE;
  1010. }
  1011. //*******************************************************************
  1012. //
  1013. // FUNCTION: DeinitCryptoLib
  1014. //
  1015. // PURPOSE: Release the Crypto API libraries.
  1016. //
  1017. // PARAMETERS: None.
  1018. //
  1019. // RETURNS: None.
  1020. //
  1021. // HISTORY:
  1022. // 96/10/01 markdu Created.
  1023. // 96/11/19 markdu No longer keep a ref count, just call this in
  1024. // DLL_PROCESS_DETACH.
  1025. //
  1026. //*******************************************************************
  1027. void DeinitCryptoLib(void)
  1028. {
  1029. UINT nIndex;
  1030. // No clients using the Crypto API library. Release it.
  1031. if (ghCryptoDLLInst)
  1032. {
  1033. FreeLibrary(ghCryptoDLLInst);
  1034. ghCryptoDLLInst = NULL;
  1035. // cycle through the API table and NULL proc addresses for all the APIs
  1036. for (nIndex = 0; nIndex < NUM_CRYPT32_CRYPTOAPI_PROCS; nIndex++)
  1037. {
  1038. *Crypt32CryptoAPIList[nIndex].ppFcnPtr = NULL;
  1039. }
  1040. }
  1041. // Now releaes the crypto functions in advapi32.dll
  1042. if (ghAdvApiDLLInst)
  1043. {
  1044. FreeLibrary(ghAdvApiDLLInst);
  1045. ghAdvApiDLLInst = NULL;
  1046. }
  1047. return;
  1048. }
  1049. //*******************************************************************
  1050. //
  1051. // FUNCTION: FileTimeToDateTimeString
  1052. //
  1053. // PURPOSE: Convert a filetime structure to displayable text.
  1054. //
  1055. // PARAMETERS: lpft - FILETIME to convert to a string
  1056. // lplpszBuf - receives buffer to hold the string
  1057. //
  1058. // RETURNS: HRESULT
  1059. //
  1060. // HISTORY:
  1061. // 96/10/02 markdu Copied from shdocvw code
  1062. // 96/12/16 markdu Made more robust, and LocalAlloc the buffer here
  1063. //
  1064. //*******************************************************************
  1065. HRESULT FileTimeToDateTimeString(
  1066. IN LPFILETIME lpft,
  1067. IN LPTSTR FAR* lplpszBuf)
  1068. {
  1069. HRESULT hr = hrSuccess;
  1070. SYSTEMTIME st;
  1071. LPTSTR szBuf;
  1072. int cbBuf = 0;
  1073. int cb = 0;
  1074. FileTimeToLocalFileTime(lpft, lpft);
  1075. FileTimeToSystemTime(lpft, &st);
  1076. // Figure out how much space we need, then allocate 2 times that just
  1077. // in case it's DBCS.
  1078. cbBuf += GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, NULL, 0);
  1079. cbBuf += GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, NULL, 0);
  1080. cbBuf *= 2;
  1081. szBuf = LocalAlloc(LMEM_ZEROINIT, cbBuf);
  1082. if (NULL == szBuf)
  1083. {
  1084. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  1085. goto out;
  1086. }
  1087. *lplpszBuf = szBuf;
  1088. // First fill in the date portion.
  1089. GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, szBuf, cbBuf);
  1090. cb = lstrlen(szBuf);
  1091. szBuf += cb;
  1092. cbBuf -= cb;
  1093. // Separate the time and date with a space. and null terminate this
  1094. // (in case GetTimeFormat doesn't add anything).
  1095. *szBuf = TEXT(' ');
  1096. szBuf = CharNext(szBuf);
  1097. *szBuf = TEXT('\0');
  1098. cbBuf-=2;
  1099. GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, szBuf, cbBuf);
  1100. out:
  1101. return hr;
  1102. }
  1103. //*******************************************************************
  1104. //
  1105. // FUNCTION: OpenSysCertStore
  1106. //
  1107. // PURPOSE: Open the specified system cert store.
  1108. //
  1109. // PARAMETERS: phcsSysCertStore - receives handle to the cert store
  1110. // phCryptProvider - If this points to a valid handle,
  1111. // this handle is used as the provider to open the store.
  1112. // otherwise, it receives a handle to the store provider
  1113. // lpszCertStore - name of the store to open
  1114. //
  1115. // RETURNS: HRESULT.
  1116. //
  1117. // HISTORY:
  1118. // 96/10/03 markdu Created.
  1119. //
  1120. //*******************************************************************
  1121. HRESULT OpenSysCertStore(
  1122. HCERTSTORE* phcsSysCertStore,
  1123. HCRYPTPROV* phCryptProvider,
  1124. LPTSTR lpszCertStore)
  1125. {
  1126. HRESULT hr = hrSuccess;
  1127. BOOL fRet;
  1128. BOOL fWeAcquiredContext = FALSE;
  1129. if (phCryptProvider != NULL)
  1130. {
  1131. // Get a handle to the crypto provider if we need one
  1132. if (0 == *phCryptProvider)
  1133. {
  1134. fRet = CryptAcquireContextWrapW(
  1135. phCryptProvider,
  1136. NULL,
  1137. NULL,
  1138. PROV_RSA_FULL,
  1139. CRYPT_VERIFYCONTEXT);
  1140. if (FALSE == fRet)
  1141. {
  1142. hr = HrGetLastError();
  1143. goto out;
  1144. }
  1145. fWeAcquiredContext = TRUE;
  1146. }
  1147. }
  1148. // Open the store
  1149. *phcsSysCertStore = gpfnCertOpenSystemStore(
  1150. ((phCryptProvider == NULL) ? (HCRYPTPROV) NULL : (*phCryptProvider)),
  1151. lpszCertStore);
  1152. if (NULL == *phcsSysCertStore)
  1153. {
  1154. hr = HrGetLastError();
  1155. // Release the crypto provider if we were unable to open the store.
  1156. if (TRUE == fWeAcquiredContext)
  1157. {
  1158. CryptReleaseContext(*phCryptProvider, 0);
  1159. *phCryptProvider = 0;
  1160. }
  1161. goto out;
  1162. }
  1163. out:
  1164. return hr;
  1165. }
  1166. //*******************************************************************
  1167. //
  1168. // FUNCTION: CloseCertStore
  1169. //
  1170. // PURPOSE: Close the specified cert store.
  1171. //
  1172. // PARAMETERS: hcsCertStore - handle to the cert store
  1173. // hCryptProvider - handle to the store provider. The
  1174. // provider will be closed as well, unless 0 is passed.
  1175. //
  1176. // RETURNS: HRESULT.
  1177. //
  1178. // HISTORY:
  1179. // 96/10/03 markdu Created.
  1180. //
  1181. //*******************************************************************
  1182. HRESULT CloseCertStore(
  1183. HCERTSTORE hcsCertStore,
  1184. HCRYPTPROV hCryptProvider)
  1185. {
  1186. HRESULT hr = hrSuccess;
  1187. BOOL fRet;
  1188. if (NULL != hcsCertStore)
  1189. {
  1190. fRet = CertCloseStore(hcsCertStore, 0);
  1191. if (FALSE == fRet)
  1192. {
  1193. hr = HrGetLastError();
  1194. }
  1195. }
  1196. // Release the crypto provider if we were able to close the store.
  1197. if ((0 != hCryptProvider) && (hrSuccess == hr))
  1198. {
  1199. fRet = CryptReleaseContext(hCryptProvider, 0);
  1200. if (FALSE == fRet)
  1201. {
  1202. hr = HrGetLastError();
  1203. }
  1204. }
  1205. return hr;
  1206. }
  1207. //*******************************************************************
  1208. //
  1209. // FUNCTION: GetNameString
  1210. //
  1211. // PURPOSE: Get the string associated with the given attribute
  1212. //
  1213. // PARAMETERS: lplpszName - pointer that will be
  1214. // allocated to hold the string
  1215. // dwEncoding - certificate's encoding
  1216. // pNameBlob - the encoded blob
  1217. // dwType - type of string, e.g. CERT_SIMPLE_NAME_STR
  1218. //
  1219. // RETURNS: HRESULT.
  1220. //
  1221. // HISTORY:
  1222. // 97/02/03 t-erikne Copied and revamped from GetAttributeString
  1223. // 96/10/03 markdu Created.
  1224. //
  1225. //*******************************************************************
  1226. HRESULT GetNameString(
  1227. LPTSTR FAR * lplpszName,
  1228. DWORD dwEncoding,
  1229. PCERT_NAME_BLOB pNameBlob,
  1230. DWORD dwType)
  1231. {
  1232. DWORD cch;
  1233. HRESULT hr = hrSuccess;
  1234. Assert(lplpszName && pNameBlob);
  1235. // Initialize so we know if any data was copied in.
  1236. *lplpszName = NULL;
  1237. cch = gpfnCertNameToStr(
  1238. dwEncoding, // indicates X509 encoding
  1239. pNameBlob, // name_blob to decode
  1240. dwType, // style for output
  1241. NULL, // NULL used when just getting length
  1242. 0); // length of buffer
  1243. *lplpszName = (LPTSTR) LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cch);
  1244. if (NULL == lplpszName)
  1245. {
  1246. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  1247. goto out;
  1248. }
  1249. gpfnCertNameToStr(dwEncoding, pNameBlob,
  1250. dwType, *lplpszName, cch);
  1251. out:
  1252. return hr;
  1253. }
  1254. //*******************************************************************
  1255. //
  1256. // FUNCTION: GetAttributeString
  1257. //
  1258. // PURPOSE: Get the string associated with the given attribute
  1259. // by parsing through the relative
  1260. // distinguished names in the object.
  1261. //
  1262. // PARAMETERS: lplpszAttributeString - pointer that will be allocated to
  1263. // hold the string
  1264. // pbEncoded - the encoded blob
  1265. // cbEncoded - size of the encoded blob
  1266. // lpszObjID - object ID of attribute to retrieve
  1267. //
  1268. // RETURNS: HRESULT.
  1269. //
  1270. // HISTORY:
  1271. // 96/10/03 markdu Created.
  1272. //
  1273. //*******************************************************************
  1274. HRESULT GetAttributeString(
  1275. LPTSTR FAR * lplpszAttributeString,
  1276. BYTE *pbEncoded,
  1277. DWORD cbEncoded,
  1278. LPSTR lpszObjID)
  1279. {
  1280. HRESULT hr = hrSuccess;
  1281. BOOL fRet;
  1282. PCERT_RDN_ATTR pRdnAttr;
  1283. PCERT_NAME_INFO pNameInfo = NULL;
  1284. DWORD cbInfo;
  1285. DWORD cbData; //N need both?
  1286. // Initialize so we know if any data was copied in.
  1287. *lplpszAttributeString = NULL;
  1288. // Get the size of the subject name data
  1289. cbInfo = 0;
  1290. gpfnCryptDecodeObject(
  1291. X509_ASN_ENCODING, // indicates X509 encoding
  1292. (LPCSTR)X509_NAME, // flag indicating a name blob is to be decoded
  1293. pbEncoded, // pointer to a buffer holding the encoded name
  1294. cbEncoded, // length in bytes of the encoded name
  1295. //N maybe can use nocopy flag
  1296. 0, // flags
  1297. NULL, // NULL used when just geting length
  1298. &cbInfo); // length in bytes of the decoded name
  1299. if (0 == cbInfo)
  1300. {
  1301. hr = HrGetLastError();
  1302. goto out;
  1303. }
  1304. // Allocate space for the decoded name
  1305. pNameInfo = (PCERT_NAME_INFO) LocalAlloc(LMEM_ZEROINIT, cbInfo);
  1306. if (NULL == pNameInfo)
  1307. {
  1308. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  1309. goto out;
  1310. }
  1311. // Get the subject name
  1312. fRet = gpfnCryptDecodeObject(
  1313. X509_ASN_ENCODING, // indicates X509 encoding
  1314. (LPCSTR)X509_NAME, // flag indicating a name blob is to be decoded
  1315. pbEncoded, // pointer to a buffer holding the encoded name
  1316. cbEncoded, // length in bytes of the encoded name
  1317. 0, // flags
  1318. pNameInfo, // the buffer where the decoded name is written to
  1319. &cbInfo); // length in bytes of the decoded name
  1320. if (FALSE == fRet)
  1321. {
  1322. hr = HrGetLastError();
  1323. goto out;
  1324. }
  1325. // Now we have a decoded name RDN array, so find the oid we want
  1326. pRdnAttr = gpfnCertFindRDNAttr(lpszObjID, pNameInfo);
  1327. if (!pRdnAttr)
  1328. {
  1329. hr = MAPI_E_NOT_FOUND;
  1330. goto out;
  1331. }
  1332. *lplpszAttributeString = SzConvertRDNString(pRdnAttr);
  1333. out:
  1334. if (NULL != pNameInfo)
  1335. {
  1336. LocalFreeAndNull(&pNameInfo);
  1337. }
  1338. return hr;
  1339. }
  1340. //*******************************************************************
  1341. //
  1342. // FUNCTION: GetCertThumbPrint
  1343. //
  1344. // PURPOSE: Gets the thumbprint of the cert.
  1345. //
  1346. // PARAMETERS: pccCertContext - cert whose thumbprint to get
  1347. // pblobCertThumbPrint - receives thumb print
  1348. //
  1349. // RETURNS: HRESULT.
  1350. //
  1351. // HISTORY:
  1352. // 96/10/13 markdu Created.
  1353. //
  1354. //*******************************************************************
  1355. HRESULT GetCertThumbPrint(
  1356. PCCERT_CONTEXT pccCertContext,
  1357. PCRYPT_DIGEST_BLOB pblobCertThumbPrint)
  1358. {
  1359. HRESULT hr = hrSuccess;
  1360. BOOL fRet;
  1361. // Get the size of the thumbprint data
  1362. pblobCertThumbPrint->cbData = 0;
  1363. fRet = gpfnCertGetCertificateContextProperty(
  1364. pccCertContext,
  1365. CERT_HASH_PROP_ID,
  1366. NULL,
  1367. &pblobCertThumbPrint->cbData);
  1368. if (FALSE == fRet)
  1369. {
  1370. hr = HrGetLastError();
  1371. goto out;
  1372. }
  1373. // Allocate memory for the thumbprint data
  1374. pblobCertThumbPrint->pbData = LocalAlloc(LMEM_ZEROINIT,
  1375. pblobCertThumbPrint->cbData);
  1376. if (NULL == pblobCertThumbPrint->pbData)
  1377. {
  1378. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  1379. goto out;
  1380. }
  1381. // Get the thumbprint
  1382. fRet = gpfnCertGetCertificateContextProperty(
  1383. pccCertContext,
  1384. CERT_HASH_PROP_ID,
  1385. pblobCertThumbPrint->pbData,
  1386. &pblobCertThumbPrint->cbData);
  1387. if (FALSE == fRet)
  1388. {
  1389. hr = HrGetLastError();
  1390. goto out;
  1391. }
  1392. out:
  1393. return hr;
  1394. }
  1395. /* SzConvertRDNString
  1396. **
  1397. ** Purpose:
  1398. ** Figure out what kind of string data is in the RDN, allocate
  1399. ** a buffer and convert the string data to DBCS/ANSI.
  1400. **
  1401. ** Takes:
  1402. ** IN pRdnAttr - Certificate RDN atteribute
  1403. ** Returns:
  1404. ** A LocalAlloc'd buffer containing the string.
  1405. */
  1406. LPTSTR SzConvertRDNString(PCERT_RDN_ATTR pRdnAttr) {
  1407. LPTSTR szRet = NULL;
  1408. ULONG cbData = 0;
  1409. // We only handle certain types
  1410. //N look to see if we should have a stack var for the ->
  1411. if ((CERT_RDN_NUMERIC_STRING != pRdnAttr->dwValueType) &&
  1412. (CERT_RDN_PRINTABLE_STRING != pRdnAttr->dwValueType) &&
  1413. (CERT_RDN_IA5_STRING != pRdnAttr->dwValueType) &&
  1414. (CERT_RDN_VISIBLE_STRING != pRdnAttr->dwValueType) &&
  1415. (CERT_RDN_ISO646_STRING != pRdnAttr->dwValueType) &&
  1416. (CERT_RDN_UNIVERSAL_STRING != pRdnAttr->dwValueType) &&
  1417. (CERT_RDN_TELETEX_STRING != pRdnAttr->dwValueType) &&
  1418. (CERT_RDN_UNICODE_STRING != pRdnAttr->dwValueType)) {
  1419. Assert((CERT_RDN_NUMERIC_STRING == pRdnAttr->dwValueType) ||
  1420. (CERT_RDN_PRINTABLE_STRING == pRdnAttr->dwValueType) ||
  1421. (CERT_RDN_IA5_STRING == pRdnAttr->dwValueType) ||
  1422. (CERT_RDN_VISIBLE_STRING == pRdnAttr->dwValueType) ||
  1423. (CERT_RDN_ISO646_STRING == pRdnAttr->dwValueType) ||
  1424. (CERT_RDN_UNIVERSAL_STRING == pRdnAttr->dwValueType) ||
  1425. (CERT_RDN_TELETEX_STRING == pRdnAttr->dwValueType) ||
  1426. (CERT_RDN_UNICODE_STRING == pRdnAttr->dwValueType));
  1427. return(NULL);
  1428. }
  1429. // Find out how much space to allocate.
  1430. switch (pRdnAttr->dwValueType) {
  1431. case CERT_RDN_UNICODE_STRING:
  1432. cbData = WideCharToMultiByte(
  1433. CP_ACP,
  1434. 0,
  1435. (LPWSTR)pRdnAttr->Value.pbData,
  1436. -1,
  1437. NULL,
  1438. 0,
  1439. NULL,
  1440. NULL);
  1441. break;
  1442. case CERT_RDN_UNIVERSAL_STRING:
  1443. case CERT_RDN_TELETEX_STRING:
  1444. cbData = gpfnCertRDNValueToStr(pRdnAttr->dwValueType,
  1445. (PCERT_RDN_VALUE_BLOB)&(pRdnAttr->Value),
  1446. NULL,
  1447. 0);
  1448. break;
  1449. default:
  1450. cbData = pRdnAttr->Value.cbData + 1;
  1451. break;
  1452. }
  1453. // Allocate the space for the string.
  1454. if (! (szRet = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cbData))) {
  1455. Assert(szRet);
  1456. return(NULL);
  1457. }
  1458. // Copy the string
  1459. switch (pRdnAttr->dwValueType) {
  1460. case CERT_RDN_UNICODE_STRING:
  1461. StrCpyN(szRet, (LPWSTR)pRdnAttr->Value.pbData, cbData);
  1462. break;
  1463. case CERT_RDN_UNIVERSAL_STRING:
  1464. case CERT_RDN_TELETEX_STRING:
  1465. gpfnCertRDNValueToStr(pRdnAttr->dwValueType,
  1466. (PCERT_RDN_VALUE_BLOB)&(pRdnAttr->Value),
  1467. szRet,
  1468. cbData);
  1469. break;
  1470. default:
  1471. ScAnsiToWCMore(NULL, NULL, pRdnAttr->Value.pbData, &szRet);
  1472. szRet[cbData - 1] = '\0';
  1473. break;
  1474. }
  1475. return(szRet);
  1476. }
  1477. /* PVDecodeObject:
  1478. **
  1479. ** Purpose:
  1480. ** Combine the "how big? okay, here." double question to decode an
  1481. ** object. Give it a thing to get and it will alloc the mem.
  1482. ** Takes:
  1483. ** IN pbEncoded - encoded data
  1484. ** IN cbEncoded - size of data in pbData
  1485. ** IN item - X509_* ... the thing to get
  1486. ** OUT OPTIONAL cbOut - (def value of NULL) size of the return
  1487. ** Notes:
  1488. ** pbEncoded can't be freed until return is freed.
  1489. ** Returns:
  1490. ** data that was obtained, NULL if failed. Caller must LocalFree buffer.
  1491. */
  1492. LPVOID PVDecodeObject(
  1493. BYTE *pbEncoded,
  1494. DWORD cbEncoded,
  1495. LPCSTR item,
  1496. DWORD *cbOut)
  1497. {
  1498. DWORD cbData;
  1499. void *pvData = NULL;
  1500. if (!(pbEncoded && cbEncoded))
  1501. {
  1502. SetLastError((DWORD)E_INVALIDARG);
  1503. goto ErrorReturn;
  1504. }
  1505. cbData = 0;
  1506. gpfnCryptDecodeObject(
  1507. X509_ASN_ENCODING, // indicates X509 encoding
  1508. item, // flag indicating type to be decoded
  1509. pbEncoded, // pointer to a buffer holding the encoded data
  1510. cbEncoded, // length in bytes of the encoded data
  1511. CRYPT_DECODE_NOCOPY_FLAG,
  1512. NULL, // NULL used when just geting length
  1513. &cbData); // length in bytes of the decoded data
  1514. if (!cbData || ! (pvData = LocalAlloc(LPTR, cbData))) {
  1515. goto ErrorReturn;
  1516. }
  1517. if (!gpfnCryptDecodeObject(
  1518. X509_ASN_ENCODING, // indicates X509 encoding
  1519. item, // flag indicating type is to be decoded
  1520. pbEncoded, // pointer to a buffer holding the encoded data
  1521. cbEncoded, // length in bytes of the encoded name
  1522. CRYPT_DECODE_NOCOPY_FLAG,
  1523. pvData, // out buffer
  1524. &cbData)) // length in bytes of the decoded data
  1525. goto ErrorReturn;
  1526. exit:
  1527. if (cbOut)
  1528. *cbOut = cbData;
  1529. return pvData;
  1530. ErrorReturn:
  1531. if (pvData)
  1532. {
  1533. IF_WIN32(LocalFree(pvData);)
  1534. IF_WIN16(LocalFree((HLOCAL)pvData);)
  1535. pvData = NULL;
  1536. }
  1537. cbData = 0;
  1538. goto exit;
  1539. }
  1540. /* SzGetAltNameEmail:
  1541. **
  1542. ** Input:
  1543. ** pCert -> certificate context
  1544. ** lpszOID -> OID or predefined id of alt name to look in. ie, OID_SUBJECT_ALT_NAME or
  1545. ** X509_ALTERNATE_NAME.
  1546. **
  1547. ** Returns:
  1548. ** Buffer containing email name or NULL if not found.
  1549. ** Caller must LocalFree the buffer.
  1550. */
  1551. LPTSTR SzGetAltNameEmail(
  1552. const PCCERT_CONTEXT pCert,
  1553. LPSTR lpszOID) {
  1554. PCERT_INFO pCertInfo = pCert->pCertInfo;
  1555. PCERT_ALT_NAME_ENTRY pAltNameEntry = NULL;
  1556. PCERT_ALT_NAME_INFO pAltNameInfo = NULL;
  1557. ULONG i, j, cbData;
  1558. LPSTR szRet = NULL;
  1559. LPTSTR sz = NULL;
  1560. if (lpszOID == (LPCSTR)X509_ALTERNATE_NAME) {
  1561. lpszOID = szOID_SUBJECT_ALT_NAME;
  1562. }
  1563. for (i = 0; i < pCertInfo->cExtension; i++)
  1564. {
  1565. if (! lstrcmpA(pCertInfo->rgExtension[i].pszObjId, lpszOID))
  1566. {
  1567. // Found the OID. Look for the email tag
  1568. if (pAltNameInfo = (PCERT_ALT_NAME_INFO)PVDecodeObject( pCertInfo->rgExtension[i].Value.pbData,
  1569. pCertInfo->rgExtension[i].Value.cbData,
  1570. lpszOID,
  1571. NULL))
  1572. {
  1573. // Cycle through the alt name entries
  1574. for (j = 0; j < pAltNameInfo->cAltEntry; j++)
  1575. {
  1576. if (pAltNameEntry = &pAltNameInfo->rgAltEntry[j])
  1577. {
  1578. if (pAltNameEntry->dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME)
  1579. {
  1580. // This is it, copy it out to a new allocation
  1581. if (pAltNameEntry->pwszRfc822Name)
  1582. {
  1583. DWORD cchSize = (lstrlen(pAltNameEntry->pwszRfc822Name)+1);
  1584. if (sz = LocalAlloc(LPTR, sizeof(TCHAR)*cchSize))
  1585. {
  1586. StrCpyN(sz, pAltNameEntry->pwszRfc822Name, cchSize);
  1587. break;
  1588. }
  1589. }
  1590. }
  1591. }
  1592. }
  1593. IF_WIN32(LocalFree(pAltNameInfo);)
  1594. IF_WIN16(LocalFree((HLOCAL)pAltNameInfo);)
  1595. pAltNameInfo = NULL;
  1596. }
  1597. }
  1598. }
  1599. LocalFreeAndNull(&pAltNameInfo);
  1600. return(sz);
  1601. }
  1602. /* SzGetCertificateEmailAddress:
  1603. **
  1604. ** Returns:
  1605. ** NULL if there is no email address
  1606. */
  1607. LPTSTR SzGetCertificateEmailAddress(
  1608. const PCCERT_CONTEXT pCert)
  1609. {
  1610. PCERT_NAME_INFO pNameInfo;
  1611. PCERT_ALT_NAME_INFO pAltNameInfo = NULL;
  1612. PCERT_RDN_ATTR pRDNAttr;
  1613. LPTSTR szRet = NULL;
  1614. Assert(pCert && pCert->pCertInfo);
  1615. pNameInfo = (PCERT_NAME_INFO)PVDecodeObject(pCert->pCertInfo->Subject.pbData,
  1616. pCert->pCertInfo->Subject.cbData, X509_NAME, 0);
  1617. if (pNameInfo)
  1618. {
  1619. pRDNAttr = gpfnCertFindRDNAttr(szOID_RSA_emailAddr, pNameInfo);
  1620. if (pRDNAttr)
  1621. {
  1622. Assert(0 == lstrcmpA(szOID_RSA_emailAddr, pRDNAttr->pszObjId));
  1623. szRet = SzConvertRDNString(pRDNAttr);
  1624. }
  1625. IF_WIN32(LocalFree(pNameInfo);)
  1626. IF_WIN16(LocalFree((HLOCAL)pNameInfo);)
  1627. }
  1628. if (! szRet)
  1629. {
  1630. if (! (szRet = SzGetAltNameEmail(pCert, szOID_SUBJECT_ALT_NAME)))
  1631. {
  1632. szRet = SzGetAltNameEmail(pCert, szOID_SUBJECT_ALT_NAME2);
  1633. }
  1634. }
  1635. return(szRet);
  1636. }
  1637. //*******************************************************************
  1638. //
  1639. // FUNCTION: GetCertsDisplayInfoFromContext
  1640. //
  1641. // PURPOSE: Gets the display info that is available in the cert
  1642. // context structure.
  1643. //
  1644. // PARAMETERS: pccCertContext - cert data
  1645. // lpCDI - structure to receive the cert data
  1646. //
  1647. // RETURNS: HRESULT.
  1648. //
  1649. // HISTORY:
  1650. // 96/10/04 markdu Created.
  1651. //
  1652. //*******************************************************************
  1653. HRESULT GetCertsDisplayInfoFromContext(
  1654. HWND hwndParent,
  1655. PCCERT_CONTEXT pccCertContext,
  1656. LPCERT_DISPLAY_INFO lpCDI)
  1657. {
  1658. HRESULT hr = hrSuccess;
  1659. PCERT_INFO pCertInfo;
  1660. pCertInfo = pccCertContext->pCertInfo;
  1661. lpCDI->lpszDisplayString = NULL,
  1662. lpCDI->lpszEmailAddress = NULL;
  1663. hr = GetAttributeString(
  1664. &lpCDI->lpszDisplayString,
  1665. pCertInfo->Subject.pbData,
  1666. pCertInfo->Subject.cbData,
  1667. szOID_COMMON_NAME);
  1668. if (hrSuccess != hr)
  1669. {
  1670. DebugTrace(TEXT("Cert has no common name\n"));
  1671. }
  1672. lpCDI->lpszEmailAddress = SzGetCertificateEmailAddress(pccCertContext);
  1673. // In case there is no common name (weird, but true)
  1674. if (! lpCDI->lpszDisplayString) {
  1675. lpCDI->lpszDisplayString = lpCDI->lpszEmailAddress;
  1676. }
  1677. if (! lpCDI->lpszDisplayString) {
  1678. DebugTrace(TEXT("Certificate had no name or email! What a pathetic cert!\n"));
  1679. }
  1680. // Some certificates won't have email addresses in them which means that
  1681. // Failure is not a (valid) option.
  1682. // just set it to empty
  1683. if (hrSuccess != hr)
  1684. {
  1685. hr = S_OK;
  1686. }
  1687. DebugTrace(TEXT("Certificate for '%s'. Email: '%s'\n"), lpCDI->lpszDisplayString ? lpCDI->lpszDisplayString : NULL, (lpCDI->lpszEmailAddress ? lpCDI->lpszEmailAddress : szEmpty));
  1688. // Determine if cert has expired
  1689. lpCDI->bIsExpired = IsCertExpired(pCertInfo);
  1690. // Determine if cert has been revoked
  1691. lpCDI->bIsRevoked = IsCertRevoked(pCertInfo);
  1692. // Determine if this certificate is trusted or not
  1693. if (FAILED(HrGetTrustState(hwndParent, pccCertContext, &lpCDI->dwTrust)))
  1694. {
  1695. lpCDI->dwTrust = CERT_VALIDITY_NO_TRUST_DATA;
  1696. hr = S_OK; // we handled this
  1697. }
  1698. if (0 == lpCDI->dwTrust)
  1699. lpCDI->bIsTrusted = TRUE;
  1700. else
  1701. lpCDI->bIsTrusted = FALSE;
  1702. return hr;
  1703. }
  1704. //*******************************************************************
  1705. //
  1706. // FUNCTION: DebugTraceCertContextName
  1707. //
  1708. // PURPOSE: Dump the subject name of a cert context
  1709. //
  1710. // PARAMETERS: pcCertContext = cert context to dump
  1711. // lpDescription = description text
  1712. //
  1713. // RETURNS: none
  1714. //
  1715. //*******************************************************************
  1716. void DebugTraceCertContextName(PCCERT_CONTEXT pcCertContext, LPTSTR lpDescription) {
  1717. #ifdef DEBUG
  1718. LPTSTR lpName = NULL;
  1719. PCERT_INFO pCertInfo = pcCertContext->pCertInfo;
  1720. GetAttributeString(
  1721. &lpName,
  1722. pCertInfo->Subject.pbData,
  1723. pCertInfo->Subject.cbData,
  1724. szOID_COMMON_NAME);
  1725. if (! lpName) {
  1726. GetAttributeString(
  1727. &lpName,
  1728. pCertInfo->Subject.pbData,
  1729. pCertInfo->Subject.cbData,
  1730. szOID_ORGANIZATION_NAME);
  1731. }
  1732. DebugTrace(TEXT("%s %s\n"), lpDescription, lpName ? lpName : TEXT("<unknown>"));
  1733. if (lpName) {
  1734. IF_WIN32(LocalFree(lpName);)
  1735. IF_WIN16(LocalFree((HLOCAL)lpName);)
  1736. }
  1737. #endif
  1738. }
  1739. //*******************************************************************
  1740. //
  1741. // FUNCTION: ReadMessageFromFile
  1742. //
  1743. // PURPOSE: Reads a single cert from a PKCS7 message file
  1744. //
  1745. // PARAMETERS: lpszFileName - name of file containing the PKCS7 encoded
  1746. // message
  1747. // hCryptProvider - handle to the store provider
  1748. // ppbEncoded - receives the encoded cert blob
  1749. // pcbEncoded - receives the size of the encoded cert blob
  1750. //
  1751. // RETURNS: HRESULT.
  1752. //
  1753. // HISTORY:
  1754. // 96/10/06 markdu Created.
  1755. //
  1756. //*******************************************************************
  1757. HRESULT ReadMessageFromFile(
  1758. LPTSTR lpszFileName,
  1759. HCRYPTPROV hCryptProvider,
  1760. PBYTE* ppbEncoded,
  1761. PDWORD pcbEncoded)
  1762. {
  1763. HRESULT hr = hrSuccess;
  1764. BOOL fRet;
  1765. DWORD cCert, cbData;
  1766. HCRYPTMSG hMsg = NULL;
  1767. PBYTE lpBuf = 0;
  1768. ULONG i, j;
  1769. DWORD dwIssuerFlags = 0;
  1770. BOOL fFound = FALSE, fIssuer;
  1771. PCERT_CONTEXT * rgpcCertContext = NULL;
  1772. HCERTSTORE hCertStoreMsg = NULL;
  1773. PCCERT_CONTEXT pcCertContextTarget = NULL, pcCertContextIssuer;
  1774. PCERT_INFO pCertInfoTarget = NULL;
  1775. if ((NULL == ppbEncoded) || (NULL == pcbEncoded)) {
  1776. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1777. }
  1778. *ppbEncoded = 0;
  1779. *pcbEncoded = 0;
  1780. // Read the data from the file.
  1781. if (hr = ReadDataFromFile(lpszFileName, &lpBuf, (PDWORD)&cbData)) {
  1782. goto out;
  1783. }
  1784. hMsg = gpfnCryptMsgOpenToDecode(
  1785. PKCS_7_ASN_ENCODING,
  1786. 0, // dwFlags
  1787. 0, // dwMsgType
  1788. hCryptProvider,
  1789. NULL, // pRecipientInfo (not supported)
  1790. NULL); // pStreamInfo (not supported)
  1791. if (NULL == hMsg) {
  1792. hr = HrGetLastError();
  1793. DebugTrace(TEXT("CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING) -> 0x%08x\n"), GetScode(hr));
  1794. goto error;
  1795. }
  1796. fRet = gpfnCryptMsgUpdate(hMsg, lpBuf, cbData, TRUE);
  1797. if (FALSE == fRet) {
  1798. hr = HrGetLastError();
  1799. DebugTrace(TEXT("CryptMsgUpdate -> 0x%08x\n"), GetScode(hr));
  1800. goto error;
  1801. }
  1802. cbData = sizeof(cCert);
  1803. fRet = gpfnCryptMsgGetParam(
  1804. hMsg,
  1805. CMSG_CERT_COUNT_PARAM, // dwParamType
  1806. 0, // dwIndex
  1807. (void *)&cCert,
  1808. &cbData); // pcbData
  1809. if (FALSE == fRet) {
  1810. hr = HrGetLastError();
  1811. DebugTrace(TEXT("CryptMsgGetParam(CMSG_CERT_COUNT_PARAM) -> 0x%08x\n"), GetScode(hr));
  1812. goto error;
  1813. }
  1814. if (cbData != sizeof(cCert)) {
  1815. hr = ResultFromScode(MAPI_E_CALL_FAILED);
  1816. goto error;
  1817. }
  1818. if (cCert == 1) {
  1819. // Just one cert. No decisions to make.
  1820. cbData = 0;
  1821. fRet = gpfnCryptMsgGetParam(
  1822. hMsg,
  1823. CMSG_CERT_PARAM,
  1824. 0, // dwIndex
  1825. NULL, // pvData
  1826. &cbData
  1827. );
  1828. if ((!fRet) || (0 == cbData)) {
  1829. hr = ResultFromScode(MAPI_E_CALL_FAILED);
  1830. DebugTrace(TEXT("CryptMsgGetParam(CMSG_CERT_PARAM) -> 0x%08x\n"), GetScode(hr));
  1831. goto error;
  1832. }
  1833. IF_WIN32(*ppbEncoded = (BYTE *)LocalAlloc(LMEM_ZEROINIT, cbData);)
  1834. IF_WIN16(*ppbEncoded = (PBYTE)LocalAlloc(LMEM_ZEROINIT, cbData);)
  1835. if (NULL == *ppbEncoded) {
  1836. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  1837. goto error;
  1838. }
  1839. fRet = gpfnCryptMsgGetParam(
  1840. hMsg,
  1841. CMSG_CERT_PARAM,
  1842. 0,
  1843. *ppbEncoded,
  1844. &cbData
  1845. );
  1846. if (FALSE == fRet) {
  1847. hr = HrGetLastError();
  1848. DebugTrace(TEXT("CryptMsgGetParam(CMSG_CERT_PARAM) -> 0x%08x\n"), GetScode(hr));
  1849. IF_WIN32(LocalFreeAndNull(ppbEncoded);) IF_WIN16(LocalFreeAndNull((LPVOID *)ppbEncoded);)
  1850. goto error;
  1851. }
  1852. *pcbEncoded = cbData;
  1853. } else {
  1854. // More than one cert in the message. Which one is it?
  1855. //
  1856. // Look for one that's a "Leaf" node.
  1857. // Unfortunately, there is no easy way to tell, so we'll have
  1858. // to loop through each cert, checking to see if it is an issuer of any other cert
  1859. // in the message. If it is not an issuer of any other cert, it must be the leaf cert.
  1860. //
  1861. hCertStoreMsg = CertOpenStore(
  1862. CERT_STORE_PROV_MSG,
  1863. X509_ASN_ENCODING,
  1864. hCryptProvider,
  1865. CERT_STORE_NO_CRYPT_RELEASE_FLAG,
  1866. hMsg);
  1867. if (hCertStoreMsg == NULL) {
  1868. hr = HrGetLastError();
  1869. DebugTrace(TEXT("CertOpenStore(msg) -> %u\n"), hr);
  1870. } else {
  1871. if (! (rgpcCertContext = LocalAlloc(LPTR, cCert * sizeof(PCERT_CONTEXT)))) {
  1872. DebugTrace(TEXT("LocalAlloc of cert table -> %u\n"), HrGetLastError());
  1873. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  1874. goto error;
  1875. }
  1876. // Enumerate all certs on this message
  1877. i = 0;
  1878. while (pcCertContextTarget = gpfnCertEnumCertificatesInStore(hCertStoreMsg,
  1879. pcCertContextTarget)) {
  1880. if (! (rgpcCertContext[i] = (PCERT_CONTEXT)CertDuplicateCertificateContext(
  1881. pcCertContextTarget))) {
  1882. DebugTrace(TEXT("CertCertificateContext -> %x\n"), HrGetLastError());
  1883. }
  1884. #ifdef DEBUG
  1885. DebugTraceCertContextName(rgpcCertContext[i], TEXT("Found Cert:"));
  1886. #endif
  1887. i++;
  1888. };
  1889. // Now we've got a table full of certs
  1890. for (i = 0; i < cCert; i++) {
  1891. pCertInfoTarget = rgpcCertContext[i]->pCertInfo;
  1892. fIssuer = FALSE;
  1893. for (j = 0; j < cCert; j++) {
  1894. if (i != j) {
  1895. dwIssuerFlags = 0;
  1896. if (pcCertContextIssuer = gpfnCertGetIssuerCertificateFromStore(hCertStoreMsg,
  1897. rgpcCertContext[j],
  1898. NULL,
  1899. &dwIssuerFlags)) {
  1900. // Found an issuer
  1901. // Is it the same as the target?
  1902. fIssuer = gpfnCertCompareCertificate(X509_ASN_ENCODING,
  1903. pCertInfoTarget, // target
  1904. pcCertContextIssuer->pCertInfo); // test issuer
  1905. gpfnCertFreeCertificateContext(pcCertContextIssuer);
  1906. if (fIssuer) {
  1907. // This test cert is issued by the target, so
  1908. // we know that Target is NOT a leaf cert
  1909. break;
  1910. } // else, loop back to the enumerate where the test cert context will be freed.
  1911. }
  1912. }
  1913. }
  1914. if (! fIssuer) {
  1915. DebugTrace(TEXT("Found a Cert which is not an issuer.\n"));
  1916. #ifdef DEBUG
  1917. DebugTraceCertContextName(rgpcCertContext[i], TEXT("Non-issuer cert:"));
  1918. #endif
  1919. // Copy the cert encoded data to a seperate allocation
  1920. cbData = rgpcCertContext[i]->cbCertEncoded;
  1921. #ifndef WIN16
  1922. if (! (*ppbEncoded = (BYTE *)LocalAlloc(LPTR, cbData))) {
  1923. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  1924. goto error;
  1925. }
  1926. #else
  1927. if (! (*ppbEncoded = (PBYTE)LocalAlloc(LPTR, cbData))) {
  1928. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  1929. goto error;
  1930. }
  1931. #endif
  1932. CopyMemory(*ppbEncoded, rgpcCertContext[i]->pbCertEncoded, cbData);
  1933. *pcbEncoded = cbData;
  1934. fFound = TRUE;
  1935. break; // done with loop
  1936. }
  1937. }
  1938. // Free the table of certs
  1939. for (i = 0; i < cCert; i++) {
  1940. gpfnCertFreeCertificateContext(rgpcCertContext[i]);
  1941. }
  1942. IF_WIN32(LocalFree((LPVOID)rgpcCertContext);)
  1943. IF_WIN16(LocalFree((HLOCAL)rgpcCertContext);)
  1944. if (! fFound) {
  1945. // Didn't find a cert that isn't an issuer. Fail.
  1946. hr = ResultFromScode(MAPI_E_NOT_FOUND);
  1947. goto error;
  1948. }
  1949. }
  1950. }
  1951. out:
  1952. if (hCertStoreMsg) {
  1953. CertCloseStore(hCertStoreMsg, 0);
  1954. }
  1955. if (hMsg) {
  1956. gpfnCryptMsgClose(hMsg);
  1957. }
  1958. if (lpBuf) {
  1959. IF_WIN32(LocalFreeAndNull(&lpBuf);) IF_WIN16(LocalFreeAndNull((LPVOID *)&lpBuf);)
  1960. }
  1961. return(hr);
  1962. error:
  1963. // some of the GetLastError calls above may not have worked.
  1964. if (hrSuccess == hr) {
  1965. hr = ResultFromScode(MAPI_E_CALL_FAILED);
  1966. }
  1967. goto out;
  1968. }
  1969. //*******************************************************************
  1970. //
  1971. // FUNCTION: WriteDERToFile
  1972. //
  1973. // PURPOSE: Writes a single cert to a file as a DER encoded blob
  1974. //
  1975. // PARAMETERS: lpszFileName - name of file to hold the encoded blob
  1976. // pccCertContext - the cert to be written
  1977. //
  1978. // RETURNS: HRESULT.
  1979. //
  1980. // HISTORY:
  1981. // 96/10/29 markdu Created.
  1982. //
  1983. //*******************************************************************
  1984. HRESULT WriteDERToFile(
  1985. LPTSTR lpszFileName,
  1986. PBYTE pbEncoded,
  1987. DWORD cbEncoded)
  1988. {
  1989. HRESULT hr = hrSuccess;
  1990. BOOL fRet;
  1991. HANDLE hFile = 0;
  1992. DWORD cbFile;
  1993. // Open the file
  1994. hFile = CreateFile(
  1995. lpszFileName,
  1996. GENERIC_READ | GENERIC_WRITE,
  1997. 0,
  1998. NULL,
  1999. CREATE_ALWAYS,
  2000. 0,
  2001. NULL);
  2002. if(INVALID_HANDLE_VALUE == hFile)
  2003. {
  2004. hr = ResultFromScode(MAPI_E_DISK_ERROR);
  2005. goto out;
  2006. }
  2007. // Write the data to the file
  2008. fRet = WriteFile(
  2009. hFile, // handle of file to write
  2010. pbEncoded, // address of buffer to write
  2011. cbEncoded, // number of bytes to write
  2012. &cbFile, // address of number of bytes written
  2013. NULL // address of structure for data
  2014. );
  2015. if (FALSE == fRet)
  2016. {
  2017. hr = ResultFromScode(MAPI_E_DISK_ERROR);
  2018. goto out;
  2019. }
  2020. if (cbEncoded != cbFile)
  2021. {
  2022. hr = ResultFromScode(MAPI_E_CALL_FAILED);
  2023. goto out;
  2024. }
  2025. out:
  2026. if (hFile)
  2027. {
  2028. IF_WIN32(CloseHandle(hFile);) IF_WIN16(CloseFile(hFile);)
  2029. }
  2030. return hr;
  2031. }
  2032. //*******************************************************************
  2033. //
  2034. // FUNCTION: GetIssuerContextAndStore
  2035. //
  2036. // PURPOSE: Get the context of the issuer by first looking in the
  2037. // CA store, then the root store.
  2038. //
  2039. // PARAMETERS: pccCertContext - cert whose issuer to find
  2040. // ppccIssuerCertContext - receives context of issuer,
  2041. // or NULL if no issuer cert found.
  2042. // phcsIssuerStore - receives handle of store containing cert.
  2043. // hCryptProvider - must be a valid provider
  2044. //
  2045. // RETURNS: HRESULT.
  2046. //
  2047. // HISTORY:
  2048. // 96/10/14 markdu Created.
  2049. //
  2050. //*******************************************************************
  2051. HRESULT GetIssuerContextAndStore(
  2052. PCCERT_CONTEXT pccCertContext,
  2053. PCCERT_CONTEXT* ppccIssuerCertContext,
  2054. HCRYPTPROV hCryptProvider,
  2055. HCERTSTORE* phcsIssuerStore)
  2056. {
  2057. HRESULT hr = hrSuccess;
  2058. DWORD dwFlags;
  2059. // Open the CA store to get the issuer data.
  2060. hr = OpenSysCertStore(phcsIssuerStore, &hCryptProvider, cszCACertStore);
  2061. if (hrSuccess == hr)
  2062. {
  2063. // Get the issuer cert context
  2064. dwFlags = 0;
  2065. *ppccIssuerCertContext = gpfnCertGetIssuerCertificateFromStore(
  2066. *phcsIssuerStore,
  2067. pccCertContext,
  2068. NULL,
  2069. &dwFlags);
  2070. if (NULL != *ppccIssuerCertContext)
  2071. {
  2072. goto out;
  2073. }
  2074. else
  2075. {
  2076. // Close the store, but don't goto error, becuase we want to try again.
  2077. CloseCertStore(*phcsIssuerStore, 0);
  2078. *phcsIssuerStore = NULL;
  2079. hr = ResultFromScode(MAPI_E_NOT_FOUND);
  2080. }
  2081. }
  2082. // We didn't find the issuer, so try the root store
  2083. hr = OpenSysCertStore(phcsIssuerStore, &hCryptProvider, cszROOTCertStore);
  2084. if (hrSuccess == hr)
  2085. {
  2086. // Get the issuer cert context
  2087. dwFlags = 0;
  2088. *ppccIssuerCertContext = gpfnCertGetIssuerCertificateFromStore(
  2089. *phcsIssuerStore,
  2090. pccCertContext,
  2091. NULL,
  2092. &dwFlags);
  2093. if (NULL != *ppccIssuerCertContext)
  2094. {
  2095. goto out;
  2096. }
  2097. else
  2098. {
  2099. goto error;
  2100. }
  2101. }
  2102. out:
  2103. // Make sure we didn't get back the same cert (ie it was self-signed).
  2104. if (hrSuccess == hr)
  2105. {
  2106. // First compare sizes since that is faster.
  2107. if (pccCertContext->cbCertEncoded == (*ppccIssuerCertContext)->cbCertEncoded)
  2108. {
  2109. // Sizes are the same, now compare the encoded cert blobs
  2110. if (0 == memcmp(
  2111. pccCertContext->pbCertEncoded,
  2112. (*ppccIssuerCertContext)->pbCertEncoded,
  2113. pccCertContext->cbCertEncoded))
  2114. {
  2115. // Certs are identical. There is no issuer.
  2116. goto error;
  2117. }
  2118. }
  2119. }
  2120. return hr;
  2121. error:
  2122. CloseCertStore(*phcsIssuerStore, 0);
  2123. *phcsIssuerStore = NULL;
  2124. return ResultFromScode(MAPI_E_NOT_FOUND);
  2125. }
  2126. /***************************************************************************
  2127. Name : HrBuildCertSBinaryData
  2128. Purpose : Takes as input all the data needed for a cert entry
  2129. in PR_USER_X509_CERTIFICATE and returns a pointer to
  2130. memory that contains all the input data in the correct
  2131. format to be plugged in to the lpb member of an SBinary
  2132. structure. This memory should be Freed by the caller.
  2133. Parameters: bIsDefault - TRUE if this is the default cert
  2134. pblobCertThumbPrint - The actual certificate thumbprint
  2135. pblobSymCaps - symcaps blob
  2136. ftSigningTime - Signing time
  2137. lpObject - object to alloc more onto, or NULL to LocalAlloc
  2138. lplpbData - receives the buffer with the data
  2139. lpcbData - receives size of the data
  2140. Returns : HRESULT
  2141. Comment :
  2142. ***************************************************************************/
  2143. HRESULT HrBuildCertSBinaryData(
  2144. BOOL bIsDefault,
  2145. BOOL fIsThumbprint,
  2146. PCRYPT_DIGEST_BLOB pPrint,
  2147. BLOB * pSymCaps,
  2148. FILETIME ftSigningTime,
  2149. LPVOID lpObject,
  2150. LPBYTE FAR* lplpbData,
  2151. ULONG FAR* lpcbData)
  2152. {
  2153. WORD cbDefault, cbPrint;
  2154. DWORD cbSymCaps;
  2155. HRESULT hr = S_OK;
  2156. LPCERTTAGS lpCurrentTag;
  2157. ULONG cbSize, cProps;
  2158. LPBYTE lpb = NULL;
  2159. cbDefault = sizeof(bIsDefault);
  2160. cbPrint = (WORD) pPrint->cbData;
  2161. cbSymCaps = pSymCaps ? pSymCaps->cbSize : 0;
  2162. cProps = 2;
  2163. cbSize = cbDefault + cbPrint;
  2164. if (cbSymCaps) {
  2165. cProps++;
  2166. cbSize += cbSymCaps;
  2167. }
  2168. if (ftSigningTime.dwLowDateTime || ftSigningTime.dwHighDateTime) {
  2169. cProps++;
  2170. cbSize += sizeof(FILETIME);
  2171. }
  2172. cbSize += (cProps * SIZE_CERTTAGS);
  2173. if (NULL == lpObject)
  2174. {
  2175. lpb = LocalAlloc(LMEM_ZEROINIT, cbSize);
  2176. if (NULL == lpb)
  2177. {
  2178. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  2179. goto exit;
  2180. }
  2181. }
  2182. else
  2183. {
  2184. SCODE sc;
  2185. sc = MAPIAllocateMore(cbSize, lpObject, (LPVOID *)&lpb);
  2186. if (sc)
  2187. {
  2188. hr = ResultFromScode(sc);
  2189. goto exit;
  2190. }
  2191. }
  2192. // Set the default property
  2193. lpCurrentTag = (LPCERTTAGS)lpb;
  2194. lpCurrentTag->tag = CERT_TAG_DEFAULT;
  2195. lpCurrentTag->cbData = SIZE_CERTTAGS + cbDefault;
  2196. memcpy(&lpCurrentTag->rgbData,
  2197. &bIsDefault,
  2198. cbDefault);
  2199. // Set the thumbprint property
  2200. lpCurrentTag = (LPCERTTAGS)((BYTE*)lpCurrentTag + lpCurrentTag->cbData);
  2201. lpCurrentTag->tag = fIsThumbprint ? CERT_TAG_THUMBPRINT : CERT_TAG_BINCERT;
  2202. lpCurrentTag->cbData = SIZE_CERTTAGS + cbPrint;
  2203. memcpy(&lpCurrentTag->rgbData, pPrint->pbData, cbPrint);
  2204. // Set the SymCaps property
  2205. if (cbSymCaps) {
  2206. lpCurrentTag = (LPCERTTAGS)((BYTE*)lpCurrentTag + lpCurrentTag->cbData);
  2207. lpCurrentTag->tag = CERT_TAG_SYMCAPS;
  2208. lpCurrentTag->cbData = (WORD) (SIZE_CERTTAGS + pSymCaps->cbSize);
  2209. memcpy(&lpCurrentTag->rgbData, pSymCaps->pBlobData, cbSymCaps);
  2210. }
  2211. // Signing time property
  2212. if (ftSigningTime.dwLowDateTime || ftSigningTime.dwHighDateTime) {
  2213. lpCurrentTag = (LPCERTTAGS)((BYTE*)lpCurrentTag + lpCurrentTag->cbData);
  2214. lpCurrentTag->tag = CERT_TAG_SIGNING_TIME;
  2215. lpCurrentTag->cbData = SIZE_CERTTAGS + sizeof(FILETIME);
  2216. memcpy(&lpCurrentTag->rgbData, &ftSigningTime, sizeof(FILETIME));
  2217. }
  2218. *lpcbData = cbSize;
  2219. *lplpbData = lpb;
  2220. exit:
  2221. return(hr);
  2222. }
  2223. //*******************************************************************
  2224. //
  2225. // FUNCTION: HrLDAPCertToMAPICert
  2226. //
  2227. // PURPOSE: Convert cert(s) returned from LDAP server to MAPI props.
  2228. // Two properties are required. The certs are placed in the
  2229. // WAB store, and all necessary indexing data is placed in
  2230. // PR_USER_X509_CERTIFICATE property. If this certificate
  2231. // didn't already exist in the WAB store, it's thumbprint is
  2232. // added to PR_WAB_TEMP_CERT_HASH so that these certs can
  2233. // be deleted from the store if the user cancels the add.
  2234. //
  2235. // PARAMETERS: lpPropArray - the prop array where the 2 props are stored
  2236. // ulX509Index - the index to the PR_USER_X509_CERTIFICATE prop
  2237. // ulTempCertIndex - the index to the PR_WAB_TEMP_CERT_HASH prop
  2238. // cbCert, lpCert - encoded cert data from the LDAP ppberval struct
  2239. // ulcCerts - the number of certs from the LDAP server
  2240. //
  2241. // RETURNS: HRESULT.
  2242. //
  2243. // HISTORY:
  2244. // 96/12/12 markdu Created.
  2245. //
  2246. //*******************************************************************
  2247. HRESULT HrLDAPCertToMAPICert(
  2248. LPSPropValue lpPropArray,
  2249. ULONG ulX509Index,
  2250. ULONG ulTempCertIndex,
  2251. ULONG cbCert,
  2252. PBYTE lpCert,
  2253. ULONG ulcCerts)
  2254. {
  2255. HRESULT hr = hrSuccess;
  2256. HRESULT hrOut = hrSuccess;
  2257. CRYPT_DIGEST_BLOB blobCertThumbPrint = {0};
  2258. PCCERT_CONTEXT pccCertToAdd;
  2259. PCCERT_CONTEXT pccCertFromStore;
  2260. HCERTSTORE hcsWABCertStore = NULL;
  2261. HCRYPTPROV hCryptProvider = 0;
  2262. PBYTE pbEncoded;
  2263. DWORD cbEncoded;
  2264. ULONG i;
  2265. ULONG cbData = 0;
  2266. LPBYTE lpbData = NULL;
  2267. FILETIME ftNull = {0, 0};
  2268. #ifdef PARAMETER_VALIDATION
  2269. ULONG ulcProps = max(ulX509Index, ulTempCertIndex);
  2270. if (ulcProps && IsBadReadPtr(lpPropArray, ulcProps * sizeof(SPropValue)))
  2271. {
  2272. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2273. }
  2274. /* if (ulcCerts && IsBadReadPtr(ppberval, ulcCerts * sizeof(struct berval)))
  2275. {
  2276. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2277. }
  2278. */
  2279. #endif // PARAMETER_VALIDATION
  2280. // Make sure we have the right kind of proparray.
  2281. if ((NULL == lpPropArray) ||
  2282. (PR_USER_X509_CERTIFICATE != lpPropArray[ulX509Index].ulPropTag) ||
  2283. (PR_WAB_TEMP_CERT_HASH != lpPropArray[ulTempCertIndex].ulPropTag))
  2284. {
  2285. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2286. }
  2287. // Load the crypto functions
  2288. if (FALSE == InitCryptoLib())
  2289. {
  2290. hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  2291. return hr;
  2292. }
  2293. // Open the store since we need to lookup certs
  2294. hr = OpenSysCertStore(&hcsWABCertStore, &hCryptProvider, cszWABCertStore);
  2295. if (hrSuccess != hr)
  2296. {
  2297. goto out;
  2298. }
  2299. // Add each cert to the props, unless it is a duplicate.
  2300. for (i=0;i<ulcCerts;i++)
  2301. {
  2302. // Convert the cert into a form we can deal with.
  2303. // BUGBUG this assumes the cert is DER encoded.
  2304. pbEncoded = lpCert; //(PBYTE)ppberval[i]->bv_val;
  2305. cbEncoded = cbCert; //(DWORD)ppberval[i]->bv_len;
  2306. // Get a context for the cert so we can get the thumbprint
  2307. pccCertToAdd = gpfnCertCreateCertificateContext(
  2308. X509_ASN_ENCODING,
  2309. pbEncoded,
  2310. cbEncoded);
  2311. if (NULL == pccCertToAdd)
  2312. {
  2313. hr = GetLastError();
  2314. goto out;
  2315. }
  2316. // Get the thumbprint for this cert.
  2317. hr = GetCertThumbPrint(
  2318. pccCertToAdd,
  2319. &blobCertThumbPrint);
  2320. if (hrSuccess != hr)
  2321. {
  2322. goto out;
  2323. }
  2324. // See if this cert is in the store already. If it is, we don't want to
  2325. // add it to the temp property for deletion later.
  2326. pccCertFromStore = gpfnCertFindCertificateInStore(
  2327. hcsWABCertStore,
  2328. X509_ASN_ENCODING,
  2329. 0,
  2330. CERT_FIND_HASH,
  2331. (void *)&blobCertThumbPrint,
  2332. NULL);
  2333. if (NULL == pccCertFromStore)
  2334. {
  2335. BOOL fRet;
  2336. // Add the cert to the store
  2337. fRet = gpfnCertAddEncodedCertificateToStore(
  2338. hcsWABCertStore,
  2339. X509_ASN_ENCODING,
  2340. pbEncoded,
  2341. cbEncoded,
  2342. CERT_STORE_ADD_NEW,
  2343. NULL);
  2344. if (FALSE == fRet)
  2345. {
  2346. hr = GetLastError();
  2347. goto out;
  2348. }
  2349. // Add the thumbprint to the temp prop so we can delete it later if the user cancels.
  2350. hr = AddPropToMVPBin(
  2351. lpPropArray,
  2352. ulTempCertIndex,
  2353. blobCertThumbPrint.pbData,
  2354. blobCertThumbPrint.cbData,
  2355. TRUE);
  2356. if (hrSuccess != hr)
  2357. {
  2358. goto out;
  2359. }
  2360. }
  2361. else
  2362. {
  2363. // We don't need to add this one to the store.
  2364. gpfnCertFreeCertificateContext(pccCertFromStore);
  2365. }
  2366. // Pack up all the cert data
  2367. cbData = 0;
  2368. hr = HrBuildCertSBinaryData(
  2369. FALSE,
  2370. TRUE,
  2371. &blobCertThumbPrint,
  2372. NULL, // SymCaps blob
  2373. ftNull, // Signing time
  2374. NULL, // This NULL means lpbData is allocated with LocalAlloc()
  2375. &lpbData,
  2376. &cbData);
  2377. if ((hrSuccess != hr) || (0 == cbData))
  2378. {
  2379. goto out;
  2380. }
  2381. // Add the cert data to the real cert prop.
  2382. hr = AddPropToMVPBin(
  2383. lpPropArray,
  2384. ulX509Index,
  2385. lpbData,
  2386. cbData,
  2387. TRUE);
  2388. if (hrSuccess != hr)
  2389. {
  2390. goto out;
  2391. }
  2392. // Add the trust for this LDAP cert to the pstore
  2393. // (doesn't have to be done because we won't trust this
  2394. // certificate by default)
  2395. // This is the way it was, wonder if that is correct
  2396. // (t-erikne)
  2397. // Free the cert context so we can do the next one.
  2398. gpfnCertFreeCertificateContext(pccCertToAdd);
  2399. pccCertToAdd = NULL;
  2400. LocalFreeAndNull(&lpbData);
  2401. cbData = 0;
  2402. // Also free the blobCertThumbPrint.pbData which is allocated with LocalAlloc()
  2403. LocalFreeAndNull(&(blobCertThumbPrint.pbData));
  2404. blobCertThumbPrint.cbData = 0;
  2405. }
  2406. out:
  2407. // Both blobCertThumbPrint.pbData and lpbData above are allocated using LocalAlloc()
  2408. // Be sure and free this memory.
  2409. LocalFreeAndNull(&lpbData);
  2410. LocalFreeAndNull(&(blobCertThumbPrint.pbData));
  2411. // Destroy any data we created if the function failed.
  2412. if (hrSuccess != hr)
  2413. {
  2414. lpPropArray[ulX509Index].ulPropTag = PR_NULL;
  2415. lpPropArray[ulTempCertIndex].ulPropTag = PR_NULL;
  2416. }
  2417. // Free the cert context. Ignore errors since there is nothing we can do.
  2418. if (NULL != pccCertToAdd)
  2419. {
  2420. gpfnCertFreeCertificateContext(pccCertToAdd);
  2421. }
  2422. // Close the cert store.
  2423. hrOut = CloseCertStore(hcsWABCertStore, hCryptProvider);
  2424. // If an error occurred in the function body, return that instead of
  2425. // any errors that occurred here in cleanup.
  2426. if (hrSuccess == hr)
  2427. {
  2428. hr = hrOut;
  2429. }
  2430. return hr;
  2431. }
  2432. //*******************************************************************
  2433. //
  2434. // FUNCTION: HrRemoveCertsFromWABStore
  2435. //
  2436. // PURPOSE: Remove the certs whose thumbprints are in the supplied
  2437. // PR_WAB_TEMP_CERT_HASH property.
  2438. //
  2439. // PARAMETERS: lpPropValue - the PR_WAB_TEMP_CERT_HASH property
  2440. //
  2441. // RETURNS: HRESULT.
  2442. //
  2443. // HISTORY:
  2444. // 96/12/13 markdu Created.
  2445. //
  2446. //*******************************************************************
  2447. HRESULT HrRemoveCertsFromWABStore(
  2448. LPSPropValue lpPropValue)
  2449. {
  2450. HRESULT hr = hrSuccess;
  2451. HRESULT hrOut = hrSuccess;
  2452. CRYPT_DIGEST_BLOB blobCertThumbPrint;
  2453. PCCERT_CONTEXT pccCertContext;
  2454. HCERTSTORE hcsWABCertStore = NULL;
  2455. HCRYPTPROV hCryptProvider = 0;
  2456. ULONG i;
  2457. ULONG ulcCerts;
  2458. BOOL fRet;
  2459. #ifdef PARAMETER_VALIDATION
  2460. if (IsBadReadPtr(lpPropValue, sizeof(SPropValue)))
  2461. {
  2462. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2463. }
  2464. #endif // PARAMETER_VALIDATION
  2465. // Make sure we have the right kind of proparray.
  2466. if ((NULL == lpPropValue) ||
  2467. (PR_WAB_TEMP_CERT_HASH != lpPropValue->ulPropTag))
  2468. {
  2469. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2470. }
  2471. // Count the number of certs in the input.
  2472. ulcCerts = lpPropValue->Value.MVbin.cValues;
  2473. if (0 == ulcCerts)
  2474. {
  2475. return hr;
  2476. }
  2477. // Load the crypto functions
  2478. if (FALSE == InitCryptoLib())
  2479. {
  2480. hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  2481. return hr;
  2482. }
  2483. // Open the store since we need to delete certs
  2484. hr = OpenSysCertStore(&hcsWABCertStore, &hCryptProvider, cszWABCertStore);
  2485. if (hrSuccess != hr)
  2486. {
  2487. return hr;
  2488. }
  2489. // Delete each cert.
  2490. for (i=0;i<ulcCerts;i++)
  2491. {
  2492. // Get the thumbprint from the propval.
  2493. blobCertThumbPrint.cbData = lpPropValue->Value.MVbin.lpbin[i].cb;
  2494. blobCertThumbPrint.pbData = lpPropValue->Value.MVbin.lpbin[i].lpb;
  2495. // Get the certificate from the WAB store using the thumbprint
  2496. // If we don't find the cert, ignore it and go on to the next one.
  2497. pccCertContext = gpfnCertFindCertificateInStore(
  2498. hcsWABCertStore,
  2499. X509_ASN_ENCODING,
  2500. 0,
  2501. CERT_FIND_HASH,
  2502. (void *)&blobCertThumbPrint,
  2503. NULL);
  2504. if (NULL != pccCertContext)
  2505. {
  2506. // Delete the cert
  2507. fRet = gpfnCertDeleteCertificateFromStore(pccCertContext);
  2508. if (FALSE == fRet)
  2509. {
  2510. hr = HrGetLastError();
  2511. goto out;
  2512. }
  2513. }
  2514. }
  2515. out:
  2516. // Close the cert store.
  2517. hrOut = CloseCertStore(hcsWABCertStore, hCryptProvider);
  2518. // If an error occurred in the function body, return that instead of
  2519. // any errors that occurred here in cleanup.
  2520. if (hrSuccess == hr)
  2521. {
  2522. hr = hrOut;
  2523. }
  2524. return hr;
  2525. }
  2526. //*******************************************************************
  2527. //
  2528. // FUNCTION: IsCertExpired
  2529. //
  2530. // PURPOSE: Check the cert info to see if it is expired or not yet valid.
  2531. //
  2532. // PARAMETERS: pCertInfo - Cert to verify
  2533. //
  2534. // RETURNS: TRUE if cert is expired, FALSE otherwise.
  2535. //
  2536. // HISTORY:
  2537. // 96/12/16 markdu Created.
  2538. // 98/03/225 brucek Use CAPI fn and be a little lenient on the start time.
  2539. //
  2540. //*******************************************************************
  2541. #define TIME_DELTA_SECONDS 600 // 10 minutes in seconds
  2542. #define FILETIME_SECOND 10000000 // 100ns intervals per second
  2543. HRESULT IsCertExpired(
  2544. PCERT_INFO pCertInfo)
  2545. {
  2546. LONG lRet;
  2547. FILETIME ftDelta;
  2548. __int64 i64Delta;
  2549. __int64 i64Offset;
  2550. FILETIME ftNow;
  2551. Assert(pCertInfo);
  2552. lRet = gpfnCertVerifyTimeValidity(NULL, pCertInfo);
  2553. if (lRet < 0) {
  2554. // Get the current time in filetime format so we can add the offset
  2555. GetSystemTimeAsFileTime(&ftNow);
  2556. i64Delta = ftNow.dwHighDateTime;
  2557. i64Delta = i64Delta << 32;
  2558. i64Delta += ftNow.dwLowDateTime;
  2559. // Add the offset into the original time to get us a new time to check
  2560. i64Offset = FILETIME_SECOND;
  2561. i64Offset *= TIME_DELTA_SECONDS;
  2562. i64Delta += i64Offset;
  2563. ftDelta.dwLowDateTime = (ULONG)i64Delta & 0xFFFFFFFF;
  2564. ftDelta.dwHighDateTime = (ULONG)(i64Delta >> 32);
  2565. lRet = gpfnCertVerifyTimeValidity(&ftDelta, pCertInfo);
  2566. }
  2567. return(lRet != 0);
  2568. }
  2569. //*******************************************************************
  2570. //
  2571. // FUNCTION: IsCertRevoked
  2572. //
  2573. // PURPOSE: Check the cert info to see if it is revoked.
  2574. //
  2575. // PARAMETERS: pCertInfo - Cert to verify
  2576. //
  2577. // RETURNS: TRUE if cert is revoked, FALSE otherwise.
  2578. //
  2579. // HISTORY:
  2580. // 96/12/16 markdu Created.
  2581. //
  2582. //*******************************************************************
  2583. HRESULT IsCertRevoked(
  2584. PCERT_INFO pCertInfo)
  2585. {
  2586. Assert(pCertInfo);
  2587. // Determine if cert has been revoked
  2588. // BUGBUG How to do this?
  2589. return FALSE;
  2590. }
  2591. //*******************************************************************
  2592. //
  2593. // FUNCTION: ReadDataFromFile
  2594. //
  2595. // PURPOSE: Read data from a file.
  2596. //
  2597. // PARAMETERS: lpszFileName - name of file containing the data to be read
  2598. // ppbData - receives the data that is read
  2599. // pcbData - receives the size of the data that is read
  2600. //
  2601. // RETURNS: HRESULT
  2602. //
  2603. // HISTORY:
  2604. // 96/12/16 markdu Created.
  2605. //
  2606. //*******************************************************************
  2607. HRESULT ReadDataFromFile(
  2608. LPTSTR lpszFileName,
  2609. PBYTE* ppbData,
  2610. PDWORD pcbData)
  2611. {
  2612. HRESULT hr = hrSuccess;
  2613. BOOL fRet;
  2614. HANDLE hFile = 0;
  2615. DWORD cbFile;
  2616. DWORD cbData;
  2617. PBYTE pbData = 0;
  2618. if ((NULL == ppbData) || (NULL == pcbData))
  2619. {
  2620. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2621. }
  2622. // Open the file and find out how big it is
  2623. hFile = CreateFile(
  2624. lpszFileName,
  2625. GENERIC_READ,
  2626. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2627. NULL,
  2628. OPEN_EXISTING,
  2629. 0,
  2630. NULL);
  2631. if(INVALID_HANDLE_VALUE == hFile)
  2632. {
  2633. hr = ResultFromScode(MAPI_E_DISK_ERROR);
  2634. goto error;
  2635. }
  2636. cbData = GetFileSize(hFile, NULL);
  2637. if (0xFFFFFFFF == cbData)
  2638. {
  2639. hr = ResultFromScode(MAPI_E_DISK_ERROR);
  2640. goto error;
  2641. }
  2642. IF_WIN32(pbData = (BYTE *)LocalAlloc(LMEM_ZEROINIT, cbData);)
  2643. IF_WIN16(pbData = (PBYTE)LocalAlloc(LMEM_ZEROINIT, cbData);)
  2644. if (NULL == pbData)
  2645. {
  2646. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  2647. goto error;
  2648. }
  2649. fRet = ReadFile(
  2650. hFile, // handle of file to read
  2651. pbData, // address of buffer that receives data
  2652. cbData, // number of bytes to read
  2653. &cbFile, // address of number of bytes read
  2654. NULL // address of structure for data
  2655. );
  2656. if (FALSE == fRet)
  2657. {
  2658. hr = ResultFromScode(MAPI_E_DISK_ERROR);
  2659. goto error;
  2660. }
  2661. if (cbData != cbFile)
  2662. {
  2663. hr = ResultFromScode(MAPI_E_CALL_FAILED);
  2664. goto error;
  2665. }
  2666. *ppbData = pbData;
  2667. *pcbData = cbData;
  2668. out:
  2669. if (hFile)
  2670. {
  2671. IF_WIN32(CloseHandle(hFile);) IF_WIN16(CloseFile(hFile);)
  2672. }
  2673. return hr;
  2674. error:
  2675. // BUGBUG some of the GetLastError calls above may not have worked.
  2676. if (hrSuccess == hr)
  2677. {
  2678. hr = ResultFromScode(MAPI_E_CALL_FAILED);
  2679. }
  2680. goto out;
  2681. }
  2682. //*******************************************************************
  2683. //
  2684. // FUNCTION: GetIssuerName
  2685. //
  2686. // PURPOSE: Wraps the several calls that one can make to try to
  2687. // get a usable name from a certificate. Esp in the
  2688. // case of self-signed certs, the issuer may just have a
  2689. // common name.
  2690. //
  2691. // PARAMETERS: lplpszIssuerName - OUT, for the name, NULL on err
  2692. // pCertInfo - IN, place from which to retrieve the data
  2693. //
  2694. // RETURNS: HRESULT.
  2695. //
  2696. // HISTORY:
  2697. // 97/02/04 t-erikne Created.
  2698. //
  2699. //*******************************************************************
  2700. HRESULT GetIssuerName(
  2701. LPTSTR FAR * lplpszIssuerName,
  2702. PCERT_INFO pCertInfo)
  2703. {
  2704. HRESULT hr;
  2705. Assert(lplpszIssuerName);
  2706. *lplpszIssuerName = '\000';
  2707. hr = GetAttributeString(
  2708. lplpszIssuerName,
  2709. pCertInfo->Issuer.pbData,
  2710. pCertInfo->Issuer.cbData,
  2711. szOID_ORGANIZATION_NAME);
  2712. if (hrSuccess != hr)
  2713. if (MAPI_E_NOT_FOUND == hr)
  2714. hr = GetAttributeString(
  2715. lplpszIssuerName,
  2716. pCertInfo->Issuer.pbData,
  2717. pCertInfo->Issuer.cbData,
  2718. szOID_COMMON_NAME);
  2719. return hr;
  2720. }
  2721. //*******************************************************************
  2722. //
  2723. // FUNCTION: HrGetTrustState
  2724. //
  2725. // PURPOSE: For newly imported certs, need to determine if an
  2726. // issuer exists for this cert or not ...
  2727. //
  2728. // HISTORY:
  2729. // 2/17/97 t-erikne created
  2730. // 7/02/97 t-erikne updated to WinTrust
  2731. //
  2732. //*******************************************************************
  2733. HRESULT HrGetTrustState(
  2734. HWND hwndParent,
  2735. PCCERT_CONTEXT pcCert,
  2736. DWORD * pdwTrust)
  2737. {
  2738. HRESULT hr;
  2739. DWORD dwErr;
  2740. GUID guidAction = CERT_CERTIFICATE_ACTION_VERIFY;
  2741. // CERT_VERIFY_CERTIFICATE_TRUST cvct = {0};
  2742. CERT_VERIFY_CERTIFICATE_TRUST trust = {0};
  2743. WINTRUST_BLOB_INFO blob = {0};
  2744. WINTRUST_DATA data = {0};
  2745. if (!(pcCert || pdwTrust))
  2746. return E_INVALIDARG;
  2747. data.cbStruct = sizeof(WINTRUST_DATA);
  2748. data.pPolicyCallbackData = NULL;
  2749. data.pSIPClientData = NULL;
  2750. data.dwUIChoice = WTD_UI_NONE;
  2751. data.fdwRevocationChecks = WTD_REVOKE_NONE;
  2752. data.dwUnionChoice = WTD_CHOICE_BLOB;
  2753. data.pBlob = &blob;
  2754. blob.cbStruct = sizeof(WINTRUST_BLOB_INFO);
  2755. blob.pcwszDisplayName = NULL;
  2756. blob.cbMemObject = sizeof(trust);
  2757. blob.pbMemObject = (LPBYTE)&trust;
  2758. trust.cbSize = sizeof(trust);
  2759. trust.pccert = pcCert;
  2760. trust.pdwErrors = pdwTrust;
  2761. trust.pszUsageOid = szOID_PKIX_KP_EMAIL_PROTECTION;
  2762. trust.dwIgnoreErr =
  2763. CERT_VALIDITY_NO_CRL_FOUND |
  2764. CERT_VALIDITY_UNKNOWN_CRITICAL_EXTENSION;
  2765. return (0 <= WinVerifyTrust(hwndParent, &guidAction, &data))
  2766. ? S_OK
  2767. : E_FAIL;
  2768. }
  2769. HRESULT DeleteCertStuff(LPADRBOOK lpAdrBook,
  2770. LPENTRYID lpEntryID,
  2771. ULONG cbEntryID)
  2772. {
  2773. SizedSPropTagArray(1, ptaCert)=
  2774. { 1, {PR_USER_X509_CERTIFICATE} };
  2775. LPMAPIPROP lpMailUser = NULL;
  2776. HRESULT hr = E_FAIL;
  2777. LPSPropValue ppv = NULL;
  2778. ULONG ul;
  2779. BLOB thumbprint;
  2780. LPWSTR szW = NULL;
  2781. //N2 not sure what to do yet about trust removal
  2782. goto out;
  2783. if (HR_FAILED(hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
  2784. cbEntryID, // cbEntryID
  2785. lpEntryID, // entryid
  2786. NULL, // interface
  2787. 0, // ulFlags
  2788. &ul, // returned object type
  2789. (LPUNKNOWN *)&lpMailUser)))
  2790. {
  2791. // Failed! Hmmm.
  2792. DebugTraceResult( TEXT("DeleteCertStuff: IAB->OpenEntry:"), hr);
  2793. goto out;
  2794. }
  2795. Assert(lpMailUser);
  2796. if(MAPI_DISTLIST == ul)
  2797. {
  2798. hr = S_OK;
  2799. goto out;
  2800. }
  2801. if (HR_FAILED(hr = lpMailUser->lpVtbl->GetProps(lpMailUser,
  2802. (LPSPropTagArray)&ptaCert, // lpPropTagArray
  2803. MAPI_UNICODE, // ulFlags
  2804. &ul, // how many properties were there?
  2805. &ppv)))
  2806. {
  2807. DebugTraceResult( TEXT("DeleteCertStuff: IAB->GetProps:"), hr);
  2808. goto out;
  2809. }
  2810. if (MAPI_W_ERRORS_RETURNED == hr)
  2811. {
  2812. if (PROP_TYPE(ppv->ulPropTag) == PT_ERROR)
  2813. // the property doesn't exist, so we have no certs
  2814. // for this entry
  2815. hr = S_OK; // cool
  2816. goto out;
  2817. }
  2818. else if (1 != ul)
  2819. {
  2820. hr = E_FAIL;
  2821. goto out;
  2822. }
  2823. else if (FAILED(hr))
  2824. goto out;
  2825. // Now need to loop over the SBinary structures to look at each cert
  2826. for (ul = 0; ul < ppv->Value.MVbin.cValues; ul++)
  2827. {
  2828. LPCERTTAGS lpCurrentTag, lpTempTag;
  2829. LPBYTE lpbTagEnd;
  2830. lpCurrentTag = (LPCERTTAGS)ppv->Value.MVbin.lpbin[ul].lpb;
  2831. lpbTagEnd = (LPBYTE)lpCurrentTag + ppv->Value.MVbin.lpbin[ul].cb;
  2832. // either this is the last cert or it is the default, so get the data
  2833. // scan for "thumbprint" tag
  2834. while ((LPBYTE)lpCurrentTag < lpbTagEnd && (CERT_TAG_THUMBPRINT != lpCurrentTag->tag)) {
  2835. lpTempTag = lpCurrentTag;
  2836. lpCurrentTag = (LPCERTTAGS)((BYTE*)lpCurrentTag + lpCurrentTag->cbData);
  2837. if (lpCurrentTag == lpTempTag) {
  2838. AssertSz(FALSE, TEXT("Bad CertTag in PR_USER_X509_CERTIFICATE\n"));
  2839. break; // Safety valve, prevent infinite loop if bad data
  2840. }
  2841. }
  2842. if (CERT_TAG_THUMBPRINT == lpCurrentTag->tag)
  2843. {
  2844. // we need to remove the trust blob
  2845. #ifdef DEBUG
  2846. if (SUCCEEDED(hr))
  2847. DebugTraceResult( TEXT("DeleteCertStuff: trust blob deleted -- "), hr);
  2848. else
  2849. DebugTraceResult( TEXT("DeleteCertStuff: FAILED trust blob delete --"), hr);
  2850. #endif
  2851. }
  2852. else
  2853. {
  2854. // no data, so go to next cert
  2855. DebugTrace(TEXT("DeleteCertStuff: odd... no data for the cert\n"));
  2856. continue;
  2857. }
  2858. } // for loop over certs
  2859. out:
  2860. if (ppv)
  2861. MAPIFreeBuffer(ppv);
  2862. if (lpMailUser)
  2863. lpMailUser->lpVtbl->Release(lpMailUser);
  2864. return hr;
  2865. }
  2866. PCCERT_CONTEXT WabGetCertFromThumbprint(CRYPT_DIGEST_BLOB thumbprint)
  2867. {
  2868. HCERTSTORE hcWAB;
  2869. PCCERT_CONTEXT pcRet;
  2870. hcWAB = CertOpenStore(
  2871. #ifdef UNICODE
  2872. CERT_STORE_PROV_SYSTEM_W,
  2873. #else
  2874. CERT_STORE_PROV_SYSTEM_A,
  2875. #endif
  2876. X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, cszWABCertStore);
  2877. if (hcWAB)
  2878. {
  2879. pcRet = CertFindCertificateInStore(
  2880. hcWAB,
  2881. X509_ASN_ENCODING,
  2882. 0, //dwFindFlags
  2883. CERT_FIND_HASH,
  2884. (void *)&thumbprint,
  2885. NULL);
  2886. CertCloseStore(hcWAB, 0);
  2887. }
  2888. else
  2889. {
  2890. pcRet = NULL;
  2891. }
  2892. return pcRet;
  2893. }