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.

5962 lines
205 KiB

  1. /*
  2. ** s e c u t i l . c p p
  3. **
  4. ** Purpose:
  5. ** Implementation of a class to wrap around CAPI functionality
  6. **
  7. ** History
  8. ** 1/12/97: (t-erikne) Recreated after VC ate the file. yum.
  9. ** 1/10/97: (t-erikne) Created.
  10. **
  11. ** Copyright (C) Microsoft Corp. 1997.
  12. */
  13. /////////////////////////////////////////////////////////////////////////////
  14. //
  15. // Depends on
  16. //
  17. #include "pch.hxx"
  18. #include "ipab.h"
  19. #include "secutil.h"
  20. #include <certs.h>
  21. #include <imsgcont.h>
  22. #include "sechtml.h"
  23. #include <ibodyobj.h>
  24. #include <wincrypt.h>
  25. #include <cryptdlg.h>
  26. #include <capi.h>
  27. #include "demand.h"
  28. #include "storecb.h"
  29. #include "shlwapip.h"
  30. #include "mailutil.h"
  31. #include "menuutil.h"
  32. #include "menures.h"
  33. #include "mimeolep.h"
  34. #include "msgprop.h"
  35. #include "shared.h"
  36. #include "htmlhelp.h"
  37. #include "seclabel.h"
  38. #include "iheader.h"
  39. #include "browser.h"
  40. #include "taskutil.h"
  41. #define szOID_MSFT_Defaults "1.3.6.1.4.1.311.16.3"
  42. #define sz_OEMS_ContIDPrefix "797374"
  43. #define PROP_ERROR(prop) (PROP_TYPE(prop.ulPropTag) == PT_ERROR)
  44. #define S_DUPLICATE_FOUND MAKE_MAPI_S(0x700)
  45. extern INT_PTR CALLBACK CertErrorDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  46. extern INT_PTR CALLBACK CertWarnDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  47. HRESULT HrBuildAndVerifyCerts(IMimeMessageTree * pTree, DWORD * pcCert, PCX509CERT ** prgpccert,
  48. PCCERT_CONTEXT pccertSender, IImnAccount *pAccount);
  49. /////////////////////////////////////////////////////////////////////////////
  50. //
  51. // Private structures, macros
  52. //
  53. static const TCHAR s_szHTMLMIME[] =
  54. "Content-Type: text/html\r\n\r\n";
  55. // Public constants
  56. const BYTE c_RC2_40_ALGORITHM_ID[] =
  57. {0x30, 0x0F, 0x30, 0x0D, 0x06, 0x08, 0x2A, 0x86,
  58. 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x02, 0x02, 0x01,
  59. 0x28};
  60. const ULONG cbRC2_40_ALGORITHM_ID = 0x11; // Must be 11 hex to match size!
  61. #define CONTENTID_SIZE 50
  62. ///////////////// CAPI Enhancement code
  63. #ifdef SMIME_V3
  64. #define ASN1_ERR_FIRST 0x80093001L
  65. #define ASN1_ERR_LAST 0x800931FFL
  66. #endif // SMIME_V3
  67. typedef struct tagFilterInfo
  68. {
  69. TCHAR *szEmail;
  70. BOOL fEncryption;
  71. DWORD dwFlags;
  72. } ACCTFILTERINFO;
  73. CRYPT_ENCODE_PARA CryptEncodeAlloc = {
  74. sizeof(CRYPT_ENCODE_PARA), CryptAllocFunc, CryptFreeFunc
  75. };
  76. CRYPT_DECODE_PARA CryptDecodeAlloc = {
  77. sizeof(CRYPT_DECODE_PARA), CryptAllocFunc, CryptFreeFunc
  78. };
  79. #define FILETIME_SECOND 10000000 // 100ns intervals per second
  80. #define TIME_DELTA_SECONDS 600 // 10 minutes in seconds
  81. /////////////////////////////////////////////////////////////////////////////
  82. //
  83. // Prototypes
  84. //
  85. static int _CompareCertAndSenderEmail(LPMIMEMESSAGE pMsg, IMimeSecurity *pSMime, PCX509CERT pCert);
  86. static HRESULT _RemoveSecurity(LPMIMEMESSAGE pMsg, HWND hWnd);
  87. static HRESULT _ValidateAndTrust(HWND hwndOwner, IMimeSecurity *pSMime, IMimeMessage *pMsg);
  88. static BOOL _IsMaskedBodySecure(LPMIMEMESSAGE pMsg, HBODY hBodyToCheck, DWORD dwMask);
  89. #ifdef SMIME_V3
  90. static HRESULT _HrPrepSecureMsgForSending(HWND hwnd, LPMIMEMESSAGE pMsg, IImnAccount *pAccount, BOOL *pfHaveSenderCert, BOOL *fDontEncryptForSelf, IHeaderSite *pHeaderSite);
  91. #else
  92. static HRESULT _HrPrepSecureMsgForSending(HWND hwnd, LPMIMEMESSAGE pMsg, IImnAccount *pAccount, BOOL *pfHaveSenderCert, BOOL *fDontEncryptForSelf);
  93. #endif // SMIME_V3
  94. int GetNumMyCertForAccount(HWND hwnd, IImnAccount * pAccount, BOOL fEncrypt, HCERTSTORE hcMy, PCCERT_CONTEXT * ppcSave);
  95. /////////////////////////////////////////////////////////////////////////////
  96. //
  97. // Inlines
  98. //
  99. /* _IsMaskedBodySecure:
  100. **
  101. ** Purpose:
  102. ** Private function to allow the IsSigned, etc queries to work
  103. ** Takes:
  104. ** IN pMsg - message to query
  105. ** IN hBodyToCheck - body to query, HBODY_ROOT is valid
  106. ** IN dwMask - bitmask for MST_ result
  107. */
  108. inline BOOL _IsMaskedBodySecure(LPMIMEMESSAGE pMsg,
  109. HBODY hBodyToCheck,
  110. DWORD dwMask)
  111. {
  112. return (dwMask & DwGetSecurityOfMessage(pMsg, hBodyToCheck));
  113. }
  114. /////////////////////////////////////////////////////////////////////////////
  115. //
  116. // Functions
  117. //
  118. /* HrGetLastError
  119. **
  120. ** Purpose:
  121. ** Convert a GetLastError value to an HRESULT
  122. ** A failure HRESULT must have the high bit set.
  123. **
  124. ** Takes:
  125. ** none
  126. **
  127. ** Returns:
  128. ** HRESULT
  129. */
  130. HRESULT HrGetLastError(void)
  131. {
  132. DWORD error;
  133. HRESULT hr;
  134. error = GetLastError();
  135. if (error && ! (error & 0x80000000))
  136. hr = error | 0x80070000; // system error
  137. else
  138. hr = (HRESULT)error;
  139. return(hr);
  140. }
  141. //
  142. // Here we include a few constants and guids from the WAB API code.
  143. // This should probably be available somewhere in the WAB headers, but it
  144. // isn't currently.
  145. // From WABAPI code: _mapiprv.h
  146. // Generic internal entry ID structure
  147. #pragma warning (disable: 4200)
  148. typedef struct _MAPIEID {
  149. BYTE abFlags[4];
  150. MAPIUID mapiuid;
  151. BYTE bData[];
  152. } MAPI_ENTRYID, *LPMAPI_ENTRYID;
  153. #pragma warning (default: 4200)
  154. // From WABAPI code: _entryid.h
  155. enum _WAB_ENTRYID_TYPE {
  156. // Must not use 0, this value is invalid.
  157. WAB_PAB = 1,
  158. WAB_DEF_DL,
  159. WAB_DEF_MAILUSER,
  160. WAB_ONEOFF,
  161. WAB_ROOT,
  162. WAB_DISTLIST,
  163. WAB_CONTAINER,
  164. WAB_LDAP_CONTAINER,
  165. WAB_LDAP_MAILUSER
  166. };
  167. // From WABAPI code: entryid.c
  168. static UUID WABGUID = { /* d3ad91c0-9d51-11cf-a4a9-00aa0047faa4 */
  169. 0xd3ad91c0,
  170. 0x9d51,
  171. 0x11cf,
  172. {0xa4, 0xa9, 0x00, 0xaa, 0x00, 0x47, 0xfa, 0xa4}
  173. };
  174. static UUID MAPIGUID = { /* a41f2b81-a3be-1910-9d6e-00dd010f5402 */
  175. 0xa41f2b81,
  176. 0xa3be,
  177. 0x1910,
  178. {0x9d, 0x6e, 0x00, 0xdd, 0x01, 0x0f, 0x54, 0x02}
  179. };
  180. /***************************************************************************
  181. Name : IsWABOneOff
  182. Purpose : Is this WAB EntryID a one-off?
  183. Parameters: cbEntryID = size of lpEntryID.
  184. lpEntryID -> entryid to check.
  185. Returns : True if this is a WAB one-off entryid
  186. Comment :
  187. ***************************************************************************/
  188. BOOL IsWABOneOff(ULONG cbEntryID, LPENTRYID lpEntryID)
  189. {
  190. BYTE bType;
  191. LPMAPI_ENTRYID lpeid;
  192. LPBYTE lpData1, lpData2, lpData3;
  193. ULONG cbData1, cbData2;
  194. LPBYTE lpb;
  195. // First check... is it big enough?
  196. if (cbEntryID < sizeof(MAPI_ENTRYID) + sizeof(bType))
  197. return(FALSE);
  198. lpeid = (LPMAPI_ENTRYID)lpEntryID;
  199. // Next check... does it contain our GUID?
  200. /// MAPI One Off stuff
  201. if (! memcmp(&lpeid->mapiuid, &MAPIGUID, sizeof(MAPIGUID)))
  202. {
  203. lpb = lpeid->bData + sizeof(DWORD);
  204. bType = WAB_ONEOFF;
  205. }
  206. else if (! memcmp(&lpeid->mapiuid, &WABGUID, sizeof(WABGUID)))
  207. {
  208. lpb = lpeid->bData;
  209. bType = *lpb;
  210. lpb++;
  211. }
  212. else
  213. return(FALSE); // No match
  214. switch ((int)bType)
  215. {
  216. case WAB_ONEOFF:
  217. return(TRUE); // This is a WAB One-off
  218. break;
  219. case WAB_PAB:
  220. case WAB_DEF_DL:
  221. case WAB_DEF_MAILUSER:
  222. case WAB_LDAP_CONTAINER:
  223. case WAB_LDAP_MAILUSER:
  224. default:
  225. break; // Not a one-off
  226. }
  227. return(FALSE);
  228. }
  229. // enum for ADRENTRY props
  230. enum {
  231. irnPR_ENTRYID = 0,
  232. irnPR_DISPLAY_NAME,
  233. irnPR_EMAIL_ADDRESS,
  234. irnPR_OBJECT_TYPE,
  235. irnMax
  236. };
  237. // enum for Resolve props
  238. enum {
  239. irsPR_ENTRYID = 0,
  240. irsPR_EMAIL_ADDRESS,
  241. irsPR_CONTACT_EMAIL_ADDRESSES,
  242. irsPR_CONTACT_ADDRTYPES,
  243. irsPR_CONTACT_DEFAULT_ADDRESS_INDEX,
  244. irsPR_DISPLAY_NAME,
  245. irsPR_OBJECT_TYPE,
  246. irsPR_USER_X509_CERTIFICATE,
  247. irsMax
  248. };
  249. SizedSPropTagArray(1, ptaCert) = {1, {PR_USER_X509_CERTIFICATE}};
  250. SizedSPropTagArray(1, ptaEntryID) = {1, {PR_ENTRYID}};
  251. SizedSPropTagArray(irsMax, ptaResolve) = {irsMax,
  252. {
  253. PR_ENTRYID,
  254. PR_EMAIL_ADDRESS_W,
  255. PR_CONTACT_EMAIL_ADDRESSES_W,
  256. PR_CONTACT_ADDRTYPES_W,
  257. PR_CONTACT_DEFAULT_ADDRESS_INDEX,
  258. PR_DISPLAY_NAME_W,
  259. PR_OBJECT_TYPE,
  260. PR_USER_X509_CERTIFICATE
  261. }
  262. };
  263. /***************************************************************************
  264. Name : HrFindThumbprint
  265. Purpose : Find a matching entry with a certificate in the WAB
  266. Parameters: pAdrInfo -> ADRINFO structure for this contact
  267. lpWabal -> WABAL object
  268. lppspv -> returned data. Caller must WABFreeBuffer the returned pointer.
  269. Returns : HRESULT, MIME_E_SECURITY_NOCERT if not found
  270. Comment :
  271. ***************************************************************************/
  272. HRESULT HrFindThumbprintInWAB(ADRINFO * pAdrInfo, LPWABAL lpWabal, LPSPropValue * lppspv)
  273. {
  274. HRESULT hr = hrSuccess, hrReturn = MIME_E_SECURITY_NOCERT;
  275. LPADRBOOK lpAdrBook;
  276. LPADRLIST lpAdrList = NULL;
  277. ULONG ulObjectType;
  278. LPMAILUSER lpMailUser = NULL;
  279. SCODE sc;
  280. ULONG cProps = 0;
  281. LPSPropValue ppv = NULL;
  282. if (! (lpAdrBook = lpWabal->GetAdrBook())) // Don't release this!
  283. {
  284. Assert(lpAdrBook);
  285. return(MIME_E_SECURITY_NOCERT);
  286. }
  287. if (sc = lpWabal->AllocateBuffer(sizeof(ADRLIST) + 1 * sizeof(ADRENTRY), (LPVOID*)&lpAdrList))
  288. {
  289. hr = ResultFromScode(sc);
  290. goto exit;
  291. }
  292. lpAdrList->cEntries = 1;
  293. lpAdrList->aEntries[0].ulReserved1 = 0;
  294. lpAdrList->aEntries[0].cValues = irnMax;
  295. // Allocate the prop array for the ADRENTRY
  296. if (sc = lpWabal->AllocateBuffer(lpAdrList->aEntries[0].cValues * sizeof(SPropValue),
  297. (LPVOID*)&lpAdrList->aEntries[0].rgPropVals))
  298. {
  299. hr = ResultFromScode(sc);
  300. goto exit;
  301. }
  302. lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].ulPropTag = PR_ENTRYID;
  303. lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin.cb = 0;
  304. lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin.lpb = NULL;
  305. lpAdrList->aEntries[0].rgPropVals[irnPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
  306. lpAdrList->aEntries[0].rgPropVals[irnPR_OBJECT_TYPE].Value.l = MAPI_MAILUSER;
  307. if (pAdrInfo->lpwszDisplay)
  308. {
  309. lpAdrList->aEntries[0].rgPropVals[irnPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME_W;
  310. lpAdrList->aEntries[0].rgPropVals[irnPR_DISPLAY_NAME].Value.lpszW = pAdrInfo->lpwszDisplay;
  311. }
  312. else
  313. lpAdrList->aEntries[0].rgPropVals[irnPR_DISPLAY_NAME].ulPropTag = PR_NULL;
  314. if (pAdrInfo->lpwszAddress)
  315. {
  316. lpAdrList->aEntries[0].rgPropVals[irnPR_EMAIL_ADDRESS].ulPropTag = PR_EMAIL_ADDRESS_W;
  317. lpAdrList->aEntries[0].rgPropVals[irnPR_EMAIL_ADDRESS].Value.lpszW = pAdrInfo->lpwszAddress;
  318. }
  319. else
  320. lpAdrList->aEntries[0].rgPropVals[irnPR_EMAIL_ADDRESS].ulPropTag = PR_NULL;
  321. hr = lpAdrBook->ResolveName((ULONG)NULL, // hwnd
  322. WAB_RESOLVE_FIRST_MATCH | WAB_RESOLVE_LOCAL_ONLY | WAB_RESOLVE_ALL_EMAILS |
  323. WAB_RESOLVE_NO_ONE_OFFS | WAB_RESOLVE_NEED_CERT | WAB_RESOLVE_UNICODE,
  324. NULL,
  325. lpAdrList);
  326. switch (GetScode(hr))
  327. {
  328. case SUCCESS_SUCCESS: // Should be a resolved entry now
  329. if (lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].ulPropTag == PR_ENTRYID)
  330. {
  331. if (! (HR_FAILED(hr = lpAdrBook->OpenEntry(lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin.cb,
  332. (LPENTRYID)lpAdrList->aEntries[0].rgPropVals[irnPR_ENTRYID].Value.bin.lpb,
  333. NULL,
  334. MAPI_MODIFY, // ulFlags
  335. &ulObjectType,
  336. (LPUNKNOWN *)&(lpMailUser)))))
  337. {
  338. // Got the entry, Get the cert property.
  339. // NOTE: don't FreeBuffer the ppv. The caller will handle this.
  340. hr = lpMailUser->GetProps((LPSPropTagArray)&ptaCert, 0, &cProps, &ppv);
  341. if (HR_FAILED(hr) || ! cProps || ! ppv || PROP_ERROR(ppv[0]))
  342. {
  343. if (ppv)
  344. lpWabal->FreeBuffer(ppv);
  345. break;
  346. }
  347. // Got the cert prop
  348. // Fill in the return prop array with our new prop array
  349. *lppspv = ppv;
  350. hrReturn = hrSuccess;
  351. }
  352. }
  353. break;
  354. case MAPI_E_AMBIGUOUS_RECIP:
  355. // More than one match. This would be really weird since we specified WAB_RESOLVE_FIRST_MATCH
  356. Assert(FALSE);
  357. break;
  358. case MAPI_E_NOT_FOUND:
  359. DOUTL(DOUTL_CRYPT, "ResolveName to find entry with cert failed.");
  360. // no match with a cert
  361. break;
  362. case MAPI_E_USER_CANCEL:
  363. hrReturn = hr;
  364. break;
  365. default:
  366. break;
  367. }
  368. exit:
  369. if (lpAdrList)
  370. {
  371. for (ULONG iEntry = 0; iEntry < lpAdrList->cEntries; ++iEntry)
  372. if(lpAdrList->aEntries[iEntry].rgPropVals)
  373. lpWabal->FreeBuffer(lpAdrList->aEntries[iEntry].rgPropVals);
  374. lpWabal->FreeBuffer(lpAdrList);
  375. }
  376. if (lpMailUser)
  377. lpMailUser->Release();
  378. return(hr);
  379. }
  380. BOOL MatchCertEmailAddress(PCCERT_CONTEXT pcCert, LPTSTR szEmailAddress)
  381. {
  382. BOOL fRet = FALSE;
  383. LPSTR szCertEmail = SzGetCertificateEmailAddress(pcCert);
  384. if (szCertEmail)
  385. {
  386. fRet = !(BOOL(lstrcmpi(szCertEmail, szEmailAddress)));
  387. MemFree(szCertEmail);
  388. }
  389. #ifdef DEBUG
  390. if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
  391. // backdoor to avoid having to care about email addresses
  392. // Hold down the shift key while the Send is happening to
  393. // skip the address check and use the first one marked default
  394. fRet = TRUE;
  395. #endif
  396. return(fRet);
  397. }
  398. BOOL CompareCertHash(PCCERT_CONTEXT pCert,
  399. DWORD dwPropId, PCRYPT_HASH_BLOB pHash )
  400. {
  401. BYTE rgbHash[20];
  402. DWORD cbHash = 20;
  403. CertGetCertificateContextProperty(pCert,
  404. dwPropId,
  405. rgbHash,
  406. &cbHash);
  407. if (cbHash == pHash->cbData &&
  408. memcmp(rgbHash, pHash->pbData, cbHash) == 0) {
  409. return TRUE;
  410. }
  411. else {
  412. return FALSE;
  413. }
  414. }
  415. HRESULT HrUserSMimeCertCracker(LPBYTE pbIn, DWORD cbIn, HCERTSTORE hCertStoreCA,
  416. HCERTSTORE hCertStore, BOOL * pfDefault,
  417. PCCERT_CONTEXT * ppccert, BLOB * pSymCaps)
  418. {
  419. DWORD cb;
  420. DWORD cbCert;
  421. DWORD cbMaxCert;
  422. DWORD cbSMimeCaps;
  423. DWORD cCerts;
  424. DWORD cSigners;
  425. DWORD cval;
  426. DWORD dwDefaults=0;
  427. DWORD dwNortelAlg;
  428. BOOL f;
  429. HCERTSTORE hstoreMem = NULL;
  430. HCRYPTMSG hmsg;
  431. HRESULT hr=S_OK;
  432. ULONG i;
  433. PCRYPT_ATTRIBUTE pattr;
  434. PCRYPT_ATTRIBUTE pattrSymCaps = NULL;
  435. LPBYTE pbCert=NULL;
  436. LPBYTE pbData;
  437. LPBYTE pbSMimeCaps;
  438. PCCERT_CONTEXT pccert;
  439. PCCERT_CONTEXT pccertReturn = NULL;
  440. PCMSG_SIGNER_INFO pinfo;
  441. PCRYPT_RECIPIENT_ID prid = NULL;
  442. PSMIME_ENC_KEY_PREFERENCE pekp = NULL;
  443. hmsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, NULL,
  444. NULL, NULL);
  445. if (hmsg == 0)
  446. {
  447. return E_FAIL;
  448. }
  449. if (!CryptMsgUpdate(hmsg, pbIn, cbIn, TRUE))
  450. {
  451. return E_FAIL;
  452. }
  453. cb = sizeof(cSigners);
  454. if (!CryptMsgGetParam(hmsg, CMSG_SIGNER_COUNT_PARAM, 0, &cSigners, &cb) ||
  455. (cSigners == 0))
  456. {
  457. return E_FAIL;
  458. }
  459. Assert(cSigners == 1);
  460. if (!CryptMsgGetParam(hmsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &cb))
  461. {
  462. goto CryptError;
  463. }
  464. pinfo = (PCMSG_SIGNER_INFO) malloc(cb);
  465. f = CryptMsgGetParam(hmsg, CMSG_SIGNER_INFO_PARAM, 0, pinfo, &cb);
  466. Assert(f);
  467. // M00BUG -- verify signature on message
  468. for (i=0; i<pinfo->AuthAttrs.cAttr; i++)
  469. {
  470. pattr = &pinfo->AuthAttrs.rgAttr[i];
  471. if (strcmp(pattr->pszObjId, szOID_RSA_SMIMECapabilities) == 0)
  472. {
  473. Assert(pattr->cValue == 1);
  474. pattrSymCaps = pattr;
  475. }
  476. else if (strcmp(pattr->pszObjId, szOID_MSFT_Defaults) == 0)
  477. {
  478. Assert(pattr->cValue == 1);
  479. Assert(pattr->rgValue[0].cbData == 3);
  480. dwDefaults = pattr->rgValue[0].pbData[2];
  481. }
  482. else if (strcmp(pattr->pszObjId, szOID_Microsoft_Encryption_Cert) == 0)
  483. {
  484. Assert(pattr->cValue == 1);
  485. f = CryptDecodeObjectEx(X509_ASN_ENCODING,
  486. szOID_Microsoft_Encryption_Cert,
  487. pattr->rgValue[0].pbData,
  488. pattr->rgValue[0].cbData,
  489. CRYPT_DECODE_ALLOC_FLAG, 0,
  490. (LPVOID *) &prid, &cb);
  491. Assert(f);
  492. }
  493. else if (strcmp(pattr->pszObjId, szOID_SMIME_Encryption_Key_Preference) == 0)
  494. {
  495. Assert(pattr->cValue == 1);
  496. f = CryptDecodeObjectEx(X509_ASN_ENCODING,
  497. szOID_SMIME_Encryption_Key_Preference,
  498. pattr->rgValue[0].pbData,
  499. pattr->rgValue[0].cbData,
  500. CRYPT_DECODE_ALLOC_FLAG, 0,
  501. (LPVOID *) &pekp, &cb);
  502. Assert(f);
  503. }
  504. }
  505. if ((prid == NULL) && (pekp == NULL))
  506. goto Exit;
  507. // Enumerate all certs and pack into the structure
  508. cbCert = sizeof(cCerts);
  509. if (!CryptMsgGetParam(hmsg, CMSG_CERT_COUNT_PARAM, 0, &cCerts, &cbCert))
  510. {
  511. goto CryptError;
  512. }
  513. cbMaxCert = 0;
  514. for (i=0; i<cCerts; i++)
  515. {
  516. if (!CryptMsgGetParam(hmsg, CMSG_CERT_PARAM, i, NULL, &cbCert))
  517. {
  518. goto CryptError;
  519. }
  520. if (cbCert > cbMaxCert)
  521. cbMaxCert = cbCert;
  522. }
  523. pbCert = (LPBYTE) LocalAlloc(0, cbMaxCert);
  524. if (pbCert == NULL)
  525. {
  526. hr = E_OUTOFMEMORY;
  527. goto Exit;
  528. }
  529. hstoreMem = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, NULL, 0, NULL);
  530. if (hstoreMem == NULL)
  531. {
  532. hr = E_OUTOFMEMORY;
  533. goto Exit;
  534. }
  535. for (i=0; i<cCerts; i++)
  536. {
  537. BOOL fFoundEncryptCert;
  538. cb = cbMaxCert;
  539. if (!CryptMsgGetParam(hmsg, CMSG_CERT_PARAM, i, pbCert, &cb))
  540. {
  541. goto CryptError;
  542. }
  543. pccert = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cb);
  544. if (pccert == NULL)
  545. continue;
  546. fFoundEncryptCert = FALSE;
  547. if (pekp != NULL) {
  548. PCERT_ID pCertId = (PCERT_ID) &pekp->RecipientId;
  549. switch (pCertId->dwIdChoice) {
  550. case CERT_ID_ISSUER_SERIAL_NUMBER:
  551. if (CertCompareCertificateName(X509_ASN_ENCODING,
  552. &pccert->pCertInfo->Issuer,
  553. &pCertId->IssuerSerialNumber.Issuer) &&
  554. CertCompareIntegerBlob(&pccert->pCertInfo->SerialNumber,
  555. &pCertId->IssuerSerialNumber.SerialNumber)) {
  556. fFoundEncryptCert = TRUE;
  557. //pval[ival].ulPropTag = PR_CERT_KEYEX_CERTIFICATE_BIN;
  558. }
  559. break;
  560. case CERT_ID_KEY_IDENTIFIER:
  561. if (CompareCertHash(pccert, CERT_KEY_IDENTIFIER_PROP_ID,
  562. &pCertId->KeyId)) {
  563. fFoundEncryptCert = TRUE;
  564. //pval[ival].ulPropTag = PR_CERT_KEYEX_CERTIFICATE_BIN;
  565. }
  566. break;
  567. case CERT_ID_SHA1_HASH:
  568. if (CompareCertHash(pccert, CERT_SHA1_HASH_PROP_ID,
  569. &pCertId->HashId)) {
  570. fFoundEncryptCert = TRUE;
  571. //pval[ival].ulPropTag = PR_CERT_KEYEX_CERTIFICATE_BIN;
  572. }
  573. break;
  574. default:
  575. Assert(FALSE);
  576. }
  577. }
  578. else if (prid != NULL) {
  579. if (CertCompareCertificateName(X509_ASN_ENCODING,
  580. &pccert->pCertInfo->Issuer,
  581. &prid->Issuer) &&
  582. CertCompareIntegerBlob(&pccert->pCertInfo->SerialNumber,
  583. &prid->SerialNumber)) {
  584. fFoundEncryptCert = TRUE;
  585. //pval[ival].ulPropTag = PR_CERT_KEYEX_CERTIFICATE_BIN;
  586. }
  587. }
  588. if (fFoundEncryptCert)
  589. {
  590. pccertReturn = CertDuplicateCertificateContext(pccert);
  591. CertAddCertificateContextToStore(hCertStore, pccert,
  592. CERT_STORE_ADD_USE_EXISTING, NULL);
  593. }
  594. CertAddCertificateContextToStore(hstoreMem, pccert,
  595. CERT_STORE_ADD_USE_EXISTING, NULL);
  596. CertFreeCertificateContext(pccert);
  597. }
  598. if (pccertReturn == NULL)
  599. {
  600. hr = S_FALSE;
  601. goto Exit;
  602. }
  603. HrSaveCACerts(hCertStoreCA, hstoreMem);
  604. *ppccert = pccertReturn;
  605. *pfDefault = dwDefaults;
  606. if (pattrSymCaps != NULL)
  607. {
  608. pSymCaps->pBlobData = (LPBYTE) LocalAlloc(0, pattrSymCaps->rgValue[0].cbData);
  609. if (pSymCaps->pBlobData != NULL)
  610. {
  611. pSymCaps->cbSize = pattrSymCaps->rgValue[0].cbData;
  612. memcpy(pSymCaps->pBlobData, pattrSymCaps->rgValue[0].pbData,
  613. pSymCaps->cbSize);
  614. }
  615. }
  616. hr = S_OK;
  617. Exit:
  618. if (pbCert != NULL) LocalFree(pbCert);
  619. if (prid != NULL) LocalFree(prid);
  620. if (pekp != NULL) LocalFree(pekp);
  621. if (pinfo != NULL) LocalFree(pinfo);
  622. if (hmsg != NULL) CryptMsgClose(hmsg);
  623. if (hstoreMem != NULL) CertCloseStore(hstoreMem, 0);
  624. return hr;
  625. CryptError:
  626. hr = E_FAIL;
  627. goto Exit;
  628. }
  629. /* HrGetThumbprint:
  630. **
  631. ** Purpose:
  632. ** Give a wabal, grab a thumbprint from the PR_X509 prop
  633. ** Takes:
  634. ** IN lpWabal - the wabal from which recipients are read
  635. ** IN pAdrInfo - wab entry to query
  636. ** OUT pThumbprint - thumbprint that was found (Caller should MemFree)
  637. ** OUT pSymCaps - symcaps that was found (Caller should MemFree)
  638. ** OUT ftSigningTime - Signing time for cert
  639. ** Returns:
  640. ** SMIME_E_NOCERT if the MAPI cert prop doesn't exist for one of the recips
  641. ** Wabal Layout:
  642. ** PR_X509 = MVBin
  643. ** SBin
  644. ** lpb = tagarr
  645. ** tag
  646. ** tagid = def, trust, thumb
  647. ** data
  648. ** tag
  649. ** tag
  650. ** SBin
  651. ** tagarr
  652. ** tag
  653. ** ...
  654. */
  655. HRESULT HrGetThumbprint(LPWABAL lpWabal, ADRINFO *pAdrInfo, THUMBBLOB *pThumbprint,
  656. BLOB * pSymCaps, FILETIME * pftSigningTime)
  657. {
  658. HRESULT hr = S_OK;
  659. int iPass;
  660. ADRINFO rAdrInfo;
  661. LPMAPIPROP pmp = NULL;
  662. LPSPropValue ppv = NULL;
  663. ULONG cCerts;
  664. ULONG ul, ulDefault = 0;
  665. HCERTSTORE hCertStore = NULL;
  666. HCERTSTORE hCertStoreCA = NULL;
  667. PCCERT_CONTEXT pccert = NULL;
  668. LPBYTE pbData;
  669. ULONG cbData;
  670. LPTSTR pszAddr = NULL;
  671. Assert(lpWabal && pAdrInfo);
  672. pThumbprint->pBlobData = NULL;
  673. pSymCaps->pBlobData = NULL;
  674. pSymCaps->cbSize = 0;
  675. pftSigningTime->dwLowDateTime = pftSigningTime->dwHighDateTime = 0;
  676. // Find out if this wabal entry is the sender
  677. if (pAdrInfo->lRecipType == MAPI_ORIG)
  678. {
  679. hr = TrapError(MIME_E_SECURITY_NOCERT);
  680. goto exit;
  681. }
  682. CHECKHR(hr = lpWabal->HrGetPMP(pAdrInfo->cbEID, (LPENTRYID)pAdrInfo->lpbEID, &ul, &pmp));
  683. CHECKHR(hr = pmp->GetProps((LPSPropTagArray)&ptaCert, 0, &ul, &ppv));
  684. if (MAPI_W_ERRORS_RETURNED == hr)
  685. {
  686. if (PROP_TYPE(ppv->ulPropTag) == PT_ERROR)
  687. {
  688. // the property doesn't exist, so we have no certs
  689. // for this wabal entry
  690. lpWabal->FreeBuffer(ppv);
  691. ppv = NULL;
  692. // Was it a one-off? If so, go look for it in the address book
  693. if (IsWABOneOff(pAdrInfo->cbEID, (LPENTRYID)pAdrInfo->lpbEID))
  694. {
  695. // Look it up
  696. hr = HrFindThumbprintInWAB(pAdrInfo, lpWabal, &ppv);
  697. if (FAILED(hr))
  698. {
  699. hr = MIME_E_SECURITY_NOCERT; // no cert in wab
  700. goto exit;
  701. }
  702. }
  703. else
  704. {
  705. hr = MIME_E_SECURITY_NOCERT;
  706. goto exit;
  707. }
  708. }
  709. else
  710. {
  711. // bad MAPI return
  712. hr = TrapError(E_FAIL);
  713. goto exit;
  714. }
  715. }
  716. else if (FAILED(hr) || 1 != ul)
  717. {
  718. hr = TrapError(E_FAIL);
  719. goto exit;
  720. }
  721. // Open Address Book Cert Store
  722. hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, 0,
  723. CERT_SYSTEM_STORE_CURRENT_USER, c_szWABCertStore);
  724. if (!hCertStore)
  725. {
  726. // Can't open cert store. No point continuing.
  727. hr = HrGetLastError();
  728. goto exit;
  729. }
  730. // Open CA Cert Store
  731. hCertStoreCA = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, 0,
  732. CERT_SYSTEM_STORE_CURRENT_USER, c_szCACertStore);
  733. if (!hCertStoreCA)
  734. {
  735. // Can't open cert store. No point continuing.
  736. hr = HrGetLastError();
  737. goto exit;
  738. }
  739. //
  740. // Here is what is going to happen for the next few lines of code. This is
  741. // drastically different from what the old code here did.
  742. //
  743. // Pass #1:
  744. // Look at each row in the binary structure for the 'default' row.
  745. // When found extract the cert and verify that it is trusted and valid.
  746. // If not valid, goto pass #2.
  747. // If not trusted, -----
  748. //
  749. // Now need to loop over the SBinary structures to look at each cert
  750. cCerts = ppv->Value.MVbin.cValues;
  751. for (iPass = 0; (pccert == NULL) && (iPass < 2); iPass++)
  752. for (ul = 0; ul < cCerts; ul++)
  753. {
  754. BOOL fDefault = 0;
  755. fDefault = FALSE;
  756. // This is the userSMimeCertificate field
  757. if (ppv->Value.MVbin.lpbin[ul].lpb[0] == CERT_TAG_SMIMECERT)
  758. {
  759. hr = HrUserSMimeCertCracker(ppv->Value.MVbin.lpbin[ul].lpb,
  760. ppv->Value.MVbin.lpbin[ul].cb,
  761. hCertStoreCA, hCertStore,
  762. &fDefault, &pccert, pSymCaps);
  763. if (FAILED(hr))
  764. continue;
  765. }
  766. else
  767. {
  768. // Grab the "default" tag for later testing.
  769. if (pbData = FindX509CertTag(&ppv->Value.MVbin.lpbin[ul], CERT_TAG_DEFAULT, &cbData))
  770. {
  771. memcpy((void*)&fDefault, pbData, min(cbData, sizeof(fDefault)));
  772. if (!fDefault && (iPass ==0))
  773. continue;
  774. }
  775. // scan for "thumbprint" tag
  776. if (pbData = FindX509CertTag(&ppv->Value.MVbin.lpbin[ul], CERT_TAG_THUMBPRINT, &cbData))
  777. {
  778. pThumbprint->cbSize = cbData;
  779. pThumbprint->pBlobData = pbData;
  780. // Find the cert in the store
  781. pccert = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING, 0,
  782. CERT_FIND_HASH, (void*)pThumbprint, NULL);
  783. if (pccert == NULL) // Got the cert context
  784. {
  785. pThumbprint->cbSize = 0;
  786. pThumbprint->pBlobData = NULL;
  787. continue; // no cert in store, skip this one
  788. }
  789. }
  790. else if (pbData = FindX509CertTag(&ppv->Value.MVbin.lpbin[ul], CERT_TAG_BINCERT, &cbData))
  791. {
  792. pccert = CertCreateCertificateContext(X509_ASN_ENCODING, pbData, cbData);
  793. if (pccert == NULL)
  794. continue;
  795. }
  796. else
  797. {
  798. continue;
  799. }
  800. }
  801. // Does the email address of the cert match the email address of the recipient?
  802. Assert(pAdrInfo->lpwszAddress);
  803. IF_NULLEXIT(pszAddr = PszToANSI(CP_ACP, pAdrInfo->lpwszAddress));
  804. BOOL fSame = MatchCertEmailAddress(pccert, pszAddr);
  805. SafeMemFree(pszAddr);
  806. if (fSame)
  807. {
  808. DWORD dw = 0;
  809. HrGetCertKeyUsage(pccert, &dw);
  810. if(dw == 0xff) // all purposes
  811. break;
  812. else if (dw & CERT_KEY_ENCIPHERMENT_KEY_USAGE) // Encryption certificate
  813. break;
  814. }
  815. CertFreeCertificateContext(pccert);
  816. pccert = NULL;
  817. if (pSymCaps->pBlobData != NULL)
  818. {
  819. LocalFree(pSymCaps->pBlobData);
  820. pSymCaps->pBlobData = NULL;
  821. pSymCaps->cbSize = 0;
  822. }
  823. // Not the same, go back and try again!
  824. pThumbprint->cbSize = 0;
  825. pThumbprint->pBlobData = NULL;
  826. } // for loop over certs
  827. if (pccert == NULL)
  828. {
  829. hr = MIME_E_SECURITY_NOCERT;
  830. goto exit;
  831. }
  832. hr = hrSuccess;
  833. // If we have a match, find other associated tags
  834. if (pThumbprint->pBlobData)
  835. {
  836. if (pbData = FindX509CertTag(&ppv->Value.MVbin.lpbin[ul], CERT_TAG_SYMCAPS, &cbData))
  837. {
  838. if (! MemAlloc((LPVOID *)&pSymCaps->pBlobData, cbData))
  839. {
  840. hr = TrapError(E_OUTOFMEMORY);
  841. goto exit;
  842. }
  843. pSymCaps->cbSize = cbData;
  844. memcpy(pSymCaps->pBlobData, pbData, cbData);
  845. }
  846. else
  847. DOUTL(DOUTL_CRYPT, "No symcaps for recipient.");
  848. if (pbData = FindX509CertTag(&ppv->Value.MVbin.lpbin[ul], CERT_TAG_SIGNING_TIME, &cbData))
  849. memcpy(pftSigningTime, &pbData, min(sizeof(FILETIME), cbData));
  850. else
  851. DOUTL(DOUTL_CRYPT, "No signing time for recipient.");
  852. }
  853. #ifdef DEBUG
  854. // Make sure the HRESULT is in sync with thumbprint
  855. if (pccert == NULL)
  856. Assert(FAILED(hr));
  857. else
  858. Assert(SUCCEEDED(hr));
  859. #endif
  860. if (SUCCEEDED(hr) && (pccert != NULL))
  861. {
  862. pThumbprint->pBlobData = (LPBYTE) PVGetCertificateParam(pccert, CERT_HASH_PROP_ID, &pThumbprint->cbSize);
  863. if (pThumbprint->pBlobData == NULL)
  864. {
  865. hr = TrapError(E_OUTOFMEMORY);
  866. goto exit;
  867. }
  868. }
  869. exit:
  870. if (! pThumbprint->pBlobData)
  871. pThumbprint->cbSize = 0;
  872. if (ppv)
  873. lpWabal->FreeBuffer(ppv);
  874. ReleaseObj(pmp);
  875. if (FAILED(hr) && (pSymCaps != NULL))
  876. {
  877. MemFree(pSymCaps->pBlobData);
  878. pSymCaps->pBlobData = NULL;
  879. pSymCaps->cbSize = 0;
  880. }
  881. if (pccert)
  882. CertFreeCertificateContext(pccert);
  883. if (hCertStoreCA)
  884. CertCloseStore(hCertStoreCA, 0);
  885. if (hCertStore)
  886. CertCloseStore(hCertStore, 0);
  887. return hr;
  888. }
  889. /* IsEncrypted:
  890. **
  891. ** Purpose:
  892. ** Answer the question
  893. **
  894. ** Takes:
  895. ** IN pMsg - message to query
  896. ** IN hBodyToCheck - body to query, HBODY_ROOT is valid
  897. ** IN fIncludeDescendents - if FALSE, returns with MST_CHILD and
  898. ** MST_SUBMSG don't count
  899. */
  900. BOOL IsEncrypted(LPMIMEMESSAGE pMsg,
  901. const HBODY hBodyToCheck,
  902. BOOL fIncludeDescendents)
  903. {
  904. return _IsMaskedBodySecure(pMsg, hBodyToCheck,
  905. fIncludeDescendents ? MST_ENCRYPT_MASK : MST_ENCRYPT_MASK & MST_THIS_MASK);
  906. }
  907. /* IsSigned:
  908. **
  909. ** Purpose:
  910. ** Answer the question
  911. **
  912. ** Takes:
  913. ** IN pMsg - message to query
  914. ** IN hBodyToCheck - body to query, HBODY_ROOT is valid
  915. ** IN fIncludeDescendents - if FALSE, returns with MST_CHILD and
  916. ** MST_SUBMSG don't count
  917. */
  918. BOOL IsSigned(LPMIMEMESSAGE pMsg,
  919. const HBODY hBodyToCheck,
  920. BOOL fIncludeDescendents)
  921. {
  922. return _IsMaskedBodySecure(pMsg, hBodyToCheck,
  923. fIncludeDescendents ? MST_SIGN_MASK : MST_SIGN_MASK & MST_THIS_MASK);
  924. }
  925. /* DwGetSecurityOfMessage:
  926. **
  927. ** Purpose:
  928. ** Wrap up the slight nastiness of options
  929. ** Takes:
  930. ** IN pMsg - message to query
  931. ** IN hBodyToCheck - body to query, HBODY_ROOT is valid
  932. */
  933. DWORD DwGetSecurityOfMessage(LPMIMEMESSAGE pMsg,
  934. const HBODY hBodyToCheck)
  935. {
  936. IMimeBody *pBody;
  937. PROPVARIANT var;
  938. DWORD dwRet = MST_NONE;
  939. Assert(pMsg);
  940. if (SUCCEEDED(pMsg->BindToObject(hBodyToCheck, IID_IMimeBody, (void**)&pBody)))
  941. {
  942. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_TYPE, &var)))
  943. dwRet = var.ulVal;
  944. pBody->Release();
  945. }
  946. return dwRet;
  947. }
  948. /* CleanupSECSTATE
  949. **
  950. ** Purpose:
  951. ** Cleanup the strings allocated by HrGetSecurityState
  952. ** Takes:
  953. ** IN secstate - secstate structure
  954. */
  955. VOID CleanupSECSTATE(SECSTATE *psecstate)
  956. {
  957. SafeMemFree(psecstate->szSignerEmail);
  958. SafeMemFree(psecstate->szSenderEmail);
  959. }
  960. /* HrHaveAnyMyCerts:
  961. **
  962. ** Purpose:
  963. ** see if any certificates exist in the CAPI "My" store
  964. ** Returns:
  965. ** S_OK if certificates exist, S_FALSE if the store is empty
  966. ** or does not exist
  967. */
  968. HRESULT HrHaveAnyMyCerts()
  969. {
  970. IMimeSecurity *pSMime = NULL;
  971. HRESULT hr;
  972. HCAPICERTSTORE hcMy = NULL;
  973. CHECKHR(hr = MimeOleCreateSecurity(&pSMime));
  974. CHECKHR(hr = pSMime->InitNew());
  975. hcMy = CertOpenStore(CERT_STORE_PROV_SYSTEM_A,
  976. X509_ASN_ENCODING, NULL, CERT_SYSTEM_STORE_CURRENT_USER, c_szMyCertStore);
  977. if (hcMy)
  978. {
  979. hr = pSMime->EnumCertificates(hcMy, 0, NULL, NULL);
  980. CertCloseStore(hcMy, 0);
  981. }
  982. else
  983. hr = S_FALSE;
  984. exit:
  985. ReleaseObj(pSMime);
  986. return hr;
  987. }
  988. /* HandleSecurity:
  989. **
  990. ** Purpose:
  991. ** Two fold. One, strip the security from the message, so it ends
  992. ** up being rebuilt from the non-secure MIME. Then build the client-
  993. ** side message properties for security.
  994. **
  995. ** Takes:
  996. ** IN pMsg - message from which to remove security
  997. */
  998. HRESULT HandleSecurity(HWND hwndOwner, LPMIMEMESSAGE pMsg)
  999. {
  1000. HRESULT hr;
  1001. HWND hWnd = NULL;
  1002. if(g_pBrowser)
  1003. g_pBrowser->GetWindow(&hWnd);
  1004. if(hWnd == NULL)
  1005. hWnd = hwndOwner;
  1006. Assert(pMsg);
  1007. hr = _RemoveSecurity(pMsg, hWnd);
  1008. if ((HR_S_NOOP != hr) && (MIME_S_SECURITY_NOOP != hr) && SUCCEEDED(hr))
  1009. {
  1010. IMimeSecurity *pSMime = NULL;
  1011. if (IsSigned(pMsg, FALSE))
  1012. {
  1013. //N2 look at the creation in removsec
  1014. hr = MimeOleCreateSecurity(&pSMime);
  1015. if (SUCCEEDED(hr))
  1016. hr = pSMime->InitNew();
  1017. if (SUCCEEDED(hr))
  1018. hr = _ValidateAndTrust(hwndOwner, pSMime, pMsg);
  1019. ReleaseObj(pSMime);
  1020. }
  1021. }
  1022. else if((hr == OSS_PDU_MISMATCH) || (hr == CRYPT_E_ASN1_BADTAG)) // bug 38394
  1023. {
  1024. AthMessageBoxW(hwndOwner, MAKEINTRESOURCEW(idsAthenaMail),
  1025. MAKEINTRESOURCEW(idsWrongSecHeader), NULL, MB_OK);
  1026. hr = HR_S_NOOP;
  1027. }
  1028. #if 0
  1029. else if(((hr >= ASN1_ERR_FIRST) && (hr <= ASN1_ERR_LAST)) || (HR_CODE(hr) == ERROR_ACCESS_DENIED))
  1030. hr = MIME_E_SECURITY_LABELACCESSDENIED;
  1031. #endif
  1032. return hr;
  1033. }
  1034. #ifdef SMIME_V3
  1035. // Find secure receipt in decoded message
  1036. HRESULT CheckDecodedForReceipt(LPMIMEMESSAGE pMsg, PSMIME_RECEIPT * ppSecReceipt)
  1037. {
  1038. IMimeBody * pBody = NULL;
  1039. LPBYTE pbData = NULL;
  1040. DWORD cbData, cb;
  1041. LPSTREAM pstmBody = NULL;
  1042. STATSTG statstg;
  1043. HRESULT hr = S_OK;
  1044. HBODY hBody = NULL;
  1045. if(!IsSecure(pMsg))
  1046. return(E_FAIL);
  1047. if(FAILED(hr = HrGetInnerLayer(pMsg, &hBody)))
  1048. goto exit;
  1049. if (FAILED(hr = pMsg->BindToObject(hBody ? hBody : HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pBody)))
  1050. goto notinit;
  1051. if (FAILED(hr = pBody->GetData(IET_BINARY, &pstmBody)))
  1052. goto notinit;
  1053. if (FAILED(hr = pstmBody->Stat(&statstg,STATFLAG_NONAME)))
  1054. goto notinit;
  1055. Assert(statstg.cbSize.HighPart == 0);
  1056. if(statstg.cbSize.LowPart == 0)
  1057. goto notinit;
  1058. if (FAILED(hr = HrAlloc((LPVOID *)&pbData, statstg.cbSize.LowPart)))
  1059. goto notinit;
  1060. if (FAILED(hr = pstmBody->Read(pbData, statstg.cbSize.LowPart, &cbData)))
  1061. {
  1062. notinit:
  1063. hr = MIME_E_SECURITY_NOTINIT;
  1064. goto exit;
  1065. }
  1066. if (!CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_SMIME_ContentType_Receipt,
  1067. pbData,
  1068. cbData,
  1069. CRYPT_ENCODE_ALLOC_FLAG, &CryptDecodeAlloc,
  1070. ppSecReceipt, &cb))
  1071. {
  1072. hr = MIME_E_SECURITY_RECEIPT_CANTDECODE;
  1073. goto exit;
  1074. }
  1075. exit:
  1076. SafeMemFree(pbData);
  1077. SafeRelease(pstmBody);
  1078. SafeRelease(pBody);
  1079. return(hr);
  1080. }
  1081. // Decode a message and find secure receipt
  1082. HRESULT HrFindSecReceipt(LPMIMEMESSAGE pMsg, PSMIME_RECEIPT * ppSecReceipt)
  1083. {
  1084. IMimeSecurity * pSMime = NULL;
  1085. IMimeBody * pBody = NULL;
  1086. LPBYTE pbData = NULL;
  1087. DWORD cbData;
  1088. LPSTREAM pstmBody = NULL;
  1089. STATSTG statstg;
  1090. HRESULT hr = S_OK;
  1091. DWORD cb = 0;
  1092. HWND hWnd = NULL;
  1093. PROPVARIANT var;
  1094. HBODY hBody = NULL;
  1095. // Need to set correct window for decode
  1096. if(g_pBrowser)
  1097. g_pBrowser->GetWindow(&hWnd);
  1098. IF_FAILEXIT(hr = HrGetInnerLayer(pMsg, &hBody));
  1099. IF_FAILEXIT(hr = pMsg->BindToObject(hBody ? hBody : HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pBody));
  1100. #ifdef _WIN64
  1101. var.vt = VT_UI8;
  1102. var.pulVal = (ULONG *) hWnd;
  1103. IF_FAILEXIT(hr = pBody->SetOption(OID_SECURITY_HWND_OWNER_64, &var));
  1104. #else
  1105. var.vt = VT_UI4;
  1106. var.ulVal = (DWORD) hWnd;
  1107. IF_FAILEXIT(hr = pBody->SetOption(OID_SECURITY_HWND_OWNER, &var));
  1108. #endif // _WIN64
  1109. SafeRelease(pBody);
  1110. if (FAILED(hr = MimeOleCreateSecurity(&pSMime)))
  1111. goto notinit;
  1112. if (FAILED(hr = pSMime->InitNew()))
  1113. {
  1114. notinit:
  1115. hr = MIME_E_SECURITY_NOTINIT;
  1116. goto exit;
  1117. }
  1118. // we handle all hr from DecodeMessage
  1119. IF_FAILEXIT(hr = pSMime->DecodeMessage(pMsg, 0));
  1120. hr = CheckDecodedForReceipt(pMsg, ppSecReceipt);
  1121. exit:
  1122. SafeRelease(pSMime);
  1123. SafeRelease(pBody);
  1124. return(hr);
  1125. }
  1126. HRESULT CheckSecReceipt(LPMIMEMESSAGE pMsg)
  1127. {
  1128. PSMIME_RECEIPT pSecReceipt = NULL;
  1129. HRESULT hr = S_OK;
  1130. hr = CheckDecodedForReceipt(pMsg, &pSecReceipt);
  1131. SafeMemFree(pSecReceipt);
  1132. return(hr);
  1133. }
  1134. #define ROWSET_FETCH 100
  1135. HRESULT HandleSecReceipt(LPMIMEMESSAGE pMsg, IImnAccount * pAcct, HWND hWnd, TCHAR **ppszSubject, TCHAR **ppszFrom, FILETIME *pftSentTime, FILETIME *pftSigningTime)
  1136. {
  1137. IMimeSecurity2 * pSMIME3 = NULL;
  1138. IMimeBody * pOrgBody = NULL;
  1139. PSMIME_RECEIPT pSecReceipt = NULL;
  1140. HRESULT hr = S_FALSE;
  1141. HRESULT hrVerify = S_OK;
  1142. LPMIMEMESSAGE pOrgMsg = NULL;
  1143. IMessageFolder *pSentItems = NULL;
  1144. HROWSET hRowset=NULL;
  1145. LPMESSAGEINFO pMessage;
  1146. MESSAGEINFO Message={0};
  1147. DWORD i = 0;
  1148. PCCERT_CONTEXT pcSigningCert = NULL;
  1149. THUMBBLOB tbSigner = {0};
  1150. BLOB blSymCaps = {0};
  1151. PROPVARIANT var;
  1152. HBODY hBody = NULL;
  1153. // bug 80490
  1154. if(pAcct == NULL)
  1155. {
  1156. hr = MIME_E_SECURITY_RECEIPT_CANTFINDSENTITEM;
  1157. goto exit;
  1158. }
  1159. // IF_FAILEXIT(hr = HrFindSecReceipt(pMsg, &pSecReceipt));
  1160. IF_FAILEXIT(hr = CheckDecodedForReceipt(pMsg, &pSecReceipt));
  1161. // check that this secure receipt is not from us
  1162. // Name from sign certificate
  1163. pftSigningTime->dwLowDateTime = 0;
  1164. pftSigningTime->dwHighDateTime = 0;
  1165. GetSigningCert(pMsg, &pcSigningCert, &tbSigner, &blSymCaps, pftSigningTime);
  1166. if(pcSigningCert)
  1167. {
  1168. HCERTSTORE hMyCertStore = NULL;
  1169. X509CERTRESULT certResult;
  1170. CERTSTATE cs;
  1171. TCHAR *pUserName = NULL;
  1172. *ppszFrom = SzGetCertificateEmailAddress(pcSigningCert);
  1173. CertFreeCertificateContext(pcSigningCert);
  1174. pcSigningCert = NULL;
  1175. SafeMemFree(tbSigner.pBlobData);
  1176. // get certificate for account
  1177. if (SUCCEEDED(hr = pAcct->GetProp(AP_SMTP_CERTIFICATE, NULL, &tbSigner.cbSize)))
  1178. {
  1179. // we have encryption certificate
  1180. hr = HrAlloc((void**)&tbSigner.pBlobData, tbSigner.cbSize);
  1181. if (SUCCEEDED(hr))
  1182. {
  1183. hr = pAcct->GetProp(AP_SMTP_CERTIFICATE, tbSigner.pBlobData, &tbSigner.cbSize);
  1184. if (SUCCEEDED(hr))
  1185. {
  1186. hMyCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING,
  1187. NULL, CERT_SYSTEM_STORE_CURRENT_USER, c_szMyCertStore);
  1188. if (hMyCertStore)
  1189. {
  1190. certResult.cEntries = 1;
  1191. certResult.rgcs = &cs;
  1192. certResult.rgpCert = &pcSigningCert;
  1193. hr = MimeOleGetCertsFromThumbprints(&tbSigner, &certResult, &hMyCertStore, 1);
  1194. pUserName = SzGetCertificateEmailAddress(pcSigningCert);
  1195. if(!lstrcmpi(pUserName, *ppszFrom))
  1196. hr = MIME_S_RECEIPT_FROMMYSELF;
  1197. SafeMemFree(pUserName);
  1198. CertCloseStore(hMyCertStore, 0);
  1199. }
  1200. else
  1201. goto notinit;
  1202. }
  1203. SafeMemFree(tbSigner.pBlobData);
  1204. }
  1205. else
  1206. {
  1207. notinit:
  1208. hr = MIME_E_SECURITY_NOTINIT;
  1209. goto exit;
  1210. }
  1211. }
  1212. }
  1213. if(hr == MIME_S_RECEIPT_FROMMYSELF)
  1214. goto exit;
  1215. // Verification of receipt
  1216. // 1. Try to find Original message
  1217. // 2. If found call pSMIME2->VerifyReceipt
  1218. // 3. Fill all text fields for displaying receipt
  1219. // Find original message
  1220. // a). Open Sent Item folder for account
  1221. if (FAILED(hr = TaskUtil_OpenSentItemsFolder(pAcct, &pSentItems)))
  1222. goto NoSentItem;
  1223. // Create a Rowset
  1224. if (FAILED(hr = pSentItems->CreateRowset(IINDEX_PRIMARY, 0, &hRowset)))
  1225. {
  1226. NoSentItem:
  1227. hr = MIME_E_SECURITY_RECEIPT_CANTFINDSENTITEM;
  1228. goto exit;
  1229. }
  1230. // Walk the Rowset
  1231. hr = MIME_E_SECURITY_RECEIPT_CANTFINDORGMSG;
  1232. while (S_OK == pSentItems->QueryRowset(hRowset, 1, (LPVOID *)&Message, NULL))
  1233. {
  1234. // Messages without request receipt doesn't have pszMSOESRec
  1235. if(Message.pszMSOESRec && (lstrlen(Message.pszMSOESRec) == ((int) pSecReceipt->ContentIdentifier.cbData)))
  1236. {
  1237. if(!memcmp(pSecReceipt->ContentIdentifier.pbData, Message.pszMSOESRec,
  1238. pSecReceipt->ContentIdentifier.cbData))
  1239. {
  1240. // Original message found!!!
  1241. // Need take pMsg and verify receipt
  1242. IF_FAILEXIT(hr = pSentItems->OpenMessage(Message.idMessage, 0, &pOrgMsg, NOSTORECALLBACK));
  1243. IF_FAILEXIT(hr = pOrgMsg->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pOrgBody));
  1244. IF_FAILEXIT(hr = pOrgBody->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &pSMIME3));
  1245. IF_FAILEXIT(hr = pSMIME3->VerifyReceipt(0, pMsg));
  1246. // If we are in here then we found original message and verified receipt.
  1247. // Now need to feel all text fields
  1248. // Subject and Sent from original message
  1249. DWORD cchSize = (lstrlen(Message.pszSubject) + 1);
  1250. if (MemAlloc((LPVOID *)ppszSubject, cchSize * sizeof((*ppszSubject)[0])))
  1251. StrCpyN(*ppszSubject, Message.pszSubject, cchSize);
  1252. pftSentTime->dwLowDateTime = Message.ftSent.dwLowDateTime;
  1253. pftSentTime->dwHighDateTime = Message.ftSent.dwHighDateTime;
  1254. if((pftSigningTime->dwLowDateTime == 0) && (pftSigningTime->dwHighDateTime == 0))
  1255. { // We may have this situation when message was signed, but certificate not included and not in storage.
  1256. SafeRelease(pOrgBody);
  1257. IF_FAILEXIT(hr = HrGetInnerLayer(pMsg, &hBody));
  1258. if(pMsg->BindToObject(hBody ? hBody : HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pOrgBody) == S_OK)
  1259. {
  1260. if (SUCCEEDED(pOrgBody->GetOption(OID_SECURITY_SIGNTIME, &var)))
  1261. {
  1262. Assert(VT_FILETIME == var.vt);
  1263. *pftSigningTime = var.filetime;
  1264. }
  1265. }
  1266. }
  1267. hr = S_OK;
  1268. goto exit;
  1269. }
  1270. }
  1271. pSentItems->FreeRecord(&Message);
  1272. }
  1273. exit:
  1274. SafeRelease(pSMIME3);
  1275. SafeRelease(pOrgBody);
  1276. SafeRelease(pOrgMsg);
  1277. if(pSentItems)
  1278. pSentItems->FreeRecord(&Message);
  1279. if(pSentItems && hRowset)
  1280. pSentItems->CloseRowset(&hRowset);
  1281. SafeRelease(pSentItems);
  1282. SafeMemFree(blSymCaps.pBlobData);
  1283. SafeMemFree(tbSigner.pBlobData);
  1284. if(pcSigningCert)
  1285. CertFreeCertificateContext(pcSigningCert);
  1286. SafeMemFree(pSecReceipt);
  1287. return(hr);
  1288. }
  1289. #endif // SMIME_V3
  1290. HRESULT _RemoveSecurity(LPMIMEMESSAGE pMsg, HWND hWnd)
  1291. {
  1292. HRESULT hr = S_OK;
  1293. IMimeSecurity *pSMime = NULL;
  1294. IMimeMessageTree *pTree = NULL;
  1295. IMimeBody * pBody = NULL;
  1296. PROPVARIANT var;
  1297. DWORD dwFlags;
  1298. //N this is expensive, so _RemoveSecurity should not be called twice
  1299. pMsg->GetFlags(&dwFlags);
  1300. if (IMF_SECURE & dwFlags)
  1301. {
  1302. IF_FAILEXIT(hr = pMsg->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pBody));
  1303. #ifdef _WIN64
  1304. var.vt = VT_UI8;
  1305. var.pulVal = (ULONG *)hWnd;
  1306. IF_FAILEXIT(hr = pBody->SetOption(OID_SECURITY_HWND_OWNER_64, &var));
  1307. #else
  1308. var.vt = VT_UI4;
  1309. var.ulVal = (DWORD) hWnd;
  1310. IF_FAILEXIT(hr = pBody->SetOption(OID_SECURITY_HWND_OWNER, &var));
  1311. #endif // _WIN64
  1312. CHECKHR(hr = MimeOleCreateSecurity(&pSMime));
  1313. CHECKHR(hr = pSMime->InitNew());
  1314. CHECKHR(hr = pMsg->QueryInterface(IID_IMimeMessageTree, (LPVOID *)&pTree));
  1315. CHECKHR(hr = pSMime->DecodeMessage(pTree, 0));
  1316. }
  1317. else
  1318. hr = HR_S_NOOP;
  1319. exit:
  1320. ReleaseObj(pBody);
  1321. ReleaseObj(pSMime);
  1322. ReleaseObj(pTree);
  1323. return hr;
  1324. }
  1325. HRESULT _ValidateAndTrust(HWND hwndOwner, IMimeSecurity *pSMime, IMimeMessage *pMsg)
  1326. {
  1327. ULONG ulTrust = ATHSEC_NOTRUSTUNKNOWN;
  1328. ULONG ulValidity = 0;
  1329. IMimeBody *pBody;
  1330. HRESULT hr;
  1331. HBODY hBody = NULL;
  1332. Assert(pSMime && pMsg);
  1333. // Cast the bones and decide if we trust this thing
  1334. // Athena only supports root-body S/MIME
  1335. if(FAILED(hr = HrGetInnerLayer(pMsg, &hBody)))
  1336. return TrapError(hr);
  1337. if (SUCCEEDED(hr = pMsg->BindToObject(hBody ? hBody : HBODY_ROOT, IID_IMimeBody, (void**)&pBody)))
  1338. {
  1339. PROPVARIANT var;
  1340. PCCERT_CONTEXT pcSigningCert;
  1341. #ifdef _WIN64
  1342. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING_64, &var)))
  1343. {
  1344. Assert(VT_UI8 == var.vt);
  1345. pcSigningCert = (PCCERT_CONTEXT)(var.pulVal);
  1346. #else // !_WIN64
  1347. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING, &var)))
  1348. {
  1349. Assert(VT_UI4 == var.vt);
  1350. pcSigningCert = (PCCERT_CONTEXT)var.ulVal;
  1351. #endif // _WIN64
  1352. if (pcSigningCert)
  1353. {
  1354. DWORD dwComputedTrust;
  1355. //N7 trust mask. what if issuer is expired. can't lose this like I do.
  1356. const DWORD dwIgnore =
  1357. // CERT_VALIDITY_BEFORE_START |
  1358. CERT_VALIDITY_AFTER_END |
  1359. CERT_VALIDITY_NO_CRL_FOUND;
  1360. dwComputedTrust = DwGenerateTrustedChain(hwndOwner, pMsg, pcSigningCert,
  1361. dwIgnore, FALSE, NULL, NULL);
  1362. // Trust
  1363. ulTrust = ATHSEC_TRUSTED;
  1364. if (dwComputedTrust & CERT_VALIDITY_NO_TRUST_DATA)
  1365. {
  1366. ulTrust |= ATHSEC_NOTRUSTUNKNOWN;
  1367. dwComputedTrust &= ~CERT_VALIDITY_NO_TRUST_DATA;
  1368. }
  1369. if (dwComputedTrust & CERT_VALIDITY_MASK_TRUST)
  1370. {
  1371. ulTrust |= ATHSEC_NOTRUSTNOTTRUSTED;
  1372. dwComputedTrust &= ~CERT_VALIDITY_MASK_TRUST;
  1373. }
  1374. // Validity
  1375. if (dwComputedTrust & CERT_VALIDITY_CERTIFICATE_REVOKED)
  1376. {
  1377. ulValidity |= ATHSEC_NOTRUSTREVOKED;
  1378. dwComputedTrust &= ~CERT_VALIDITY_CERTIFICATE_REVOKED;
  1379. }
  1380. if (dwComputedTrust & CERT_VALIDITY_NO_CRL_FOUND)
  1381. {
  1382. ulValidity |= ATHSEC_NOTRUSTREVFAIL;
  1383. dwComputedTrust &= ~CERT_VALIDITY_NO_CRL_FOUND;
  1384. }
  1385. if (dwComputedTrust & CERT_VALIDITY_MASK_VALIDITY)
  1386. {
  1387. ulValidity |= ATHSEC_NOTRUSTOTHER;
  1388. dwComputedTrust &= ~CERT_VALIDITY_MASK_VALIDITY;
  1389. }
  1390. Assert(dwComputedTrust == ATHSEC_TRUSTED); // Should have removed it all by now
  1391. //N this could become a helper fn call as part of the trust
  1392. //N provider. Currently trust helpers are nyi.
  1393. if (0 != _CompareCertAndSenderEmail(pMsg, pSMime, pcSigningCert))
  1394. ulValidity |= ATHSEC_NOTRUSTWRONGADDR;
  1395. CertFreeCertificateContext(pcSigningCert);
  1396. }
  1397. else
  1398. // if we don't have a cert then the signing is already
  1399. // in trouble. trust has no meaning
  1400. Assert(!ulValidity);
  1401. }
  1402. Assert(!(ulTrust & ulValidity)); // no overlap
  1403. hr = (ulTrust | ulValidity) ? S_FALSE : S_OK;
  1404. var.vt = VT_UI4;
  1405. var.ulVal = ulTrust|ulValidity;
  1406. pBody->SetOption(OID_SECURITY_USER_VALIDITY, &var);
  1407. pBody->Release();
  1408. }
  1409. DOUTL(DOUTL_CRYPT, "SMIME: _ValidateAndTrust returns trust:0x%lX, valid:0x%lX", ulTrust, ulValidity);
  1410. return TrapError(hr);
  1411. }
  1412. /***************************************************************************
  1413. Name : GetSenderEmail
  1414. Purpose : Get the email address of the sender of the message
  1415. Parameters: pMsg = IMimeMsg object
  1416. Returns : MemAlloc'ed string. Caller must MemFree it.
  1417. ***************************************************************************/
  1418. LPTSTR GetSenderEmail(LPMIMEMESSAGE pMsg)
  1419. {
  1420. ADDRESSLIST rAdrList = {0};
  1421. LPTSTR pszReturn = NULL;
  1422. Assert(pMsg);
  1423. if (SUCCEEDED(pMsg->GetAddressTypes(IAT_FROM, IAP_EMAIL, &rAdrList)))
  1424. {
  1425. if (rAdrList.cAdrs > 0)
  1426. {
  1427. DWORD cchSize = (lstrlen(rAdrList.prgAdr[0].pszEmail) + 1);
  1428. Assert(rAdrList.prgAdr[0].pszEmail);
  1429. if (MemAlloc((LPVOID *)&pszReturn, cchSize * sizeof(pszReturn[0])))
  1430. StrCpyN(pszReturn, rAdrList.prgAdr[0].pszEmail, cchSize);
  1431. }
  1432. }
  1433. g_pMoleAlloc->FreeAddressList(&rAdrList);
  1434. return pszReturn;
  1435. }
  1436. /* _CompareCertAndSenderEmail:
  1437. **
  1438. ** Returns:
  1439. ** 0 if they are equal (case insensitive)
  1440. ** //N SECURITY: what about whitespace in the email. mimeOLE strips it?
  1441. ** nonzero if unequal
  1442. */
  1443. int _CompareCertAndSenderEmail(LPMIMEMESSAGE pMsg, IMimeSecurity *pSMime, PCX509CERT pCert)
  1444. {
  1445. int ret = 1;
  1446. PROPVARIANT var;
  1447. HRESULT hr;
  1448. LPTSTR szSenderEmail = NULL;
  1449. Assert(pMsg && pCert && pSMime);
  1450. szSenderEmail = GetSenderEmail(pMsg);
  1451. if (szSenderEmail && SUCCEEDED(hr = pSMime->GetCertData(pCert, CDID_EMAIL, &var)))
  1452. {
  1453. Assert(VT_LPSTR == var.vt);
  1454. ret = lstrcmpi(szSenderEmail, var.pszVal);
  1455. MemFree(var.pszVal);
  1456. }
  1457. SafeMemFree(szSenderEmail);
  1458. return ret;
  1459. }
  1460. /***************************************************************************
  1461. Name : HrInitSecurityOptions
  1462. Purpose : Set some basic security options on the message.
  1463. Parameters: pMsg = IMimeMsg object
  1464. ulSecurityType = SMIME security type:
  1465. MST_THIS_SIGN
  1466. MST_THIS_ENCRYPT
  1467. MST_CLASS_SMIME_V1
  1468. MST_THIS_BLOBSIGN
  1469. Returns : HRESULT
  1470. Comment : Sets the security type option on all messages
  1471. Sets hash algorithm only if we are signing.
  1472. ***************************************************************************/
  1473. HRESULT HrInitSecurityOptions(LPMIMEMESSAGE pMsg, ULONG ulSecurityType)
  1474. {
  1475. HRESULT hr;
  1476. IMimeBody *pBody = NULL;
  1477. PROPVARIANT var;
  1478. hr = pMsg->BindToObject(HBODY_ROOT, IID_IMimeBody, (void**)&pBody);
  1479. if (FAILED(hr))
  1480. goto exit;
  1481. var.vt = VT_UI4;
  1482. var.ulVal = ulSecurityType;
  1483. hr = pBody->SetOption(OID_SECURITY_TYPE, &var);
  1484. if (FAILED(hr))
  1485. goto exit;
  1486. if (ulSecurityType & MST_SIGN_MASK)
  1487. {
  1488. // Hack! This is the ALOGORITHM ID for SHA1, our only supported signing algorithm
  1489. BYTE rgbHash[] = {0x30, 0x09, 0x30, 0x07, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A};
  1490. ULONG cbHash = sizeof(rgbHash);
  1491. var.vt = VT_BLOB;
  1492. var.blob.cbSize = cbHash;
  1493. var.blob.pBlobData = rgbHash;
  1494. hr = pBody->SetOption(OID_SECURITY_ALG_HASH, &var);
  1495. }
  1496. if(ulSecurityType == MST_THIS_SIGN)
  1497. {
  1498. var.vt = VT_BOOL;
  1499. var.boolVal = TRUE;
  1500. hr = pMsg->SetOption(OID_SAVEBODY_KEEPBOUNDARY, &var);
  1501. }
  1502. exit:
  1503. ReleaseObj(pBody);
  1504. return(hr);
  1505. }
  1506. // Get inner layer for using with multisign messages
  1507. HRESULT HrGetInnerLayer(LPMIMEMESSAGE pMsg, HBODY *phBody)
  1508. {
  1509. HRESULT hr = S_OK;
  1510. HBODY hBody = NULL;
  1511. BOOL fWrapped = FALSE;
  1512. IMimeBody *pBody = NULL;
  1513. Assert(pMsg);
  1514. hr = pMsg->GetBody(IBL_ROOT, NULL, &hBody);
  1515. if(FAILED(hr))
  1516. return(hr);
  1517. do
  1518. {
  1519. if (SUCCEEDED(hr = pMsg->BindToObject(hBody, IID_IMimeBody, (void **)&pBody)))
  1520. {
  1521. fWrapped = (pBody->IsContentType(STR_CNT_MULTIPART, "y-security") == S_OK);
  1522. if(phBody)
  1523. *phBody = hBody;
  1524. SafeRelease(pBody);
  1525. if (fWrapped)
  1526. {
  1527. hr = pMsg->GetBody(IBL_FIRST, hBody, &hBody);
  1528. Assert(SUCCEEDED(hr));
  1529. if (FAILED(hr))
  1530. break;
  1531. }
  1532. }
  1533. else
  1534. break;
  1535. }while(fWrapped && hBody);
  1536. return hr;
  1537. }
  1538. HRESULT HrGetSecurityState(LPMIMEMESSAGE pMsg, SECSTATE *pSecState, HBODY *phBody)
  1539. {
  1540. HRESULT hr = S_OK;
  1541. IMimeBody *pBody = NULL;
  1542. PROPVARIANT var;
  1543. BOOL fWrapped = FALSE;
  1544. pSecState->szSignerEmail = NULL;
  1545. pSecState->szSenderEmail = NULL;
  1546. HBODY hBody;
  1547. hr = pMsg->GetBody(IBL_ROOT, NULL, &hBody);
  1548. if(FAILED(hr))
  1549. return(hr);
  1550. do
  1551. {
  1552. if (SUCCEEDED(hr = pMsg->BindToObject(hBody, IID_IMimeBody, (void **)&pBody)))
  1553. {
  1554. SafeMemFree(pSecState->szSignerEmail);
  1555. SafeMemFree(pSecState->szSenderEmail);
  1556. pSecState->type = SUCCEEDED(pBody->GetOption(OID_SECURITY_TYPE, &var))
  1557. ? var.ulVal
  1558. : MST_NONE;
  1559. pSecState->szSenderEmail = GetSenderEmail(pMsg);
  1560. if (MST_NONE != pSecState->type)
  1561. {
  1562. pSecState->user_validity = SUCCEEDED(pBody->GetOption(OID_SECURITY_USER_VALIDITY, &var))
  1563. ? var.ulVal
  1564. : 0;
  1565. pSecState->ro_msg_validity = SUCCEEDED(pBody->GetOption(OID_SECURITY_RO_MSG_VALIDITY, &var))
  1566. ? var.ulVal
  1567. : MSV_OK;
  1568. #ifdef _WIN64
  1569. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING_64, &var)))
  1570. {
  1571. pSecState->fHaveCert = (NULL != (PCCERT_CONTEXT)(var.pulVal));
  1572. if (pSecState->fHaveCert)
  1573. {
  1574. pSecState->szSignerEmail = SzGetCertificateEmailAddress((PCCERT_CONTEXT)(var.pulVal));
  1575. CertFreeCertificateContext((PCCERT_CONTEXT)(var.pulVal));
  1576. }
  1577. }
  1578. #else //!_WIN64
  1579. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING, &var)))
  1580. {
  1581. pSecState->fHaveCert = (NULL != ((PCCERT_CONTEXT)var.ulVal));
  1582. if (pSecState->fHaveCert)
  1583. {
  1584. pSecState->szSignerEmail = SzGetCertificateEmailAddress((PCCERT_CONTEXT)var.ulVal);
  1585. CertFreeCertificateContext((PCCERT_CONTEXT)var.ulVal);
  1586. }
  1587. }
  1588. #endif // _WIN64
  1589. else
  1590. pSecState->fHaveCert = FALSE;
  1591. }
  1592. fWrapped = (pBody->IsContentType(STR_CNT_MULTIPART, "y-security") == S_OK);
  1593. if(phBody)
  1594. *phBody = hBody;
  1595. SafeRelease(pBody);
  1596. if (fWrapped)
  1597. {
  1598. hr = pMsg->GetBody(IBL_FIRST, hBody, &hBody);
  1599. Assert(SUCCEEDED(hr));
  1600. if (FAILED(hr))
  1601. break;
  1602. }
  1603. }
  1604. else
  1605. break;
  1606. if(IsSigned(pSecState->type) && !IsSignTrusted(pSecState))
  1607. break;
  1608. if(IsEncrypted(pSecState->type) && !IsEncryptionOK(pSecState))
  1609. break;
  1610. }while(fWrapped && hBody);
  1611. return hr;
  1612. }
  1613. /***************************************************************************
  1614. Name : CheckAndFixMissingCert
  1615. Purpose : Check to see if we can locate the certs for the missing
  1616. entries.
  1617. Parameters: hwnd = window handle
  1618. pAdrTable = Address Table object
  1619. pAccount = sending account
  1620. Returns : TRUE if we able to find and fix at least one missing cert.
  1621. FALSE if there was nothing we could do.
  1622. Comment :
  1623. ***************************************************************************/
  1624. BOOL CheckAndFixMissingMeCert(HWND hwnd, IMimeAddressTable *pAdrTable, IImnAccount *pAccount)
  1625. {
  1626. IMimeEnumAddressTypes *pEnum = NULL;
  1627. ADDRESSPROPS apAddress = {0};
  1628. ADDRESSPROPS apModify = {0};
  1629. TCHAR szAcctEmailAddress[CCHMAX_EMAIL_ADDRESS + 1] = "";
  1630. HRESULT hr;
  1631. THUMBBLOB tbSender = {0, 0};
  1632. BOOL fRet = FALSE;
  1633. PCCERT_CONTEXT pcCert = NULL;
  1634. Assert(pAdrTable && pAccount);
  1635. pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szAcctEmailAddress, sizeof(szAcctEmailAddress));
  1636. if (FAILED(pAdrTable->EnumTypes(IAT_TO | IAT_CC | IAT_BCC, IAP_HANDLE | IAP_EMAIL | IAP_ADRTYPE | IAP_CERTSTATE | IAP_FRIENDLY, &pEnum)))
  1637. return(FALSE);
  1638. while (S_OK == pEnum->Next(1, &apAddress, NULL))
  1639. {
  1640. if (CERTIFICATE_NOT_PRESENT == apAddress.certstate || CERTIFICATE_NOPRINT == apAddress.certstate)
  1641. {
  1642. // Don't have this recipient's cert
  1643. // Is this recipient ME?
  1644. if (! lstrcmpi(apAddress.pszEmail, szAcctEmailAddress))
  1645. {
  1646. // Yes, this is me. Get my cert and put it in here.
  1647. // Do I have a cert in the account?
  1648. hr = pAccount->GetProp(AP_SMTP_CERTIFICATE, NULL, &apModify.tbEncryption.cbSize);
  1649. if (SUCCEEDED(hr))
  1650. {
  1651. if (SUCCEEDED(HrAlloc((void**)&apModify.tbEncryption.pBlobData, apModify.tbEncryption.cbSize)))
  1652. pAccount->GetProp(AP_SMTP_CERTIFICATE, apModify.tbEncryption.pBlobData, &apModify.tbEncryption.cbSize);
  1653. }
  1654. else
  1655. {
  1656. // No, go get one
  1657. hr = _HrFindMyCertForAccount(hwnd, &pcCert, pAccount, FALSE);
  1658. if (SUCCEEDED(hr) && pcCert)
  1659. {
  1660. // Get the thumbprint
  1661. apModify.tbEncryption.pBlobData = (BYTE *)PVGetCertificateParam(pcCert, CERT_HASH_PROP_ID, &apModify.tbEncryption.cbSize);
  1662. CertFreeCertificateContext(pcCert);
  1663. pcCert = NULL;
  1664. }
  1665. }
  1666. // OK, do I finally have a cert?
  1667. if (apModify.tbEncryption.pBlobData && apModify.tbEncryption.cbSize)
  1668. {
  1669. apModify.dwProps = IAP_ENCRYPTION_PRINT;
  1670. if (SUCCEEDED(hr = pAdrTable->SetProps(apAddress.hAddress, &apModify)))
  1671. fRet = TRUE;
  1672. }
  1673. SafeMemFree(apModify.tbEncryption.pBlobData);
  1674. apModify.tbEncryption.cbSize = 0;
  1675. }
  1676. }
  1677. g_pMoleAlloc->FreeAddressProps(&apAddress);
  1678. }
  1679. ReleaseObj(pEnum);
  1680. return(fRet);
  1681. }
  1682. HRESULT SendSecureMailToOutBox(IStoreCallback *pStoreCB, LPMIMEMESSAGE pMsg, BOOL fSendImmediate, BOOL fNoUI, BOOL fMail, IHeaderSite *pHeaderSite)
  1683. {
  1684. HRESULT hr;
  1685. BOOL fNoErrorUI;
  1686. BOOL fContLoop;
  1687. BOOL fHaveSender;
  1688. BOOL fAllowTryAgain;
  1689. PROPVARIANT var;
  1690. BOOL fDontEncryptForSelf = !!DwGetOption(OPT_NO_SELF_ENCRYPT);
  1691. HWND hwndOwner = 0;
  1692. IImnAccount *pAccount = NULL;
  1693. CERTERRPARAM CertErrParam = {0};
  1694. Assert(IsSecure(pMsg));
  1695. pStoreCB->GetParentWindow(0, &hwndOwner);
  1696. AssertSz(hwndOwner, "How did we not get an hwnd???");
  1697. var.vt = VT_LPSTR;
  1698. hr = pMsg->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var);
  1699. if (FAILED(hr))
  1700. return hr;
  1701. hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, var.pszVal, &pAccount);
  1702. SafeMemFree(var.pszVal);
  1703. if (FAILED(hr))
  1704. return hr;
  1705. if (FAILED(hr = _HrPrepSecureMsgForSending(hwndOwner, pMsg, pAccount, &fHaveSender, &fDontEncryptForSelf, pHeaderSite)))
  1706. {
  1707. SafeRelease(pAccount);
  1708. return hr;
  1709. }
  1710. var.ulVal = 0;
  1711. hr = pMsg->GetOption(OID_SECURITY_ENCODE_FLAGS, &var);
  1712. if (fHaveSender)
  1713. {
  1714. var.ulVal |= SEF_SENDERSCERTPROVIDED;
  1715. hr = pMsg->SetOption(OID_SECURITY_ENCODE_FLAGS, &var);
  1716. }
  1717. fNoErrorUI = FALSE;
  1718. fContLoop = TRUE;
  1719. fAllowTryAgain = TRUE;
  1720. do
  1721. {
  1722. hr = SendMailToOutBox(pStoreCB, pMsg, fSendImmediate, fNoUI, fMail);
  1723. if (SUCCEEDED(hr))
  1724. {
  1725. fContLoop = FALSE;
  1726. break;
  1727. }
  1728. else if ((MIME_E_SECURITY_CERTERROR == hr) || (MIME_E_SECURITY_NOCERT == hr))
  1729. {
  1730. IMimeAddressTable *pAdrTable;
  1731. if (SUCCEEDED(hr = pMsg->GetAddressTable(&pAdrTable)))
  1732. {
  1733. // First off, are we sending to ourselves? If so, find our cert, make sure
  1734. // there's a cert associated with the account and then add it to the address
  1735. // table.
  1736. if (fAllowTryAgain && CheckAndFixMissingMeCert(hwndOwner,
  1737. pAdrTable,
  1738. pAccount))
  1739. {
  1740. // Try again, we found at least one missing cert.
  1741. fContLoop = TRUE;
  1742. }
  1743. else
  1744. {
  1745. // Didn't get them all, tell the user.
  1746. CertErrParam.pAdrTable = pAdrTable;
  1747. CertErrParam.fForceEncryption = FALSE;
  1748. if (pHeaderSite != NULL)
  1749. {
  1750. if(pHeaderSite->IsForceEncryption() == S_OK)
  1751. CertErrParam.fForceEncryption = TRUE;
  1752. }
  1753. if(IDOK == DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddSecCerificateErr),
  1754. hwndOwner, CertErrorDlgProc, (LPARAM)(&CertErrParam)))
  1755. {
  1756. ULONG ulSecurityType = MST_CLASS_SMIME_V1;
  1757. if (IsSigned(pMsg, TRUE))
  1758. ulSecurityType |= ((DwGetOption(OPT_OPAQUE_SIGN)) ? MST_THIS_BLOBSIGN : MST_THIS_SIGN);
  1759. else
  1760. ulSecurityType &= ~((DwGetOption(OPT_OPAQUE_SIGN)) ? MST_THIS_BLOBSIGN : MST_THIS_SIGN);
  1761. ulSecurityType &= ~MST_THIS_ENCRYPT;
  1762. hr = HrInitSecurityOptions(pMsg, ulSecurityType);
  1763. fContLoop = TRUE;
  1764. }
  1765. else
  1766. fContLoop = FALSE; //N work item: allow users to send anyway
  1767. fNoErrorUI = TRUE;
  1768. }
  1769. pAdrTable->Release();
  1770. fAllowTryAgain = FALSE;
  1771. }
  1772. }
  1773. else if (MIME_E_SECURITY_ENCRYPTNOSENDERCERT == hr)
  1774. {
  1775. // We may have situations in here Signed & Crypted, but no certificate (bug 60056)
  1776. if (IsSigned(pMsg, TRUE))
  1777. {
  1778. AthMessageBoxW(hwndOwner, MAKEINTRESOURCEW(idsSecurityWarning), MAKEINTRESOURCEW(idsErrSecurityNoSigningCert), NULL, MB_OK | MB_ICONEXCLAMATION);
  1779. fNoErrorUI = TRUE;
  1780. fContLoop = FALSE;
  1781. }
  1782. // find out if user doesn't care
  1783. else if (fDontEncryptForSelf || (IDYES == AthMessageBoxW(hwndOwner,
  1784. MAKEINTRESOURCEW(idsSecurityWarning),
  1785. MAKEINTRESOURCEW(idsWrnSecurityNoCertForEnc), NULL,
  1786. MB_YESNO|MB_DEFBUTTON2|MB_ICONWARNING|MB_SETFOREGROUND)))
  1787. {
  1788. var.ulVal |= SEF_ENCRYPTWITHNOSENDERCERT;
  1789. // abort on failure to avoid extra looping
  1790. if (FAILED(hr = pMsg->SetOption(OID_SECURITY_ENCODE_FLAGS, &var)))
  1791. fContLoop = FALSE;
  1792. }
  1793. else
  1794. {
  1795. fNoErrorUI = TRUE;
  1796. fContLoop = FALSE;
  1797. }
  1798. }
  1799. else if (CRYPT_E_NO_KEY_PROPERTY == hr)
  1800. {
  1801. // no choice for this one
  1802. AthMessageBoxW(hwndOwner,
  1803. MAKEINTRESOURCEW(idsSecurityWarning),
  1804. MAKEINTRESOURCEW(idsErrSecurityNoPrivateKey), NULL,
  1805. MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
  1806. fContLoop = FALSE;
  1807. fNoErrorUI = TRUE;
  1808. }
  1809. else if (E_ACCESSDENIED == hr)
  1810. {
  1811. // no choice for this one
  1812. AthMessageBoxW(hwndOwner,
  1813. MAKEINTRESOURCEW(idsSecurityWarning),
  1814. MAKEINTRESOURCEW(idsErrSecurityAccessDenied), NULL,
  1815. MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
  1816. fContLoop = FALSE;
  1817. fNoErrorUI = TRUE;
  1818. }
  1819. else
  1820. // unknown error
  1821. fContLoop = FALSE;
  1822. } while (fContLoop);
  1823. if (fNoErrorUI)
  1824. // return the recognized error code
  1825. hr = HR_E_ATHSEC_FAILED;
  1826. ReleaseObj(pAccount);
  1827. return hr;
  1828. }
  1829. HRESULT HrBuildAndVerifyCerts(HWND hwnd, IMimeMessageTree * pTree, DWORD * pcCert,
  1830. PCX509CERT ** prgpccert, PCCERT_CONTEXT pccertSender, IImnAccount *pAccount, IHeaderSite *pHeaderSite)
  1831. {
  1832. ADDRESSPROPS apEntry;
  1833. ADDRESSPROPS apModify;
  1834. DWORD cCerts;
  1835. DWORD cPrints = 0;
  1836. DWORD dw;
  1837. HRESULT hr;
  1838. DWORD i;
  1839. IMimeAddressTable * pAdrTbl = NULL;
  1840. IMimeEnumAddressTypes * pAdrEnum = NULL;
  1841. HCERTSTORE rgCertStore[2];
  1842. PCX509CERT * rgpccert = NULL;
  1843. CERTERRPARAM CertErrParam = {0};
  1844. if (SUCCEEDED(hr = pTree->BindToObject(HBODY_ROOT, IID_IMimeAddressTable,
  1845. (void**)&pAdrTbl))) {
  1846. hr = pAdrTbl->EnumTypes(IAT_TO | IAT_CC | IAT_BCC | IAT_SENDER,
  1847. IAP_HANDLE | IAP_ADRTYPE | IAP_SIGNING_PRINT |
  1848. IAP_ENCRYPTION_PRINT | IAP_CERTSTATE, &pAdrEnum);
  1849. }
  1850. pAdrEnum->Count(&cCerts);
  1851. if (cCerts == 0) {
  1852. return MIME_S_SECURITY_NOOP;
  1853. }
  1854. if (!MemAlloc((LPVOID *) &rgpccert, sizeof(PCX509CERT)*(cCerts+1))) {
  1855. return E_OUTOFMEMORY;
  1856. }
  1857. memset(rgpccert, 0, sizeof(CERTSTATE)*(cCerts+1));
  1858. rgCertStore[1] = CertOpenStore(CERT_STORE_PROV_SYSTEM_A,
  1859. X509_ASN_ENCODING, NULL,
  1860. CERT_STORE_READONLY_FLAG|CERT_SYSTEM_STORE_CURRENT_USER, c_szMyCertStore);
  1861. if (rgCertStore[1] == NULL) {
  1862. hr = MIME_S_SECURITY_ERROROCCURED;
  1863. goto Exit;
  1864. }
  1865. rgCertStore[0] = CertOpenStore(CERT_STORE_PROV_SYSTEM_A,
  1866. X509_ASN_ENCODING, NULL,
  1867. CERT_STORE_READONLY_FLAG|CERT_SYSTEM_STORE_CURRENT_USER, c_szWABCertStore);
  1868. if (rgCertStore[0] == NULL) {
  1869. hr = MIME_S_SECURITY_ERROROCCURED;
  1870. goto Exit;
  1871. }
  1872. pAdrEnum->Reset();
  1873. apModify.dwProps = IAP_CERTSTATE;
  1874. while (pAdrEnum->Next(1, &apEntry, NULL) == S_OK) {
  1875. Assert((apEntry.tbEncryption.pBlobData && apEntry.tbEncryption.cbSize) ||
  1876. (!apEntry.tbEncryption.pBlobData && !apEntry.tbEncryption.cbSize));
  1877. if (apEntry.tbEncryption.cbSize) {
  1878. CRYPT_DIGEST_BLOB blob;
  1879. // Make an assumption
  1880. apModify.certstate = CERTIFICATE_INVALID;
  1881. // we need to null out the thumbprint flag so print doesn't get
  1882. // freed below
  1883. blob.pbData = apEntry.tbEncryption.pBlobData;
  1884. blob.cbData = apEntry.tbEncryption.cbSize;
  1885. for (i=0; i<2; i++) {
  1886. rgpccert[cPrints] = CertFindCertificateInStore(rgCertStore[i],
  1887. X509_ASN_ENCODING, 0,
  1888. CERT_FIND_HASH,
  1889. (LPVOID) &blob, NULL);
  1890. if (rgpccert[cPrints] == NULL)
  1891. continue;
  1892. HrGetCertKeyUsage(rgpccert[cPrints], &dw);
  1893. if (!(dw & CERT_KEY_ENCIPHERMENT_KEY_USAGE)) {
  1894. CertFreeCertificateContext(rgpccert[cPrints]);
  1895. rgpccert[cPrints] = NULL;
  1896. continue;
  1897. }
  1898. dw = DwGenerateTrustedChain(hwnd, NULL, rgpccert[cPrints],
  1899. CERT_VALIDITY_NO_CRL_FOUND, TRUE, NULL, NULL);
  1900. if (dw & CERT_VALIDITY_NO_TRUST_DATA) {
  1901. apModify.certstate = CERTIFICATE_NOT_TRUSTED;
  1902. }
  1903. else if (dw & CERT_VALIDITY_NO_ISSUER_CERT_FOUND) {
  1904. apModify.certstate = CERTIFICATE_MISSING_ISSUER;
  1905. }
  1906. else if (dw & (CERT_VALIDITY_BEFORE_START | CERT_VALIDITY_AFTER_END)) {
  1907. apModify.certstate = CERTIFICATE_EXPIRED;
  1908. }
  1909. else if (dw & CERT_VALIDITY_CERTIFICATE_REVOKED) {
  1910. apModify.certstate = CERTIFICATE_CRL_LISTED;
  1911. }
  1912. else if (dw & CERT_VALIDITY_MASK_TRUST) {
  1913. apModify.certstate = CERTIFICATE_NOT_TRUSTED;
  1914. }
  1915. else if (dw & CERT_VALIDITY_MASK_VALIDITY) {
  1916. apModify.certstate = CERTIFICATE_INVALID;
  1917. }
  1918. // Check label
  1919. hr = S_OK;
  1920. if(pHeaderSite != NULL)
  1921. {
  1922. PSMIME_SECURITY_LABEL plabel = NULL;
  1923. hr = pHeaderSite->GetLabelFromNote(&plabel);
  1924. if(plabel)
  1925. {
  1926. hr = HrValidateLabelRecipCert(plabel, hwnd, rgpccert[cPrints]);
  1927. if(FAILED(hr))
  1928. apModify.certstate = CERTIFICATE_INVALID;
  1929. }
  1930. else
  1931. hr = S_OK; // ignore any error
  1932. }
  1933. if (dw || FAILED(hr))
  1934. {
  1935. CertFreeCertificateContext(rgpccert[cPrints]);
  1936. rgpccert[cPrints] = NULL;
  1937. continue;
  1938. }
  1939. apModify.certstate = CERTIFICATE_OK;
  1940. cPrints += 1;
  1941. break;
  1942. }
  1943. }
  1944. else {
  1945. apModify.certstate = CERTIFICATE_NOT_PRESENT;
  1946. }
  1947. SideAssert(SUCCEEDED(pAdrTbl->SetProps(apEntry.hAddress, &apModify)));
  1948. g_pMoleAlloc->FreeAddressProps(&apEntry);
  1949. }
  1950. // First off, are we sending to ourselves? If so, find our cert, make sure
  1951. // there's a cert associated with the account and then add it to the address
  1952. // table.
  1953. if ((pccertSender != NULL) && CheckAndFixMissingMeCert(hwnd, pAdrTbl, pAccount))
  1954. {
  1955. rgpccert[cPrints] = CertDuplicateCertificateContext(pccertSender);
  1956. cPrints += 1;
  1957. if (cCerts != cPrints)
  1958. goto NoCert;
  1959. }
  1960. else if (cCerts != cPrints) {
  1961. NoCert:
  1962. // Didn't get them all, tell the user.
  1963. CertErrParam.pAdrTable = pAdrTbl;
  1964. CertErrParam.fForceEncryption = FALSE;
  1965. if (pHeaderSite != NULL)
  1966. {
  1967. if(pHeaderSite->IsForceEncryption() == S_OK)
  1968. CertErrParam.fForceEncryption = TRUE;
  1969. }
  1970. if(IDOK ==DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddSecCerificateErr),
  1971. hwnd, CertErrorDlgProc, (LPARAM)(&CertErrParam)))
  1972. hr = S_FALSE;
  1973. else
  1974. hr = HR_E_ATHSEC_FAILED;
  1975. goto Exit;
  1976. }
  1977. else if(pccertSender != NULL) // include sender if we send encrypted message
  1978. {
  1979. rgpccert[cPrints] = CertDuplicateCertificateContext(pccertSender);
  1980. cPrints += 1;
  1981. }
  1982. *prgpccert = rgpccert;
  1983. *pcCert = cPrints;
  1984. Exit:
  1985. if (FAILED(hr)) {
  1986. for (i=0; i<cPrints; i++) {
  1987. if (rgpccert[i] != NULL) {
  1988. CertFreeCertificateContext(rgpccert[i]);
  1989. }
  1990. }
  1991. }
  1992. CertCloseStore(rgCertStore[1], 0);
  1993. CertCloseStore(rgCertStore[0], 0);
  1994. if(pAdrTbl)
  1995. ReleaseObj(pAdrTbl);
  1996. ReleaseObj(pAdrEnum);
  1997. return hr;
  1998. }
  1999. // This function parse error for signing certificate and do autoassociation in case if we have more signing certificate
  2000. //
  2001. HRESULT ProceedSignCertError(HWND hwnd, IImnAccount *pCertAccount, DWORD dwTrust)
  2002. {
  2003. ERRIDS ErrIds = {0, 0};
  2004. int cCert = 0;
  2005. HRESULT hr = S_OK;
  2006. if(!dwTrust)
  2007. return(S_OK);
  2008. // we must here parse the error
  2009. // Sure, the user might get multiple errors from this,
  2010. // but it is so rare I'll let this slide.
  2011. if (CERT_VALIDITY_BEFORE_START & dwTrust ||
  2012. CERT_VALIDITY_AFTER_END & dwTrust)
  2013. {
  2014. // do the fatal one first
  2015. ErrIds.idsText1 = idsErrSecuritySendExpiredSign;
  2016. }
  2017. else if(CERT_VALIDITY_OTHER_EXTENSION_FAILURE & dwTrust)
  2018. {
  2019. ErrIds.idsText1 = idsErrSecurityExtFailure;
  2020. }
  2021. else if(CERT_VALIDITY_CERTIFICATE_REVOKED & dwTrust)
  2022. {
  2023. ErrIds.idsText1 = idsErrSecurityCertRevoked;
  2024. }
  2025. else
  2026. {
  2027. ErrIds.idsText1 = idsErrSecuritySendTrust;
  2028. }
  2029. // Check # of available signed certificates for autoassociation.
  2030. cCert = GetNumMyCertForAccount(hwnd, pCertAccount, FALSE, NULL, NULL);
  2031. if(cCert < 1)
  2032. ErrIds.idsText2 = idsErrSignCertText20;
  2033. else if(cCert == 1)
  2034. ErrIds.idsText2 = idsErrSignCertText21;
  2035. else
  2036. ErrIds.idsText2 = idsErrSignCertText22;
  2037. INT uiRes = (INT) DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddWarnSecuritySigningCert),
  2038. hwnd, CertWarnDlgProc, ((LPARAM)(&ErrIds)));
  2039. if(uiRes == IDCANCEL) // cancel, return to note
  2040. hr = HR_E_ATHSEC_FAILED;
  2041. else if(uiRes == IDOK)
  2042. {
  2043. if(cCert < 1) // Go to web and return to note
  2044. {
  2045. GetDigitalIDs(pCertAccount);
  2046. hr = HR_E_ATHSEC_FAILED;
  2047. }
  2048. else // Do autoassociation
  2049. hr = HR_E_ATHSEC_USENEWSIGN;
  2050. }
  2051. else // Don't sign
  2052. hr = HR_E_ATHSEC_DONTSIGN;
  2053. return(hr);
  2054. }
  2055. // This function parse error for encryption certificate and uf user like to do it then remove it from account
  2056. //
  2057. HRESULT ProceedEncCertError(HWND hwnd, IImnAccount *pCertAccount, DWORD dwTrust)
  2058. {
  2059. WORD ids = 0;
  2060. HRESULT hr = S_OK;
  2061. if(!dwTrust)
  2062. return(S_OK);
  2063. // we must here parse the error
  2064. // Sure, the user might get multiple errors from this,
  2065. // but it is so rare I'll let this slide.
  2066. if (CERT_VALIDITY_BEFORE_START & dwTrust ||
  2067. CERT_VALIDITY_AFTER_END & dwTrust)
  2068. {
  2069. // do the fatal one first
  2070. ids = idsErrSecuritySendExpSignEnc;
  2071. }
  2072. else if(CERT_VALIDITY_OTHER_EXTENSION_FAILURE & dwTrust)
  2073. {
  2074. ids = idsErrSecurityExtFailureEnc;
  2075. }
  2076. else if(CERT_VALIDITY_CERTIFICATE_REVOKED & dwTrust)
  2077. {
  2078. ids = idsErrSecurityCertRevokedEnc;
  2079. }
  2080. else
  2081. {
  2082. ids = idsErrSecuritySendTrustEnc;
  2083. }
  2084. if(AthMessageBoxW(hwnd,
  2085. MAKEINTRESOURCEW(idsSecurityWarning),
  2086. MAKEINTRESOURCEW(ids), MAKEINTRESOURCEW(idsErrEncCertCommon),
  2087. MB_YESNO| MB_ICONWARNING| MB_SETFOREGROUND) != IDYES)
  2088. {
  2089. // Cancel send message in this case
  2090. hr = HR_E_ATHSEC_FAILED;
  2091. }
  2092. else
  2093. {
  2094. // remove wrong certificate from property
  2095. pCertAccount->SetProp(AP_SMTP_ENCRYPT_CERT, NULL, 0);
  2096. // send message anyway
  2097. hr = HR_E_ATHSEC_SAMEASSIGNED;
  2098. }
  2099. return(hr);
  2100. }
  2101. // Get certificate from Account, check it, display erro, set cheain to msg cert store
  2102. HRESULT HrPrepSignCert(HWND hwnd, BOOL fEncryptCert, BOOL fIsSigned, IImnAccount *pCertAccount, IMimeBody *pBody, PCX509CERT * ppCert,
  2103. BOOL *fDontEncryptForSelf, BOOL *fEncryptForMe, PCX509CERT pCertSig)
  2104. {
  2105. // need to check also encryption certificate and send it
  2106. THUMBBLOB tbCert = {0, 0};
  2107. HRESULT hr = S_OK;
  2108. HCERTSTORE hMyCertStore = NULL;
  2109. PROPVARIANT var;
  2110. DWORD dw = 0;
  2111. if (SUCCEEDED(hr = pCertAccount->GetProp((fEncryptCert ? AP_SMTP_ENCRYPT_CERT : AP_SMTP_CERTIFICATE), NULL, &tbCert.cbSize)))
  2112. {
  2113. // we have encryption certificate
  2114. hr = HrAlloc((void**)&tbCert.pBlobData, tbCert.cbSize);
  2115. if (SUCCEEDED(hr))
  2116. {
  2117. hr = pCertAccount->GetProp((fEncryptCert ? AP_SMTP_ENCRYPT_CERT : AP_SMTP_CERTIFICATE), tbCert.pBlobData, &tbCert.cbSize);
  2118. if (SUCCEEDED(hr))
  2119. {
  2120. hMyCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING,
  2121. NULL, CERT_SYSTEM_STORE_CURRENT_USER, c_szMyCertStore);
  2122. if (hMyCertStore)
  2123. {
  2124. //
  2125. // Check the chain
  2126. //
  2127. X509CERTRESULT certResult;
  2128. CERTSTATE cs;
  2129. PCX509CERT pCert = NULL;
  2130. certResult.cEntries = 1;
  2131. certResult.rgcs = &cs;
  2132. certResult.rgpCert = &pCert;
  2133. hr = MimeOleGetCertsFromThumbprints(&tbCert, &certResult, &hMyCertStore, 1);
  2134. if (S_OK == hr)
  2135. {
  2136. DWORD dwTrust;
  2137. PCCERT_CONTEXT *rgCertChain = NULL;
  2138. DWORD cCertChain = 0;
  2139. const DWORD dwIgnore = CERT_VALIDITY_NO_CRL_FOUND;
  2140. Assert(1 == certResult.cEntries);
  2141. // If we asking about encryption certificate we need to check that it's not the same
  2142. // as signrd
  2143. if(fEncryptCert && fIsSigned)
  2144. {
  2145. if(CertCompareCertificate(X509_ASN_ENCODING, pCert->pCertInfo, pCertSig->pCertInfo))
  2146. {
  2147. hr = HR_E_ATHSEC_SAMEASSIGNED;
  2148. goto Exit;
  2149. }
  2150. }
  2151. // As to CRLs, if we'll ever have one!
  2152. dwTrust = DwGenerateTrustedChain(hwnd, NULL, pCert,
  2153. dwIgnore, TRUE, &cCertChain, &rgCertChain);
  2154. if (dwTrust)
  2155. {
  2156. if (fIsSigned)
  2157. {
  2158. if(fEncryptCert)
  2159. {
  2160. if(pCertSig && SUCCEEDED(HrGetCertKeyUsage(pCertSig, &dw)))
  2161. {
  2162. if ((dw & (CERT_KEY_ENCIPHERMENT_KEY_USAGE |
  2163. CERT_KEY_AGREEMENT_KEY_USAGE)))
  2164. {
  2165. hr = HR_E_ATHSEC_SAMEASSIGNED;
  2166. goto Exit;
  2167. }
  2168. }
  2169. else
  2170. {
  2171. hr = HR_E_ATHSEC_SAMEASSIGNED;
  2172. goto Exit;
  2173. }
  2174. hr = ProceedEncCertError(hwnd, pCertAccount, dwTrust);
  2175. }
  2176. else
  2177. hr = ProceedSignCertError(hwnd, pCertAccount, dwTrust);
  2178. }
  2179. else
  2180. { // Encryption certificate
  2181. // we must here parse the error
  2182. WORD ids;
  2183. BOOL fFatal = TRUE;
  2184. // Sure, the user might get multiple errors from this,
  2185. // but it is so rare I'll let this slide.
  2186. if (CERT_VALIDITY_BEFORE_START & dwTrust ||
  2187. CERT_VALIDITY_AFTER_END & dwTrust)
  2188. {
  2189. // Assert(IsEncrypted(pMsg, TRUE));
  2190. ids = idsErrSecuritySendExpiredEnc;
  2191. fFatal = FALSE;
  2192. }
  2193. else if(CERT_VALIDITY_OTHER_EXTENSION_FAILURE & dwTrust)
  2194. {
  2195. ids = idsErrSecurityExtFailure;
  2196. fFatal = TRUE;
  2197. }
  2198. else if(CERT_VALIDITY_CERTIFICATE_REVOKED & dwTrust)
  2199. {
  2200. ids = (fEncryptCert ? idsErrSecurityCertRevokedEnc : idsErrSecurityCertRevoked);
  2201. fFatal = TRUE;
  2202. }
  2203. else
  2204. {
  2205. ids = idsErrSecuritySendTrustEnc;
  2206. fFatal = FALSE;
  2207. }
  2208. if (fFatal)
  2209. {
  2210. AthMessageBoxW(hwnd,
  2211. MAKEINTRESOURCEW(idsSecurityWarning),
  2212. MAKEINTRESOURCEW(ids), NULL,
  2213. MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
  2214. hr = HR_E_ATHSEC_FAILED;
  2215. }
  2216. else
  2217. {
  2218. if (IDYES != AthMessageBoxW(hwnd,
  2219. MAKEINTRESOURCEW(idsSecurityWarning),
  2220. MAKEINTRESOURCEW(ids), MAKEINTRESOURCEW(idsWrnSecEncryption),
  2221. MB_YESNO|MB_ICONWARNING|MB_SETFOREGROUND))
  2222. {
  2223. // This error code has the special meaning of
  2224. // "don't show any more UI, the user has been
  2225. // beaten enough"
  2226. hr = HR_E_ATHSEC_FAILED;
  2227. }
  2228. else
  2229. {
  2230. if(!fEncryptCert)
  2231. {
  2232. // Since the user's cert is expired, we won't
  2233. // let it be used to encrypt
  2234. *fEncryptForMe = FALSE;
  2235. *fDontEncryptForSelf = TRUE;
  2236. }
  2237. }
  2238. }
  2239. }
  2240. }
  2241. else // no errors
  2242. {
  2243. // We need to add encryption certificate to message cert store
  2244. #ifdef _WIN64 // (YST) I believe Win64 part will be not work...
  2245. if (DwGetOption(OPT_MAIL_INCLUDECERT))
  2246. {
  2247. var.vt = VT_VECTOR | VT_UI8;
  2248. if (0 != cCertChain)
  2249. {
  2250. var.cauh.cElems = cCertChain;
  2251. var.cauh.pElems = (ULARGE_INTEGER *)rgCertChain;
  2252. }
  2253. else
  2254. {
  2255. var.cauh.cElems = 1;
  2256. var.cauh.pElems = (ULARGE_INTEGER *)&pCert;
  2257. }
  2258. hr = pBody->SetOption(OID_SECURITY_RG_CERT_BAG_64, &var);
  2259. Assert((cCertChain > 0) || dwTrust);
  2260. }
  2261. #else //_WIN64
  2262. if (DwGetOption(OPT_MAIL_INCLUDECERT))
  2263. {
  2264. var.vt = VT_VECTOR | VT_UI4;
  2265. if (0 != cCertChain)
  2266. {
  2267. var.caul.cElems = cCertChain;
  2268. var.caul.pElems = (ULONG *)rgCertChain;
  2269. }
  2270. else
  2271. {
  2272. var.caul.cElems = 1;
  2273. var.caul.pElems = (ULONG *)&pCert;
  2274. }
  2275. hr = pBody->SetOption(OID_SECURITY_2KEY_CERT_BAG, &var);
  2276. Assert((cCertChain > 0) || dwTrust);
  2277. }
  2278. #endif // _WIN64
  2279. }
  2280. Exit:
  2281. *ppCert = pCert;
  2282. // Still might have a chain on error, so run the
  2283. // freeing code outside the result test
  2284. if (rgCertChain)
  2285. {
  2286. for (cCertChain--; int(cCertChain)>=0; cCertChain--)
  2287. CertFreeCertificateContext(rgCertChain[cCertChain]);
  2288. MemFree(rgCertChain);
  2289. }
  2290. }
  2291. else
  2292. hr = MIME_S_SECURITY_ERROROCCURED;
  2293. }
  2294. else
  2295. hr = MIME_S_SECURITY_ERROROCCURED;
  2296. if(hMyCertStore)
  2297. CertCloseStore(hMyCertStore, 0);
  2298. }
  2299. else
  2300. hr = MIME_S_SECURITY_ERROROCCURED;
  2301. }
  2302. if(tbCert.pBlobData)
  2303. MemFree(tbCert.pBlobData);
  2304. }
  2305. else
  2306. {
  2307. if (fIsSigned)
  2308. {
  2309. if(fEncryptCert)
  2310. {
  2311. if(pCertSig && SUCCEEDED(HrGetCertKeyUsage(pCertSig, &dw)))
  2312. {
  2313. if ((dw & (CERT_KEY_ENCIPHERMENT_KEY_USAGE |
  2314. CERT_KEY_AGREEMENT_KEY_USAGE)))
  2315. {
  2316. hr = HR_E_ATHSEC_SAMEASSIGNED;
  2317. return(hr);
  2318. }
  2319. }
  2320. else
  2321. {
  2322. hr = HR_E_ATHSEC_SAMEASSIGNED;
  2323. return(hr);
  2324. }
  2325. }
  2326. }
  2327. hr = MIME_S_SECURITY_ERROROCCURED;
  2328. }
  2329. return(hr);
  2330. }
  2331. HRESULT _HrPrepSecureMsgForSending(HWND hwnd, LPMIMEMESSAGE pMsg, IImnAccount *pAccount, BOOL *pfHaveSenderCert, BOOL *fDontEncryptForSelf, IHeaderSite *pHeaderSite)
  2332. {
  2333. HRESULT hr;
  2334. IMimeBody *pBody = NULL;
  2335. // THUMBBLOB tbSender = {0, 0};
  2336. BOOL fIsSigned = IsSigned(pMsg, TRUE);
  2337. BOOL fIsEncrypted = IsEncrypted(pMsg, TRUE);
  2338. BOOL fAllowTryAgain = TRUE;
  2339. IImnAccount *pCertAccount = NULL;
  2340. ACCTTYPE acctType;
  2341. PROPVARIANT var;
  2342. SYSTEMTIME stNow;
  2343. DWORD cCert=0;
  2344. DWORD i;
  2345. PCCERT_CONTEXT pccertSender = NULL;
  2346. PCX509CERT * rgpccert = NULL;
  2347. hr = pAccount->GetAccountType(&acctType);
  2348. if (FAILED(hr))
  2349. goto Exit;
  2350. if (ACCT_NEWS == acctType)
  2351. {
  2352. if (IDCANCEL == DoDontShowMeAgainDlg(hwnd, c_szDSUseMailCertInNews, MAKEINTRESOURCE(idsAthena),
  2353. MAKEINTRESOURCE(idsWarnUseMailCertInNews), MB_OKCANCEL))
  2354. hr = MAPI_E_USER_CANCEL;
  2355. else
  2356. hr = g_pAcctMan->GetDefaultAccount(ACCT_MAIL, &pCertAccount);
  2357. if (FAILED(hr))
  2358. goto Exit;
  2359. }
  2360. else
  2361. ReplaceInterface(pCertAccount, pAccount);
  2362. Assert(pMsg && pAccount && pfHaveSenderCert);
  2363. *pfHaveSenderCert = FALSE;
  2364. hr = pMsg->BindToObject(HBODY_ROOT, IID_IMimeBody, (void **)&pBody);
  2365. if (FAILED(hr))
  2366. goto Exit;
  2367. GetSystemTime(&stNow);
  2368. SystemTimeToFileTime(&stNow, &var.filetime);
  2369. var.vt = VT_FILETIME;
  2370. pBody->SetOption(OID_SECURITY_SIGNTIME, &var);
  2371. // Here, we should check the encryption algorithm
  2372. if (fIsEncrypted)
  2373. {
  2374. if (SUCCEEDED(hr = pBody->GetOption(OID_SECURITY_ALG_BULK, &var)))
  2375. {
  2376. DWORD dwStrength = 40; // default
  2377. DWORD dwWarnStrength = DwGetOption(OPT_MAIL_ENCRYPT_WARN_BITS);
  2378. // Figure out the bit-strength of this algorithm.
  2379. Assert(var.vt == VT_BLOB);
  2380. if (var.blob.pBlobData)
  2381. {
  2382. MimeOleAlgStrengthFromSMimeCap(var.blob.pBlobData, var.blob.cbSize, TRUE, &dwStrength);
  2383. SafeMemFree(var.blob.pBlobData);
  2384. }
  2385. if (! dwWarnStrength) // zero is the default to highest available
  2386. // Calculate the highest available
  2387. dwWarnStrength = GetHighestEncryptionStrength();
  2388. if (dwStrength < dwWarnStrength)
  2389. {
  2390. // Load the warning string and fill it in with the numbers.
  2391. LPTSTR lpMessage = NULL;
  2392. DWORD rgdw[2] = {dwStrength, dwWarnStrength};
  2393. TCHAR szBuffer[256] = ""; // really ought to be big enough
  2394. DWORD dwResult = IDNO;
  2395. LoadString(g_hLocRes, idsWrnLowSecurity, szBuffer, sizeof(szBuffer));
  2396. if (szBuffer[0])
  2397. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  2398. FORMAT_MESSAGE_FROM_STRING |
  2399. FORMAT_MESSAGE_ARGUMENT_ARRAY, szBuffer,
  2400. 0, 0,
  2401. (LPTSTR)&lpMessage, 0, (va_list *)rgdw);
  2402. if (lpMessage)
  2403. {
  2404. dwResult = AthMessageBox(hwnd,
  2405. MAKEINTRESOURCE(idsSecurityWarning),
  2406. lpMessage,
  2407. NULL,
  2408. MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING | MB_SETFOREGROUND);
  2409. LocalFree(lpMessage); // allocated by WIN32 inside FormatMessage
  2410. }
  2411. if (IDYES != dwResult)
  2412. {
  2413. hr = HR_E_ATHSEC_FAILED;
  2414. goto Exit;
  2415. }
  2416. }
  2417. }
  2418. }
  2419. try_again:
  2420. if ((*fDontEncryptForSelf))
  2421. hr = E_NoPropData;
  2422. if ((!(*fDontEncryptForSelf) || fIsSigned))
  2423. {
  2424. PCX509CERT pCert = NULL;
  2425. BOOL fEncryptForMe = TRUE;
  2426. #ifndef _WIN64
  2427. var.ulVal = 0;
  2428. var.vt = VT_UI4;
  2429. hr = pBody->SetOption(OID_SECURITY_HCERTSTORE, &var);
  2430. #else
  2431. var.pulVal = 0;
  2432. var.vt = VT_UI8;
  2433. hr = pBody->SetOption(OID_SECURITY_HCERTSTORE_64, &var);
  2434. #endif
  2435. hr = S_OK;
  2436. if(fIsSigned)
  2437. hr = HrPrepSignCert(hwnd,
  2438. FALSE /* fEncryptCert*/,
  2439. fIsSigned,
  2440. pCertAccount,
  2441. pBody,
  2442. &pCert,
  2443. fDontEncryptForSelf,
  2444. &fEncryptForMe,
  2445. NULL);
  2446. else
  2447. pCert = NULL;
  2448. // This will only be valid if we got an S_OK from the cert
  2449. // finder.
  2450. if(hr == S_OK)
  2451. {
  2452. #ifdef _WIN64
  2453. var.vt = VT_UI8;
  2454. var.pulVal = (ULONG *) pCert;
  2455. hr = pBody->SetOption(OID_SECURITY_CERT_SIGNING_64, &var);
  2456. #else //_WIN64
  2457. var.vt = VT_UI4;
  2458. var.ulVal = (ULONG) pCert;
  2459. if(fIsSigned)
  2460. hr = pBody->SetOption(OID_SECURITY_CERT_SIGNING, &var);
  2461. #endif // _WIN64
  2462. // need to check also encryption certificate and send it
  2463. PCX509CERT pCertEnc = NULL;
  2464. fAllowTryAgain = TRUE;
  2465. try_encrypt:
  2466. hr = HrPrepSignCert(hwnd,
  2467. TRUE, // fEncryptCert,
  2468. fIsSigned,
  2469. pCertAccount,
  2470. pBody,
  2471. &pCertEnc,
  2472. fDontEncryptForSelf,
  2473. &fEncryptForMe,
  2474. pCert // Signed certificate
  2475. );
  2476. if((hr == HR_E_ATHSEC_SAMEASSIGNED) || // Encryption certificate is the same as signed
  2477. (hr == E_NoPropData))
  2478. {
  2479. if(fEncryptForMe)
  2480. {
  2481. pccertSender = CertDuplicateCertificateContext(pCert);
  2482. *pfHaveSenderCert = TRUE;
  2483. }
  2484. // Do nothing in this case
  2485. hr = S_OK;
  2486. goto EncrDone;
  2487. }
  2488. // This will only be valid if we got an S_OK from the cert
  2489. // finder. This is because we only ask for one.
  2490. if(hr == S_OK)
  2491. {
  2492. if(fEncryptForMe)
  2493. {
  2494. pccertSender = CertDuplicateCertificateContext(pCertEnc);
  2495. *pfHaveSenderCert = TRUE;
  2496. }
  2497. if(!fIsSigned)
  2498. goto EncrDone;
  2499. // Now wee need to set auth attribute
  2500. // OE will use Issuer and Serial # for searching certificate in Message store
  2501. // 1. Prepare CRYPT_RECIPIENT_ID
  2502. // 2. Add it to the message
  2503. CRYPT_RECIPIENT_ID rid;
  2504. LPBYTE pbData = NULL;
  2505. DWORD cbData = 0;
  2506. CRYPT_ATTRIBUTE attr;
  2507. CRYPT_ATTRIBUTES Attrs;
  2508. CRYPT_ATTR_BLOB BlobEnc;
  2509. LPBYTE pbBlob = NULL;
  2510. DWORD cbBlob = 0;
  2511. IMimeSecurity2 * psm2 = NULL;
  2512. IF_FAILEXIT(hr = pBody->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &psm2));
  2513. // 1. Prepare CRYPT_RECIPIENT_ID
  2514. rid.dwRecipientType = 0;
  2515. rid.Issuer = pCertEnc->pCertInfo->Issuer;
  2516. rid.SerialNumber = pCertEnc->pCertInfo->SerialNumber;
  2517. BOOL fResult = CryptEncodeObjectEx(X509_ASN_ENCODING, szOID_Microsoft_Encryption_Cert,
  2518. &rid, CRYPT_ENCODE_ALLOC_FLAG, &CryptEncodeAlloc,
  2519. &pbData,
  2520. &cbData);
  2521. // Fatal error if fResult is FALSE,
  2522. // need a parsing
  2523. if(!fResult)
  2524. {
  2525. FatalEnc:
  2526. CertFreeCertificateContext(pCertEnc);
  2527. AthMessageBoxW(hwnd,
  2528. MAKEINTRESOURCEW(idsSecurityWarning),
  2529. MAKEINTRESOURCEW(idsErrSecurityExtFailure), NULL,
  2530. MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
  2531. hr = HR_E_ATHSEC_FAILED;
  2532. goto exit;
  2533. }
  2534. // 2. Prepare array of attributes (in our case just 1)
  2535. BlobEnc.cbData = cbData;
  2536. BlobEnc.pbData = pbData;
  2537. attr.pszObjId = szOID_Microsoft_Encryption_Cert;
  2538. attr.cValue = 1;
  2539. attr.rgValue = &BlobEnc;
  2540. hr = psm2->SetAttribute(0, 0, SMIME_ATTRIBUTE_SET_SIGNED, &attr);
  2541. if (FAILED(hr))
  2542. goto FatalEnc;
  2543. psm2->Release();
  2544. }
  2545. else if (MIME_S_SECURITY_ERROROCCURED == hr)
  2546. {
  2547. // We are missing a encryption cert. If it is signed or encrypted
  2548. // go try to find a cert to use.
  2549. //
  2550. // If it is encrypted to someone else, let the S/MIME engine handle
  2551. // This allows the order of errors to become
  2552. // 1) errors for lack of recip certs
  2553. // 2) warn no sender cert
  2554. if (fAllowTryAgain && (fIsSigned || !(*fDontEncryptForSelf)))
  2555. {
  2556. fAllowTryAgain = FALSE; // Only one more try, please. Prevent infinite loop.
  2557. // Is there a cert that I can use? If so, let's go associate it with the
  2558. // account and try again.
  2559. if (SUCCEEDED(hr = _HrFindMyCertForAccount(hwnd, NULL, pAccount, TRUE)))
  2560. {
  2561. // Go back and try again.
  2562. pCertEnc = NULL;
  2563. goto try_encrypt;
  2564. }
  2565. else if(hr != MAPI_E_USER_CANCEL)
  2566. {
  2567. if(!fIsEncrypted || (IDYES == AthMessageBoxW(hwnd,
  2568. MAKEINTRESOURCEW(idsSecurityWarning),
  2569. MAKEINTRESOURCEW(idsWrnSecurityNoCertForEnc), NULL,
  2570. MB_YESNO|MB_DEFBUTTON2|MB_ICONWARNING|MB_SETFOREGROUND)))
  2571. hr = S_OK;
  2572. else
  2573. hr = HR_E_ATHSEC_FAILED;
  2574. }
  2575. }
  2576. }
  2577. EncrDone:
  2578. if(pCertEnc)
  2579. CertFreeCertificateContext(pCertEnc);
  2580. if((HR_E_ATHSEC_FAILED != hr) && (hr != MAPI_E_USER_CANCEL))
  2581. {
  2582. // check secutity label
  2583. if ((pHeaderSite != NULL) && fIsSigned)
  2584. {
  2585. PSMIME_SECURITY_LABEL plabel = NULL;
  2586. CRYPT_ATTRIBUTE attrCrypt;
  2587. CRYPT_ATTR_BLOB valCrypt;
  2588. IMimeSecurity2 * pSMIME3 = NULL;
  2589. if(pBody->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &pSMIME3) == S_OK)
  2590. {
  2591. hr = pHeaderSite->GetLabelFromNote(&plabel);
  2592. if(hr == S_OK )
  2593. {
  2594. if((plabel != NULL) && SUCCEEDED(hr = HrValidateLabelOnSend(plabel, hwnd, pCert, 0, NULL)))
  2595. {
  2596. LPBYTE pbLabel = NULL;
  2597. DWORD cbLabel;
  2598. // hr = HrEncodeAndAlloc(X509_ASN_ENCODING,
  2599. // szOID_SMIME_Security_Label, plabel,
  2600. // &pbLabel, &cbLabel);
  2601. if(CryptEncodeObjectEx(X509_ASN_ENCODING, szOID_SMIME_Security_Label,
  2602. plabel, CRYPT_ENCODE_ALLOC_FLAG, &CryptEncodeAlloc,
  2603. &pbLabel, &cbLabel))
  2604. {
  2605. attrCrypt.pszObjId = szOID_SMIME_Security_Label;
  2606. attrCrypt.cValue = 1;
  2607. attrCrypt.rgValue = &valCrypt;
  2608. valCrypt.cbData = cbLabel;
  2609. valCrypt.pbData = pbLabel;
  2610. hr = pSMIME3->SetAttribute(0, 0, SMIME_ATTRIBUTE_SET_SIGNED, &attrCrypt);
  2611. }
  2612. else
  2613. hr = HR_E_ATHSEC_FAILED;
  2614. SafeMemFree(pbLabel);
  2615. }
  2616. else
  2617. {
  2618. if(SUCCEEDED(hr))
  2619. hr = HR_E_ATHSEC_FAILED;
  2620. }
  2621. if(FAILED(hr))
  2622. {
  2623. if(hr != HR_E_ATHSEC_FAILED)
  2624. {
  2625. AthMessageBoxW(hwnd,
  2626. MAKEINTRESOURCEW(idsSecurityWarning),
  2627. MAKEINTRESOURCEW(idsSecPolicyBadCert), NULL,
  2628. MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
  2629. hr = HR_E_ATHSEC_FAILED;
  2630. }
  2631. else if(IDYES == AthMessageBoxW(hwnd,
  2632. MAKEINTRESOURCEW(idsSecurityWarning),
  2633. MAKEINTRESOURCEW(idsSendLabelErr), NULL,
  2634. MB_YESNO|MB_DEFBUTTON2|MB_ICONWARNING|MB_SETFOREGROUND))
  2635. hr = S_OK;
  2636. else
  2637. hr = HR_E_ATHSEC_FAILED;
  2638. }
  2639. if(FAILED(hr))
  2640. {
  2641. SafeRelease(pSMIME3);
  2642. goto exit;
  2643. }
  2644. }
  2645. // Check security receipts
  2646. if (pHeaderSite->IsSecReceiptRequest() == S_OK)
  2647. {
  2648. CERT_NAME_BLOB blob;
  2649. // DATA_BLOB BlobId;
  2650. SMIME_RECEIPT_REQUEST req = {0};
  2651. DWORD cbName;
  2652. SpBYTE pbName;
  2653. LPBYTE pbReq = NULL;
  2654. DWORD cbReq = 0;
  2655. CERT_ALT_NAME_INFO SenderName;
  2656. PCERT_ALT_NAME_ENTRY palt;
  2657. // Get a sender name and encrypt it
  2658. LPSTR szCertEmailAddress = SzGetCertificateEmailAddress(pCert);
  2659. Assert(szCertEmailAddress != NULL);
  2660. if(MemAlloc((LPVOID *) &palt, sizeof(CERT_ALT_NAME_ENTRY)))
  2661. {
  2662. TCHAR pchContentID[CONTENTID_SIZE]; // length this will be 46. See CreateContentIdentifier comment
  2663. CreateContentIdentifier(pchContentID, ARRAYSIZE(pchContentID), pMsg);
  2664. MimeOleSetBodyPropA(pMsg, HBODY_ROOT, STR_HDR_XMSOESREC, NOFLAGS, pchContentID);
  2665. req.ContentIdentifier.pbData = (BYTE *) pchContentID;
  2666. req.ContentIdentifier.cbData = lstrlen(pchContentID);
  2667. palt->pwszRfc822Name = NULL;
  2668. palt->dwAltNameChoice = CERT_ALT_NAME_RFC822_NAME;
  2669. cbName = MultiByteToWideChar(CP_ACP, 0, szCertEmailAddress, -1, NULL, 0);
  2670. if (MemAlloc((LPVOID *) &(palt->pwszRfc822Name), (cbName + 1)*sizeof(WCHAR)))
  2671. {
  2672. MultiByteToWideChar(CP_ACP, 0, szCertEmailAddress, -1, palt->pwszRfc822Name, cbName);
  2673. SenderName.cAltEntry = 1;
  2674. SenderName.rgAltEntry = palt;
  2675. if(CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
  2676. &SenderName, CRYPT_ENCODE_ALLOC_FLAG, &CryptEncodeAlloc,
  2677. &pbName, &cbName))
  2678. {
  2679. blob.pbData = pbName;
  2680. blob.cbData = cbName;
  2681. // create sec receipt request
  2682. req.ReceiptsFrom.AllOrFirstTier = SMIME_RECEIPTS_FROM_ALL;
  2683. req.ReceiptsFrom.cNames = 0;
  2684. req.cReceiptsTo = 1;
  2685. req.rgReceiptsTo = &blob;
  2686. // Encrypt it
  2687. if(CryptEncodeObjectEx(X509_ASN_ENCODING, szOID_SMIME_Receipt_Request,
  2688. &req, CRYPT_ENCODE_ALLOC_FLAG, &CryptEncodeAlloc,
  2689. &pbReq, &cbReq))
  2690. {
  2691. // Set sec receipt request attribute
  2692. attrCrypt.pszObjId = szOID_SMIME_Receipt_Request;
  2693. attrCrypt.cValue = 1;
  2694. attrCrypt.rgValue = &valCrypt;
  2695. valCrypt.cbData = cbReq;
  2696. valCrypt.pbData = pbReq;
  2697. hr = pSMIME3->SetAttribute(0, 0, SMIME_ATTRIBUTE_SET_SIGNED, &attrCrypt);
  2698. Assert(hr == S_OK);
  2699. SafeMemFree(pbReq);
  2700. }
  2701. else
  2702. hr = HR_E_ATHSEC_FAILED;
  2703. SafeMemFree(pbName);
  2704. }
  2705. else
  2706. hr = HR_E_ATHSEC_FAILED;
  2707. SafeMemFree(palt->pwszRfc822Name);
  2708. }
  2709. else
  2710. hr = HR_E_ATHSEC_FAILED;
  2711. SafeMemFree(palt);
  2712. }
  2713. else
  2714. hr = HR_E_ATHSEC_FAILED;
  2715. if(FAILED(hr))
  2716. {
  2717. if(IDYES == AthMessageBoxW(hwnd,
  2718. MAKEINTRESOURCEW(idsSecurityWarning),
  2719. MAKEINTRESOURCEW(idsSendRecRequestErr), NULL,
  2720. MB_YESNO|MB_DEFBUTTON2|MB_ICONWARNING|MB_SETFOREGROUND))
  2721. hr = S_OK;
  2722. else
  2723. hr = HR_E_ATHSEC_FAILED;
  2724. }
  2725. if(FAILED(hr))
  2726. goto exit;
  2727. SafeMemFree(szCertEmailAddress);
  2728. }
  2729. SafeRelease(pSMIME3);
  2730. }
  2731. }
  2732. }
  2733. }
  2734. else if (MIME_S_SECURITY_ERROROCCURED == hr)
  2735. {
  2736. // We are missing a MY cert. If it is signed or encrypted
  2737. // go try to find a cert to use.
  2738. //
  2739. // If it is encrypted to someone else, let the S/MIME engine handle
  2740. // This allows the order of errors to become
  2741. // 1) errors for lack of recip certs
  2742. // 2) warn no sender cert
  2743. hr = fIsSigned ? HR_E_ATHSEC_NOCERTTOSIGN : S_OK;
  2744. if (fAllowTryAgain && (fIsSigned || !(*fDontEncryptForSelf)))
  2745. {
  2746. fAllowTryAgain = FALSE; // Only one more try, please. Prevent infinite loop.
  2747. // Is there a cert that I can use? If so, let's go associate it with the
  2748. // account and try again.
  2749. if (SUCCEEDED(hr = _HrFindMyCertForAccount(hwnd, NULL, pAccount, /*fIsSigned ?*/ FALSE /*: TRUE*/)))
  2750. // Go back and try again.
  2751. goto try_again;
  2752. else if(fIsEncrypted)
  2753. {
  2754. if(IDYES == AthMessageBoxW(hwnd,
  2755. MAKEINTRESOURCEW(idsSecurityWarning),
  2756. MAKEINTRESOURCEW(idsWrnSecurityNoCertForEnc), NULL,
  2757. MB_YESNO|MB_DEFBUTTON2|MB_ICONWARNING|MB_SETFOREGROUND))
  2758. hr = S_OK;
  2759. else
  2760. hr = HR_E_ATHSEC_FAILED;
  2761. }
  2762. }
  2763. }
  2764. // This will only be valid if we got an S_OK from the cert
  2765. // finder. This is because we only ask for one.
  2766. if(pCert)
  2767. CertFreeCertificateContext(pCert);
  2768. }
  2769. else
  2770. {
  2771. if (E_NoPropData == hr)
  2772. {
  2773. BOOL fTryAgain = FALSE;
  2774. DOUTL(DOUTL_CRYPT, "No certificate for this account...");
  2775. // We are missing a MY cert. If it is signed or encrypted
  2776. // go try to find a cert to use.
  2777. //
  2778. // If it is encrypted to someone else, let the S/MIME engine handle
  2779. // This allows the order of errors to become
  2780. // 1) errors for lack of recip certs
  2781. // 2) warn no sender cert
  2782. hr = fIsSigned ? HR_E_ATHSEC_NOCERTTOSIGN : S_OK;
  2783. if (fAllowTryAgain && (fIsSigned || !(*fDontEncryptForSelf)))
  2784. {
  2785. fAllowTryAgain = FALSE; // Only one more try, please. Prevent infinite loop.
  2786. // Is there a cert that I can use? If so, let's go associate it with the
  2787. // account and try again.
  2788. if (SUCCEEDED(hr = _HrFindMyCertForAccount(hwnd, NULL, pAccount, TRUE)))
  2789. // Go back and try again.
  2790. goto try_again;
  2791. }
  2792. }
  2793. }
  2794. if(FAILED(hr))
  2795. goto Exit;
  2796. if (fIsEncrypted)
  2797. {
  2798. if((hr = HrBuildAndVerifyCerts(hwnd, pMsg, &cCert, &rgpccert, pccertSender, pAccount, pHeaderSite)) == S_FALSE)
  2799. {
  2800. ULONG ulSecurityType = MST_CLASS_SMIME_V1;
  2801. if (fIsSigned)
  2802. ulSecurityType |= ((DwGetOption(OPT_OPAQUE_SIGN)) ? MST_THIS_BLOBSIGN : MST_THIS_SIGN);
  2803. else
  2804. ulSecurityType &= ~((DwGetOption(OPT_OPAQUE_SIGN)) ? MST_THIS_BLOBSIGN : MST_THIS_SIGN);
  2805. ulSecurityType &= ~MST_THIS_ENCRYPT;
  2806. hr = HrInitSecurityOptions(pMsg, ulSecurityType);
  2807. fIsEncrypted = FALSE;
  2808. goto exit;
  2809. }
  2810. CHECKHR(hr);
  2811. if (cCert > 0)
  2812. {
  2813. PROPVARIANT var;
  2814. #ifdef _WIN64
  2815. var.vt = VT_UI8;
  2816. var.cauh.cElems = cCert;
  2817. var.cauh.pElems = (ULARGE_INTEGER *) rgpccert;
  2818. CHECKHR(hr = pBody->SetOption(OID_SECURITY_RG_CERT_ENCRYPT_64, &var));
  2819. #else // !_WIN64
  2820. var.vt = VT_UI4;
  2821. var.caul.cElems = cCert;
  2822. var.caul.pElems = (ULONG *) rgpccert;
  2823. CHECKHR(hr = pBody->SetOption(OID_SECURITY_RG_CERT_ENCRYPT, &var));
  2824. #endif // _WIN64
  2825. }
  2826. }
  2827. Exit:
  2828. // For signing messages
  2829. if(fIsSigned)
  2830. {
  2831. // Do autoassociation
  2832. if(hr == HR_E_ATHSEC_USENEWSIGN)
  2833. {
  2834. if (SUCCEEDED(hr = _HrFindMyCertForAccount(hwnd, NULL, pAccount, FALSE)))
  2835. {
  2836. // Go back and try again.
  2837. fAllowTryAgain = TRUE;
  2838. goto try_again;
  2839. }
  2840. }
  2841. else if(hr == HR_E_ATHSEC_DONTSIGN) // Don't sign message
  2842. {
  2843. ULONG ulSecurityType = MST_CLASS_SMIME_V1;
  2844. if (fIsEncrypted)
  2845. ulSecurityType |= MST_THIS_ENCRYPT;
  2846. ulSecurityType &= ~((DwGetOption(OPT_OPAQUE_SIGN)) ? MST_THIS_BLOBSIGN : MST_THIS_SIGN);
  2847. hr = HrInitSecurityOptions(pMsg, ulSecurityType);
  2848. fIsSigned = FALSE;
  2849. }
  2850. }
  2851. exit:
  2852. ReleaseObj(pBody);
  2853. ReleaseObj(pCertAccount);
  2854. if (rgpccert != NULL)
  2855. {
  2856. for (i=0; i<cCert; i++)
  2857. {
  2858. if (rgpccert[i] != NULL)
  2859. CertFreeCertificateContext(rgpccert[i]);
  2860. }
  2861. if (pccertSender != NULL)
  2862. CertFreeCertificateContext(pccertSender);
  2863. }
  2864. return TrapError(hr);
  2865. }
  2866. DWORD DwGenerateTrustedChain(
  2867. HWND hwnd,
  2868. IMimeMessage * pMsg,
  2869. PCCERT_CONTEXT pcCertToTest,
  2870. DWORD dwToIgnore,
  2871. BOOL fFullSearch,
  2872. DWORD * pcChain,
  2873. PCCERT_CONTEXT ** prgChain)
  2874. {
  2875. DWORD dwErr = 0;
  2876. GUID guidAction = CERT_CERTIFICATE_ACTION_VERIFY;
  2877. CERT_VERIFY_CERTIFICATE_TRUST trust = {0};
  2878. WINTRUST_BLOB_INFO blob = {0};
  2879. WINTRUST_DATA data = {0};
  2880. IMimeBody * pBody;
  2881. PROPVARIANT var;
  2882. HCERTSTORE rgCAs[3] = {0};
  2883. HCERTSTORE *pCAs = NULL;
  2884. HCERTSTORE hMsg = NULL;
  2885. FILETIME FileTime;
  2886. SYSTEMTIME SysTime;
  2887. LONG lr = 0;
  2888. BOOL fIgnoreTimeError = FALSE;
  2889. HBODY hBody = NULL;
  2890. Assert(pcCertToTest);
  2891. if (pMsg)
  2892. {
  2893. if(FAILED(HrGetInnerLayer(pMsg, &hBody)))
  2894. goto contin;
  2895. pMsg->BindToObject(hBody ? hBody : HBODY_ROOT, IID_IMimeBody, (void**)&pBody);
  2896. if (pBody)
  2897. {
  2898. #ifdef _WIN64
  2899. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE_64, &var)))
  2900. hMsg = (HCERTSTORE) (var.pulVal);
  2901. #else // !_WIN64
  2902. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE, &var)))
  2903. hMsg = (HCERTSTORE)var.ulVal;
  2904. #endif // _WIN64
  2905. pBody->Release();
  2906. if (hMsg)
  2907. {
  2908. rgCAs[0] = hMsg;
  2909. rgCAs[1] = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, c_szMyCertStore);
  2910. if (rgCAs[1])
  2911. {
  2912. rgCAs[2] = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, c_szCACertStore);
  2913. if (rgCAs[2])
  2914. pCAs = rgCAs;
  2915. }
  2916. }
  2917. }
  2918. }
  2919. contin:
  2920. data.cbStruct = sizeof(WINTRUST_DATA);
  2921. data.pPolicyCallbackData = NULL;
  2922. data.pSIPClientData = NULL;
  2923. data.dwUIChoice = WTD_UI_NONE;
  2924. data.fdwRevocationChecks = WTD_REVOKE_NONE;
  2925. data.dwUnionChoice = WTD_CHOICE_BLOB;
  2926. data.pBlob = &blob;
  2927. blob.cbStruct = sizeof(WINTRUST_BLOB_INFO);
  2928. blob.pcwszDisplayName = NULL;
  2929. blob.cbMemObject = sizeof(trust);
  2930. blob.pbMemObject = (LPBYTE)&trust;
  2931. trust.cbSize = sizeof(trust);
  2932. trust.pccert = pcCertToTest;
  2933. trust.dwFlags = (fFullSearch ? CERT_TRUST_DO_FULL_SEARCH : 0);
  2934. trust.pdwErrors = &dwErr;
  2935. trust.pszUsageOid = szOID_PKIX_KP_EMAIL_PROTECTION;
  2936. trust.pcChain = pcChain;
  2937. trust.prgChain = prgChain;
  2938. if(!((DwGetOption(OPT_REVOKE_CHECK) != 0) && !g_pConMan->IsGlobalOffline() && CheckCDPinCert(pcCertToTest)))
  2939. trust.dwFlags |= CRYPTDLG_REVOCATION_NONE;
  2940. else
  2941. trust.dwFlags |= CRYPTDLG_REVOCATION_ONLINE;
  2942. //cvct.prgdwErrors
  2943. trust.dwIgnoreErr = dwToIgnore;
  2944. if (pCAs)
  2945. {
  2946. trust.dwFlags |= CERT_TRUST_ADD_CERT_STORES;
  2947. trust.rghstoreCAs = pCAs;
  2948. trust.cStores = 3;
  2949. }
  2950. // Delta checking
  2951. GetSystemTime(&SysTime);
  2952. if(SystemTimeToFileTime(&SysTime, &FileTime))
  2953. {
  2954. LONG lRet;
  2955. // Need to check with Delta
  2956. lr = CertVerifyTimeValidity(&FileTime, pcCertToTest->pCertInfo);
  2957. if(lr < 0)
  2958. {
  2959. FILETIME ftNow;
  2960. __int64 i64Offset;
  2961. union
  2962. {
  2963. FILETIME ftDelta;
  2964. __int64 i64Delta;
  2965. };
  2966. GetSystemTimeAsFileTime(&ftNow);
  2967. i64Delta = ftNow.dwHighDateTime;
  2968. i64Delta = i64Delta << 32;
  2969. i64Delta += ftNow.dwLowDateTime;
  2970. // Add the offset into the original time to get us a new time to check
  2971. i64Offset = FILETIME_SECOND;
  2972. i64Offset *= TIME_DELTA_SECONDS;
  2973. i64Delta += i64Offset;
  2974. lr = CertVerifyTimeValidity(&ftDelta, pcCertToTest->pCertInfo);
  2975. }
  2976. if(lr == 0)
  2977. fIgnoreTimeError = TRUE;
  2978. }
  2979. // End of delta checking
  2980. lr = WinVerifyTrust(hwnd, &guidAction, (void*)&data);
  2981. if(((LRESULT) lr) == CERT_E_REVOKED)
  2982. dwErr = CERT_VALIDITY_CERTIFICATE_REVOKED;
  2983. else if(((LRESULT) lr) == CERT_E_REVOCATION_FAILURE)
  2984. {
  2985. Assert(FALSE);
  2986. dwErr = CERT_VALIDITY_NO_CRL_FOUND;
  2987. }
  2988. else if (0 > lr) // WinVerifyTrust(hwnd, &guidAction, (void*)&data))
  2989. dwErr = CERT_VALIDITY_NO_TRUST_DATA;
  2990. if (dwErr)
  2991. DOUTL(DOUTL_CRYPT, "Trust provider returned 0x%.8lx", dwErr);
  2992. // Filter these out since the trust provider isn't.
  2993. if(fIgnoreTimeError)
  2994. dwErr &= ~(CERT_VALIDITY_BEFORE_START | CERT_VALIDITY_AFTER_END);
  2995. if(!(CheckCDPinCert(pMsg) && (dwErr == CERT_VALIDITY_NO_CRL_FOUND)))
  2996. dwErr &= ~dwToIgnore;
  2997. CertCloseStore(rgCAs[0], 0);
  2998. CertCloseStore(rgCAs[1], 0);
  2999. CertCloseStore(rgCAs[2], 0);
  3000. return dwErr;
  3001. }
  3002. HRESULT CommonUI_ViewSigningProperties(HWND hwnd, PCCERT_CONTEXT pCert, HCERTSTORE hcMsg, UINT nStartPage)
  3003. {
  3004. CERT_VIEWPROPERTIES_STRUCT cvps;
  3005. TCHAR szTitle[CCHMAX_STRINGRES];
  3006. LPSTR oidPurpose = szOID_PKIX_KP_EMAIL_PROTECTION;
  3007. AthLoadString(idsSigningCertProperties, szTitle, ARRAYSIZE(szTitle));
  3008. memset((void*)&cvps, 0, sizeof(cvps));
  3009. cvps.dwSize = sizeof(cvps);
  3010. cvps.hwndParent = hwnd;
  3011. cvps.hInstance = g_hLocRes;
  3012. cvps.szTitle = szTitle;
  3013. cvps.pCertContext = pCert;
  3014. cvps.nStartPage = nStartPage;
  3015. cvps.arrayPurposes = &oidPurpose;
  3016. cvps.cArrayPurposes = 1;
  3017. cvps.cStores = hcMsg ? 1 : 0; // Count of other stores to search
  3018. cvps.rghstoreCAs = hcMsg ? &hcMsg : NULL; // Array of other stores to search
  3019. cvps.dwFlags = hcMsg ? CM_ADD_CERT_STORES : 0;
  3020. if(!((DwGetOption(OPT_REVOKE_CHECK) != 0) && !g_pConMan->IsGlobalOffline()))
  3021. cvps.dwFlags |= CRYPTDLG_REVOCATION_NONE;
  3022. else
  3023. cvps.dwFlags |= CRYPTDLG_REVOCATION_ONLINE;
  3024. return CertViewProperties(&cvps) ? S_OK : S_FALSE;
  3025. }
  3026. HRESULT LoadResourceToHTMLStream(LPCTSTR szResName, IStream **ppstm)
  3027. {
  3028. HRESULT hr;
  3029. Assert(ppstm);
  3030. hr = MimeOleCreateVirtualStream(ppstm);
  3031. if (SUCCEEDED(hr))
  3032. {
  3033. // MIME header
  3034. // don't fail
  3035. (*ppstm)->Write(s_szHTMLMIME, sizeof(s_szHTMLMIME)-sizeof(TCHAR), NULL);
  3036. // HTML Header information
  3037. hr = HrLoadStreamFileFromResource(szResName, ppstm);
  3038. // If we didn't get the resource, lose the stream. The caller
  3039. // won't want it
  3040. if (FAILED(hr))
  3041. {
  3042. (*ppstm)->Release();
  3043. *ppstm = NULL;
  3044. }
  3045. }
  3046. return hr;
  3047. }
  3048. #ifdef YST
  3049. /***************************************************************************
  3050. Name : FreeCertArray
  3051. Purpose : Frees the array of certs returned by HrGetMyCerts.
  3052. Parameters: rgcc = array of cert contexts
  3053. ccc = count of cert contexts in rgcc
  3054. Returns : none
  3055. Comment :
  3056. ***************************************************************************/
  3057. void FreeCertArray(PCCERT_CONTEXT * rgcc, ULONG ccc)
  3058. {
  3059. if (rgcc)
  3060. {
  3061. for (ULONG i = 0; i < ccc; i++)
  3062. if (rgcc[i])
  3063. CertFreeCertificateContext(rgcc[i]);
  3064. MemFree(rgcc);
  3065. }
  3066. }
  3067. #endif // YST
  3068. /***************************************************************************
  3069. Name : GetSignersEncryptionCert
  3070. Purpose : Gets the signer's encryption cert from the message
  3071. Parameters: pMsg -> Message Object
  3072. Returns : HRESULT - S_OK on success, MIME_E_SECURITY_NOCERT if no cert
  3073. Comment : Zero fills any return structures with no matching parameter
  3074. *************************************************************************/
  3075. HRESULT GetSignerEncryptionCert(IMimeMessage * pMsg, PCCERT_CONTEXT * ppcEncryptCert,
  3076. THUMBBLOB * ptbEncrypt, BLOB * pblSymCaps,
  3077. FILETIME * pftSigningTime)
  3078. {
  3079. DWORD cb;
  3080. HRESULT hr;
  3081. HCERTSTORE hcMsg = NULL;
  3082. DWORD i;
  3083. IMimeBody * pBody = NULL;
  3084. PCCERT_CONTEXT pccertEncrypt = NULL;
  3085. PCCERT_CONTEXT pccertSender = NULL;
  3086. THUMBBLOB tbTemp = {0, 0};
  3087. // Next 5 lines repeats in 3 others places of OE and we may have a separate function from then in future.
  3088. HBODY hBody = NULL;
  3089. SECSTATE SecState ={0};
  3090. if(FAILED(hr = HrGetSecurityState(pMsg, &SecState, &hBody)))
  3091. return(hr);
  3092. CleanupSECSTATE(&SecState);
  3093. Assert((ptbEncrypt != NULL) && (pblSymCaps != NULL) && (pftSigningTime != NULL));
  3094. // Init return structure
  3095. ptbEncrypt->pBlobData = NULL;
  3096. ptbEncrypt->cbSize = 0;
  3097. pblSymCaps->pBlobData = NULL;
  3098. pblSymCaps->cbSize = 0;
  3099. pftSigningTime->dwLowDateTime = 0;
  3100. pftSigningTime->dwHighDateTime = 0;
  3101. if (SUCCEEDED(hr = pMsg->BindToObject(hBody ? hBody : HBODY_ROOT, IID_IMimeBody, (void **)&pBody)))
  3102. {
  3103. PROPVARIANT var;
  3104. hr = MIME_E_SECURITY_NOCERT; // assume failure;
  3105. #ifdef _WIN64
  3106. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE_64, &var)))
  3107. {
  3108. hcMsg = (HCERTSTORE *) (var.pulVal);
  3109. }
  3110. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING_64, &var)))
  3111. {
  3112. Assert(VT_UI8 == var.vt);
  3113. pccertSender = (PCCERT_CONTEXT) (var.pulVal);
  3114. }
  3115. #else // !_WIN64
  3116. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE, &var)))
  3117. {
  3118. hcMsg = (HCERTSTORE) var.ulVal;
  3119. }
  3120. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING, &var)))
  3121. {
  3122. Assert(VT_UI4 == var.vt);
  3123. pccertSender = (PCCERT_CONTEXT) var.ulVal;
  3124. }
  3125. #endif // _WIN64
  3126. //
  3127. // Need to do a bit of work to identify the sender's encryption
  3128. // certificate.
  3129. //
  3130. // 1. Look for the id-aa-encryptKeyPref
  3131. // 2. Look for the Microsoft_Encryption_Key_Preference
  3132. // 3. If this is a sign only cert, look for a cert with the same
  3133. // issuer and subject
  3134. // 4. If this is a sign only cert, look for a cert with the same
  3135. // subject
  3136. //
  3137. if (hcMsg && SUCCEEDED(pBody->GetOption(OID_SECURITY_AUTHATTR, &var)))
  3138. {
  3139. PCRYPT_ATTRIBUTE pattr;
  3140. PCRYPT_ATTRIBUTES pattrs = NULL;
  3141. if (CryptDecodeObjectEx(X509_ASN_ENCODING,
  3142. szOID_Microsoft_Attribute_Sequence,
  3143. var.blob.pBlobData, var.blob.cbSize,
  3144. CRYPT_ENCODE_ALLOC_FLAG, NULL, &pattrs, &cb))
  3145. {
  3146. for (i=0, pattr = NULL; i < pattrs->cAttr; i++)
  3147. {
  3148. if (strcmp(pattrs->rgAttr[i].pszObjId,
  3149. szOID_Microsoft_Encryption_Cert) == 0)
  3150. {
  3151. PCRYPT_RECIPIENT_ID prid = NULL;
  3152. pattr = &pattrs->rgAttr[i];
  3153. if (CryptDecodeObjectEx(X509_ASN_ENCODING,
  3154. szOID_Microsoft_Encryption_Cert,
  3155. pattr->rgValue[0].pbData,
  3156. pattr->rgValue[0].cbData,
  3157. CRYPT_ENCODE_ALLOC_FLAG, NULL, &prid, &cb))
  3158. {
  3159. CERT_INFO certinfo;
  3160. certinfo.SerialNumber = prid->SerialNumber;
  3161. certinfo.Issuer = prid->Issuer;
  3162. pccertEncrypt = CertGetSubjectCertificateFromStore(
  3163. hcMsg, X509_ASN_ENCODING, &certinfo);
  3164. }
  3165. LocalFree(prid);
  3166. }
  3167. else if (strcmp(pattrs->rgAttr[i].pszObjId,
  3168. szOID_SMIME_Encryption_Key_Preference) == 0)
  3169. {
  3170. PSMIME_ENC_KEY_PREFERENCE pekp = NULL;
  3171. pattr = &pattrs->rgAttr[i];
  3172. if (CryptDecodeObjectEx(X509_ASN_ENCODING,
  3173. szOID_SMIME_Encryption_Key_Preference,
  3174. pattr->rgValue[0].pbData,
  3175. pattr->rgValue[0].cbData,
  3176. CRYPT_ENCODE_ALLOC_FLAG, NULL, &pekp, &cb))
  3177. {
  3178. pccertEncrypt = CertFindCertificateInStore(hcMsg,
  3179. X509_ASN_ENCODING, 0,
  3180. CERT_FIND_CERT_ID,
  3181. &pekp->RecipientId, NULL);
  3182. }
  3183. LocalFree(pekp);
  3184. break;
  3185. }
  3186. }
  3187. LocalFree(pattrs);
  3188. }
  3189. MemFree(var.blob.pBlobData);
  3190. }
  3191. if ((pccertEncrypt == NULL) && (pccertSender != NULL))
  3192. {
  3193. DWORD dw;
  3194. HrGetCertKeyUsage(pccertSender, &dw);
  3195. if (!(dw & (CERT_KEY_ENCIPHERMENT_KEY_USAGE |
  3196. CERT_KEY_AGREEMENT_KEY_USAGE)))
  3197. {
  3198. pccertEncrypt = CertFindCertificateInStore(hcMsg,
  3199. X509_ASN_ENCODING, 0,
  3200. CERT_FIND_SUBJECT_NAME,
  3201. &pccertSender->pCertInfo->Subject, NULL);
  3202. while (pccertEncrypt != NULL) {
  3203. HrGetCertKeyUsage(pccertEncrypt, &dw);
  3204. if (dw & CERT_KEY_ENCIPHERMENT_KEY_USAGE) {
  3205. break;
  3206. }
  3207. pccertEncrypt = CertFindCertificateInStore(
  3208. hcMsg, X509_ASN_ENCODING, 0,
  3209. CERT_FIND_SUBJECT_NAME,
  3210. &pccertSender->pCertInfo->Subject,
  3211. pccertEncrypt);
  3212. }
  3213. }
  3214. else
  3215. pccertEncrypt = CertDuplicateCertificateContext(pccertSender);
  3216. }
  3217. if (pccertEncrypt == NULL)
  3218. goto error;
  3219. tbTemp.pBlobData =
  3220. (BYTE *)PVGetCertificateParam(pccertEncrypt, CERT_HASH_PROP_ID,
  3221. &tbTemp.cbSize);
  3222. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_SYMCAPS, &var)))
  3223. {
  3224. if (var.blob.cbSize) {
  3225. // we don't have to dupe the symcaps because we won't free
  3226. // the var's.
  3227. *pblSymCaps = var.blob;
  3228. }
  3229. }
  3230. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_SIGNTIME, &var)))
  3231. {
  3232. if (var.filetime.dwLowDateTime != 0 || var.filetime.dwHighDateTime != 0) {
  3233. *pftSigningTime = var.filetime;
  3234. }
  3235. }
  3236. if (tbTemp.pBlobData && tbTemp.cbSize)
  3237. {
  3238. ptbEncrypt->cbSize = tbTemp.cbSize;
  3239. ptbEncrypt->pBlobData = tbTemp.pBlobData;
  3240. tbTemp.pBlobData = NULL;
  3241. }
  3242. if (ppcEncryptCert != NULL)
  3243. *ppcEncryptCert = CertDuplicateCertificateContext(pccertEncrypt);
  3244. hr = S_OK;
  3245. }
  3246. error:
  3247. SafeRelease(pBody);
  3248. if (tbTemp.pBlobData != NULL)
  3249. MemFree(tbTemp.pBlobData);
  3250. if (hcMsg != NULL)
  3251. CertCloseStore(hcMsg, 0);
  3252. if (pccertSender != NULL)
  3253. CertFreeCertificateContext(pccertSender);
  3254. if (pccertEncrypt != NULL)
  3255. CertFreeCertificateContext(pccertEncrypt);
  3256. return hr;
  3257. }
  3258. /***************************************************************************
  3259. Name : GetSigningCert
  3260. Purpose : Gets the signing cert from the message
  3261. Parameters: pMsg -> Message object
  3262. ppcSigningCert -> returned signing cert context. (optional)
  3263. Caller must CertFreeCertificateContext.
  3264. ptbSigner -> thumbprint blob.
  3265. Caller should supply the blob but must free the pbData.
  3266. pblSymCaps -> SymCaps blob.
  3267. Caller should supply the blob but must free the pbData.
  3268. pftSigningTime -> returned signing time
  3269. Returns : HRESULT - S_OK on success, MIME_E_SECURITY_NOCERT if no cert
  3270. Comment : Zero fills any return structures which have no matching
  3271. parameter.
  3272. ***************************************************************************/
  3273. HRESULT GetSigningCert(IMimeMessage * pMsg, PCCERT_CONTEXT * ppcSigningCert, THUMBBLOB * ptbSigner, BLOB * pblSymCaps, FILETIME * pftSigningTime)
  3274. {
  3275. HRESULT hr = S_OK;
  3276. IMimeBody *pBody = NULL;
  3277. HBODY hBody = NULL;
  3278. Assert(ptbSigner && pblSymCaps && pftSigningTime);
  3279. // Init return structure
  3280. ptbSigner->pBlobData = NULL;
  3281. ptbSigner->cbSize = 0;
  3282. pblSymCaps->pBlobData = NULL;
  3283. pblSymCaps->cbSize = 0;
  3284. pftSigningTime->dwLowDateTime = 0;
  3285. pftSigningTime->dwHighDateTime = 0;
  3286. if(FAILED(hr = HrGetInnerLayer(pMsg, &hBody)))
  3287. return(hr);
  3288. if (SUCCEEDED(hr = pMsg->BindToObject(hBody ? hBody : HBODY_ROOT, IID_IMimeBody, (void**)&pBody)))
  3289. {
  3290. PROPVARIANT var;
  3291. PCCERT_CONTEXT pcSigningCert;
  3292. THUMBBLOB tbTemp = {0,0};
  3293. hr = MIME_E_SECURITY_NOCERT; // assume failure
  3294. #ifdef _WIN64
  3295. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING_64, &var)))
  3296. {
  3297. Assert(VT_UI8 == var.vt);
  3298. pcSigningCert = (PCCERT_CONTEXT)(var.pulVal);
  3299. #else // !_WIN64
  3300. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING, &var)))
  3301. {
  3302. Assert(VT_UI4 == var.vt);
  3303. pcSigningCert = (PCCERT_CONTEXT) var.ulVal;
  3304. #endif // _WIN64
  3305. if (pcSigningCert)
  3306. {
  3307. // Get the thumbprint
  3308. tbTemp.pBlobData = (BYTE *)PVGetCertificateParam(pcSigningCert, CERT_HASH_PROP_ID, &tbTemp.cbSize);
  3309. if (tbTemp.pBlobData && tbTemp.cbSize)
  3310. {
  3311. // Allocate return buffer
  3312. if (! MemAlloc((LPVOID *)&ptbSigner->pBlobData, tbTemp.cbSize))
  3313. hr = ResultFromScode(E_OUTOFMEMORY);
  3314. else
  3315. {
  3316. ptbSigner->cbSize = tbTemp.cbSize;
  3317. memcpy(ptbSigner->pBlobData, tbTemp.pBlobData, tbTemp.cbSize);
  3318. MemFree(tbTemp.pBlobData);
  3319. hr = S_OK;
  3320. // Have a thumbprint. Go get the symcaps and signing time
  3321. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_SYMCAPS, &var)))
  3322. {
  3323. Assert(VT_BLOB == var.vt);
  3324. *pblSymCaps = var.blob;
  3325. // Have a symcaps. Go get the signing time
  3326. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_SIGNTIME, &var)))
  3327. {
  3328. Assert(VT_FILETIME == var.vt);
  3329. *pftSigningTime = var.filetime;
  3330. }
  3331. }
  3332. }
  3333. }
  3334. if (ppcSigningCert)
  3335. *ppcSigningCert = pcSigningCert; // Let caller free it.
  3336. else
  3337. CertFreeCertificateContext(pcSigningCert);
  3338. }
  3339. }
  3340. }
  3341. SafeRelease(pBody);
  3342. return(hr);
  3343. }
  3344. /***************************************************************************
  3345. Name : HrSaveCACerts
  3346. Purpose : Add the messages CA certs to the CA store
  3347. Parameters: hcCA = CA system cert store
  3348. hcMsg = message cert store
  3349. Returns : HRESULT
  3350. Comment :
  3351. ***************************************************************************/
  3352. HRESULT HrSaveCACerts(HCERTSTORE hcCA, HCERTSTORE hcMsg)
  3353. {
  3354. HRESULT hr = S_OK;
  3355. PCCERT_CONTEXT pccert = NULL;
  3356. PCCERT_CONTEXT pccertSubject;
  3357. PCERT_EXTENSION pext;
  3358. // Verify good parameters exist
  3359. if ((hcCA == NULL) || (hcMsg == NULL))
  3360. {
  3361. Assert((hcCA != NULL) && (hcMsg != NULL));
  3362. goto error;
  3363. }
  3364. //
  3365. // The logic we are going to following to determine if we should be adding
  3366. // a certificate to the CA store is as follows:
  3367. //
  3368. // 1. If the basic constraints extension exists, and says its a CA then add
  3369. // to the CA store. Note that the converse is not true as NT4 Cert Server
  3370. // generated CA certs with the end-entity version of basic contraints.
  3371. // 2. If the certificate's subject is matched by the issuer of antoher cert in
  3372. // the store then it goes into the CA cert store.
  3373. //
  3374. // Note: There are some certificates in the store which may not get added to
  3375. // the CA store and are not. If the basic constraints extension is
  3376. // missing, but no issued cert is included in the message then it will
  3377. // be dropped on the floor. This case should not matter in practice.
  3378. //
  3379. while (pccert = CertEnumCertificatesInStore(hcMsg, pccert))
  3380. {
  3381. pext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
  3382. pccert->pCertInfo->cExtension,
  3383. pccert->pCertInfo->rgExtension);
  3384. if (pext != NULL)
  3385. {
  3386. ; // M00TODO
  3387. }
  3388. pccertSubject = CertFindCertificateInStore(hcMsg, X509_ASN_ENCODING, 0,
  3389. CERT_FIND_ISSUER_NAME,
  3390. &pccert->pCertInfo->Subject, NULL);
  3391. if (pccertSubject != NULL)
  3392. {
  3393. if (!CertAddCertificateContextToStore(hcCA, pccert,
  3394. CERT_STORE_ADD_USE_EXISTING, NULL))
  3395. // Don't really fail
  3396. DebugTrace("CertAddCertificateContextToStore -> %x\n", GetLastError());
  3397. CertFreeCertificateContext(pccertSubject);
  3398. }
  3399. }
  3400. error:
  3401. return(hr);
  3402. }
  3403. /***************************************************************************
  3404. Name : IsThumbprintInMVPBin
  3405. Purpose : Check the PR_USER_X509_CERTIFICATE prop for this thumbprint
  3406. Parameters: spv = prop value structure of PR_USER_X509_CERTIFICATE
  3407. lpThumbprint -> THUMBBLOB structure to find
  3408. lpIndex -> Returned index in MVP (or NULL)
  3409. pblSymCaps -> symcaps blob to fill in (or NULL)
  3410. lpftSigningTime -> returned signing time (or NULL)
  3411. lpfDefault -> returned default flag (or NULL)
  3412. Returns : TRUE if found
  3413. Comment : Note that the values returned in pblSymCaps and lpftSigningTime
  3414. are only valid if TRUE is returned.
  3415. ***************************************************************************/
  3416. BOOL IsThumbprintInMVPBin(SPropValue spv, THUMBBLOB * lpThumbprint, ULONG * lpIndex,
  3417. BLOB * pblSymCaps, FILETIME * lpftSigningTime, BOOL * lpfDefault)
  3418. {
  3419. ULONG cValues, i;
  3420. LPSBinary lpsb = NULL;
  3421. CERTTAGS UNALIGNED *lpCurrentTag = NULL;
  3422. CERTTAGS UNALIGNED *lpTempTag;
  3423. LPBYTE lpbTagEnd;
  3424. BOOL fFound = FALSE;
  3425. // Initialize the return data
  3426. if (lpIndex)
  3427. *lpIndex = (ULONG)-1;
  3428. if (lpftSigningTime)
  3429. lpftSigningTime->dwLowDateTime = lpftSigningTime->dwHighDateTime = 0;
  3430. if (pblSymCaps)
  3431. {
  3432. pblSymCaps->cbSize = 0;
  3433. pblSymCaps->pBlobData = 0;
  3434. }
  3435. if (! PROP_ERROR((spv)))
  3436. {
  3437. lpsb = spv.Value.MVbin.lpbin;
  3438. cValues = spv.Value.MVbin.cValues;
  3439. // Check for duplicates
  3440. for (i = 0; i < cValues; i++)
  3441. {
  3442. lpCurrentTag = (LPCERTTAGS)lpsb[i].lpb;
  3443. lpbTagEnd = (LPBYTE)lpCurrentTag + lpsb[i].cb;
  3444. // Init the return structures
  3445. if (lpftSigningTime)
  3446. lpftSigningTime->dwLowDateTime = lpftSigningTime->dwHighDateTime = 0;
  3447. if (pblSymCaps)
  3448. {
  3449. pblSymCaps->cbSize = 0;
  3450. pblSymCaps->pBlobData = 0;
  3451. }
  3452. if (lpfDefault)
  3453. *lpfDefault = FALSE;
  3454. while ((LPBYTE)lpCurrentTag < lpbTagEnd)
  3455. {
  3456. // Check if this is the tag that contains the thumbprint
  3457. if (CERT_TAG_THUMBPRINT == lpCurrentTag->tag)
  3458. {
  3459. if ((lpThumbprint->cbSize == lpCurrentTag->cbData - SIZE_CERTTAGS) &&
  3460. ! memcmp(lpThumbprint->pBlobData, &lpCurrentTag->rgbData,
  3461. lpThumbprint->cbSize))
  3462. {
  3463. if (lpIndex)
  3464. *lpIndex = i;
  3465. fFound = TRUE;
  3466. }
  3467. }
  3468. if (lpfDefault && (CERT_TAG_DEFAULT == lpCurrentTag->tag))
  3469. memcpy(lpfDefault, &lpCurrentTag->rgbData, min(sizeof(*lpfDefault), lpCurrentTag->cbData));
  3470. if (lpftSigningTime && (CERT_TAG_SIGNING_TIME == lpCurrentTag->tag))
  3471. memcpy(lpftSigningTime, &lpCurrentTag->rgbData, min(sizeof(FILETIME), lpCurrentTag->cbData));
  3472. if (pblSymCaps && (CERT_TAG_SYMCAPS == lpCurrentTag->tag))
  3473. {
  3474. pblSymCaps->cbSize = lpCurrentTag->cbData - SIZE_CERTTAGS;
  3475. pblSymCaps->pBlobData = lpCurrentTag->rgbData;
  3476. }
  3477. lpTempTag = lpCurrentTag;
  3478. lpCurrentTag = (LPCERTTAGS)((BYTE*)lpCurrentTag + lpCurrentTag->cbData);
  3479. if (lpCurrentTag == lpTempTag)
  3480. {
  3481. DOUTL(DOUTL_CRYPT, "Bad CertTag in PR_USER_X509_CERTIFICATE");
  3482. break; // Safety valve, prevent infinite loop if bad data
  3483. }
  3484. }
  3485. if (fFound)
  3486. return(TRUE);
  3487. }
  3488. }
  3489. return(FALSE);
  3490. }
  3491. /***************************************************************************
  3492. Name : MatchCertificate
  3493. Purpose : Checks if a specific certificate is in the WAB entry
  3494. Parameters: lpAdrBook -> IADRBook object
  3495. lpWabal -> Wabal object (for allocators)
  3496. lpbEntryID -> EntryID of this entry
  3497. cbEntryID -> Size of EntryID
  3498. pSenderThumbprint -> THUMBBLOB structure to find
  3499. lppMailUser -> [optional] returned MailUser object
  3500. Returns : TRUE if a match is found
  3501. Comment :
  3502. ***************************************************************************/
  3503. BOOL MatchCertificate(LPADRBOOK lpAdrBook,
  3504. LPWABAL lpWabal,
  3505. DWORD cbEntryID,
  3506. LPBYTE lpbEntryID,
  3507. THUMBBLOB * pSenderThumbprint,
  3508. LPMAILUSER * lppMailUser)
  3509. {
  3510. HRESULT hr;
  3511. LPMAILUSER lpMailUser = NULL;
  3512. ULONG ulObjectType;
  3513. ULONG ul;
  3514. LPSPropValue ppv = NULL;
  3515. BOOL fReturn = FALSE;
  3516. if (HR_FAILED(hr = lpAdrBook->OpenEntry(cbEntryID, (LPENTRYID)lpbEntryID, NULL, MAPI_MODIFY, &ulObjectType, (LPUNKNOWN *)&(lpMailUser))))
  3517. {
  3518. Assert(FALSE);
  3519. goto exit;
  3520. }
  3521. if (HR_FAILED(hr = lpMailUser->GetProps((LPSPropTagArray)&ptaCert, 0, &ul, &ppv)))
  3522. // Shouldn't happen, but if it does, we don't have a ppv
  3523. goto exit;
  3524. fReturn = IsThumbprintInMVPBin(ppv[0], pSenderThumbprint, NULL, NULL, NULL, NULL);
  3525. exit:
  3526. if (ppv)
  3527. lpWabal->FreeBuffer(ppv);
  3528. if (lpMailUser)
  3529. {
  3530. if (lppMailUser && fReturn)
  3531. *lppMailUser = lpMailUser;
  3532. else
  3533. lpMailUser->Release();
  3534. }
  3535. else if (lppMailUser)
  3536. *lppMailUser = NULL;
  3537. return(fReturn);
  3538. }
  3539. /***************************************************************************
  3540. Name : InitPropertyRestriction
  3541. Purpose : Fills in the property restriction structure
  3542. Parameters: lpsres -> SRestriction to fill in
  3543. lpspv -> property value structure for this property restriction
  3544. Returns : none
  3545. Comment :
  3546. ***************************************************************************/
  3547. void InitPropertyRestriction(LPSRestriction lpsres, LPSPropValue lpspv)
  3548. {
  3549. lpsres->rt = RES_PROPERTY; // Restriction type Property
  3550. lpsres->res.resProperty.relop = RELOP_EQ;
  3551. lpsres->res.resProperty.ulPropTag = lpspv->ulPropTag;
  3552. lpsres->res.resProperty.lpProp = lpspv;
  3553. }
  3554. /***************************************************************************
  3555. Name : FreeProws
  3556. Purpose : Destroys an SRowSet structure.
  3557. Parameters: prows -> row set to free
  3558. Returns : none
  3559. Comment :
  3560. ***************************************************************************/
  3561. void FreeProws(LPWABAL lpWabal, LPSRowSet prows)
  3562. {
  3563. register ULONG irow;
  3564. if (prows)
  3565. {
  3566. for (irow = 0; irow < prows->cRows; ++irow)
  3567. if (prows->aRow[irow].lpProps)
  3568. lpWabal->FreeBuffer(prows->aRow[irow].lpProps);
  3569. lpWabal->FreeBuffer(prows);
  3570. }
  3571. }
  3572. /***************************************************************************
  3573. Name : AddPropToMVPString
  3574. Purpose : Add a property to a multi-valued binary property in a prop array
  3575. Parameters: lpWabal -> Wabal object with allocator functions
  3576. lpaProps -> array of properties
  3577. uPropTag = property tag for MVP
  3578. index = index in lpaProps of MVP
  3579. lpszNew -> new data string
  3580. fNoDuplicates = TRUE if we should do nothing on duplicate adds
  3581. fCaseSensitive = TRUE if the duplicate check should be case sensitive
  3582. Returns : HRESULT
  3583. S_DUPLICATE_FOUND if we didn't add because of a duplicate
  3584. Comment : Find the size of the existing MVP
  3585. Add in the size of the new entry
  3586. allocate new space
  3587. copy old to new
  3588. free old
  3589. copy new entry
  3590. point prop array LPSZ to the new space
  3591. increment cValues
  3592. Note: The new MVP memory is AllocMore'd onto the lpaProps
  3593. allocation. We will unlink the pointer to the old MVP array,
  3594. but this will be cleaned up when the prop array is freed.
  3595. ***************************************************************************/
  3596. HRESULT AddPropToMVPString(LPWABAL lpWabal, LPSPropValue lpaProps, DWORD index, LPWSTR lpwszNew,
  3597. BOOL fNoDuplicates, BOOL fCaseSensitive)
  3598. {
  3599. SWStringArray UNALIGNED *lprgwszOld = NULL; // old SString array
  3600. LPWSTR *lppwszNew = NULL; // new prop array
  3601. LPWSTR *lppwszOld = NULL; // old prop array
  3602. ULONG cbMVP = 0;
  3603. ULONG cExisting = 0;
  3604. LPBYTE lpNewTemp = NULL;
  3605. HRESULT hResult = hrSuccess;
  3606. SCODE sc = SUCCESS_SUCCESS;
  3607. ULONG i;
  3608. ULONG cbNew;
  3609. cbNew = lpwszNew ? (lstrlenW(lpwszNew) + 1)*sizeof(*lpwszNew) : 0;
  3610. // Find the size of any existing MVP entries
  3611. if (PROP_ERROR(lpaProps[index]))
  3612. // Un-ERROR the property tag
  3613. lpaProps[index].ulPropTag = PROP_TAG(MV_FLAG|PT_UNICODE, PROP_ID(lpaProps[index].ulPropTag));
  3614. else
  3615. {
  3616. // point to the structure in the prop array.
  3617. lprgwszOld = &(lpaProps[index].Value.MVszW);
  3618. lppwszOld = lprgwszOld->lppszW;
  3619. cExisting = lprgwszOld->cValues;
  3620. cbMVP = cExisting * sizeof(LPWSTR);
  3621. // Check for duplicates
  3622. if (fNoDuplicates)
  3623. {
  3624. for (i = 0; i < cExisting; i++)
  3625. if (fCaseSensitive ? (! StrCmpW(lpwszNew, lppwszOld[i])) : (! StrCmpIW(lpwszNew, lppwszOld[i])))
  3626. {
  3627. DOUTL(DOUTL_CRYPT,"AddPropToMVPStringfound duplicate.\n");
  3628. return(S_DUPLICATE_FOUND);
  3629. }
  3630. }
  3631. }
  3632. // cbMVP now contains the current size of the MVP
  3633. cbMVP += sizeof(LPWSTR); // room in the MVP for another string pointer
  3634. // Allocate room for new MVP array
  3635. if (sc = lpWabal->AllocateMore(cbMVP, lpaProps, (LPVOID *)&lppwszNew))
  3636. {
  3637. DebugTrace("AddPropToMVPString allocation (%u) failed %x\n", cbMVP, sc);
  3638. hResult = ResultFromScode(sc);
  3639. return(hResult);
  3640. }
  3641. // If there are properties there already, copy them to our new MVP
  3642. for (i = 0; i < cExisting; i++)
  3643. // Copy this property value to the MVP
  3644. lppwszNew[i] = lppwszOld[i];
  3645. // Add the new property value
  3646. // Allocate room for it
  3647. if (cbNew)
  3648. {
  3649. if (sc = lpWabal->AllocateMore(cbNew, lpaProps, (LPVOID *)&(lppwszNew[i])))
  3650. {
  3651. DebugTrace("AddPropToMVPString allocation (%u) failed %x\n", cbNew, sc);
  3652. hResult = ResultFromScode(sc);
  3653. return(hResult);
  3654. }
  3655. StrCpyNW(lppwszNew[i], lpwszNew, cbNew / sizeof(WCHAR));
  3656. lpaProps[index].Value.MVszW.lppszW= lppwszNew;
  3657. lpaProps[index].Value.MVszW.cValues = cExisting + 1;
  3658. }
  3659. else
  3660. lppwszNew[i] = NULL;
  3661. return(hResult);
  3662. }
  3663. /***************************************************************************
  3664. Name : AddPropToMVPBin
  3665. Purpose : Add a property to a multi-valued binary property in a prop array
  3666. Parameters: lpaProps -> array of properties
  3667. uPropTag = property tag for MVP
  3668. index = index in lpaProps of MVP
  3669. lpNew -> new data
  3670. cbNew = size of lpbNew
  3671. fNoDuplicates = TRUE if we should not add duplicates
  3672. Returns : HRESULT
  3673. S_DUPLICATE_FOUND if we didn't add because of a duplicate
  3674. Comment : Find the size of the existing MVP
  3675. Add in the size of the new entry
  3676. allocate new space
  3677. copy old to new
  3678. free old
  3679. copy new entry
  3680. point prop array lpbin the new space
  3681. increment cValues
  3682. Note: The new MVP memory is AllocMore'd onto the lpaProps
  3683. allocation. We will unlink the pointer to the old MVP array,
  3684. but this will be cleaned up when the prop array is freed.
  3685. ***************************************************************************/
  3686. HRESULT AddPropToMVPBin(LPWABAL lpWabal, LPSPropValue lpaProps, DWORD index, LPVOID lpNew,
  3687. ULONG cbNew, BOOL fNoDuplicates)
  3688. {
  3689. SBinaryArray UNALIGNED * lprgsbOld = NULL;
  3690. SBinaryArray * lprgsbNew = NULL;
  3691. LPSBinary lpsbOld = NULL;
  3692. LPSBinary lpsbNew = NULL;
  3693. ULONG cbMVP = 0;
  3694. ULONG cExisting = 0;
  3695. LPBYTE lpNewTemp = NULL;
  3696. HRESULT hResult = hrSuccess;
  3697. SCODE sc = SUCCESS_SUCCESS;
  3698. ULONG i;
  3699. // Find the size of any existing MVP entries
  3700. if (PT_ERROR == PROP_TYPE(lpaProps[index].ulPropTag))
  3701. // Un-ERROR the property tag
  3702. lpaProps[index].ulPropTag = PROP_TAG(PT_MV_BINARY, PROP_ID(lpaProps[index].ulPropTag));
  3703. else
  3704. {
  3705. // point to the structure in the prop array.
  3706. lprgsbOld = &(lpaProps[index].Value.MVbin);
  3707. lpsbOld = lprgsbOld->lpbin;
  3708. cExisting = lprgsbOld->cValues;
  3709. // Check for duplicates
  3710. if (fNoDuplicates)
  3711. {
  3712. for (i = 0; i < cExisting; i++)
  3713. if (cbNew == lpsbOld[i].cb && !memcmp(lpNew, lpsbOld[i].lpb, cbNew))
  3714. {
  3715. DOUTL(DOUTL_CRYPT,"AddPropToMVPBin found duplicate.\n");
  3716. return(S_DUPLICATE_FOUND);
  3717. }
  3718. }
  3719. cbMVP = cExisting * sizeof(SBinary);
  3720. }
  3721. // cbMVP now contains the current size of the MVP
  3722. cbMVP += sizeof(SBinary); // room in the MVP for another Sbin
  3723. // Allocate room for new MVP
  3724. if (sc = lpWabal->AllocateMore(cbMVP, lpaProps, (LPVOID*)&lpsbNew))
  3725. {
  3726. DOUTL(DOUTL_CRYPT,"AddPropToMVPBin allocation (%u) failed %x\n", cbMVP, sc);
  3727. hResult = ResultFromScode(sc);
  3728. return(hResult);
  3729. }
  3730. // If there are properties there already, copy them to our new MVP
  3731. for (i = 0; i < cExisting; i++)
  3732. {
  3733. // Copy this property value to the MVP
  3734. lpsbNew[i].cb = lpsbOld[i].cb;
  3735. lpsbNew[i].lpb = lpsbOld[i].lpb;
  3736. }
  3737. // Add the new property value
  3738. // Allocate room for it
  3739. if (sc = lpWabal->AllocateMore(cbNew, lpaProps, (LPVOID*)&(lpsbNew[i].lpb)))
  3740. {
  3741. DOUTL(DOUTL_CRYPT,"AddPropToMVPBin allocation (%u) failed %x\n", cbNew, sc);
  3742. hResult = ResultFromScode(sc);
  3743. return(hResult);
  3744. }
  3745. lpsbNew[i].cb = cbNew;
  3746. CopyMemory(lpsbNew[i].lpb, lpNew, cbNew);
  3747. lpaProps[index].Value.MVbin.lpbin = lpsbNew;
  3748. lpaProps[index].Value.MVbin.cValues = cExisting + 1;
  3749. return(hResult);
  3750. }
  3751. /***************************************************************************
  3752. Name : RemoveValueFromMVPBinByIndex
  3753. Purpose : Remove a value from a multi-valued binary property in a prop array
  3754. Parameters: lpaProps -> array of properties
  3755. cProps = number of props in lpaProps
  3756. PropIndex = index in lpaProps of MVP
  3757. ValueIndex = index in MVP of value to remove
  3758. Returns : HRESULT
  3759. Comment :
  3760. ***************************************************************************/
  3761. HRESULT RemovePropFromMVBinByIndex(LPSPropValue lpaProps, DWORD cProps, DWORD PropIndex, DWORD ValueIndex)
  3762. {
  3763. SBinaryArray UNALIGNED * lprgsb = NULL;
  3764. LPSBinary lpsb = NULL;
  3765. ULONG cbTest;
  3766. LPBYTE lpTest;
  3767. ULONG cExisting;
  3768. // Find the size of any existing MVP entries
  3769. if (PROP_ERROR(lpaProps[PropIndex]))
  3770. // Property value doesn't exist.
  3771. return(ResultFromScode(MAPI_W_PARTIAL_COMPLETION));
  3772. // point to the structure in the prop array.
  3773. lprgsb = &(lpaProps[PropIndex].Value.MVbin);
  3774. lpsb = lprgsb->lpbin;
  3775. cExisting = lprgsb->cValues;
  3776. Assert(ValueIndex < cExisting);
  3777. // Look for value
  3778. lpsb = &(lprgsb->lpbin[ValueIndex]);
  3779. // Decrment number of values
  3780. if (--lprgsb->cValues == 0)
  3781. // If there are none left, mark the prop as an error
  3782. lpaProps[PropIndex].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(lpaProps[PropIndex].ulPropTag));
  3783. else
  3784. // Copy the remaining entries down over it.
  3785. if (ValueIndex + 1 < cExisting) // Are there any higher entries to copy?
  3786. CopyMemory(lpsb, lpsb + 1, ((cExisting - ValueIndex) - 1) * sizeof(SBinary));
  3787. return S_OK;
  3788. }
  3789. #ifdef DEBUG
  3790. void DebugFileTime(FILETIME ft)
  3791. {
  3792. SYSTEMTIME st = {0};
  3793. TCHAR szBuffer[256];
  3794. FileTimeToSystemTime(&ft, &st);
  3795. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), "%02d/%02d/%04d %02d:%02d:%02d\n", st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond);
  3796. OutputDebugString(szBuffer);
  3797. }
  3798. #endif
  3799. /***************************************************************************
  3800. Name : HrAddCertToWabContact
  3801. Purpose : Update a certificate in a particular wab contact
  3802. Parameters: lpWabal -> WABAL for WAB function access
  3803. lpAdrBook -> WAB ADRBOOK object
  3804. cbEntryID = size of lpEntryID
  3805. lpEntryID = entry id to operate on
  3806. pThumbprint -> certificate thumbprint
  3807. szEmailAddress -> email address to search for (optional)
  3808. szCertEmailAddress -> email address from the cert
  3809. pblSymCaps -> symcap blob (will be calculated if thumbprint is NULL)
  3810. ftSigningTime = signing time (will be calculated if thumbprint is NULL)
  3811. dwFlags = WFF_SHOWUI (we are allowed to show UI)
  3812. Returns : HRESULT
  3813. Comment : dwFlags is currently ignored
  3814. ***************************************************************************/
  3815. HRESULT HrAddCertToWabContact(HWND hwnd, LPWABAL lpWabal, LPADRBOOK lpAdrBook, ULONG cbEntryID, LPBYTE lpEntryID,
  3816. THUMBBLOB * pThumbprint, LPWSTR lpwszEmailAddress, LPWSTR lpwszCertEmailAddress, BLOB *pblSymCaps,
  3817. FILETIME ftSigningTime, DWORD dwFlags)
  3818. {
  3819. HRESULT hr;
  3820. ULONG ulObjectType;
  3821. LPMAILUSER lpMailUser = NULL;
  3822. ULONG cProps = 0;
  3823. LPSPropValue ppv = NULL;
  3824. ULONG MVPindex;
  3825. BOOL fExistingSymCaps,
  3826. fMsgSymCaps,
  3827. fExistingSigningTime,
  3828. fMsgSigningTime,
  3829. fExists,
  3830. fExisted,
  3831. fDefault = FALSE,
  3832. fNewerThanExistingTime,
  3833. fNoCert;
  3834. BLOB blExistingSymCaps = {0};
  3835. FILETIME ftExistingSigningTime;
  3836. UNALIGNED BYTE * lpCertProp = NULL;
  3837. ULONG cbCertProp;
  3838. Assert(lpWabal);
  3839. Assert(lpEntryID);
  3840. Assert(pThumbprint);
  3841. Assert(lpwszEmailAddress || lpwszCertEmailAddress);
  3842. hr = lpAdrBook->OpenEntry(cbEntryID, (LPENTRYID)lpEntryID, NULL, MAPI_MODIFY, &ulObjectType, (LPUNKNOWN *)&(lpMailUser));
  3843. if (HR_FAILED(hr))
  3844. goto exit;
  3845. hr = lpMailUser->GetProps((LPSPropTagArray)&ptaResolve, 0, &cProps, &ppv);
  3846. if (HR_FAILED(hr) || ! cProps || ! ppv || PROP_ERROR(ppv[0]))
  3847. goto exit;
  3848. // Do we need to remove the existing value? Only if it has the same
  3849. // thumbprint, has a sMimeCapability and a signing time < the signing time
  3850. // input and the sMIMEcapability is different.
  3851. // The returned data is not reallocated, but the blobs point into the property data
  3852. fNoCert = PROP_ERROR(ppv[irsPR_USER_X509_CERTIFICATE]);
  3853. fExisted = fExists = IsThumbprintInMVPBin(ppv[irsPR_USER_X509_CERTIFICATE], pThumbprint, &MVPindex,
  3854. &blExistingSymCaps, &ftExistingSigningTime, &fDefault);
  3855. if (fExists)
  3856. {
  3857. // Create a bunch of flags to aid in deciding when to replace a cert and when to add one.
  3858. fExistingSymCaps = blExistingSymCaps.cbSize;
  3859. fMsgSymCaps = pblSymCaps && pblSymCaps->cbSize;
  3860. fExistingSigningTime = ftExistingSigningTime.dwLowDateTime || ftExistingSigningTime.dwHighDateTime;
  3861. fMsgSigningTime = ftSigningTime.dwLowDateTime || ftSigningTime.dwHighDateTime;
  3862. #ifdef DEBUG
  3863. DebugFileTime(ftSigningTime);
  3864. DebugFileTime(ftExistingSigningTime);
  3865. #endif
  3866. fNewerThanExistingTime = (CompareFileTime(&ftSigningTime, &ftExistingSigningTime) > 0);
  3867. if (fExists && fMsgSymCaps &&
  3868. (! fExistingSymCaps ||
  3869. fMsgSigningTime && !fExistingSigningTime ||
  3870. fMsgSigningTime && fExistingSigningTime && fNewerThanExistingTime))
  3871. {
  3872. RemovePropFromMVBinByIndex(ppv, cProps, irsPR_USER_X509_CERTIFICATE, MVPindex);
  3873. fExists = FALSE;
  3874. }
  3875. }
  3876. if (!fExists)
  3877. {
  3878. // Build up the PR_USER_X509_CERTIFICATE data
  3879. if (HR_FAILED(hr = HrBuildCertSBinaryData(fNoCert || (fExisted && fDefault), pThumbprint, pblSymCaps,
  3880. ftSigningTime, &lpCertProp, &cbCertProp)))
  3881. {
  3882. goto exit;
  3883. }
  3884. // Add the new thumbprint to PR_USER_X509_CERTIFICATE
  3885. if (HR_FAILED(hr = AddPropToMVPBin(lpWabal, ppv, irsPR_USER_X509_CERTIFICATE, lpCertProp, cbCertProp, TRUE)))
  3886. goto exit;
  3887. // Make sure that the e-mail addresses are in this contact.
  3888. // NOTE: Add szEmailAddress BEFORE szCertEmailAddress!
  3889. if (lpwszEmailAddress)
  3890. {
  3891. if (! AddPropToMVPString(lpWabal, ppv, irsPR_CONTACT_EMAIL_ADDRESSES, lpwszEmailAddress, TRUE, FALSE))
  3892. // If we succeeded in adding an email address, we must match it with an
  3893. // address type.
  3894. AddPropToMVPString(lpWabal, ppv, irsPR_CONTACT_ADDRTYPES, (LPWSTR)c_wszSMTP, FALSE, FALSE);
  3895. // Don't care on failure
  3896. }
  3897. if (lpwszCertEmailAddress)
  3898. {
  3899. if (! AddPropToMVPString(lpWabal, ppv, irsPR_CONTACT_EMAIL_ADDRESSES, lpwszCertEmailAddress, TRUE, FALSE))
  3900. // If we succeeded in adding an email address, we must match it with an address type.
  3901. AddPropToMVPString(lpWabal, ppv, irsPR_CONTACT_ADDRTYPES, (LPWSTR)c_wszSMTP, FALSE, FALSE);
  3902. // Don't care on failure
  3903. }
  3904. // Make sure there is a PR_EMAIL_ADDRESS
  3905. if (PROP_ERROR(ppv[irsPR_EMAIL_ADDRESS]))
  3906. {
  3907. ppv[irsPR_EMAIL_ADDRESS].ulPropTag = PR_EMAIL_ADDRESS_W;
  3908. ppv[irsPR_EMAIL_ADDRESS].Value.lpszW = lpwszEmailAddress ? lpwszEmailAddress : lpwszCertEmailAddress;
  3909. }
  3910. // Make sure there is a PR_CONTACT_DEFAULT_ADDRESS_INDEX
  3911. if (PROP_ERROR(ppv[irsPR_CONTACT_DEFAULT_ADDRESS_INDEX]))
  3912. {
  3913. ppv[irsPR_CONTACT_DEFAULT_ADDRESS_INDEX].ulPropTag = PR_CONTACT_DEFAULT_ADDRESS_INDEX;
  3914. ppv[irsPR_CONTACT_DEFAULT_ADDRESS_INDEX].Value.ul = 0;
  3915. }
  3916. hr = lpMailUser->SetProps(cProps, ppv, NULL);
  3917. if (SUCCEEDED(hr))
  3918. hr = lpMailUser->SaveChanges(KEEP_OPEN_READWRITE);
  3919. if (HR_FAILED(hr))
  3920. goto exit;
  3921. }
  3922. exit:
  3923. SafeMemFree(lpCertProp);
  3924. if (ppv)
  3925. lpWabal->FreeBuffer(ppv);
  3926. ReleaseObj(lpMailUser);
  3927. return(hr);
  3928. }
  3929. /***************************************************************************
  3930. Name : HrAddCertToWab
  3931. Purpose : Add or update a certificate in the wab
  3932. Parameters: hwnd = parent window handle
  3933. lpWabal -> WABAL for WAB function access
  3934. pThumbprint -> certificate thumbprint (optional)
  3935. pcCertContext -> certificate context (optional, if not supplied, we
  3936. will find it based on the pSenderThumbprint)
  3937. szEmailAddress -> email address to search for (optional)
  3938. szDisplayName -> display name for NEW contacts (optional)
  3939. pblSymCaps -> symcap blob (will be calculated if thumbprint is NULL)
  3940. ftSigningTime = signing time (will be calculated if thumbprint is NULL)
  3941. dwFlags = WFF_SHOWUI (we are allowed to show UI)
  3942. WFF_CREATE (we are allowed to create an entry if not found)
  3943. Returns : HRESULT
  3944. Comment : Must have either pSenderThumbprint or pcCertContext.
  3945. This function will search the address book for all occurences of
  3946. the email addresses specified (szEmailAddress and the one in the cert)
  3947. and and will add or update the cert thumbprint and associated symcap
  3948. and signing time to each entry found.
  3949. ***************************************************************************/
  3950. HRESULT HrAddCertToWab(HWND hwnd, LPWABAL lpWabal, THUMBBLOB *pThumbprint, PCCERT_CONTEXT pcCertContext,
  3951. LPWSTR lpwszEmailAddress, LPWSTR lpwszDisplayName, BLOB *pblSymCaps, FILETIME ftSigningTime, DWORD dwFlags)
  3952. {
  3953. HRESULT hr = S_OK;
  3954. ULONG ulObjectType;
  3955. ULONG cbWABEID;
  3956. LPENTRYID lpWABEID = NULL;
  3957. LPABCONT lpABCont = NULL;
  3958. LPMAPITABLE lpContentsTable = NULL;
  3959. LPSRowSet lpRow = NULL;
  3960. SRestriction res;
  3961. SRestriction resOr[4]; // array for OR restrictions
  3962. SPropValue propEmail1, propEmail2, propEmails1, propEmails2;
  3963. ULONG resCount;
  3964. LPADRBOOK lpAdrBook = NULL; // Don't Release!
  3965. HCERTSTORE hCertStore = NULL;
  3966. PCCERT_CONTEXT pcCertContextLocal = NULL;
  3967. LPWSTR pwszCertEmailAddress = NULL;
  3968. THUMBBLOB ThumbprintLocal = {0};
  3969. LPWABOBJECT lpWabObject;
  3970. LPMAILUSER lpMailUser = NULL;
  3971. ULONG cProps = 0;
  3972. LPSPropValue ppv = NULL;
  3973. ULONG ulRowCount = 0;
  3974. LPSTR pszCertEmail = NULL;
  3975. Assert(pcCertContext || pThumbprint);
  3976. if (! pcCertContext && !pThumbprint)
  3977. {
  3978. hr = E_INVALIDARG;
  3979. goto exit;
  3980. }
  3981. // Get the email address from the cert
  3982. if (! pcCertContext)
  3983. {
  3984. hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, NULL,
  3985. CERT_SYSTEM_STORE_CURRENT_USER, c_szWABCertStore);
  3986. if (hCertStore)
  3987. {
  3988. // Find the cert in the store
  3989. if (pcCertContextLocal = CertFindCertificateInStore( hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_HASH, (void *)pThumbprint, NULL))
  3990. pcCertContext = pcCertContextLocal;
  3991. }
  3992. }
  3993. if (pcCertContext)
  3994. {
  3995. pszCertEmail = SzGetCertificateEmailAddress(pcCertContext); // in msoert
  3996. pwszCertEmailAddress = PszToUnicode(CP_ACP, pszCertEmail);
  3997. if (!pwszCertEmailAddress && pszCertEmail)
  3998. IF_NULLEXIT(NULL);
  3999. if (pcCertContextLocal)
  4000. CertFreeCertificateContext(pcCertContextLocal);
  4001. // Make sure we have a thumbprint
  4002. if (! pThumbprint)
  4003. {
  4004. ThumbprintLocal.pBlobData = (BYTE *)PVGetCertificateParam(pcCertContext, CERT_HASH_PROP_ID, &ThumbprintLocal.cbSize);
  4005. if (ThumbprintLocal.pBlobData)
  4006. pThumbprint = &ThumbprintLocal;
  4007. }
  4008. }
  4009. if (hCertStore)
  4010. CertCloseStore(hCertStore, 0);
  4011. // Must have an email address and a thumbprint
  4012. if (! (pwszCertEmailAddress || lpwszEmailAddress) || ! pThumbprint)
  4013. {
  4014. hr = E_INVALIDARG;
  4015. goto exit;
  4016. }
  4017. // Get Address Book object
  4018. if (! (lpAdrBook = lpWabal->GetAdrBook())) // Don't release this!
  4019. {
  4020. Assert(lpAdrBook);
  4021. goto exit;
  4022. }
  4023. // Open the contents table on the local WAB. This will be a time hit with a large WAB.
  4024. if (HR_FAILED(hr = lpAdrBook->GetPAB(&cbWABEID, &lpWABEID)))
  4025. goto exit; // extremely unlikely failure
  4026. if (HR_FAILED(hr = lpAdrBook->OpenEntry(cbWABEID, lpWABEID, NULL, 0, &ulObjectType, (LPUNKNOWN *)&lpABCont)))
  4027. goto exit;
  4028. hr = lpABCont->GetContentsTable((WAB_PROFILE_CONTENTS|MAPI_UNICODE), &lpContentsTable);
  4029. if (SUCCEEDED(hr))
  4030. {
  4031. // Set the column set
  4032. hr = lpContentsTable->SetColumns((LPSPropTagArray)&ptaResolve, 0);
  4033. if (HR_FAILED(hr))
  4034. goto exit;
  4035. // Set up the property values for restrictions
  4036. // At least ONE of these will be filled in.
  4037. if (pwszCertEmailAddress)
  4038. {
  4039. propEmail1.ulPropTag = PR_EMAIL_ADDRESS_W;
  4040. propEmail1.Value.lpszW = pwszCertEmailAddress;
  4041. propEmails1.ulPropTag = PR_CONTACT_EMAIL_ADDRESSES_W;
  4042. propEmails1.Value.MVszW.cValues = 1;
  4043. propEmails1.Value.MVszW.lppszW = &pwszCertEmailAddress;
  4044. }
  4045. if (lpwszEmailAddress)
  4046. {
  4047. propEmail2.ulPropTag = PR_EMAIL_ADDRESS_W;
  4048. propEmail2.Value.lpszW = lpwszEmailAddress;
  4049. propEmails2.ulPropTag = PR_CONTACT_EMAIL_ADDRESSES_W;
  4050. propEmails2.Value.MVszW.cValues = 1;
  4051. propEmails2.Value.MVszW.lppszW = &lpwszEmailAddress;
  4052. }
  4053. resCount = 0;
  4054. res.rt = RES_OR;
  4055. res.res.resOr.lpRes = resOr;
  4056. if (pwszCertEmailAddress)
  4057. {
  4058. // PR_CONTACT_EMAIL_ADDRESSES match for cert email address
  4059. resOr[resCount].rt = RES_CONTENT;
  4060. resOr[resCount].res.resContent.ulFuzzyLevel = FL_IGNORECASE | FL_FULLSTRING;
  4061. resOr[resCount].res.resContent.ulPropTag = PR_CONTACT_EMAIL_ADDRESSES_W;
  4062. resOr[resCount++].res.resContent.lpProp = &propEmails1;
  4063. // PR_EMAIL_ADDRESS for cert email address
  4064. InitPropertyRestriction(&(resOr[resCount++]), &propEmail1);
  4065. }
  4066. if (lpwszEmailAddress && (!pwszCertEmailAddress || StrCmpIW(lpwszEmailAddress, pwszCertEmailAddress)))
  4067. {
  4068. // PR_CONTACT_EMAIL_ADDRESSES match for specified email address
  4069. resOr[resCount].rt = RES_CONTENT;
  4070. resOr[resCount].res.resContent.ulFuzzyLevel = FL_IGNORECASE | FL_FULLSTRING;
  4071. resOr[resCount].res.resContent.ulPropTag = PR_CONTACT_EMAIL_ADDRESSES_W;
  4072. resOr[resCount++].res.resContent.lpProp = &propEmails2;
  4073. // PR_EMAIL_ADDRESS for specified email address
  4074. InitPropertyRestriction(&(resOr[resCount++]), &propEmail2);
  4075. }
  4076. Assert(resCount);
  4077. res.res.resOr.cRes = resCount;
  4078. // Perform the restriction.
  4079. if (HR_FAILED(hr = lpContentsTable->Restrict(&res, 0)))
  4080. goto exit;
  4081. // Find any matches?
  4082. if (HR_FAILED(hr = lpContentsTable->GetRowCount(0, &ulRowCount)))
  4083. goto exit;
  4084. }
  4085. if (ulRowCount)
  4086. {
  4087. Assert(lpContentsTable);
  4088. // For each one, update the cert properties.
  4089. do
  4090. {
  4091. if (lpRow)
  4092. {
  4093. FreeProws(lpWabal, lpRow);
  4094. lpRow = NULL;
  4095. }
  4096. lpContentsTable->QueryRows(1, 0, &lpRow);
  4097. if (lpRow)
  4098. {
  4099. if (lpRow->cRows)
  4100. {
  4101. // Update the cert props for this contact
  4102. hr = HrAddCertToWabContact(hwnd, lpWabal, lpAdrBook,
  4103. lpRow->aRow[0].lpProps[irsPR_ENTRYID].Value.bin.cb,
  4104. lpRow->aRow[0].lpProps[irsPR_ENTRYID].Value.bin.lpb,
  4105. pThumbprint, lpwszEmailAddress, pwszCertEmailAddress,
  4106. pblSymCaps, ftSigningTime, dwFlags);
  4107. if (HR_FAILED(hr))
  4108. break;
  4109. }
  4110. else
  4111. {
  4112. FreeProws(lpWabal, lpRow);
  4113. lpRow = NULL;
  4114. }
  4115. }
  4116. } while (lpRow);
  4117. }
  4118. else if (dwFlags & WFF_CREATE)
  4119. {
  4120. // Need to create a new entry and set it's properties
  4121. if (! (lpWabObject = lpWabal->GetWABObject())) // Don't release this!
  4122. {
  4123. Assert(lpWabObject);
  4124. hr = E_INVALIDARG;
  4125. goto exit;
  4126. }
  4127. hr = HrWABCreateEntry(lpAdrBook, lpWabObject, lpwszDisplayName, NULL, 0, &lpMailUser);
  4128. if (lpMailUser)
  4129. {
  4130. // Get the ENTRYID for this object
  4131. hr = lpMailUser->GetProps((LPSPropTagArray)&ptaEntryID, 0, &cProps, &ppv);
  4132. ReleaseObj(lpMailUser);
  4133. if (HR_FAILED(hr) || ! cProps || ! ppv || PROP_ERROR(ppv[0]))
  4134. goto exit;
  4135. // Update the cert props and email addresses for this contact
  4136. hr = HrAddCertToWabContact(hwnd, lpWabal, lpAdrBook, ppv[0].Value.bin.cb, ppv[0].Value.bin.lpb,
  4137. pThumbprint, lpwszEmailAddress, pwszCertEmailAddress, pblSymCaps, ftSigningTime, dwFlags);
  4138. if (HR_FAILED(hr))
  4139. goto exit;
  4140. }
  4141. }
  4142. else
  4143. hr = ResultFromScode(MAPI_E_NOT_FOUND);
  4144. exit:
  4145. if (ppv)
  4146. lpWabal->FreeBuffer(ppv);
  4147. if (lpRow)
  4148. FreeProws(lpWabal, lpRow);
  4149. if (lpWABEID)
  4150. lpWabal->FreeBuffer(lpWABEID);
  4151. ReleaseObj(lpABCont);
  4152. ReleaseObj(lpContentsTable);
  4153. MemFree(ThumbprintLocal.pBlobData);
  4154. MemFree(pwszCertEmailAddress);
  4155. MemFree(pszCertEmail);
  4156. return(hr);
  4157. }
  4158. /***************************************************************************
  4159. Name : HrAddSenderCertToWab
  4160. Purpose : Add or update a sender's certificate in the wab
  4161. Parameters: hwnd = parent window handle
  4162. pMsg -> mimeole msg
  4163. lpWabal -> wabal for this message (will be calculated if NULL)
  4164. pSenderThumbprint -> sender's thumbprint (will be calculated if NULL)
  4165. pblSymCaps -> symcap blob (will be calculated if thumbprint is NULL)
  4166. ftSigningTime = signing time (will be calculated if thumbprint is NULL)
  4167. dwFlags = WFF_SHOWUI (we are allowed to show UI)
  4168. WFF_CREATE (we are allowed to create an entry if
  4169. not found)
  4170. Returns : HRESULT
  4171. Comment :
  4172. ***************************************************************************/
  4173. HRESULT HrAddSenderCertToWab(HWND hwnd, LPMIMEMESSAGE pMsg, LPWABAL lpWabal,
  4174. THUMBBLOB *pSenderThumbprint, BLOB *pblSymCaps,
  4175. FILETIME ftSigningTime, DWORD dwFlags)
  4176. {
  4177. HRESULT hr = S_OK;
  4178. BOOL fFound;
  4179. ADRINFO rAdrInfo;
  4180. ULONG cProps;
  4181. THUMBBLOB tbThumbprint = {0};
  4182. BLOB blSymCaps = {0};
  4183. LPWABAL lpLocalWabal = NULL;
  4184. BOOL fLocalCert = FALSE;
  4185. CRYPT_HASH_BLOB hash;
  4186. HCERTSTORE hcsAddressBook = NULL;
  4187. HCERTSTORE hcsCA = NULL;
  4188. HCERTSTORE hcsMsg = NULL;
  4189. IMimeBody * pBody = NULL;
  4190. PCCERT_CONTEXT pcSignerCert = NULL;
  4191. PROPVARIANT var;
  4192. HBODY hBody = NULL;
  4193. // If we don't have all the required inputs, get them.
  4194. if (! pSenderThumbprint)
  4195. {
  4196. Assert(! pblSymCaps);
  4197. // Point the parameters to local blobs
  4198. pblSymCaps = &blSymCaps;
  4199. pSenderThumbprint = &tbThumbprint;
  4200. hr = GetSignerEncryptionCert(pMsg, NULL, pSenderThumbprint, pblSymCaps,
  4201. &ftSigningTime);
  4202. if (HR_FAILED(hr))
  4203. goto exit;
  4204. fLocalCert = TRUE;
  4205. if (! pSenderThumbprint || ! pSenderThumbprint->cbSize)
  4206. {
  4207. // No cert. Give it up.
  4208. hr = E_FAIL;
  4209. goto exit;
  4210. }
  4211. }
  4212. if (! lpWabal)
  4213. {
  4214. hr = HrGetWabalFromMsg(pMsg, &lpLocalWabal);
  4215. if (HR_FAILED(hr))
  4216. goto exit;
  4217. lpWabal = lpLocalWabal;
  4218. }
  4219. if (!(lpWabal && pMsg && pSenderThumbprint))
  4220. {
  4221. AssertSz(pSenderThumbprint, "Null thumbprint");
  4222. hr = E_FAIL;
  4223. goto exit;
  4224. }
  4225. // Get the message certs into AddressBook and CA CAPI stores
  4226. if(FAILED(hr = HrGetInnerLayer(pMsg, &hBody)))
  4227. goto exit;
  4228. hr = pMsg->BindToObject(hBody ? hBody : HBODY_ROOT, IID_IMimeBody, (void **)&pBody);
  4229. if (SUCCEEDED(hr))
  4230. {
  4231. hcsAddressBook = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, NULL,
  4232. CERT_SYSTEM_STORE_CURRENT_USER, c_szWABCertStore);
  4233. #ifdef _WIN64
  4234. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING_64, &var)))
  4235. {
  4236. pcSignerCert = (PCCERT_CONTEXT)(var.pulVal);
  4237. #else // !_WIN64
  4238. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING, &var)))
  4239. {
  4240. Assert(VT_UI4 == var.vt);
  4241. pcSignerCert = (PCCERT_CONTEXT) var.ulVal;
  4242. #endif // _WIN64
  4243. if (pcSignerCert)
  4244. {
  4245. if (hcsAddressBook)
  4246. {
  4247. CertAddCertificateContextToStore(hcsAddressBook, pcSignerCert, CERT_STORE_ADD_REPLACE_EXISTING, NULL);
  4248. }
  4249. CertFreeCertificateContext(pcSignerCert);
  4250. }
  4251. }
  4252. // Get the certbag property which contains the CA chain
  4253. #ifdef _WIN64
  4254. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE_64, &var)))
  4255. {
  4256. hcsMsg = (HCERTSTORE)(var.pulVal);
  4257. #else // !_WIN64
  4258. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE, &var)))
  4259. {
  4260. hcsMsg = (HCERTSTORE) var.ulVal;
  4261. #endif // _WIN64
  4262. if (hcsMsg) // message store containing certs
  4263. {
  4264. // Add the CA certs
  4265. hcsCA = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, NULL,
  4266. CERT_SYSTEM_STORE_CURRENT_USER, c_szCACertStore);
  4267. if (hcsCA)
  4268. {
  4269. HrSaveCACerts(hcsCA, hcsMsg);
  4270. CertCloseStore(hcsCA, 0);
  4271. }
  4272. // We have a thumbprint, we need to get that cert and add it to the
  4273. // address book store.
  4274. hash.cbData = pSenderThumbprint->cbSize;
  4275. hash.pbData = pSenderThumbprint->pBlobData;
  4276. pcSignerCert = CertFindCertificateInStore(hcsMsg, X509_ASN_ENCODING, 0,
  4277. CERT_FIND_SHA1_HASH, &hash, NULL);
  4278. if (pcSignerCert != NULL)
  4279. {
  4280. CertAddCertificateContextToStore(hcsAddressBook, pcSignerCert,
  4281. CERT_STORE_ADD_REPLACE_EXISTING,
  4282. NULL);
  4283. CertFreeCertificateContext(pcSignerCert);
  4284. }
  4285. CertCloseStore(hcsMsg, 0);
  4286. }
  4287. }
  4288. if (hcsAddressBook)
  4289. CertCloseStore(hcsAddressBook, 0);
  4290. SafeRelease(pBody);
  4291. }
  4292. fFound = lpWabal->FGetFirst(&rAdrInfo);
  4293. while (fFound)
  4294. {
  4295. // Get a sender (there may be more than one)
  4296. if (MAPI_ORIG == rAdrInfo.lRecipType && (rAdrInfo.lpwszDisplay || rAdrInfo.lpwszAddress))
  4297. {
  4298. hr = HrAddCertToWab(hwnd, lpWabal, pSenderThumbprint, NULL, rAdrInfo.lpwszAddress,
  4299. rAdrInfo.lpwszDisplay, pblSymCaps, ftSigningTime, dwFlags);
  4300. if (HR_FAILED(hr))
  4301. goto exit;
  4302. }
  4303. // Get the next address
  4304. fFound = lpWabal->FGetNext(&rAdrInfo);
  4305. } // while fFound
  4306. exit:
  4307. SafeRelease(lpLocalWabal);
  4308. if (fLocalCert)
  4309. {
  4310. if (tbThumbprint.pBlobData)
  4311. MemFree(tbThumbprint.pBlobData);
  4312. if (blSymCaps.pBlobData)
  4313. MemFree(blSymCaps.pBlobData);
  4314. }
  4315. if ((dwFlags & WFF_SHOWUI) && HR_FAILED(hr))
  4316. AthErrorMessageW(hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrAddCertToWAB), hr);
  4317. return(hr);
  4318. }
  4319. BOOL CertFilterFunction(PCCERT_CONTEXT pCertContext, LPARAM dwEmailAddr, DWORD, DWORD)
  4320. {
  4321. // return TRUE to show, FALSE to hide
  4322. BOOL fRet = TRUE;
  4323. ACCTFILTERINFO * pFilterInfo = (ACCTFILTERINFO *) dwEmailAddr;
  4324. PCCERT_CONTEXT *rgCertChain = NULL;
  4325. DWORD cCertChain = 0;
  4326. const DWORD dwIgnore = CERT_VALIDITY_NO_CRL_FOUND | CERT_VALIDITY_NO_TRUST_DATA;
  4327. LONG lRet;
  4328. // return TRUE to show, FALSE to hide
  4329. if(MatchCertEmailAddress(pCertContext, pFilterInfo->szEmail) == FALSE)
  4330. return FALSE;
  4331. DWORD dw = 0;
  4332. if(SUCCEEDED(HrGetCertKeyUsage(pCertContext, &dw)))
  4333. {
  4334. if(pFilterInfo->fEncryption)
  4335. {
  4336. if (!(dw & (CERT_KEY_ENCIPHERMENT_KEY_USAGE |
  4337. CERT_KEY_AGREEMENT_KEY_USAGE)))
  4338. {
  4339. return(FALSE);
  4340. }
  4341. }
  4342. else
  4343. {
  4344. if(!(dw & (CERT_DIGITAL_SIGNATURE_KEY_USAGE)))
  4345. return(FALSE);
  4346. }
  4347. }
  4348. DWORD dwErr = DwGenerateTrustedChain(NULL, NULL, pCertContext, dwIgnore, TRUE, &cCertChain, &rgCertChain);
  4349. if (rgCertChain)
  4350. {
  4351. for (cCertChain--; int(cCertChain) >= 0; cCertChain--)
  4352. CertFreeCertificateContext(rgCertChain[cCertChain]);
  4353. MemFree(rgCertChain);
  4354. }
  4355. if(dwErr != 0)
  4356. return(FALSE);
  4357. return(fRet);
  4358. }
  4359. int GetNumMyCertForAccount(HWND hwnd, IImnAccount * pAccount, BOOL fEncrypt, HCERTSTORE hc, PCCERT_CONTEXT * ppcSave)
  4360. {
  4361. HRESULT hr = S_OK;
  4362. ULONG cCerts = 0;
  4363. PCCERT_CONTEXT pcCert = NULL;
  4364. TCHAR szAcctEmailAddress[CCHMAX_EMAIL_ADDRESS + 1] = "";
  4365. HCERTSTORE hcMy = NULL;
  4366. Assert(pAccount);
  4367. if(!hc)
  4368. {
  4369. hcMy = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, NULL, CERT_SYSTEM_STORE_CURRENT_USER, c_szMyCertStore);
  4370. }
  4371. else
  4372. hcMy = hc;
  4373. if (!hcMy)
  4374. goto Exit;
  4375. // Is there a cert that I can use? If so, let's go associate it with the
  4376. // account and try again.
  4377. pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szAcctEmailAddress, sizeof(szAcctEmailAddress));
  4378. // Enumerate all certs on this message
  4379. while (pcCert = CertEnumCertificatesInStore(hcMy, pcCert))
  4380. {
  4381. // Does this cert match our account?
  4382. if (MatchCertEmailAddress(pcCert, szAcctEmailAddress))
  4383. {
  4384. // Is it valid and trusted?
  4385. DWORD dwTrust;
  4386. PCCERT_CONTEXT *rgCertChain = NULL;
  4387. DWORD cCertChain = 0;
  4388. const DWORD dwIgnore = CERT_VALIDITY_NO_CRL_FOUND |
  4389. CERT_VALIDITY_NO_TRUST_DATA;
  4390. if(SUCCEEDED(HrGetCertKeyUsage(pcCert, &dwTrust)))
  4391. {
  4392. if(fEncrypt)
  4393. {
  4394. if (!(dwTrust & (CERT_KEY_ENCIPHERMENT_KEY_USAGE |
  4395. CERT_KEY_AGREEMENT_KEY_USAGE)))
  4396. continue;
  4397. }
  4398. else
  4399. {
  4400. if(!(dwTrust & (CERT_DIGITAL_SIGNATURE_KEY_USAGE)))
  4401. continue;
  4402. }
  4403. }
  4404. dwTrust = DwGenerateTrustedChain(hwnd, NULL, pcCert, dwIgnore, TRUE, &cCertChain, &rgCertChain);
  4405. if (!dwTrust)
  4406. {
  4407. cCerts++;
  4408. if(ppcSave)
  4409. {
  4410. if (cCerts == 1)
  4411. *ppcSave = (PCERT_CONTEXT)CertDuplicateCertificateContext(pcCert);
  4412. else if (*ppcSave)
  4413. {
  4414. // more than one cert, get rid of the one we saved
  4415. CertFreeCertificateContext(*ppcSave);
  4416. *ppcSave = NULL;
  4417. }
  4418. }
  4419. }
  4420. // clean up the cert chain
  4421. if (rgCertChain)
  4422. {
  4423. for (cCertChain--; int(cCertChain) >= 0; cCertChain--)
  4424. CertFreeCertificateContext(rgCertChain[cCertChain]);
  4425. MemFree(rgCertChain);
  4426. }
  4427. }
  4428. }
  4429. Exit:
  4430. if((hc == NULL) && hcMy)
  4431. CertCloseStore(hcMy, 0);
  4432. return(cCerts);
  4433. }
  4434. HRESULT _HrFindMyCertForAccount(HWND hwnd, PCCERT_CONTEXT * ppcCertContext, IImnAccount * pAccount, BOOL fEncrypt)
  4435. {
  4436. HRESULT hr = S_OK;
  4437. ULONG cCerts = 0;
  4438. HCERTSTORE hcMy = NULL;
  4439. PCCERT_CONTEXT pcSave = NULL;
  4440. TCHAR szAcctEmailAddress[CCHMAX_EMAIL_ADDRESS + 1] = "";
  4441. ACCTFILTERINFO FilterInfo;
  4442. Assert(pAccount);
  4443. hcMy = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, NULL, CERT_SYSTEM_STORE_CURRENT_USER, c_szMyCertStore);
  4444. if (!hcMy)
  4445. {
  4446. hr = E_FAIL;
  4447. goto Exit;
  4448. }
  4449. cCerts = GetNumMyCertForAccount(hwnd, pAccount, fEncrypt, hcMy, &pcSave);
  4450. pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szAcctEmailAddress, sizeof(szAcctEmailAddress));
  4451. if (cCerts > 1)
  4452. {
  4453. // Bring up a cert selector UI for the account
  4454. CERT_SELECT_STRUCT css;
  4455. LPTSTR lpTitle = NULL;
  4456. TCHAR szAcctName[CCHMAX_ACCOUNT_NAME + 1] = "";
  4457. TCHAR szTitleFormat[200] = "%1";
  4458. LPTSTR rgpsz[1] = {szAcctName};
  4459. memset(&css, 0, sizeof(css));
  4460. pcSave = NULL;
  4461. AthLoadString(fEncrypt ? idsSelectEncrCertTitle : idsSelectMyCertTitle, szTitleFormat, ARRAYSIZE(szTitleFormat));
  4462. pAccount->GetPropSz(AP_ACCOUNT_NAME, szAcctName, sizeof(szAcctName));
  4463. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  4464. FORMAT_MESSAGE_FROM_STRING |
  4465. FORMAT_MESSAGE_ARGUMENT_ARRAY, szTitleFormat, 0, 0,
  4466. (LPTSTR)&lpTitle, 0, (va_list *)rgpsz);
  4467. css.dwSize = sizeof(css);
  4468. css.hwndParent = hwnd;
  4469. css.hInstance = g_hInst;
  4470. css.szTitle = lpTitle;
  4471. css.arrayCertStore = &hcMy;
  4472. css.cCertStore = 1;
  4473. css.szPurposeOid = szOID_PKIX_KP_EMAIL_PROTECTION;
  4474. css.arrayCertContext = &pcSave;
  4475. css.cCertContext = 1;
  4476. FilterInfo.fEncryption = fEncrypt;
  4477. FilterInfo.dwFlags = 0;
  4478. FilterInfo.szEmail = szAcctEmailAddress;
  4479. css.lCustData = (LPARAM)(&FilterInfo);
  4480. css.pfnFilter = CertFilterFunction;
  4481. if (CertSelectCertificate(&css) && pcSave)
  4482. cCerts = 1;
  4483. else
  4484. hr = MAPI_E_USER_CANCEL;
  4485. if (lpTitle)
  4486. LocalFree(lpTitle); // Note, this is allocated by WIN32 function: FormatMessage
  4487. }
  4488. else if (cCerts == 0)
  4489. // No matches.
  4490. if(fEncrypt)
  4491. hr = MIME_E_SECURITY_NOCERT;
  4492. else
  4493. hr = MIME_E_SECURITY_NOSIGNINGCERT;
  4494. if (cCerts == 1)
  4495. {
  4496. PCCERT_CONTEXT pcCertContext = NULL;
  4497. THUMBBLOB tbSender = {0, 0};
  4498. // Found a cert. Associate it with the account!
  4499. // Get the thumbprint
  4500. tbSender.pBlobData = (BYTE *)PVGetCertificateParam(pcSave, CERT_HASH_PROP_ID, &tbSender.cbSize);
  4501. if (tbSender.pBlobData && tbSender.cbSize)
  4502. {
  4503. hr = pAccount->SetProp((fEncrypt ? AP_SMTP_ENCRYPT_CERT: AP_SMTP_CERTIFICATE), tbSender.pBlobData, tbSender.cbSize);
  4504. hr = pAccount->SaveChanges();
  4505. }
  4506. SafeMemFree(tbSender.pBlobData);
  4507. if (ppcCertContext)
  4508. *ppcCertContext = pcSave;
  4509. else
  4510. CertFreeCertificateContext(pcSave);
  4511. }
  4512. Exit:
  4513. if (hcMy)
  4514. CertCloseStore(hcMy, 0);
  4515. return(hr);
  4516. }
  4517. ULONG GetHighestEncryptionStrength(void)
  4518. {
  4519. static ULONG ulHighestStrength = 0;
  4520. if (! ulHighestStrength)
  4521. // we haven't figured it out yet. Ask MimeOle what's highest.
  4522. MimeOleAlgStrengthFromSMimeCap(NULL, 0, TRUE, &ulHighestStrength);
  4523. return(ulHighestStrength);
  4524. }
  4525. // Largest symcap is currently 0x4E with 3DES, RC2/128, RC2/64, DES, RC2/40 and SHA-1.
  4526. // You may want to bump up the size when FORTEZZA algorithms are supported.
  4527. #define CCH_BEST_SYMCAP 0x50
  4528. HRESULT HrGetHighestSymcaps(LPBYTE * ppbSymcap, LPULONG pcbSymcap)
  4529. {
  4530. HRESULT hr=S_OK;
  4531. LPVOID pvSymCapsCookie = NULL;
  4532. LPBYTE pbEncode = NULL;
  4533. ULONG cbEncode = 0;
  4534. DWORD dwBits;
  4535. // The MimeOleSMimeCapsFull call is quite expensive. The results are always
  4536. // the same during a session. (They can only change with software upgrade.)
  4537. // Cache the results here for better performance.
  4538. static BYTE szSaveBestSymcap[CCH_BEST_SYMCAP];
  4539. static ULONG cbSaveBestSymcap = 0;
  4540. if (cbSaveBestSymcap == 0)
  4541. {
  4542. // Init with no symcap gives max allowed by providers
  4543. hr = MimeOleSMimeCapInit(NULL, NULL, &pvSymCapsCookie);
  4544. if (FAILED(hr))
  4545. goto exit;
  4546. if (pvSymCapsCookie)
  4547. {
  4548. // Finish up with SymCaps
  4549. MimeOleSMimeCapsFull(pvSymCapsCookie, TRUE, FALSE, pbEncode, &cbEncode);
  4550. if (cbEncode)
  4551. {
  4552. if (! MemAlloc((LPVOID *)&pbEncode, cbEncode))
  4553. cbEncode = 0;
  4554. else
  4555. {
  4556. hr = MimeOleSMimeCapsFull(pvSymCapsCookie, TRUE, FALSE, pbEncode, &cbEncode);
  4557. if (SUCCEEDED(hr))
  4558. {
  4559. // Save this symcap in the static array for next time
  4560. // Only if we have room!
  4561. if (cbEncode <= CCH_BEST_SYMCAP)
  4562. {
  4563. cbSaveBestSymcap = min(sizeof(szSaveBestSymcap),cbEncode);
  4564. memcpy(szSaveBestSymcap, pbEncode, cbSaveBestSymcap);
  4565. }
  4566. }
  4567. }
  4568. }
  4569. SafeMemFree(pvSymCapsCookie);
  4570. }
  4571. }
  4572. else
  4573. {
  4574. // We have saved the best in the static array. Avoid the time intensive
  4575. // MimeOle query.
  4576. cbEncode = cbSaveBestSymcap;
  4577. if (! MemAlloc((LPVOID *)&pbEncode, cbEncode))
  4578. cbEncode = 0;
  4579. else
  4580. memcpy(pbEncode, szSaveBestSymcap, cbEncode);
  4581. }
  4582. exit:
  4583. if (! pbEncode)
  4584. {
  4585. // Hey, there should ALWAYS be at least RC2 (40 bit). What happened?
  4586. AssertSz(cbEncode, "MimeOleSMimeCapGetEncAlg gave us no encoding algorithm");
  4587. // Try to fix it up as best you can. Stick in the RC2 value.
  4588. cbEncode = cbRC2_40_ALGORITHM_ID;
  4589. if (MemAlloc((LPVOID *)&pbEncode, cbEncode))
  4590. {
  4591. memcpy(pbEncode, (LPBYTE)c_RC2_40_ALGORITHM_ID, cbEncode);
  4592. hr = S_OK;
  4593. }
  4594. }
  4595. if (cbEncode && pbEncode)
  4596. {
  4597. *pcbSymcap = cbEncode;
  4598. *ppbSymcap = pbEncode;
  4599. }
  4600. return(hr);
  4601. }
  4602. // Not in use anymore
  4603. #if 0
  4604. HRESULT ShowSecurityPopup(HWND hwnd, DWORD cmdID, POINT *pPoint, IMimeMessage *pMsg)
  4605. {
  4606. HRESULT hr = S_OK;
  4607. HMENU hMenu;
  4608. INT id;
  4609. BOOL fDisableCertMenus = TRUE;
  4610. IMimeBody *pRoot = NULL;
  4611. PROPVARIANT var;
  4612. TCHAR szT[CCHMAX_STRINGRES];
  4613. AssertSz(pMsg, "Didn't expect to get here without a pMsg.");
  4614. hMenu = LoadPopupMenu(IDR_SECURE_MESSAGE_POPUP);
  4615. if (hMenu)
  4616. {
  4617. if ((OECSECCMD_ENCRYPTED == cmdID))
  4618. {
  4619. // remove the edit-trust menu
  4620. RemoveMenu(hMenu, ID_EDIT_TRUST, MF_BYCOMMAND);
  4621. RemoveMenu(hMenu, ID_SEPARATOR_1, MF_BYCOMMAND);
  4622. AthLoadString(idsViewEncryptID, szT, ARRAYSIZE(szT));
  4623. ModifyMenu(hMenu, ID_DIGITAL_ID, MF_BYCOMMAND | MF_STRING, ID_ENCRYPT_ID, szT);
  4624. }
  4625. hr = pMsg->BindToObject(HBODY_ROOT, IID_IMimeBody, (void**)&pRoot);
  4626. if (SUCCEEDED(hr))
  4627. {
  4628. #ifdef _WIN64
  4629. DWORD dwOption = (OECSECCMD_ENCRYPTED == cmdID) ? OID_SECURITY_CERT_DECRYPTION_64 : OID_SECURITY_CERT_SIGNING_64;
  4630. hr = pRoot->GetOption(dwOption, &var);
  4631. if (SUCCEEDED(hr))
  4632. {
  4633. Assert(VT_UI8 == var.vt);
  4634. if ((PCCERT_CONTEXT )(var.pulVal))
  4635. {
  4636. fDisableCertMenus = FALSE;
  4637. CertFreeCertificateContext((PCCERT_CONTEXT)(var.pulVal));
  4638. }
  4639. }
  4640. #else // !_WIN64
  4641. DWORD dwOption = (OECSECCMD_ENCRYPTED == cmdID) ? OID_SECURITY_CERT_DECRYPTION : OID_SECURITY_CERT_SIGNING;
  4642. hr = pRoot->GetOption(dwOption, &var);
  4643. if (SUCCEEDED(hr))
  4644. {
  4645. Assert(VT_UI4 == var.vt);
  4646. if ((PCCERT_CONTEXT) var.ulVal)
  4647. {
  4648. fDisableCertMenus = FALSE;
  4649. CertFreeCertificateContext((PCCERT_CONTEXT) var.ulVal);
  4650. }
  4651. }
  4652. #endif // !_WIN64
  4653. }
  4654. if (fDisableCertMenus)
  4655. {
  4656. EnableMenuItem(hMenu, ID_DIGITAL_ID, MF_GRAYED);
  4657. EnableMenuItem(hMenu, ID_EDIT_TRUST, MF_GRAYED);
  4658. // EnableMenuItem(hMenu, ID_DIGITAL_ID, MF_GRAYED);
  4659. }
  4660. id = (INT)TrackPopupMenu(
  4661. hMenu,
  4662. TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
  4663. pPoint->x,
  4664. pPoint->y,
  4665. 0,
  4666. hwnd,
  4667. NULL);
  4668. // we have to use TPM_RETURNCMD here as we need to process the command-id before returning from this
  4669. // function, other wise trident will be confused about the object being clicked on.
  4670. switch (id)
  4671. {
  4672. case ID_SECURITY_PROPERTIES:
  4673. {
  4674. MSGPROP msgProp={0};
  4675. msgProp.hwndParent = hwnd;
  4676. msgProp.dwFlags = ARF_RECEIVED;
  4677. msgProp.pMsg=pMsg;
  4678. msgProp.fSecure = IsSecure(msgProp.pMsg);
  4679. if (msgProp.fSecure)
  4680. {
  4681. msgProp.mpStartPage = MP_SECURITY;
  4682. HrGetWabalFromMsg(msgProp.pMsg, &msgProp.lpWabal);
  4683. }
  4684. // This will prevent the (possibly wrong) attachment count from being shown in the properties dialog.
  4685. msgProp.fFromListView = TRUE;
  4686. hr = HrMsgProperties(&msgProp);
  4687. ReleaseObj(msgProp.lpWabal);
  4688. break;
  4689. }
  4690. case ID_DIGITAL_ID:
  4691. case ID_ENCRYPT_ID:
  4692. case ID_EDIT_TRUST:
  4693. {
  4694. if (pRoot)
  4695. {
  4696. HCERTSTORE hcMsg = 0;
  4697. #ifdef _WIN64
  4698. if (SUCCEEDED(hr = pRoot->GetOption(OID_SECURITY_HCERTSTORE_64, &var)))
  4699. {
  4700. if (var.vt == VT_UI8)
  4701. hcMsg = (HCERTSTORE)(var.pulVal);
  4702. }
  4703. if (SUCCEEDED(hr = pRoot->GetOption((ID_ENCRYPT_ID == id) ? OID_SECURITY_CERT_DECRYPTION_64 : OID_SECURITY_CERT_SIGNING_64, &var)))
  4704. {
  4705. Assert(VT_UI8 == var.vt);
  4706. if ((PCCERT_CONTEXT)(var.pulVal))
  4707. {
  4708. if (ID_EDIT_TRUST != id)
  4709. hr = CommonUI_ViewSigningCertificate(hwnd, (PCCERT_CONTEXT)(var.pulVal), hcMsg);
  4710. else
  4711. hr = CommonUI_ViewSigningCertificateTrust(hwnd, (PCCERT_CONTEXT)(var.pulVal), hcMsg);
  4712. CertFreeCertificateContext(*(PCCERT_CONTEXT *)(&(var.uhVal)));
  4713. }
  4714. }
  4715. #else // !_WIN64
  4716. if (SUCCEEDED(hr = pRoot->GetOption(OID_SECURITY_HCERTSTORE, &var)))
  4717. {
  4718. if (var.vt == VT_UI4)
  4719. hcMsg = (HCERTSTORE) var.ulVal;
  4720. }
  4721. if (SUCCEEDED(hr = pRoot->GetOption((ID_ENCRYPT_ID == id) ? OID_SECURITY_CERT_DECRYPTION : OID_SECURITY_CERT_SIGNING, &var)))
  4722. {
  4723. Assert(VT_UI4 == var.vt);
  4724. if ((PCCERT_CONTEXT) var.ulVal)
  4725. {
  4726. if (ID_EDIT_TRUST != id)
  4727. hr = CommonUI_ViewSigningCertificate(hwnd, (PCCERT_CONTEXT) var.ulVal, hcMsg);
  4728. else
  4729. hr = CommonUI_ViewSigningCertificateTrust(hwnd, (PCCERT_CONTEXT) var.ulVal, hcMsg);
  4730. CertFreeCertificateContext((PCCERT_CONTEXT) var.ulVal);
  4731. }
  4732. }
  4733. #endif // _WIN64
  4734. if (hcMsg)
  4735. CertCloseStore(hcMsg, 0);
  4736. }
  4737. break;
  4738. }
  4739. case ID_HELP_SECURITY:
  4740. OEHtmlHelp(hwnd, c_szCtxHelpFileHTMLCtx, HH_DISPLAY_TOPIC, (DWORD_PTR)(LPCSTR)"mail_overview_send_secure_messages.htm");
  4741. break;
  4742. }
  4743. DestroyMenu(hMenu);
  4744. SafeRelease(pRoot);
  4745. } else
  4746. hr = E_FAIL;
  4747. return hr;
  4748. }
  4749. #endif // 0
  4750. void ShowDigitalIDs(HWND hWnd)
  4751. {
  4752. CRYPTUI_CERT_MGR_STRUCT mgrCert;
  4753. mgrCert.dwSize = sizeof(mgrCert);
  4754. mgrCert.hwndParent = hWnd;
  4755. mgrCert.dwFlags = 0;
  4756. mgrCert.pwszTitle = NULL;
  4757. mgrCert.pszInitUsageOID = NULL;
  4758. CryptUIDlgCertMgr(&mgrCert);
  4759. return;
  4760. }
  4761. BOOL CheckCDPinCert(LPMIMEMESSAGE pMsg)
  4762. {
  4763. BOOL fRet;
  4764. IMimeBody *pBody;
  4765. HBODY hBody = NULL;
  4766. if(!pMsg)
  4767. return(FALSE);
  4768. fRet = FALSE;
  4769. if(FAILED(HrGetInnerLayer(pMsg, &hBody)))
  4770. return(FALSE);
  4771. if (SUCCEEDED(pMsg->BindToObject(hBody ? hBody : HBODY_ROOT, IID_IMimeBody, (void**)&pBody)))
  4772. {
  4773. PROPVARIANT var;
  4774. #ifdef _WIN64
  4775. if(SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING_64, &var)))
  4776. {
  4777. Assert(VT_UI8 == var.vt);
  4778. PCCERT_CONTEXT pcCert= (PCCERT_CONTEXT)(var.pulVal);
  4779. fRet = CheckCDPinCert(pcCert);
  4780. }
  4781. #else // !_WIN64
  4782. if(SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING, &var)))
  4783. {
  4784. Assert(VT_UI4 == var.vt);
  4785. PCCERT_CONTEXT pcCert= (PCCERT_CONTEXT) var.ulVal;
  4786. fRet = CheckCDPinCert(pcCert);
  4787. }
  4788. #endif // _WIN64
  4789. pBody->Release();
  4790. }
  4791. return(fRet);
  4792. }
  4793. BOOL CheckCDPinCert(PCCERT_CONTEXT pcCert)
  4794. {
  4795. if (pcCert)
  4796. {
  4797. PCERT_EXTENSION pExt = CertFindExtension(szOID_CRL_DIST_POINTS, pcCert->pCertInfo->cExtension, pcCert->pCertInfo->rgExtension);
  4798. if(pExt != NULL)
  4799. return TRUE;
  4800. }
  4801. return(FALSE);
  4802. }
  4803. #ifdef YST
  4804. BOOL ParseNames(DWORD * pcNames, PCERT_NAME_BLOB * prgNames, HWND hwnd, DWORD idc)
  4805. {
  4806. DWORD cb;
  4807. DWORD cEntry = 0;
  4808. DWORD cNames = 0;
  4809. BOOL f;
  4810. DWORD i;
  4811. LPWSTR pwsz;
  4812. LPWSTR pwsz1;
  4813. CRYPT_DER_BLOB rgDer[50] = {0};
  4814. CERT_ALT_NAME_INFO rgNames[50] = {0};
  4815. CERT_ALT_NAME_ENTRY rgEntry[200] = {0};
  4816. WCHAR rgwch[4096];
  4817. GetDlgItemTextW(hwnd, idc, rgwch, sizeof(rgwch)/sizeof(WCHAR));
  4818. pwsz = rgwch;
  4819. while (*pwsz != 0) {
  4820. if (*pwsz == ' ') {
  4821. while (*pwsz == ' ') pwsz++;
  4822. rgNames[cNames-1].cAltEntry += 1;
  4823. }
  4824. else {
  4825. cNames += 1;
  4826. rgNames[cNames-1].rgAltEntry = &rgEntry[cEntry];
  4827. rgNames[cNames-1].cAltEntry = 1;
  4828. }
  4829. if (_wcsnicmp(pwsz, L"SMTP:", 5) == 0) {
  4830. pwsz += 5;
  4831. while (*pwsz == ' ') pwsz++;
  4832. rgEntry[cEntry].dwAltNameChoice = CERT_ALT_NAME_RFC822_NAME;
  4833. rgEntry[cEntry].pwszRfc822Name = pwsz;
  4834. while ((*pwsz != 0) && (*pwsz != '\n') && (*pwsz != '\r')) pwsz++;
  4835. }
  4836. else if (_wcsnicmp(pwsz, L"X500:", 5) == 0) {
  4837. pwsz += 5;
  4838. while (*pwsz == ' ') pwsz++;
  4839. for (pwsz1 = pwsz; ((*pwsz != 0) && (*pwsz != '\n') &&
  4840. (*pwsz != '\r')); pwsz++);
  4841. if (*pwsz != 0) {
  4842. *pwsz = 0;
  4843. pwsz++;
  4844. }
  4845. rgEntry[cEntry].dwAltNameChoice = CERT_ALT_NAME_DIRECTORY_NAME;
  4846. f = CertStrToNameW(X509_ASN_ENCODING, pwsz1,
  4847. CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG, NULL,
  4848. NULL, &cb, NULL);
  4849. if (!f) return FALSE;
  4850. rgEntry[cEntry].DirectoryName.pbData = (LPBYTE) malloc(cb);
  4851. f = CertStrToNameW(X509_ASN_ENCODING, pwsz1,
  4852. CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG, NULL,
  4853. rgEntry[cEntry].DirectoryName.pbData, &cb,
  4854. NULL);
  4855. if (!f) return FALSE;
  4856. rgEntry[cEntry].DirectoryName.cbData = cb;
  4857. }
  4858. else {
  4859. return FALSE;
  4860. }
  4861. if (*pwsz == '\r') {
  4862. *pwsz = 0;
  4863. pwsz++;
  4864. }
  4865. if (*pwsz == '\n') {
  4866. *pwsz = 0;
  4867. pwsz++;
  4868. }
  4869. cEntry += 1;
  4870. }
  4871. *prgNames = (PCERT_NAME_BLOB) malloc(sizeof(CERT_NAME_BLOB) * cNames);
  4872. if (*prgNames == NULL) return FALSE;
  4873. for (i=0; i<cNames; i++) {
  4874. f = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
  4875. &rgNames[i], CRYPT_ENCODE_ALLOC_FLAG, NULL,
  4876. &(*prgNames)[i].pbData, &(*prgNames)[i].cbData);
  4877. if (!f) return f;
  4878. }
  4879. *pcNames = cNames;
  4880. return f;
  4881. }
  4882. #endif // YST
  4883. #ifdef SMIME_V3
  4884. BOOL FNameInList(LPSTR szAddr, DWORD cReceiptFromList, CERT_NAME_BLOB *rgReceiptFromList)
  4885. {
  4886. BOOL fResult = FALSE;
  4887. if (cReceiptFromList == 0)
  4888. {
  4889. fResult = TRUE;
  4890. }
  4891. else {
  4892. DWORD cb;
  4893. DWORD i;
  4894. DWORD i1;
  4895. char rgch[256];
  4896. for (i=0; !fResult && (i<cReceiptFromList); i++)
  4897. {
  4898. CERT_ALT_NAME_INFO * pname = NULL;
  4899. if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
  4900. rgReceiptFromList[i].pbData, rgReceiptFromList[i].cbData,
  4901. CRYPT_DECODE_ALLOC_FLAG,NULL,
  4902. &pname, &cb))
  4903. {
  4904. for (i1=0; !fResult && (i1<pname->cAltEntry); i1++)
  4905. {
  4906. switch (pname->rgAltEntry[i1].dwAltNameChoice)
  4907. {
  4908. case CERT_ALT_NAME_RFC822_NAME:
  4909. cb = WideCharToMultiByte(CP_ACP, 0,
  4910. (pname->rgAltEntry[i1]).pwszRfc822Name, -1,
  4911. rgch, sizeof(rgch), NULL, NULL);
  4912. Assert(cb < sizeof(rgch) - 2);
  4913. if (lstrcmpi(szAddr, rgch))
  4914. {
  4915. fResult = TRUE;
  4916. }
  4917. }
  4918. }
  4919. LocalFree(pname);
  4920. }
  4921. else
  4922. {
  4923. AssertSz(FALSE, "Bad Receipt From Name");
  4924. // $TODO - handle this error
  4925. }
  4926. }
  4927. }
  4928. return fResult;
  4929. }
  4930. // Return security label as Unicode text string
  4931. HRESULT HrGetLabelString(LPMIMEMESSAGE pMsg, LPWSTR *pwStr)
  4932. {
  4933. PCRYPT_ATTRIBUTE pattrLabel;
  4934. CRYPT_ATTR_BLOB valLabel;
  4935. LPBYTE pbLabel = NULL;
  4936. DWORD cbLabel;
  4937. PSMIME_SECURITY_LABEL plabel = NULL;
  4938. HRESULT hr = E_FAIL;
  4939. IMimeSecurity2 * pSMIME3 = NULL;
  4940. IMimeBody *pBody = NULL;
  4941. HBODY hBody = NULL;
  4942. Assert(pMsg);
  4943. if(FAILED(hr = HrGetInnerLayer(pMsg, &hBody)))
  4944. return(hr);
  4945. if(pMsg->BindToObject(hBody ? hBody : HBODY_ROOT, IID_IMimeBody, (void **)&pBody) == S_OK)
  4946. {
  4947. if(pBody->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &pSMIME3) == S_OK)
  4948. {
  4949. // Get label attribute
  4950. if(pSMIME3->GetAttribute(0, 0, SMIME_ATTRIBUTE_SET_SIGNED,
  4951. 0, szOID_SMIME_Security_Label,
  4952. &pattrLabel) == S_OK)
  4953. {
  4954. // decode label
  4955. if(CryptDecodeObjectEx(X509_ASN_ENCODING,
  4956. szOID_SMIME_Security_Label,
  4957. pattrLabel->rgValue[0].pbData,
  4958. pattrLabel->rgValue[0].cbData,
  4959. CRYPT_DECODE_ALLOC_FLAG,
  4960. &CryptDecodeAlloc, &plabel, &cbLabel))
  4961. {
  4962. SpISMimePolicyLabelInfo spspli;
  4963. // Get the required interface to the policy module.
  4964. if(HrQueryPolicyInterface(0, plabel->pszObjIdSecurityPolicy, IID_ISMimePolicyLabelInfo,
  4965. (LPVOID *) &spspli) == S_OK)
  4966. {
  4967. LPWSTR pwchLabel = NULL;
  4968. // get label description string
  4969. if(spspli->GetStringizedLabel(0, plabel, &pwchLabel) == S_OK)
  4970. {
  4971. *pwStr = pwchLabel;
  4972. hr = S_OK;
  4973. }
  4974. }
  4975. else
  4976. hr = S_FALSE;
  4977. SafeMemFree(plabel);
  4978. }
  4979. }
  4980. SafeRelease(pSMIME3);
  4981. }
  4982. ReleaseObj(pBody);
  4983. }
  4984. return(hr);
  4985. }
  4986. #endif // SMIME_V3
  4987. HRESULT HrShowSecurityProperty(HWND hwnd, LPMIMEMESSAGE pMsg)
  4988. {
  4989. MSGPROP msgProp={0};
  4990. HRESULT hr = S_OK;
  4991. msgProp.hwndParent = hwnd;
  4992. msgProp.dwFlags = ARF_RECEIVED;
  4993. msgProp.pMsg = pMsg;
  4994. msgProp.fSecure = IsSecure(msgProp.pMsg);
  4995. if (msgProp.fSecure)
  4996. {
  4997. msgProp.mpStartPage = MP_SECURITY;
  4998. HrGetWabalFromMsg(msgProp.pMsg, &msgProp.lpWabal);
  4999. }
  5000. hr = HrMsgProperties(&msgProp);
  5001. ReleaseObj(msgProp.lpWabal);
  5002. return(hr);
  5003. }
  5004. void CreateContentIdentifier(TCHAR *pchContentID, DWORD cchSize, LPMIMEMESSAGE pMsg)
  5005. {
  5006. SYSTEMTIME SysTime;
  5007. LPWSTR lpszSubj = NULL;
  5008. int nLen = 0;
  5009. TCHAR szTmp[21];
  5010. GetSystemTime(&SysTime);
  5011. MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &lpszSubj);
  5012. nLen = lstrlenW(lpszSubj);
  5013. for(int i =0; (i < 5) && (i < nLen); i++)
  5014. wnsprintf(szTmp + i*4, (ARRAYSIZE(szTmp) - i*4), "%04d", lpszSubj[i]);
  5015. szTmp[i*4] = _T('\0');
  5016. // ContentId is sequence of following text characters
  5017. // 1. Prefix ("797374" + "-" and code - 7 chars
  5018. // 2. System time + "-" - 18 chars
  5019. // 3. First 5 Unicode chars (or lstrlen) in dec of Subject - 20 chars
  5020. // Total # of chars 7 + 18 + 20 + 1 = 46
  5021. // if you change this, also change CONTENTID_SIZE
  5022. wnsprintf(pchContentID, cchSize, "%s-%4d%2d%1d%2d%2d%2d%2d%2d-%s",
  5023. sz_OEMS_ContIDPrefix,
  5024. SysTime.wYear,
  5025. SysTime.wMonth,
  5026. SysTime.wDayOfWeek,
  5027. SysTime.wDay,
  5028. SysTime.wHour,
  5029. SysTime.wMinute,
  5030. SysTime.wSecond,
  5031. SysTime.wMilliseconds,
  5032. szTmp);
  5033. SafeMimeOleFree(lpszSubj);
  5034. }