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.

4607 lines
152 KiB

  1. /*
  2. ** s m i m e . c p p
  3. **
  4. ** Purpose:
  5. ** Implementation of a class to wrap around CAPI functionality
  6. **
  7. ** History
  8. ** 1/26/98 (brucek) Allow multiple security layers (triple-wrapping)
  9. ** 6/15/97: (t-erikne) CAPI streaming
  10. ** 5/18/97: (t-erikne) new IMimeSecurity interface
  11. ** 2/07/97: (t-erikne) multipart/signed
  12. ** 1/06/97: (t-erikne) Moved into MimeOLE
  13. ** 11/14/96: (t-erikne) CAPI Post-SDR work
  14. ** 8/27/96: (t-erikne) Created.
  15. **
  16. ** Copyright (C) Microsoft Corp. 1996-1998.
  17. */
  18. ///////////////////////////////////////////////////////////////////////////
  19. //
  20. // Depends on
  21. //
  22. #include "pch.hxx"
  23. #include "smime.h"
  24. #include "vstream.h"
  25. #include "olealloc.h"
  26. #include "capistm.h"
  27. #include "bookbody.h"
  28. #ifndef MAC
  29. #include <shlwapi.h>
  30. #endif // !MAC
  31. #include <demand.h>
  32. // from dllmain.h
  33. extern CMimeAllocator * g_pMoleAlloc;
  34. extern CRITICAL_SECTION g_csDllMain;
  35. extern ULONG DllAddRef(void);
  36. extern ULONG DllRelease(void);
  37. extern HCERTSTORE WINAPI OpenCachedMyStore();
  38. extern HCERTSTORE WINAPI OpenCachedAddressBookStore();
  39. #define MST_THIS_SIGN_ENCRYPT (MST_THIS_SIGN | MST_THIS_ENCRYPT)
  40. ///////////////////////////////////////////////////////////////////////////
  41. //
  42. // Static Prototypes
  43. //
  44. static void _FreeCertArray(PCCERT_CONTEXT *rgpCert, const UINT cCerts);
  45. static HRESULT _HrConvertHrFromGetCertToEncode(HRESULT hr, const BOOL fEncrypt);
  46. #ifndef SMIME_V3
  47. static HRESULT ConstructAuthAttributes(BLOB * pblEncoded, BLOB * pblAuthAttr, FILETIME * pftSigntime, BLOB * pblSymcaps);
  48. #endif // SMIME_V3
  49. extern HRESULT HrCopyBlob(LPCBLOB pIn, LPBLOB pOut);
  50. static LPBYTE DuplicateMemory(LPBYTE lpvIn, ULONG cbIn);
  51. ///////////////////////////////////////////////////////////////////////////
  52. //
  53. // Macros
  54. //
  55. #define CHECKSMIMEINITDW { if (FAILED(CheckInit())) return (DWORD)-1; }
  56. #define CHECKSMIMEINITV { if (FAILED(CheckInit())) return; }
  57. #define CHECKSMIMEINITB { if (FAILED(CheckInit())) return FALSE; }
  58. #define CHECKSMIMEINIT { if (FAILED(CheckInit())) return MIME_E_SECURITY_NOTINIT; }
  59. #define SCHECKSMIMEINITP { if (FAILED(StaticCheckInit())) return NULL; }
  60. #define SCHECKSMIMEINITV { if (FAILED(StaticCheckInit())) return; }
  61. #define SCHECKSMIMEINIT { if (FAILED(StaticCheckInit())) return MIME_E_SECURITY_NOTINIT; }
  62. #define ALLOCED(_pv) \
  63. (0 != g_pMalloc->DidAlloc(_pv))
  64. #define THIS_AS_UNK ((IUnknown *)(IStream *)this)
  65. ///////////////////////////////////////////////////////////////////////////
  66. //
  67. // Globals
  68. //
  69. ASSERTDATA
  70. static const char s_szSMIMEP7s[] = "smime.p7s";
  71. static const char s_szSMIMEP7m[] = "smime.p7m";
  72. #ifdef DEBUG
  73. static LPCSTR s_lpszCertStore = "c:\\ttfn\\debug.sto";
  74. // emit signatures, encryption that should be broken
  75. static BOOL s_fDebugEmitBroken = 0;
  76. // show the certificate found by HrGetUsableCert
  77. static BOOL s_fDebugShowFoundCert = 0;
  78. // copy the message source to a BYTE *
  79. static BOOL s_fDebugDumpWholeMsg = 1;
  80. // show/select certs w/o email oids
  81. static BOOL s_fDebugAllowNoEmail = 1;
  82. #endif // DEBUG
  83. static const char s_cszMy[] = "My";
  84. static const char s_cszWABCertStore[] = "AddressBook";
  85. CRYPT_ENCODE_PARA CryptEncodeAlloc = {
  86. sizeof(CRYPT_ENCODE_PARA), CryptAllocFunc, CryptFreeFunc
  87. };
  88. CRYPT_DECODE_PARA CryptDecodeAlloc = {
  89. sizeof(CRYPT_DECODE_PARA), CryptAllocFunc, CryptFreeFunc
  90. };
  91. ///////////////////////////////////////////////////////////////////////////
  92. //
  93. // Initialization of statics to class
  94. //
  95. #ifdef MAC
  96. EXTERN_C WINCRYPT32API HCERTSTORE WINAPI MacCertOpenStore(LPCSTR lpszStoreProvider,
  97. DWORD dwEncodingType,
  98. HCRYPTPROV hCryptProv,
  99. DWORD dwFlags,
  100. const void *pvPara);
  101. #define CertOpenStore MacCertOpenStore
  102. // We don't have DLL's on the Mac, so let's just hardcode the vtable.
  103. CAPIfuncs CSMime::ms_CAPI = { CertEnumCertificatesInStore,
  104. CertNameToStrA
  105. };
  106. #endif // MAC
  107. ///////////////////////////////////////////////////////////////////////////
  108. //
  109. // inlines
  110. //
  111. INLINE void ReleaseCert(PCCERT_CONTEXT pc)
  112. { if (pc) CertFreeCertificateContext(pc); }
  113. INLINE void ReleaseCertStore(HCERTSTORE hc)
  114. { if (hc) CertCloseStore(hc, 0); }
  115. INLINE void FreeCert(PCCERT_CONTEXT pc)
  116. { CertFreeCertificateContext(pc); }
  117. INLINE PCCERT_CONTEXT DupCert(const PCCERT_CONTEXT pc)
  118. { return CertDuplicateCertificateContext(pc); }
  119. ///////////////////////////////////////////////////////////////////////////
  120. //
  121. // ctor, dtor
  122. //
  123. CSMime::CSMime(void)
  124. {
  125. DllAddRef();
  126. m_cRef = 1;
  127. InitializeCriticalSection(&m_cs);
  128. DOUT("CSMIME::constructor() %#x -> %d", this, m_cRef);
  129. }
  130. CSMime::~CSMime()
  131. {
  132. DOUT("CSMIME::destructor() %#x -> %d", this, m_cRef);
  133. DeleteCriticalSection(&m_cs);
  134. DllRelease();
  135. }
  136. ///////////////////////////////////////////////////////////////////////////
  137. //
  138. // IUnknown methods
  139. //
  140. STDMETHODIMP CSMime::QueryInterface(REFIID riid, LPVOID *ppv)
  141. {
  142. if (!ppv)
  143. return TrapError(E_INVALIDARG);
  144. // Find IID
  145. if (IID_IUnknown == riid)
  146. *ppv = (IUnknown *)(IMimeSecurity *)this;
  147. else if (IID_IMimeSecurity == riid)
  148. *ppv = (IMimeSecurity *)this;
  149. else
  150. {
  151. *ppv = NULL;
  152. return TrapError(E_NOINTERFACE);
  153. }
  154. ((IUnknown *)*ppv)->AddRef();
  155. return S_OK;
  156. }
  157. STDMETHODIMP_(ULONG) CSMime::AddRef(void)
  158. {
  159. DOUT("CSMime::AddRef() %#x -> %d", this, m_cRef+1);
  160. InterlockedIncrement((LPLONG)&m_cRef);
  161. return m_cRef;
  162. }
  163. STDMETHODIMP_(ULONG) CSMime::Release(void)
  164. {
  165. DOUT("CSMime::Release() %#x -> %d", this, m_cRef-1);
  166. if (0 == InterlockedDecrement((LPLONG)&m_cRef))
  167. {
  168. delete this;
  169. return 0;
  170. }
  171. return m_cRef;
  172. }
  173. ///////////////////////////////////////////////////////////////////////////
  174. //
  175. // Initialization functions
  176. //
  177. STDMETHODIMP CSMime::CheckInit(void)
  178. {
  179. register BOOL f;
  180. EnterCriticalSection(&m_cs);
  181. #ifdef MAC
  182. f = TRUE;
  183. #else // !MAC
  184. f = !!DemandLoadCrypt32();
  185. #endif // MAC
  186. #ifdef DEBUG
  187. if(!f) {
  188. DebugStrf("CSMime not initialized ! ! !\n");
  189. }
  190. #endif
  191. LeaveCriticalSection(&m_cs);
  192. return f ? S_OK : MIME_E_SECURITY_NOTINIT;
  193. }
  194. inline HRESULT CSMime::StaticCheckInit(void)
  195. {
  196. #ifdef MAC
  197. return S_OK;
  198. #else // !MAC
  199. HRESULT hr;
  200. if(DemandLoadCrypt32()) {
  201. hr = S_OK;
  202. }
  203. else {
  204. #ifdef DEBUG
  205. DebugStrf("CSMime not initialized ! ! !\n");
  206. #endif
  207. hr = MIME_E_SECURITY_NOTINIT;
  208. }
  209. return hr;
  210. #endif // MAC
  211. }
  212. /* InitNew:
  213. **
  214. ** Purpose:
  215. ** Called after the ctor by clients. Initializes CSMime.
  216. */
  217. STDMETHODIMP CSMime::InitNew(void)
  218. {
  219. register HRESULT hr;
  220. EnterCriticalSection(&m_cs);
  221. hr = HrInitCAPI();
  222. #ifdef DEBUG
  223. if (SUCCEEDED(hr))
  224. #ifdef MAC
  225. InitDebugHelpers((HINSTANCE) 1);
  226. #else // !MAC
  227. InitDebugHelpers(/*g_hCryptoDll*/ (HINSTANCE) 1);
  228. #endif // MAC
  229. if (0) {
  230. DumpAlgorithms();
  231. }
  232. TrapError(hr);
  233. #endif
  234. LeaveCriticalSection(&m_cs);
  235. if (E_FAIL == hr) {
  236. hr = MIME_E_SECURITY_NOTINIT;
  237. }
  238. return hr;
  239. }
  240. /* InitCAPI:
  241. **
  242. ** Purpose:
  243. ** Loads the required dll and inits the function table.
  244. ** Returns:
  245. ** MIME_E_SECURITY_LOADCRYPT32 if LoadLibrary fails
  246. ** MIME_E_SECURITY_BADPROCADDR if any of the GetProcAddress calls fail
  247. */
  248. HRESULT CSMime::HrInitCAPI()
  249. {
  250. #ifdef MAC
  251. return S_OK;
  252. #else // !MAC
  253. HRESULT hr = S_OK;
  254. UINT u = 0;
  255. FARPROC *pVTable;
  256. EnterCriticalSection(&g_csDllMain);
  257. if (!DemandLoadCrypt32()) {
  258. hr = TrapError(MIME_E_SECURITY_LOADCRYPT32);
  259. goto ErrorReturn;
  260. }
  261. exit:
  262. LeaveCriticalSection(&g_csDllMain);
  263. return hr;
  264. ErrorReturn:
  265. {
  266. DWORD dwErr = GetLastError();
  267. UnloadCAPI();
  268. SetLastError(dwErr);
  269. Assert(S_OK != hr);
  270. }
  271. goto exit;
  272. #endif // MAC
  273. }
  274. /* UnloadAll:
  275. **
  276. ** Purpose:
  277. ** Called during deinit of our DLL to unload S/MIME
  278. */
  279. void CSMime::UnloadAll(void)
  280. {
  281. UnloadCAPI();
  282. return;
  283. }
  284. /* UnloadCAPI:
  285. **
  286. ** Purpose:
  287. ** Frees the crypt32 library. Note that this will
  288. ** cause subsequent CheckInit calls to fail
  289. */
  290. void CSMime::UnloadCAPI()
  291. {
  292. }
  293. ///////////////////////////////////////////////////////////////////////////
  294. //
  295. // Encode/Decode stuff . . .
  296. //
  297. ///////////////////////////////////////////////////////////////////////////
  298. ///////////////////////////////////////////////////////////////////////////
  299. //
  300. // Message crackers
  301. //
  302. #ifndef WIN16
  303. HRESULT CSMime::GetMessageType(
  304. HWND hwndParent,
  305. IMimeBody *const pBody,
  306. DWORD *const pdwSecType)
  307. #else
  308. HRESULT CSMime::GetMessageType(
  309. const HWND hwndParent,
  310. IMimeBody *const pBody,
  311. DWORD *const pdwSecType)
  312. #endif // !WIN16
  313. {
  314. return StaticGetMessageType(hwndParent, pBody, pdwSecType);
  315. }
  316. /* StaticGetMessageType:
  317. **
  318. ** Purpose:
  319. ** Used to figure out if a message is signed/encrypted/none/both
  320. ** without doing any cryptographic operations.
  321. ** Takes:
  322. ** IN hwndParent - all modal UI to this
  323. ** IN pBody - body to decode
  324. ** OUT dwSecType - which, if any, S/MIME types have been applied
  325. ** Notes:
  326. ** if MIME_E_SECURITY_BADSECURETYPE is returned, pdwSecType is set
  327. ** to the actual CMSG_ return from CAPI.
  328. ** (7/10/97) MIME_E_SECURITY_BADSECURETYPE now comes from CAPISTM.
  329. */
  330. HRESULT CSMime::StaticGetMessageType(
  331. HWND hwndParent,
  332. IMimeBody *const pBody,
  333. DWORD *const pdwSecType)
  334. {
  335. HRESULT hr;
  336. // SCHECKSMIMEINIT
  337. if (!(pBody && pdwSecType))
  338. return TrapError(E_INVALIDARG);
  339. CCAPIStm capistmMsg(NULL);
  340. hr = capistmMsg.HrInitialize(0, hwndParent, FALSE, NULL, CSTM_TYPE_ONLY, NULL, NULL);
  341. if (SUCCEEDED(hr)) {
  342. IStream * pstmCapi;
  343. PSECURITY_LAYER_DATA psld;
  344. capistmMsg.QueryInterface(IID_IStream, (void**)&pstmCapi);
  345. #ifdef N_BAD1
  346. // This is what would happen if I were passed a stream
  347. // instead of a body
  348. LPSTREAM pstmBody;
  349. ULARGE_INTEGER uliCopy;
  350. hr = pBody->GetData(IET_BINARY, &pstmBody);
  351. uliCopy.HighPart = (ULONG)-1;
  352. uliCopy.LowPart = (ULONG)-1;
  353. pstmBody->CopyTo(pstmCapi, uliCopy, NULL, NULL);
  354. #else
  355. hr = pBody->GetDataHere(IET_BINARY, pstmCapi);
  356. #endif
  357. // We expect CAPISTM_E_GOTTYPE because the streamer
  358. // fails its Write() as soon as it gets the type
  359. Assert(FAILED(hr));
  360. // However, try to get the data even if we succeeded. That
  361. // would surprise me.
  362. // BUGBUG: Does this make sense? We're only dealing with the outer layer here.
  363. if (psld = capistmMsg.GetSecurityLayerData()) {
  364. if (CAPISTM_E_GOTTYPE == hr) {
  365. hr = S_OK;
  366. }
  367. *pdwSecType = psld->m_dwMsgEnhancement;
  368. psld->Release();
  369. } else {
  370. hr = E_FAIL;
  371. }
  372. pstmCapi->Release();
  373. hr = capistmMsg.EndStreaming();
  374. }
  375. return hr;
  376. }
  377. ///////////////////////////////////////////////////////////////////////////
  378. //
  379. // Encode methods
  380. //
  381. /* EncodeMessage:
  382. **
  383. ** Purpose:
  384. ** call EncodeBody for lazy developers
  385. ** Takes:
  386. ** IN pTree - the tree of the message
  387. ** IN dwFlags - SEF_*
  388. */
  389. STDMETHODIMP CSMime::EncodeMessage(
  390. IMimeMessageTree *const pTree,
  391. DWORD dwFlags)
  392. {
  393. HRESULT hr;
  394. HBODY hRoot;
  395. if (!pTree || (dwFlags & ~SEF_MASK)) {
  396. hr = TrapError(E_INVALIDARG);
  397. }
  398. else if (SUCCEEDED(hr = pTree->GetBody(IBL_ROOT, NULL, &hRoot))) {
  399. hr = TrapError(EncodeBody(pTree, hRoot, dwFlags|EBF_RECURSE|EBF_COMMITIFDIRTY));
  400. }
  401. return hr;
  402. }
  403. HRESULT CSMime::EncodeMessage2(IMimeMessageTree *const pTree, DWORD dwFlags,
  404. HWND hwnd)
  405. {
  406. HRESULT hr;
  407. HBODY hRoot;
  408. if (!pTree || (dwFlags & ~SEF_MASK)) {
  409. hr = TrapError(E_INVALIDARG);
  410. }
  411. else if (SUCCEEDED(hr = pTree->GetBody(IBL_ROOT, NULL, &hRoot))) {
  412. hr = TrapError(EncodeBody2(pTree, hRoot, dwFlags|EBF_RECURSE|
  413. EBF_COMMITIFDIRTY, hwnd));
  414. }
  415. return hr;
  416. }
  417. /* EncodeBody:
  418. **
  419. ** Purpose:
  420. ** Do the entirety of the S/MIME encode operation. This includes converting bodyoptions
  421. ** to SMIMEINFO and calling the appropriate encoding subfunctions.
  422. **
  423. ** Takes:
  424. ** IN pTree - the tree of the body to encode
  425. ** IN hEncodeRoot - body from which to encode downward
  426. ** IN dwFlags - set of EBF_ or SEF_
  427. */
  428. STDMETHODIMP CSMime::EncodeBody(
  429. IMimeMessageTree *const pTree,
  430. HBODY hEncodeRoot,
  431. DWORD dwFlags)
  432. {
  433. HRESULT hr;
  434. HWND hwnd = NULL;
  435. IMimeBody * pEncodeRoot = NULL;
  436. PROPVARIANT var;
  437. if (! pTree || ! hEncodeRoot) {
  438. hr = TrapError(E_INVALIDARG);
  439. goto exit;
  440. }
  441. // Get the body we are suppose to be encoding
  442. CHECKHR(hr = pTree->BindToObject(hEncodeRoot, IID_IMimeBody, (void**)&pEncodeRoot));
  443. #ifdef _WIN64
  444. if (SUCCEEDED(pEncodeRoot->GetOption(OID_SECURITY_HWND_OWNER_64, &var)) && (NULL != (HWND)(var.pulVal))) {
  445. Assert(VT_UI8 == var.vt);
  446. hwnd = *(HWND *)(&(var.uhVal));
  447. }
  448. #else
  449. if (SUCCEEDED(pEncodeRoot->GetOption(OID_SECURITY_HWND_OWNER, &var)) && (NULL != var.ulVal))
  450. {
  451. Assert(VT_UI4 == var.vt);
  452. hwnd = (HWND)var.ulVal;
  453. }
  454. #endif // _WIN64
  455. hr = EncodeBody2(pTree, hEncodeRoot, dwFlags, hwnd);
  456. exit:
  457. ReleaseObj(pEncodeRoot);
  458. return hr;
  459. }
  460. HRESULT CSMime::EncodeBody2(IMimeMessageTree *const pTree, HBODY hEncodeRoot,
  461. DWORD dwFlags, HWND hwnd)
  462. {
  463. IMimeAddressTable * pAdrTable = NULL;
  464. IMimeEnumAddressTypes * pAdrEnum = NULL;
  465. CVirtualStream * pvstmEncoded = NULL;
  466. IMimeBody * pEncodeRoot = NULL;
  467. HRESULT hr;
  468. SMIMEINFO si;
  469. CERTARRAY caCerts;
  470. BOOL fIgnoreSenderCertProbs;
  471. PSECURITY_LAYER_DATA psldLoop;
  472. PROPVARIANT var;
  473. memset(&si, 0, sizeof(si));
  474. memset(&caCerts, 0, sizeof(caCerts));
  475. if (! pTree || ! hEncodeRoot) {
  476. hr = TrapError(E_INVALIDARG);
  477. goto exit;
  478. }
  479. // Get the body we are suppose to be encoding
  480. CHECKHR(hr = pTree->BindToObject(hEncodeRoot, IID_IMimeBody, (void**)&pEncodeRoot));
  481. // We are going to set the state to don't encode this body
  482. // We we are called this should never be set to TRUE as we are getting explicity called.
  483. // If it is true, then ignore it.
  484. #ifdef DEBUG
  485. hr = pEncodeRoot->GetOption(OID_NOSECURITY_ONSAVE, &var);
  486. Assert((hr == S_OK) && (var.boolVal == FALSE));
  487. #endif // DEBUG
  488. var.boolVal = TRUE;
  489. CHECKHR(hr = pEncodeRoot->SetOption(OID_NOSECURITY_ONSAVE, &var));
  490. hr = OptionsToSMIMEINFO(TRUE, pTree, pEncodeRoot, &si);
  491. if (S_OK != hr) {
  492. goto exit;
  493. }
  494. if (MIME_S_SECURITY_NOOP == hr) {
  495. SMDOUT("Encode body called on plain set.");
  496. goto exit;
  497. }
  498. if (EBF_RECURSE & dwFlags) {
  499. if (MST_DESCENDENT_MASK & si.dwMsgEnhancement) {
  500. AssertSz(0, "nyi: recursion.");
  501. }
  502. }
  503. if (MIME_S_SECURITY_RECURSEONLY == hr) {
  504. hr = MIME_S_SECURITY_NOOP;
  505. SMDOUT("Encode body called on plain body.");
  506. goto exit;
  507. }
  508. fIgnoreSenderCertProbs = (SEF_ENCRYPTWITHNOSENDERCERT|SEF_SENDERSCERTPROVIDED) & dwFlags;
  509. psldLoop = si.psldLayers;
  510. while (psldLoop) {
  511. // Can only apply one of signing or encryption
  512. Assert(!!(psldLoop->m_dwMsgEnhancement & MST_THIS_SIGN) +
  513. !!(psldLoop->m_dwMsgEnhancement & MST_THIS_ENCRYPT) == 1);
  514. if (psldLoop->m_dwMsgEnhancement & MST_SIGN_MASK) {
  515. // 2nd attempt at finding a signing cert
  516. Assert(psldLoop->m_rgSigners != NULL);
  517. if (psldLoop->m_rgSigners[0].pccert == NULL) {
  518. CHECKHR(hr = HrGetNeededAddresses(IAT_FROM, pTree, &pAdrTable,
  519. &pAdrEnum));
  520. hr = HrGetCertificates(pAdrTable, pAdrEnum, ITT_SIGNING,
  521. fIgnoreSenderCertProbs, &caCerts);
  522. if (S_OK != hr) {
  523. hr = _HrConvertHrFromGetCertToEncode(hr, FALSE);
  524. Assert(FAILED(hr));
  525. goto exit;
  526. }
  527. Assert(caCerts.rgpCerts);
  528. Assert(1 == caCerts.cCerts);
  529. // need the sender's cert listed a second time
  530. if (caCerts.rgpCerts[0]) {
  531. psldLoop->m_rgSigners[0].pccert = DupCert(caCerts.rgpCerts[0]);
  532. }
  533. }
  534. }
  535. if (psldLoop->m_dwMsgEnhancement & MST_THIS_ENCRYPT) {
  536. Assert(! caCerts.rgpCerts);
  537. // 2nd place to look for encryption certs
  538. ReleaseObj(pAdrTable);
  539. ReleaseObj(pAdrEnum);
  540. // NOTE: Do NOT include IAT_REPLYTO in the needed addresses!
  541. #ifdef SMIME_V3
  542. if (psldLoop->m_rgRecipientInfo == NULL) {
  543. hr = E_FAIL;
  544. Assert(FAILED(hr));
  545. goto exit;
  546. }
  547. #else // !SMIME_V3
  548. if (psldLoop->m_rgEncryptItems == NULL) {
  549. hr = HrGetNeededAddresses(IAT_FROM | IAT_TO | IAT_CC | IAT_BCC | IAT_SENDER, pTree, &pAdrTable, &pAdrEnum);
  550. if (SUCCEEDED(hr)) {
  551. DWORD i;
  552. DWORD dexBogus; // the index into certResults of the NULL sender's cert
  553. hr = HrGetCertificates(pAdrTable, pAdrEnum, ITT_ENCRYPTION,
  554. fIgnoreSenderCertProbs, &caCerts);
  555. //
  556. // Outlook98 doesn't pass us an address table, all of the certs
  557. // are already in the SMIMEINFO struct. So if we're told that the
  558. // sender certs are provided, and we don't have any certificates
  559. // from the table, we just continue. We'll fail properly
  560. // in the zero certificate case down below.
  561. //
  562. if ((S_OK != hr) &&
  563. !((MIME_S_SECURITY_NOOP == hr) &&
  564. ((fIgnoreSenderCertProbs & SEF_SENDERSCERTPROVIDED) != 0))) {
  565. hr = _HrConvertHrFromGetCertToEncode(hr, TRUE);
  566. Assert(FAILED(hr));
  567. goto exit;
  568. }
  569. if (caCerts.cCerts == 0) {
  570. hr = TrapError(MIME_E_SECURITY_NOCERT);
  571. goto exit;
  572. }
  573. // just reference the certResults as the encryption array
  574. Assert(0 == psldLoop->m_cEncryptItems);
  575. if (!MemAlloc((LPVOID *) &psldLoop->m_rgEncryptItems,
  576. sizeof(EncryptItem))) {
  577. hr = E_OUTOFMEMORY;
  578. goto exit;
  579. }
  580. psldLoop->m_cEncryptItems = 1;
  581. psldLoop->m_rgEncryptItems[0].dwTagType = ENCRYPT_ITEM_TRANSPORT;
  582. psldLoop->m_rgEncryptItems[0].Transport.cCert = caCerts.cCerts;
  583. psldLoop->m_rgEncryptItems[0].Transport.rgpccert = caCerts.rgpCerts;
  584. psldLoop->m_rgEncryptItems[0].Transport.blobAlg.pBlobData = NULL;
  585. psldLoop->m_rgEncryptItems[0].Transport.blobAlg.cbSize = 0;
  586. caCerts.rgpCerts = NULL; // we're holding it in the layer now
  587. // Encryption algorithm
  588. if (SUCCEEDED(pEncodeRoot->GetOption(OID_SECURITY_ALG_BULK, &var)) &&
  589. (0 != var.blob.cbSize)) {
  590. Assert(VT_BLOB == var.vt);
  591. psldLoop->m_rgEncryptItems[0].Transport.blobAlg.pBlobData = var.blob.pBlobData;
  592. psldLoop->m_rgEncryptItems[0].Transport.blobAlg.cbSize = var.blob.cbSize;
  593. }
  594. }
  595. }
  596. else {
  597. if (!fIgnoreSenderCertProbs) {
  598. hr = TrapError(MIME_E_SECURITY_ENCRYPTNOSENDERCERT);
  599. goto exit;
  600. }
  601. }
  602. #endif // SMIME_V3
  603. } // encryption
  604. // Clean up cert array for next round
  605. if (caCerts.rgpCerts) {
  606. _FreeCertArray(caCerts.rgpCerts, caCerts.cCerts);
  607. caCerts.rgpCerts = NULL;
  608. }
  609. psldLoop = psldLoop->m_psldInner;
  610. }
  611. if (!(pvstmEncoded = new CVirtualStream)) {
  612. hr = TrapError(E_OUTOFMEMORY);
  613. goto exit;
  614. }
  615. if (FClearSign(si.dwMsgEnhancement)) {
  616. if (FEncrypt(si.dwMsgEnhancement)) {
  617. si.dwMsgEnhancement |= MST_BLOB_FLAG;
  618. CHECKHR(hr = HrEncodeOpaque(&si, pTree, hEncodeRoot, pEncodeRoot, pvstmEncoded, hwnd));
  619. }
  620. else {
  621. CHECKHR(hr = HrEncodeClearSigned(&si, pTree, hEncodeRoot, pEncodeRoot,
  622. pvstmEncoded, (dwFlags & EBF_COMMITIFDIRTY), hwnd));
  623. // Since this went multi-part, the root body changed on us and we need to get
  624. // it back
  625. pEncodeRoot->Release();
  626. CHECKHR(hr = pTree->BindToObject(hEncodeRoot, IID_IMimeBody,
  627. (void**)&pEncodeRoot));
  628. }
  629. }
  630. else {
  631. // encryption and/or signedData signature
  632. CHECKHR(hr = HrEncodeOpaque(&si, pTree, hEncodeRoot, pEncodeRoot, pvstmEncoded, hwnd));
  633. }
  634. CommonReturn:
  635. if (pEncodeRoot != NULL)
  636. {
  637. var.boolVal = FALSE;
  638. pEncodeRoot->SetOption(OID_NOSECURITY_ONSAVE, &var);
  639. }
  640. ReleaseObj(pAdrTable);
  641. ReleaseObj(pAdrEnum);
  642. ReleaseObj(pvstmEncoded);
  643. ReleaseObj(pEncodeRoot);
  644. FreeSMIMEINFO(&si);
  645. return hr;
  646. exit:
  647. // these objects are only need attention on error
  648. _FreeCertArray(caCerts.rgpCerts, caCerts.cCerts);
  649. goto CommonReturn;
  650. }
  651. /* HrEncodeClearSigned:
  652. **
  653. ** Purpose:
  654. ** Builds the multipart message needed for clear signing and
  655. ** retrieves the data stream to pass to the stream wrapepr.
  656. ** Takes:
  657. ** IN psi - needs the certificate array, signing
  658. ** certificate, etc.
  659. ** IN pTree - tree containing body to convert to m/s
  660. ** IN pEncodeRoot - body that will become 1st child of the m/s
  661. ** OUT lpstmOut - contains the signature bits (PKCS#7 nodata)
  662. ** Returns:
  663. ** hresult. no function-specific return values.
  664. */
  665. HRESULT CSMime::HrEncodeClearSigned(
  666. SMIMEINFO *const psi,
  667. IMimeMessageTree *const pTree,
  668. const HBODY hEncodeRoot,
  669. IMimeBody *const pEncodeRoot,
  670. LPSTREAM lpstmOut,
  671. BOOL fCommit,
  672. HWND hwnd)
  673. {
  674. HBODY hNew, hSignature, hData;
  675. HRESULT hr;
  676. HRESULT hr_smime = S_OK;
  677. DWORD i;
  678. IMimeBody * pSig = NULL;
  679. IMimeBody * pMS = NULL;
  680. IMimeBody * pData = NULL;
  681. IMimeBody * pRoot = NULL;
  682. IStream * pstmMsg = NULL;
  683. BODYOFFSETS boData;
  684. LARGE_INTEGER liPos;
  685. PROPVARIANT var;
  686. #ifdef DEBUG
  687. BLOB blobMsg = {NULL,0};
  688. #endif
  689. ULARGE_INTEGER uliCopy;
  690. ALG_ID aid;
  691. const char * lpszProtocol;
  692. CCAPIStm capistmMsg(lpstmOut);
  693. // We need lpstmOut because it is the media of transmission for
  694. // the signature. The sig body gets it through SetData
  695. Assert(psi && hEncodeRoot && pEncodeRoot && pTree && lpstmOut);
  696. CHECKHR(hr = pTree->ToMultipart(hEncodeRoot, STR_SUB_SIGNED, &hNew));
  697. if (fCommit) {
  698. BOOL fCleanup;
  699. // Need to commit the tree, but if Tonja cleans it, I'll lose my
  700. // multipart. So, turn off cleaning and save the value to set back.
  701. CHECKHR(hr = pTree->GetOption(OID_CLEANUP_TREE_ON_SAVE, &var));
  702. fCleanup = var.boolVal ? TRUE : FALSE;
  703. var.boolVal = FALSE;
  704. CHECKHR(hr = pTree->SetOption(OID_CLEANUP_TREE_ON_SAVE, &var));
  705. CHECKHR(hr = pTree->Commit(COMMIT_SMIMETRANSFERENCODE));
  706. var.boolVal = (VARIANT_BOOL) !!fCleanup;
  707. pTree->SetOption(OID_CLEANUP_TREE_ON_SAVE, &var);
  708. }
  709. CHECKHR(hr = pTree->GetBody(IBL_FIRST, hNew, &hData));
  710. CHECKHR(hr = pTree->BindToObject(hData, IID_IMimeBody, (LPVOID *)&pData));
  711. CHECKHR(hr = pData->GetOffsets(&boData));
  712. // BUG 38411: I need a clean pristine virginal-white stream
  713. // so we have to go straight to the horse's smelly mouth.
  714. CHECKHR(hr = pTree->GetMessageSource(&pstmMsg, 0));
  715. #if defined(DEBUG) && !defined(MAC)
  716. if (s_fDebugDumpWholeMsg) {
  717. hr = HrStreamToByte(pstmMsg, &blobMsg.pBlobData, &blobMsg.cbSize);
  718. HrRewindStream(pstmMsg);
  719. }
  720. #endif
  721. // Now slice out the part we actually want
  722. liPos.HighPart = 0;
  723. liPos.LowPart = boData.cbHeaderStart;
  724. CHECKHR(hr = pstmMsg->Seek(liPos, STREAM_SEEK_SET, NULL));
  725. CHECKHR(hr = capistmMsg.HrInitialize(0, hwnd, TRUE, psi, CSTM_DETACHED, NULL, psi->psldInner));
  726. if (SUCCEEDED(hr)) {
  727. IStream *pstmCapi;
  728. uliCopy.HighPart = 0;
  729. uliCopy.LowPart = boData.cbBodyEnd-boData.cbHeaderStart;
  730. capistmMsg.QueryInterface(IID_IStream, (void**)&pstmCapi);
  731. hr = pstmMsg->CopyTo(pstmCapi, uliCopy, NULL, NULL);
  732. pstmCapi->Release();
  733. CHECKHR(hr = capistmMsg.EndStreaming());
  734. }
  735. CHECKHR(hr = pTree->InsertBody(IBL_LAST, hNew, &hSignature));
  736. CHECKHR(hr = pTree->BindToObject(hSignature, IID_IMimeBody, (void**)&pSig));
  737. CHECKHR(hr = pSig->SetData(IET_BINARY, STR_CNT_APPLICATION,
  738. STR_SUB_XPKCS7SIG, IID_IStream, (void*)lpstmOut));
  739. if (-1 != psi->ietRequested) {
  740. var.vt = VT_UI4;
  741. var.ulVal = psi->ietRequested;
  742. pSig->SetOption(OID_TRANSMIT_BODY_ENCODING, &var);
  743. }
  744. // Set the properties for the signature blob as in S/MIGv2 3.3
  745. var.vt = VT_LPSTR;
  746. var.pszVal = (LPSTR)STR_DIS_ATTACHMENT;
  747. CHECKHR(hr = pSig->SetProp(PIDTOSTR(PID_HDR_CNTDISP), 0, &var));
  748. var.pszVal = (char *)s_szSMIMEP7s;
  749. pSig->SetProp(PIDTOSTR(PID_PAR_FILENAME), 0, &var);
  750. pSig->SetProp(PIDTOSTR(PID_PAR_NAME), 0, &var);
  751. // Set the parameters on the m/s root as in rfc1847 2.1
  752. CHECKHR(hr = pTree->BindToObject(hNew, IID_IMimeBody, (void**)&pMS));
  753. var.pszVal = (char *)STR_MIME_APPL_PKCS7SIG;
  754. CHECKHR(hr = pMS->SetProp(STR_PAR_PROTOCOL, 0, &var));
  755. // Get the HASH algorithm. Note that we should NOT get a multi-layer
  756. // message with Multipart/Signed so we should not have to worry about
  757. // what layer this is for.
  758. Assert(psi->psldLayers);
  759. Assert(psi->psldLayers->m_psldInner == NULL);
  760. Assert(psi->psldLayers->m_cSigners > 0);
  761. Assert(psi->psldLayers->m_rgSigners != NULL);
  762. if (psi->psldLayers->m_cSigners == 0) {
  763. hr = E_INVALIDARG;
  764. goto exit;
  765. }
  766. lpszProtocol = "unknown";
  767. // M00BUG -- should add these together and remove duplicates
  768. for (i=0; i<psi->psldLayers->m_cSigners; i++) {
  769. hr = MimeOleAlgNameFromSMimeCap(psi->psldLayers->m_rgSigners[i].blobHashAlg.pBlobData,
  770. psi->psldLayers->m_rgSigners[i].blobHashAlg.cbSize,
  771. &lpszProtocol);
  772. }
  773. var.pszVal = (LPSTR)lpszProtocol;
  774. CHECKHR(hr = pMS->SetProp(STR_PAR_MICALG, 0, &var));
  775. var.ulVal = 0;
  776. CHECKHR(hr = pTree->BindToObject(HBODY_ROOT, IID_IMimeBody, (void**)&pRoot));
  777. SideAssert(SUCCEEDED(pRoot->SetOption(OID_SECURITY_SIGNATURE_COUNT, &var)));
  778. SideAssert(SUCCEEDED(pRoot->SetOption(OID_SECURITY_TYPE, &var)));
  779. exit:
  780. #ifdef DEBUG
  781. if (blobMsg.pBlobData) {
  782. MemFree(blobMsg.pBlobData);
  783. }
  784. #endif
  785. ReleaseObj(pRoot);
  786. ReleaseObj(pSig);
  787. ReleaseObj(pData);
  788. ReleaseObj(pMS);
  789. ReleaseObj(pstmMsg);
  790. if (FAILED(hr) && hNew) {
  791. // need to undo the multipartization and delete the sig body
  792. // errors are not as important as the one that has already occured
  793. if (hSignature) {
  794. pTree->DeleteBody(hSignature, 0);
  795. }
  796. pTree->DeleteBody(hNew, DELETE_PROMOTE_CHILDREN);
  797. }
  798. if (S_OK != hr_smime && SUCCEEDED(hr)) {
  799. hr = hr_smime;
  800. }
  801. return hr;
  802. }
  803. /* HrEncodeOpaque:
  804. **
  805. ** Purpose:
  806. **
  807. ** Takes:
  808. ** IN psi - needs signing cert,
  809. ** certificate array (opt)
  810. ** IN pTree - the normal tree baggage
  811. ** IN hEncodeRoot - the tree likes handles
  812. ** IN pEncodeRoot - body to begin encoding at
  813. ** OUT lpstmOut - contains the PKCS#7 message
  814. */
  815. HRESULT CSMime::HrEncodeOpaque(
  816. SMIMEINFO *const psi,
  817. IMimeMessageTree * pTree,
  818. HBODY hEncodeRoot,
  819. IMimeBody * pEncodeRoot,
  820. LPSTREAM lpstmOut,
  821. HWND hwnd)
  822. {
  823. HRESULT hr;
  824. HRESULT hrCAPI = S_OK;
  825. CCAPIStm capistmMsg(lpstmOut);
  826. IMimePropertySet *pFullProp = NULL, *pBodyProp = NULL;
  827. hr = capistmMsg.HrInitialize(0, hwnd, TRUE, psi, 0, NULL, psi->psldInner);
  828. #ifdef INTEROP2
  829. //N8 This is one half of the fix to do headers correctly
  830. // In the inner, no 822 headers, just MIME
  831. // See another N8 comment for the other half, which is to
  832. // have the outer 822's merged with the inner's MIME headers
  833. // on decode
  834. if (SUCCEEDED(hr)) {
  835. hr = pEncodeRoot->BindToObject(IID_IMimePropertySet, (LPVOID *)&pBodyProp);
  836. }
  837. if (SUCCEEDED(hr)) {
  838. hr = pBodyProp->Clone(&pFullProp);
  839. }
  840. if (SUCCEEDED(hr)) {
  841. LPCSTR rgszHdrKeep[] = {
  842. PIDTOSTR(PID_HDR_CNTTYPE),
  843. PIDTOSTR(PID_HDR_CNTXFER),
  844. PIDTOSTR(PID_HDR_CNTID),
  845. PIDTOSTR(PID_HDR_CNTDESC),
  846. PIDTOSTR(PID_HDR_CNTDISP),
  847. PIDTOSTR(PID_HDR_CNTBASE),
  848. PIDTOSTR(PID_HDR_CNTLOC),
  849. };
  850. hr = pBodyProp->DeleteExcept(ARRAYSIZE(rgszHdrKeep), rgszHdrKeep);
  851. #endif
  852. if (SUCCEEDED(hr)) {
  853. IStream *pstmCapi;
  854. capistmMsg.QueryInterface(IID_IStream, (void**)&pstmCapi);
  855. hr = pTree->SaveBody(hEncodeRoot, 0, pstmCapi);
  856. #if defined(DEBUG) && !defined(MAC)
  857. if (s_fDebugDumpWholeMsg) {
  858. BYTE *pb;
  859. DWORD cb;
  860. if (SUCCEEDED(HrStreamToByte(lpstmOut, &pb, &cb))) {
  861. MemFree(pb);
  862. }
  863. }
  864. #endif
  865. pstmCapi->Release();
  866. hrCAPI = capistmMsg.EndStreaming();
  867. if (SUCCEEDED(hr)) { // hr from the SaveBody takes precedence
  868. hr = hrCAPI;
  869. }
  870. }
  871. #ifdef INTEROP2
  872. }
  873. #endif
  874. if (SUCCEEDED(hr)) {
  875. PROPVARIANT var;
  876. pTree->DeleteBody(hEncodeRoot, DELETE_CHILDREN_ONLY);
  877. pEncodeRoot->EmptyData();
  878. var.ulVal = 0;
  879. SideAssert(SUCCEEDED(pEncodeRoot->SetOption(OID_SECURITY_TYPE, &var)));
  880. SideAssert(SUCCEEDED(pEncodeRoot->SetOption(OID_SECURITY_SIGNATURE_COUNT, &var)));
  881. #ifdef INTEROP2
  882. // reset the propset
  883. pFullProp->CopyProps(0, NULL, pBodyProp);
  884. #endif
  885. //QPTEST DebugDumpStreamToFile(lpstmOut, "c:\\hexin.bin");
  886. hr = pEncodeRoot->SetData(IET_BINARY, STR_CNT_APPLICATION,
  887. STR_SUB_XPKCS7MIME, IID_IStream, (void*)lpstmOut);
  888. if (SUCCEEDED(hr)) {
  889. PROPVARIANT var;
  890. var.vt = VT_UI4;
  891. if (-1 != psi->ietRequested) {
  892. var.ulVal = psi->ietRequested;
  893. }
  894. else {
  895. var.ulVal = IET_BASE64;
  896. }
  897. pEncodeRoot->SetOption(OID_TRANSMIT_BODY_ENCODING, &var);
  898. // Set the properties for the opaque blob as in S/MIGv2 3.3
  899. var.vt = VT_LPSTR;
  900. var.pszVal = (LPSTR)STR_DIS_ATTACHMENT;
  901. pEncodeRoot->SetProp(PIDTOSTR(PID_HDR_CNTDISP), 0, &var);
  902. var.pszVal = (LPSTR)s_szSMIMEP7m;
  903. pEncodeRoot->SetProp(PIDTOSTR(PID_PAR_FILENAME), 0, &var);
  904. pEncodeRoot->SetProp(PIDTOSTR(PID_PAR_NAME), 0, &var);
  905. if (FEncrypt(psi->dwMsgEnhancement))
  906. {
  907. var.pszVal = (LPSTR) STR_SMT_ENVELOPEDDATA;
  908. }
  909. else
  910. {
  911. #ifdef SMIME_V3
  912. if ((psi->pszInnerContent != NULL) &&
  913. (strcmp(psi->pszInnerContent, szOID_SMIME_ContentType_Receipt) == 0))
  914. {
  915. var.pszVal = (LPSTR) STR_SMT_SIGNEDRECEIPT;
  916. }
  917. else
  918. {
  919. var.pszVal = (LPSTR) STR_SMT_SIGNEDDATA;
  920. }
  921. #else // !SMIME_V3
  922. var.pszVal = (LPSTR) STR_SMT_SIGNEDDATA;
  923. #endif // SMIME_V3
  924. }
  925. pEncodeRoot->SetProp(STR_PAR_SMIMETYPE, 0, &var);
  926. }
  927. }
  928. ReleaseObj(pFullProp);
  929. ReleaseObj(pBodyProp);
  930. return hr;
  931. }
  932. ///////////////////////////////////////////////////////////////////////////
  933. //
  934. // Decode methods
  935. //
  936. /* DecodeMessage:
  937. **
  938. ** Purpose:
  939. ** To rip the shroud of secrecy from a message, leaving it naked in the
  940. ** harsh light of dawning comprehension. However, this function hides
  941. ** the unsightly goings-on that accomplish this task, simply returning
  942. ** a radically different tree
  943. ** Takes:
  944. ** IN pTree - the message's tree
  945. ** IN dwFlags - expansion. must be 0
  946. ** Returns:
  947. ** a variety of good and bad responses
  948. */
  949. HRESULT CSMime::DecodeMessage(
  950. IMimeMessageTree *const pTree,
  951. DWORD dwFlags)
  952. {
  953. HRESULT hr;
  954. HBODY hRoot;
  955. HWND hwnd = NULL;
  956. IMimeBody * pDecodeRoot = NULL;
  957. PROPVARIANT var;
  958. if (!pTree || (dwFlags & ~SEF_MASK)) {
  959. return TrapError(E_INVALIDARG);
  960. }
  961. if (SUCCEEDED(hr = pTree->GetBody(IBL_ROOT, NULL, &hRoot))) {
  962. CHECKHR(hr = pTree->BindToObject(hRoot, IID_IMimeBody, (void**)&pDecodeRoot));
  963. #ifdef _WIN64
  964. if (SUCCEEDED(pDecodeRoot->GetOption(OID_SECURITY_HWND_OWNER_64, &var)) &&
  965. (NULL != (HWND)(var.pulVal)))
  966. {
  967. Assert(VT_UI8 == var.vt);
  968. hwnd = *(HWND *)(&(var.uhVal));
  969. }
  970. #else
  971. if (SUCCEEDED(pDecodeRoot->GetOption(OID_SECURITY_HWND_OWNER, &var)) &&
  972. (NULL != var.ulVal))
  973. {
  974. Assert(VT_UI4 == var.vt);
  975. hwnd = (HWND)var.ulVal;
  976. }
  977. #endif // _WIN64
  978. hr = TrapError(DecodeBody2(pTree, hRoot, dwFlags|EBF_RECURSE, NULL,
  979. hwnd, NULL));
  980. }
  981. exit:
  982. ReleaseObj(pDecodeRoot);
  983. return hr;
  984. }
  985. HRESULT CSMime::DecodeMessage2(IMimeMessageTree *const pTree, DWORD dwFlags,
  986. HWND hwnd, IMimeSecurityCallback * pCallback)
  987. {
  988. HRESULT hr;
  989. HBODY hRoot;
  990. if (!pTree || (dwFlags & ~SEF_MASK)) {
  991. return TrapError(E_INVALIDARG);
  992. }
  993. if (SUCCEEDED(hr = pTree->GetBody(IBL_ROOT, NULL, &hRoot))) {
  994. hr = TrapError(DecodeBody2(pTree, hRoot, dwFlags|EBF_RECURSE, NULL,
  995. hwnd, pCallback));
  996. }
  997. return hr;
  998. }
  999. /* DecodeBody:
  1000. **
  1001. ** Purpose:
  1002. ** Do the entirety of the S/MIME decode operation.
  1003. **
  1004. ** Takes:
  1005. ** IN pTree - the tree of the body to decode
  1006. ** IN hEncodeRoot - body from which to decode downward
  1007. ** IN dwFlags - set of DBF_ or SDF_
  1008. */
  1009. HRESULT CSMime::DecodeBody(
  1010. IMimeMessageTree *const pTree,
  1011. HBODY hDecodeRoot,
  1012. DWORD dwFlags)
  1013. {
  1014. return DecodeBody(pTree, hDecodeRoot, dwFlags, NULL);
  1015. }
  1016. /* DecodeBody:
  1017. **
  1018. ** Purpose:
  1019. ** The X-rated version of the released (interface) copy. This
  1020. ** one can tell if it has been recursed and merge the data.
  1021. **
  1022. ** Takes:
  1023. ** all the scenes of the original film plus:
  1024. ** IN psiOuterOp - SMIMEINFO from the outer operation
  1025. ** Note that this doesn't really mean
  1026. ** subbodys or messages, but nested S/MIME.
  1027. ** Simplest case is clearsigned in encryption.
  1028. */
  1029. HRESULT CSMime::DecodeBody(
  1030. IMimeMessageTree *const pTree,
  1031. HBODY hDecodeRoot,
  1032. DWORD dwFlags,
  1033. SMIMEINFO * psiOuterOp)
  1034. {
  1035. HRESULT hr;
  1036. HWND hwnd = NULL;
  1037. IMimeBody * pDecodeRoot = NULL;
  1038. PROPVARIANT var;
  1039. if (! pTree || ! hDecodeRoot) {
  1040. hr = TrapError(E_INVALIDARG);
  1041. goto exit;
  1042. }
  1043. // Get the body we are suppose to be encoding
  1044. CHECKHR(hr = pTree->BindToObject(hDecodeRoot, IID_IMimeBody, (void**)&pDecodeRoot));
  1045. #ifdef _WIN64
  1046. if (SUCCEEDED(pDecodeRoot->GetOption(OID_SECURITY_HWND_OWNER_64, &var)) && (NULL != (HWND)(var.pulVal))) {
  1047. Assert(VT_UI8 == var.vt);
  1048. hwnd = *(HWND *)(&(var.uhVal));
  1049. }
  1050. #else
  1051. if (SUCCEEDED(pDecodeRoot->GetOption(OID_SECURITY_HWND_OWNER, &var)) && (NULL != var.ulVal))
  1052. {
  1053. Assert(VT_UI4 == var.vt);
  1054. hwnd = (HWND)var.ulVal;
  1055. }
  1056. #endif // _WIN6
  1057. hr = DecodeBody2(pTree, hDecodeRoot, dwFlags, psiOuterOp, hwnd, NULL);
  1058. exit:
  1059. ReleaseObj(pDecodeRoot);
  1060. return hr;
  1061. }
  1062. HRESULT CSMime::DecodeBody2(
  1063. IMimeMessageTree *const pTree,
  1064. HBODY hDecodeRoot,
  1065. DWORD dwFlags,
  1066. SMIMEINFO * psiOuterOp,
  1067. HWND hwnd,
  1068. IMimeSecurityCallback * pCallback)
  1069. {
  1070. PROPVARIANT var;
  1071. IMimeBody * pData;
  1072. IMimeBody * pDecodeRoot = NULL;
  1073. HRESULT hr, hr_smime = S_OK;
  1074. HBODY hSignature, hData;
  1075. SMIMEINFO si;
  1076. CVirtualStream * pvstmDecoded = NULL;
  1077. IStream * pstmMsg = NULL;
  1078. if (!(pTree && hDecodeRoot)) {
  1079. hr = TrapError(E_INVALIDARG);
  1080. goto exit;
  1081. }
  1082. //
  1083. // Get the body we are going to decode
  1084. //
  1085. CHECKHR(hr = pTree->BindToObject(hDecodeRoot, IID_IMimeBody, (void**)&pDecodeRoot));
  1086. memset(&si, 0, sizeof(SMIMEINFO));
  1087. OptionsToSMIMEINFO(FALSE, pTree, pDecodeRoot, &si);
  1088. //
  1089. // If we know what crypt provider to use, then grab it
  1090. //
  1091. #ifndef _WIN64
  1092. if (SUCCEEDED(pDecodeRoot->GetOption(OID_SECURITY_HCRYPTPROV, &var)) &&
  1093. (NULL != var.ulVal))
  1094. {
  1095. Assert(VT_UI4 == var.vt);
  1096. si.hProv = var.ulVal;
  1097. }
  1098. #else // _WIN64
  1099. if (SUCCEEDED(pDecodeRoot->GetOption(OID_SECURITY_HCRYPTPROV_64, &var)) &&
  1100. (NULL != var.pulVal))
  1101. {
  1102. Assert(VT_UI8 == var.vt);
  1103. si.hProv = (HCRYPTPROV) var.pulVal;
  1104. }
  1105. #endif //_WIN64
  1106. //
  1107. // Determine if this is a multi-part signed message, if so then do the appropriate
  1108. // decoding. Determined by "content-type: multipart/signed; protocol=pkcs7-signature"
  1109. //
  1110. if (S_OK == pDecodeRoot->IsContentType(STR_CNT_MULTIPART, STR_SUB_SIGNED) &&
  1111. IsSMimeProtocol(pDecodeRoot)) {
  1112. CHECKHR(hr = pTree->GetBody(IBL_FIRST, hDecodeRoot, &hData));
  1113. CHECKHR(hr = pTree->GetBody(IBL_LAST, hDecodeRoot, &hSignature));
  1114. if FAILED(hr_smime = HrDecodeClearSigned(dwFlags, &si, pTree, hData,
  1115. hSignature, hwnd, pCallback)) {
  1116. goto exit;
  1117. }
  1118. // now we need to make the message readable. get rid of the signature
  1119. // blob. this will leave the m/s with one child, the message data.
  1120. // delete the parent with DELETE_PROMOTE_CHILDREN and this will
  1121. // kick the data body up as the only remaining body.
  1122. pTree->DeleteBody(hSignature, 0);
  1123. pTree->DeleteBody(hDecodeRoot, DELETE_PROMOTE_CHILDREN);
  1124. pTree->Commit(0);
  1125. }
  1126. //
  1127. // Determine if this is a blob signed or encrypted message. If it is then
  1128. // do the appropriate decoding.
  1129. //
  1130. else if (S_OK == pDecodeRoot->IsContentType(STR_CNT_APPLICATION, STR_SUB_XPKCS7MIME) ||
  1131. S_OK == pDecodeRoot->IsContentType(STR_CNT_APPLICATION, STR_SUB_PKCS7MIME)) {
  1132. //
  1133. // Create the stream to hold the decoded mime body
  1134. //
  1135. if (!(pvstmDecoded = new CVirtualStream)) {
  1136. hr = TrapError(E_OUTOFMEMORY);
  1137. goto exit;
  1138. }
  1139. //
  1140. // Do the actual decode of the message. This produces the decode stream in
  1141. // pvstmDecode.
  1142. //
  1143. if (FAILED(hr_smime = HrDecodeOpaque(dwFlags, &si, pDecodeRoot,
  1144. pvstmDecoded, hwnd, pCallback))) {
  1145. goto exit;
  1146. }
  1147. // Header bug fix:
  1148. // we need to blow away the subtree below this body
  1149. // however, we have to keep the 822 headers around. This option
  1150. // change does this, mostly. the EmptyData call removes
  1151. // some of the body's properties, most notably the content-*
  1152. // ones. when I use RELOAD_HEADER_REPLACE, the inner body
  1153. // will blow away any of the overlapping outer headers, but
  1154. // keep the ones that don't exist.
  1155. //
  1156. // Why did I do this?
  1157. // Deming doesn't put a from: line in the #7 signedData. We
  1158. // shoudln't either. Now we don't. Without this fix, this
  1159. // would prevent us from being able to add to WAB because
  1160. // the address table would be empty.
  1161. CHECKHR(hr = pTree->DeleteBody(hDecodeRoot, DELETE_CHILDREN_ONLY));
  1162. CHECKHR(hr = pDecodeRoot->EmptyData());
  1163. ULONG ulOldval;
  1164. pTree->GetOption(OID_HEADER_RELOAD_TYPE, &var);
  1165. Assert(VT_UI4 == var.vt);
  1166. ulOldval = var.ulVal;
  1167. var.ulVal = RELOAD_HEADER_REPLACE;
  1168. pTree->SetOption(OID_HEADER_RELOAD_TYPE, &var);
  1169. //
  1170. // Load the decoded message back into the message so that we can have the
  1171. // decrypted message.
  1172. //
  1173. CHECKHR(hr = pTree->Load(pvstmDecoded));
  1174. var.ulVal = ulOldval;
  1175. pTree->SetOption(OID_HEADER_RELOAD_TYPE, &var);
  1176. //
  1177. // Grab the root node -- this is where we are going to put the info relative
  1178. // to the decryption/decoding we just did.
  1179. //
  1180. CHECKHR(hr = pTree->GetBody(IBL_ROOT, NULL, &hData));
  1181. }
  1182. else {
  1183. hr = MIME_S_SECURITY_NOOP;
  1184. goto exit;
  1185. }
  1186. // now, this could be way cool and actually have another S/MIME part inside
  1187. // The most common case is a clear signed message inside of encryption, but
  1188. // others could occur.
  1189. // Recurse!
  1190. {
  1191. HBODY hRoot;
  1192. if (SUCCEEDED(hr = pTree->GetBody(IBL_ROOT, NULL, &hRoot))) {
  1193. hr = TrapError(DecodeBody2(pTree, hRoot, dwFlags|EBF_RECURSE, &si,
  1194. hwnd, pCallback));
  1195. }
  1196. CHECKHR(hr);
  1197. }
  1198. if (hr == MIME_S_SECURITY_NOOP) {
  1199. hr = S_OK;
  1200. }
  1201. else {
  1202. hData = HBODY_ROOT;
  1203. }
  1204. //
  1205. // If this is the root of the decode, then we move the decryption information back
  1206. // into the message we are dealing with. If this is not the root then merge together
  1207. // the S/MIME info structure from the caller.
  1208. //
  1209. if (psiOuterOp == NULL) {
  1210. hr = SMIMEINFOToOptions(pTree, &si, hData);
  1211. }
  1212. else {
  1213. hr = MergeSMIMEINFO(psiOuterOp, &si);
  1214. }
  1215. Assert(SUCCEEDED(hr));
  1216. exit:
  1217. ReleaseObj(pDecodeRoot);
  1218. ReleaseObj(pstmMsg);
  1219. ReleaseObj(pvstmDecoded);
  1220. FreeSMIMEINFO(&si);
  1221. if (S_OK != hr_smime && SUCCEEDED(hr)) {
  1222. hr = (MIME_E_SECURITY_NOOP == hr_smime) ? MIME_S_SECURITY_NOOP : hr_smime;
  1223. }
  1224. return TrapError(hr);
  1225. }
  1226. /* HrDecodeOpaque:
  1227. **
  1228. ** Purpose:
  1229. **
  1230. ** Takes:
  1231. **
  1232. **
  1233. */
  1234. HRESULT CSMime::HrDecodeOpaque(DWORD dwFlags,
  1235. SMIMEINFO *const psi,
  1236. IMimeBody *const pBody,
  1237. IStream *const pstmOut,
  1238. HWND hwnd,
  1239. IMimeSecurityCallback * pCallback)
  1240. {
  1241. HRESULT hr;
  1242. CCAPIStm capistmMsg(pstmOut);
  1243. hr = capistmMsg.HrInitialize(dwFlags, hwnd, FALSE, psi, 0, pCallback, NULL);
  1244. if (SUCCEEDED(hr)) {
  1245. IStream * pstmCapi;
  1246. HCRYPTMSG hMsg;
  1247. //QPTEST hr = pBody->GetDataHere(IET_BINARY, pstmOut);
  1248. //QPTEST DebugDumpStreamToFile(pstmOut, "c:\\stmout.bin");
  1249. //QPTEST HrRewindStream(pstmOut);
  1250. capistmMsg.QueryInterface(IID_IStream, (void**)&pstmCapi);
  1251. hr = pBody->GetDataHere(IET_BINARY, pstmCapi);
  1252. pstmCapi->Release();
  1253. if (FAILED(hr)) goto exit;
  1254. CHECKHR(hr = capistmMsg.EndStreaming());
  1255. #if defined(DEBUG) && !defined(MAC)
  1256. if (s_fDebugDumpWholeMsg) {
  1257. BYTE *pb;
  1258. DWORD cb;
  1259. if (SUCCEEDED(HrStreamToByte(pstmOut, &pb, &cb))) {
  1260. MemFree(pb);
  1261. }
  1262. }
  1263. #endif
  1264. hr = CAPISTMtoSMIMEINFO(&capistmMsg, psi);
  1265. }
  1266. exit:
  1267. return hr;
  1268. }
  1269. /* HrDecodeClearSigned:
  1270. **
  1271. ** Purpose:
  1272. ** Reform the signed body to be hashed and extract the signature
  1273. ** data. Pass these through to the interface stream method.
  1274. ** Takes:
  1275. ** IN dwFlags - Control Flags for the decode
  1276. ** IN OUT psi - passed to DecodeDetachedStream
  1277. ** IN pTree - tree to get message source from
  1278. ** IN hData - handle to body with signed data
  1279. ** IN hSig - handle to body with signature
  1280. ** Returns:
  1281. ** hresult. no function-specific return values.
  1282. */
  1283. HRESULT CSMime::HrDecodeClearSigned(DWORD dwFlags,
  1284. SMIMEINFO *const psi,
  1285. IMimeMessageTree *const pTree,
  1286. const HBODY hData,
  1287. const HBODY hSig,
  1288. HWND hwnd, IMimeSecurityCallback * pCallback)
  1289. {
  1290. HRESULT hr, hr_smime=S_OK;
  1291. IMimeBody *pData = NULL,
  1292. *pSig = NULL;
  1293. IStream *pstmSig,
  1294. *pstmMsg = NULL;
  1295. BODYOFFSETS boData;
  1296. LARGE_INTEGER liPos;
  1297. ULARGE_INTEGER uliToCopy;
  1298. CVirtualStream *pvstmDecoded = NULL;
  1299. CCAPIStm capistmMsg(NULL);
  1300. #ifdef DEBUG
  1301. BLOB blobMsg = {NULL,0};
  1302. #endif
  1303. CHECKHR(hr = pTree->BindToObject(hData, IID_IMimeBody, (void**)&pData));
  1304. CHECKHR(hr = pData->GetOffsets(&boData));
  1305. // BUG 38411: I need a clean pristine virginal-white stream
  1306. // so we have to go straight to the horse's smelly mouth.
  1307. CHECKHR(hr = pTree->GetMessageSource(&pstmMsg, 0));
  1308. #if defined(DEBUG) && !defined(MAC)
  1309. if (s_fDebugDumpWholeMsg) {
  1310. CHECKHR (hr = HrStreamToByte(pstmMsg, &blobMsg.pBlobData, &blobMsg.cbSize));
  1311. HrRewindStream(pstmMsg);
  1312. }
  1313. #endif
  1314. // Compute the portion we want of the mondo stream
  1315. liPos.HighPart = 0;
  1316. liPos.LowPart = boData.cbHeaderStart;
  1317. CHECKHR(hr = pstmMsg->Seek(liPos, STREAM_SEEK_SET, NULL));
  1318. hr = capistmMsg.HrInitialize(dwFlags, hwnd, FALSE, psi, CSTM_DETACHED, pCallback, NULL);
  1319. if (SUCCEEDED(hr)) {
  1320. IStream *pstmCapi;
  1321. capistmMsg.QueryInterface(IID_IStream, (void**)&pstmCapi);
  1322. // Get the signature data and feed it in
  1323. hr = pTree->BindToObject(hSig, IID_IMimeBody, (void**)&pSig);
  1324. if (SUCCEEDED(hr)) {
  1325. hr = pSig->GetDataHere(IET_BINARY, pstmCapi);
  1326. if (SUCCEEDED(hr)) {
  1327. hr = capistmMsg.EndStreaming();
  1328. }
  1329. }
  1330. uliToCopy.HighPart = 0;
  1331. uliToCopy.LowPart = boData.cbBodyEnd-boData.cbHeaderStart;
  1332. // Now feed in the actual data to hash
  1333. if (SUCCEEDED(hr)) {
  1334. hr = pstmMsg->CopyTo(pstmCapi, uliToCopy, NULL, NULL);
  1335. }
  1336. if (SUCCEEDED(hr)) {
  1337. hr = capistmMsg.EndStreaming();
  1338. }
  1339. if (SUCCEEDED(hr)) {
  1340. hr = CAPISTMtoSMIMEINFO(&capistmMsg, psi);
  1341. }
  1342. pstmCapi->Release();
  1343. }
  1344. exit:
  1345. ReleaseObj(pData);
  1346. ReleaseObj(pSig);
  1347. ReleaseObj(pstmMsg);
  1348. #ifdef DEBUG
  1349. if (blobMsg.pBlobData) {
  1350. MemFree(blobMsg.pBlobData);
  1351. }
  1352. #endif
  1353. if (S_OK != hr_smime && SUCCEEDED(hr)) {
  1354. hr = hr_smime;
  1355. }
  1356. return hr;
  1357. }
  1358. HRESULT CSMime::CAPISTMtoSMIMEINFO(CCAPIStm *pcapistm, SMIMEINFO *psi)
  1359. {
  1360. DWORD i;
  1361. PSECURITY_LAYER_DATA psldMessage = pcapistm->GetSecurityLayerData();
  1362. psi->dwMsgEnhancement = MST_NONE;
  1363. psi->ulMsgValidity = MSV_OK;
  1364. #ifdef DEBUG
  1365. {
  1366. DWORD dwLevel = 0;
  1367. PSECURITY_LAYER_DATA psldLoop;
  1368. psldLoop = psldMessage;
  1369. if (psldLoop) {
  1370. SMDOUT("Decode called on:");
  1371. }
  1372. else {
  1373. SMDOUT("Decode called but the message data is NULL.");
  1374. }
  1375. dwLevel = 0;
  1376. while (psldLoop) {
  1377. for (DWORD i = 0; i <= dwLevel; i++) {
  1378. DebugTrace(" ");
  1379. }
  1380. if (MST_BLOB_FLAG & psldLoop->m_dwMsgEnhancement) {
  1381. SMDOUT("CMSG_SIGNED");
  1382. }
  1383. else if ((MST_THIS_SIGN | MST_THIS_ENCRYPT) ==
  1384. ((MST_THIS_SIGN | MST_THIS_ENCRYPT) & psldLoop->m_dwMsgEnhancement)) {
  1385. SMDOUT("CMSG_SIGNED_AND_ENVELOPED, uhoh.");
  1386. }
  1387. else if (MST_THIS_SIGN & psldLoop->m_dwMsgEnhancement) {
  1388. SMDOUT("clear signed mail");
  1389. }
  1390. else if (MST_THIS_ENCRYPT & psldLoop->m_dwMsgEnhancement) {
  1391. SMDOUT("CMSG_ENVELOPED");
  1392. }
  1393. dwLevel++;
  1394. psldLoop = psldLoop->m_psldInner;
  1395. }
  1396. }
  1397. #endif
  1398. if (psldMessage) {
  1399. PSECURITY_LAYER_DATA psldLoop;
  1400. Assert(0 == psi->dwMsgEnhancement);
  1401. Assert(0 == psi->ulMsgValidity);
  1402. Assert(NULL == psi->psldLayers);
  1403. Assert(NULL == psi->psldEncrypt);
  1404. Assert(NULL == psi->psldInner);
  1405. psi->psldLayers = psldMessage;
  1406. psi->psldLayers->AddRef();
  1407. for (psldLoop = psldMessage; psldLoop != NULL;
  1408. psldLoop = psldLoop->m_psldInner) {
  1409. psi->dwMsgEnhancement |= psldLoop->m_dwMsgEnhancement;
  1410. psi->fCertWithMsg |= psldLoop->m_fCertInLayer;
  1411. if (MST_THIS_SIGN & psldLoop->m_dwMsgEnhancement) {
  1412. for (i=0; i<psldLoop->m_cSigners; i++) {
  1413. psi->ulMsgValidity |= psldLoop->m_rgSigners[i].ulValidity;
  1414. }
  1415. }
  1416. //
  1417. // We need to get the inner most encryption item here.
  1418. //
  1419. if (MST_THIS_ENCRYPT & psldLoop->m_dwMsgEnhancement) {
  1420. psi->ulMsgValidity |= psldLoop->m_ulDecValidity;
  1421. // Keep track of the innermost encryption layer for easy access
  1422. psi->psldEncrypt = psldLoop;
  1423. }
  1424. if (! psldLoop->m_psldInner) {
  1425. psi->psldInner = psldLoop;
  1426. }
  1427. }
  1428. CCAPIStm::FreeSecurityLayerData(psldMessage);
  1429. }
  1430. // need to handle this stuff again
  1431. //hr = MIME_E_SECURITY_CANTDECRYPT;
  1432. //case CMSG_SIGNED_AND_ENVELOPED:
  1433. //case CMSG_DATA:
  1434. //default:
  1435. //hr = MIME_E_SECURITY_UNKMSGTYPE;
  1436. return S_OK;
  1437. }
  1438. ///////////////////////////////////////////////////////////////////////////
  1439. //
  1440. // Crytographic transformations... functions that do the real work
  1441. //
  1442. ///////////////////////////////////////////////////////////////////////////
  1443. ///////////////////////////////////////////////////////////////////////////
  1444. //
  1445. // Signature verification and decryption
  1446. //
  1447. ///////////////////////////////////////////////////////////////////////////
  1448. //
  1449. // Other function sets
  1450. //
  1451. ///////////////////////////////////////////////////////////////////////////
  1452. ///////////////////////////////////////////////////////////////////////////
  1453. //
  1454. // Other certificate routines
  1455. //
  1456. /* GetCertificateName:
  1457. **
  1458. ** Purpose:
  1459. **
  1460. ** Takes:
  1461. ** IN pX509Cert - certificate from which to snarf name
  1462. ** IN cn - style of name to return (SIMPLE|OID|X500)
  1463. ** OUT ppszName - name gets stuffed here. Caller frees.
  1464. ** Returns:
  1465. ** hresult
  1466. */
  1467. STDMETHODIMP CSMime::GetCertificateName(
  1468. const PCX509CERT pX509Cert,
  1469. const CERTNAMETYPE cn,
  1470. LPSTR * ppszName)
  1471. {
  1472. DWORD flag, cch;
  1473. HRESULT hr;
  1474. CHECKSMIMEINIT
  1475. if (!(pX509Cert && ppszName)) {
  1476. hr = TrapError(E_INVALIDARG);
  1477. goto exit;
  1478. }
  1479. // convert to CAPI flag
  1480. switch (cn) {
  1481. case SIMPLE:
  1482. flag = CERT_SIMPLE_NAME_STR;
  1483. break;
  1484. case OID:
  1485. flag = CERT_OID_NAME_STR;
  1486. break;
  1487. case X500:
  1488. flag = CERT_X500_NAME_STR;
  1489. break;
  1490. default:
  1491. hr = TrapError(E_INVALIDARG);
  1492. goto exit;
  1493. }
  1494. #define pCert ((PCCERT_CONTEXT)pX509Cert)
  1495. cch = CertNameToStr(pCert->dwCertEncodingType, &pCert->pCertInfo->Subject,
  1496. flag, NULL, 0);
  1497. CHECKHR(hr = HrAlloc((void**)ppszName, cch*sizeof(TCHAR)));
  1498. CertNameToStr(pCert->dwCertEncodingType, &pCert->pCertInfo->Subject,
  1499. flag|CERT_NAME_STR_SEMICOLON_FLAG, *ppszName, cch);
  1500. #undef pCert
  1501. exit:
  1502. return hr;
  1503. }
  1504. /* HrGetCertsFromThumbprints:
  1505. **
  1506. ** Purpose:
  1507. ** This version of the function opens the "My" and "AddressBook" stores
  1508. ** and calls the exposed GetCertsFromThumbprints method.
  1509. **
  1510. */
  1511. HRESULT CSMime::HrGetCertsFromThumbprints(
  1512. THUMBBLOB *const rgThumbprint,
  1513. X509CERTRESULT *const pResults)
  1514. {
  1515. HRESULT hr = E_FAIL;
  1516. const DWORD cStores = 2;
  1517. HCERTSTORE rgCertStore[cStores];
  1518. rgCertStore[0] = OpenCachedMyStore();
  1519. if (rgCertStore[0]) {
  1520. rgCertStore[1] = OpenCachedAddressBookStore();
  1521. if (rgCertStore[1]) {
  1522. hr = MimeOleGetCertsFromThumbprints(rgThumbprint, pResults, rgCertStore, cStores);
  1523. CertCloseStore(rgCertStore[1], 0);
  1524. }
  1525. else {
  1526. // No WAB store, so there are NO matching certs
  1527. CRDOUT("No thumbprints in WAB");
  1528. for (ULONG iEntry = 0; iEntry < pResults->cEntries; iEntry++) {
  1529. pResults->rgpCert[iEntry] = NULL;
  1530. pResults->rgcs[iEntry] = CERTIFICATE_NOPRINT;
  1531. }
  1532. hr = MIME_S_SECURITY_ERROROCCURED;
  1533. }
  1534. CertCloseStore(rgCertStore[0], 0);
  1535. }
  1536. return hr;
  1537. }
  1538. /* EnumCertificates:
  1539. **
  1540. ** Purpose:
  1541. ** enumerate certificates from a store
  1542. ** Takes:
  1543. ** IN hc - store to query
  1544. ** IN dwUsage - ITT_* or 0
  1545. ** maps to a CAPI dwKeyUsage (AT_*)
  1546. ** IN pPrev - last certificate received from this function
  1547. ** (NULL to get first cert)
  1548. ** OUT pCert - certificate next in enumeration
  1549. ** Notes:
  1550. ** pPrev and pCert may reference the same variable
  1551. ** dwUsage may be 0 if caller just wants to check for existance of any certs
  1552. ** Returns:
  1553. ** CRYPT_E_NOT_FOUND if no more certs
  1554. ** S_FALSE if dwUsage is 0 and no certs exist
  1555. */
  1556. STDMETHODIMP CSMime::EnumCertificates(
  1557. HCAPICERTSTORE hc,
  1558. DWORD dwUsage,
  1559. PCX509CERT pPrev,
  1560. PCX509CERT * ppCert)
  1561. {
  1562. HRESULT hr;
  1563. PCCERT_CONTEXT pNewCert = NULL;
  1564. CHECKSMIMEINIT
  1565. if (!(hc && (ppCert || !dwUsage))) {
  1566. hr = TrapError(E_INVALIDARG);
  1567. goto exit;
  1568. }
  1569. if (ITT_SIGNING == dwUsage || ITT_ENCRYPTION == dwUsage) {
  1570. dwUsage = AT_KEYEXCHANGE;
  1571. hr = HrFindUsableCert((HCERTSTORE)hc, (BYTE)dwUsage, (PCCERT_CONTEXT)pPrev, &pNewCert);
  1572. }
  1573. else if (0 == dwUsage) {
  1574. pNewCert = CertEnumCertificatesInStore(hc, NULL);
  1575. if (pNewCert) {
  1576. hr = S_OK;
  1577. FreeCert(pNewCert);
  1578. }
  1579. else {
  1580. hr = S_FALSE;
  1581. }
  1582. }
  1583. else {
  1584. hr = TrapError(E_INVALIDARG);
  1585. }
  1586. exit:
  1587. if (ppCert) {
  1588. *ppCert = (PCX509CERT)pNewCert;
  1589. }
  1590. return hr;
  1591. }
  1592. /* HrGetLastError
  1593. **
  1594. ** Purpose:
  1595. ** Convert a GetLastError value to an HRESULT
  1596. ** A failure HRESULT must have the high bit set.
  1597. **
  1598. ** Takes:
  1599. ** none
  1600. **
  1601. ** Returns:
  1602. ** HRESULT
  1603. */
  1604. HRESULT HrGetLastError(void)
  1605. {
  1606. DWORD error;
  1607. HRESULT hr;
  1608. error = GetLastError();
  1609. if (!(error & 0x80000000)) {
  1610. hr = error | 0x80070000; // system error
  1611. } else {
  1612. hr = (HRESULT)error;
  1613. }
  1614. return(hr);
  1615. }
  1616. /* HrFindUsableCert:
  1617. **
  1618. ** Purpose:
  1619. ** Get a cert out of a cert store that has the right keyspec
  1620. ** Takes:
  1621. ** IN hCertStore - store to enumerate
  1622. ** IN dwKeySpec - AT_SIGNATURE or AT_KEYEXCHANGE
  1623. ** IN pPrevCert - last certificate received from this function
  1624. ** (NULL to get first cert)
  1625. ** OUT ppCert - the matching cert, NULL iff none
  1626. ** Returns:
  1627. ** SMIME_E_NOCERT if no cert can be found
  1628. */
  1629. HRESULT CSMime::HrFindUsableCert(
  1630. HCERTSTORE hCertStore,
  1631. BYTE dwKeySpec,
  1632. PCCERT_CONTEXT pPrevCert,
  1633. PCCERT_CONTEXT *ppCert)
  1634. {
  1635. PCCERT_CONTEXT pCert;
  1636. PCRYPT_KEY_PROV_INFO pKPI;
  1637. HRESULT hr = S_OK;
  1638. BOOL fFound = FALSE;
  1639. PCERT_NAME_INFO pNameInfo;
  1640. PCERT_RDN_ATTR pRDNAttr;
  1641. #ifdef DEBUG
  1642. DWORD count=0;
  1643. #endif
  1644. LPTSTR lpEmailAddress;
  1645. CHECKSMIMEINIT
  1646. Assert(hCertStore && ppCert);
  1647. Assert(AT_SIGNATURE == dwKeySpec || AT_KEYEXCHANGE == dwKeySpec);
  1648. *ppCert = NULL;
  1649. pKPI = NULL;
  1650. while (!fFound) {
  1651. pCert = CertEnumCertificatesInStore(hCertStore, pPrevCert);
  1652. if (pCert == NULL) { // no more certs?
  1653. break;
  1654. }
  1655. // Need to find the key provider
  1656. pKPI = (PCRYPT_KEY_PROV_INFO)PVGetCertificateParam(pCert, CERT_KEY_PROV_INFO_PROP_ID, NULL);
  1657. #ifdef DEBUG
  1658. count++;
  1659. // We want to be able to send broken mail so that the
  1660. // verify/decrypt fails.
  1661. if (s_fDebugEmitBroken) {
  1662. if (pKPI && pKPI->dwKeySpec != dwKeySpec) fFound = TRUE;
  1663. }
  1664. else {
  1665. if (pKPI && pKPI->dwKeySpec == dwKeySpec) fFound = TRUE;
  1666. }
  1667. #else
  1668. if (pKPI && pKPI->dwKeySpec == dwKeySpec) {
  1669. fFound = TRUE;
  1670. }
  1671. #endif
  1672. // Validate the email address
  1673. if (fFound && (lpEmailAddress = SzGetCertificateEmailAddress(pCert))) {
  1674. MemFree(lpEmailAddress);
  1675. }
  1676. else {
  1677. #ifdef DEBUG
  1678. {
  1679. SMDOUT("Certificate %d has no email address", count);
  1680. if (fFound && !s_fDebugAllowNoEmail) {
  1681. fFound = FALSE;
  1682. }
  1683. }
  1684. #else
  1685. fFound = FALSE;
  1686. #endif
  1687. }
  1688. if (pKPI) {
  1689. MemFree(pKPI);
  1690. pKPI = NULL;
  1691. }
  1692. pPrevCert = pCert; // next enumeration round
  1693. } // enum
  1694. if (pCert == NULL) {
  1695. CRDOUT("Couldn't find a signature cert having a key provider");
  1696. hr = HrGetLastError();
  1697. if (hr == CRYPT_E_NOT_FOUND) {
  1698. hr = S_FALSE;
  1699. }
  1700. else {
  1701. hr = MIME_E_SECURITY_NOCERT;
  1702. }
  1703. }
  1704. #ifdef DEBUG
  1705. else {
  1706. CRDOUT("Usable cert #%d found with keyspec==%d", count, dwKeySpec);
  1707. Assert(pCert);
  1708. if (s_fDebugShowFoundCert) {
  1709. DisplayCert(pCert);
  1710. }
  1711. }
  1712. #endif
  1713. *ppCert = pCert;
  1714. return TrapError(hr);
  1715. }
  1716. ///////////////////////////////////////////////////////////////////////////
  1717. //
  1718. // Other functions
  1719. //
  1720. ///////////////////////////////////////////////////////////////////////////
  1721. /* HrGetNeededAddresses:
  1722. **
  1723. ** Purpose:
  1724. ** get the maximum set of addresses needed for S/MIME to work
  1725. ** Takes:
  1726. ** IN dwTypes - class(es) of addresses to get
  1727. ** IN pTree - source of addresses
  1728. ** OUT ppEnum - enumerator for found addresses
  1729. */
  1730. HRESULT CSMime::HrGetNeededAddresses(
  1731. const DWORD dwTypes,
  1732. IMimeMessageTree * pTree,
  1733. IMimeAddressTable ** ppAdrTable,
  1734. IMimeEnumAddressTypes **ppEnum)
  1735. {
  1736. HRESULT hr;
  1737. Assert(ppEnum && ppAdrTable && pTree);
  1738. if (SUCCEEDED(hr = pTree->BindToObject(HBODY_ROOT, IID_IMimeAddressTable, (void**)ppAdrTable))) {
  1739. hr = (*ppAdrTable)->EnumTypes(dwTypes,
  1740. IAP_HANDLE | IAP_ADRTYPE | IAP_SIGNING_PRINT | IAP_ENCRYPTION_PRINT | IAP_CERTSTATE, ppEnum);
  1741. }
  1742. return hr;
  1743. }
  1744. /* HrGetThumbprints:
  1745. **
  1746. ** Purpose:
  1747. **
  1748. ** Takes:
  1749. ** IN pEnum - enumerator walked for source addresses
  1750. ** IN dwType - which SECURE-type certs are needed
  1751. ** OUT rgThumbprint - array of found thumbprints
  1752. ** Returns:
  1753. ** S_OK, unless a GetProp call fails
  1754. ** E_FAIL if the loop doesn't run for Count times
  1755. */
  1756. HRESULT CSMime::HrGetThumbprints(
  1757. IMimeEnumAddressTypes * pEnum,
  1758. const ITHUMBPRINTTYPE ittType,
  1759. THUMBBLOB *const rgThumbprint)
  1760. {
  1761. HRESULT hr = S_OK;
  1762. ADDRESSPROPS apEntry;
  1763. const ULONG numToGet = 1;
  1764. ULONG cPrints = 0;
  1765. Assert(pEnum && rgThumbprint);
  1766. Assert((ITT_SIGNING == ittType) || (ITT_ENCRYPTION == ittType));
  1767. Assert(!IsBadWritePtr(rgThumbprint, sizeof(THUMBBLOB)*cPrints));
  1768. pEnum->Reset();
  1769. while(S_OK == pEnum->Next(numToGet, &apEntry, NULL)) {
  1770. // if the print isn't found, we deal with that elsewhere
  1771. if (ITT_SIGNING == ittType) {
  1772. Assert((apEntry.tbSigning.pBlobData && apEntry.tbSigning.cbSize) ||
  1773. (!apEntry.tbSigning.pBlobData && !apEntry.tbSigning.cbSize));
  1774. if (apEntry.tbSigning.cbSize) {
  1775. // we need to null out the thumbprint flag so print doesn't get
  1776. // freed below
  1777. rgThumbprint[cPrints].pBlobData = apEntry.tbSigning.pBlobData;
  1778. rgThumbprint[cPrints].cbSize = apEntry.tbSigning.cbSize;
  1779. apEntry.dwProps &= ~IAP_SIGNING_PRINT;
  1780. }
  1781. }
  1782. else {
  1783. Assert(ITT_ENCRYPTION == ittType);
  1784. Assert((apEntry.tbEncryption.pBlobData && apEntry.tbEncryption.cbSize) ||
  1785. (!apEntry.tbEncryption.pBlobData && !apEntry.tbEncryption.cbSize));
  1786. if (apEntry.tbEncryption.cbSize) {
  1787. // we need to null out the thumbprint flag so print doesn't get
  1788. // freed below
  1789. rgThumbprint[cPrints].pBlobData = apEntry.tbEncryption.pBlobData;
  1790. rgThumbprint[cPrints].cbSize = apEntry.tbEncryption.cbSize;
  1791. apEntry.dwProps &= ~IAP_ENCRYPTION_PRINT;
  1792. }
  1793. }
  1794. cPrints++;
  1795. g_pMoleAlloc->FreeAddressProps(&apEntry);
  1796. }
  1797. return hr;
  1798. }
  1799. /* HrGetCertificates:
  1800. **
  1801. ** Purpose:
  1802. ** Get certificates based from thumbprints, then update the address
  1803. ** table based on the return of that operation
  1804. ** Takes:
  1805. ** IN pEnum - enumerator that provides the thumbprints
  1806. ** IN dwType - which certs are needed
  1807. ** IN fAlreadyHaveSendersCert - if the sender's cert is already found
  1808. ** OUT pResults - get an array of certs and the assoc certstates
  1809. ** pResults->cEntries has the size measured in entries
  1810. ** Returns:
  1811. ** SMIME_E_CERTERROR if not all certs were retrieved
  1812. */
  1813. HRESULT CSMime::HrGetCertificates(
  1814. IMimeAddressTable *const pAdrTable,
  1815. IMimeEnumAddressTypes * pEnum,
  1816. const DWORD dwType,
  1817. const BOOL fAlreadyHaveSendersCert,
  1818. CERTARRAY * pcaCerts)
  1819. {
  1820. HRESULT hr;
  1821. THUMBBLOB * rgThumbprint;
  1822. ULONG cCerts;
  1823. X509CERTRESULT certResults;
  1824. Assert(pAdrTable && pEnum && pcaCerts);
  1825. pcaCerts->rgpCerts = NULL;
  1826. pcaCerts->cCerts = 0;
  1827. pEnum->Count(&cCerts);
  1828. if (! cCerts) {
  1829. return MIME_S_SECURITY_NOOP;
  1830. }
  1831. if (! MemAlloc((void**)&rgThumbprint, sizeof(THUMBBLOB)*cCerts)) {
  1832. return E_OUTOFMEMORY;
  1833. }
  1834. memset(rgThumbprint, 0, sizeof(THUMBBLOB)*cCerts);
  1835. if (! MemAlloc((void**)&certResults.rgpCert, sizeof(PCX509CERT)*cCerts)) {
  1836. return E_OUTOFMEMORY;
  1837. }
  1838. memset(certResults.rgpCert, 0, sizeof(PCX509CERT)*cCerts);
  1839. if (! MemAlloc((void**)&certResults.rgcs, sizeof(CERTSTATE)*cCerts)) {
  1840. return E_OUTOFMEMORY;
  1841. }
  1842. memset(certResults.rgcs, 0, sizeof(CERTSTATE)*cCerts);
  1843. certResults.cEntries = cCerts;
  1844. HrGetThumbprints(pEnum, dwType, rgThumbprint);
  1845. hr = HrGetCertsFromThumbprints(rgThumbprint, &certResults);
  1846. if (SUCCEEDED(hr)) {
  1847. hr = HrGenerateCertsStatus(&certResults, pAdrTable, pEnum, fAlreadyHaveSendersCert);
  1848. if (SUCCEEDED(hr)) {
  1849. pcaCerts->cCerts = certResults.cEntries;
  1850. pcaCerts->rgpCerts = (PCCERT_CONTEXT*)certResults.rgpCert;
  1851. }
  1852. }
  1853. if (FAILED(hr)) {
  1854. _FreeCertArray((PCCERT_CONTEXT *)certResults.rgpCert, certResults.cEntries);
  1855. }
  1856. MemFree(certResults.rgcs);
  1857. if (rgThumbprint) {
  1858. for (DWORD i = 0; i < cCerts; i++) {
  1859. if (rgThumbprint[i].pBlobData) {
  1860. MemFree(rgThumbprint[i].pBlobData);
  1861. }
  1862. }
  1863. MemFree(rgThumbprint);
  1864. }
  1865. return hr;
  1866. }
  1867. /* HrGenerateCertsStatus:
  1868. **
  1869. ** Purpose:
  1870. ** No assumptions about the rghr in pResults, this function scans the
  1871. ** HRESULTs and sets the CERTSTATEs in pAdrTable (1:1 mapping) accordingly
  1872. ** Takes:
  1873. ** IN pResults - results to use for CERTSTATEs
  1874. ** IN pAdrTable - address table to set states on
  1875. ** IN pEnum - list of address handles
  1876. ** Returns:
  1877. **
  1878. */
  1879. HRESULT CSMime::HrGenerateCertsStatus(
  1880. X509CERTRESULT * pResults,
  1881. IMimeAddressTable *const pAdrTable,
  1882. IMimeEnumAddressTypes *const pEnum,
  1883. const BOOL fIgnoreSenderError)
  1884. {
  1885. ADDRESSPROPS apEntry;
  1886. ADDRESSPROPS apModify;
  1887. UINT i;
  1888. const ULONG numToGet = 1;
  1889. DWORD dexBogus = (DWORD)-1;
  1890. HRESULT hr = S_OK;
  1891. // Walk the entire Enumerator
  1892. i=0;
  1893. pEnum->Reset();
  1894. apModify.dwProps = IAP_CERTSTATE;
  1895. while(S_OK == pEnum->Next(numToGet, &apEntry, NULL)) {
  1896. Assert(apEntry.hAddress);
  1897. apModify.certstate = pResults->rgcs[i];
  1898. // Why was this added, you ask?
  1899. // if the client has set OID_SECURITY_CERT_INCLUDED then
  1900. // we need to not return spurious errors about the sender's
  1901. // certificate. if we didn't find it but were given it
  1902. // elsewhere, say things are cool.
  1903. // make sure to run through the whole array because the
  1904. // error MIME_S_SECURITY_CERTERROR is the most important
  1905. // since the sender cert one is really just a warning.
  1906. if (CERTIFICATE_OK != apModify.certstate) {
  1907. if (FMissingCert(apModify.certstate)) {
  1908. if (apEntry.dwAdrType == IAT_FROM) {
  1909. if (fIgnoreSenderError) {
  1910. apModify.certstate = CERTIFICATE_OK;
  1911. }
  1912. else {
  1913. // since this can be ignored with fIgnoreSenderError
  1914. // it should never override another warning
  1915. if (S_OK == hr) {
  1916. hr = MIME_S_SECURITY_NOSENDERCERT;
  1917. }
  1918. }
  1919. dexBogus = i;
  1920. }
  1921. else {
  1922. hr = MIME_S_SECURITY_NOCERT;
  1923. }
  1924. }
  1925. else {
  1926. hr = MIME_S_SECURITY_CERTERROR;
  1927. }
  1928. }
  1929. SideAssert(SUCCEEDED(pAdrTable->SetProps(apEntry.hAddress, &apModify)));
  1930. g_pMoleAlloc->FreeAddressProps(&apEntry);
  1931. i++;
  1932. }
  1933. if (i == pResults->cEntries) { // success
  1934. if ((DWORD)-1 != dexBogus) {
  1935. // we found the sender and the cert for this entry is NULL.
  1936. // CAPI doesn't like null certificates, so replace it
  1937. if (dexBogus != pResults->cEntries-1) {
  1938. // don't need to dupe b/c the end will no
  1939. // longer be included in the count
  1940. pResults->rgpCert[dexBogus] = pResults->rgpCert[pResults->cEntries-1];
  1941. }
  1942. --pResults->cEntries;
  1943. }
  1944. }
  1945. else {
  1946. hr = E_FAIL;
  1947. }
  1948. return hr;
  1949. }
  1950. ///////////////////////////////////////////////////////////////////////////
  1951. //
  1952. // CAPI wrappers
  1953. //
  1954. /* GetCertData:
  1955. **
  1956. ** Returns:
  1957. ** MIME_E_NOT_FOUND if the data is not in the cert
  1958. **
  1959. ** Note:
  1960. ** Currently only supports CDID_EMAIL
  1961. */
  1962. STDMETHODIMP CSMime::GetCertData(
  1963. const PCX509CERT pX509Cert,
  1964. const CERTDATAID dataid,
  1965. LPPROPVARIANT pValue)
  1966. {
  1967. #define pCert ((PCCERT_CONTEXT)pX509Cert)
  1968. PCERT_NAME_INFO pNameInfo = NULL;
  1969. PCERT_RDN_ATTR pRDNAttr;
  1970. HRESULT hr = MIME_E_NOT_FOUND;
  1971. LPSTR szOID;
  1972. CHECKSMIMEINIT
  1973. if (!(pX509Cert && pCert->pCertInfo) || dataid >= CDID_MAX) {
  1974. return TrapError(E_INVALIDARG);
  1975. }
  1976. switch (dataid) {
  1977. case CDID_EMAIL:
  1978. // Let msoert handle this request
  1979. if (pValue->pszVal = SzGetCertificateEmailAddress(pCert)) {
  1980. pValue->vt = VT_LPSTR;
  1981. hr = S_OK;
  1982. }
  1983. break;
  1984. // if you add any cases, rewrite the findRDN code below
  1985. // I assume IA5 and PhilH's NULL's at the end, leaving me
  1986. // a very clean copy
  1987. default:
  1988. hr = E_INVALIDARG;
  1989. goto exit;
  1990. }
  1991. exit:
  1992. return TrapError(hr);
  1993. #undef pCert
  1994. }
  1995. ///////////////////////////////////////////////////////////////////////////
  1996. //
  1997. // Static functions
  1998. //
  1999. ///////////////////////////////////////////////////////////////////////////
  2000. /***************************************************************************
  2001. Name : _HrConvertHrFromGetCertToEncode
  2002. Purpose :
  2003. Parameters: hr = input HRESULT
  2004. fEncrypt = TRUE if we are encrypting
  2005. Returns : HRESULT
  2006. Comment :
  2007. ***************************************************************************/
  2008. HRESULT _HrConvertHrFromGetCertToEncode(HRESULT hr, const BOOL fEncrypt)
  2009. {
  2010. if (MIME_S_SECURITY_NOSENDERCERT == hr)
  2011. if (fEncrypt) {
  2012. hr = MIME_E_SECURITY_ENCRYPTNOSENDERCERT;
  2013. }
  2014. else {
  2015. hr = MIME_E_SECURITY_NOSIGNINGCERT;
  2016. }
  2017. else if (MIME_S_SECURITY_CERTERROR == hr) {
  2018. hr = MIME_E_SECURITY_CERTERROR;
  2019. }
  2020. else if (MIME_S_SECURITY_NOCERT == hr) {
  2021. hr = MIME_E_SECURITY_NOCERT;
  2022. }
  2023. return hr;
  2024. }
  2025. /***************************************************************************
  2026. Name : _FreeCertArray
  2027. Purpose : Free an array of certs
  2028. Parameters: rgpCert = array of cert pointers
  2029. cCerts = number of certs in rgpCert
  2030. Returns : void
  2031. Comment :
  2032. ***************************************************************************/
  2033. void _FreeCertArray(PCCERT_CONTEXT *rgpCert, const UINT cCerts)
  2034. {
  2035. if (rgpCert) {
  2036. for (register DWORD i = 0; i < cCerts; i++) {
  2037. ReleaseCert(rgpCert[i]);
  2038. }
  2039. Assert(ALLOCED(rgpCert));
  2040. MemFree(rgpCert);
  2041. }
  2042. }
  2043. #ifdef DEBUG
  2044. ///////////////////////////////////////////////////////////////////////////
  2045. //
  2046. // Debugging functions
  2047. //
  2048. ///////////////////////////////////////////////////////////////////////////
  2049. /***************************************************************************
  2050. Name : DumpAlgorithms
  2051. Purpose : Debug dump of algorithms
  2052. Parameters: void
  2053. Returns : void
  2054. Comment :
  2055. ***************************************************************************/
  2056. void CSMime::DumpAlgorithms()
  2057. {
  2058. DWORD dwAlgCount;
  2059. char *ptr = NULL;
  2060. DWORD i;
  2061. ALG_ID aiAlgid;
  2062. DWORD dwBits;
  2063. DWORD dwNameLen;
  2064. char szName[100];
  2065. BYTE pbData[1000];
  2066. DWORD dwDataLen;
  2067. DWORD dwFlags;
  2068. CHAR *pszAlgType = NULL;
  2069. HCRYPTPROV hProv;
  2070. CryptAcquireContext(&hProv, NULL, NULL, 5, 0);
  2071. Assert(hProv);
  2072. for(i=0; ;i++) {
  2073. if (0==i) {
  2074. dwFlags = CRYPT_FIRST;
  2075. }
  2076. else {
  2077. dwFlags = 0;
  2078. }
  2079. dwDataLen = 1000;
  2080. if(!CryptGetProvParam(hProv, PP_ENUMALGS, pbData, &dwDataLen, 0)) {
  2081. if (ERROR_NO_MORE_ITEMS == GetLastError()) {
  2082. break;
  2083. }
  2084. else {
  2085. Assert(0);
  2086. }
  2087. }
  2088. ptr = (char *)pbData;
  2089. aiAlgid = *(ALG_ID *)ptr;
  2090. ptr += sizeof(ALG_ID);
  2091. dwBits = *(DWORD *)ptr;
  2092. ptr += sizeof(DWORD);
  2093. dwNameLen = *(DWORD *)ptr;
  2094. ptr += sizeof(DWORD);
  2095. StrCpyN(szName, ptr, (int)(min(dwNameLen, ARRAYSIZE(szName))));
  2096. switch(GET_ALG_CLASS(aiAlgid)) {
  2097. case ALG_CLASS_DATA_ENCRYPT:
  2098. pszAlgType = "Encrypt ";
  2099. break;
  2100. case ALG_CLASS_HASH:
  2101. pszAlgType = "Hash ";
  2102. break;
  2103. case ALG_CLASS_KEY_EXCHANGE:
  2104. pszAlgType = "Exchange ";
  2105. break;
  2106. case ALG_CLASS_SIGNATURE:
  2107. pszAlgType = "Signature";
  2108. break;
  2109. default:
  2110. pszAlgType = "Unknown ";
  2111. }
  2112. DOUTL(CRYPT_LEVEL, "Algid:%8.8xh, Bits:%-4d, Type:%s, NameLen:%-2d, Name:%s\n",
  2113. aiAlgid, dwBits, pszAlgType, dwNameLen, szName);
  2114. }
  2115. CryptReleaseContext(hProv, 0);
  2116. return;
  2117. }
  2118. #endif // debug
  2119. BOOL FSameAgreeParameters(CMS_RECIPIENT_INFO * pRecipInfo1,
  2120. CMS_RECIPIENT_INFO * pRecipInfo2)
  2121. {
  2122. if (pRecipInfo1->dwU1 != pRecipInfo2->dwU1) return FALSE;
  2123. if (pRecipInfo1->dwU1 == CMS_RECIPIENT_INFO_PUBKEY_EPHEMERAL_KEYAGREE) {
  2124. if ((lstrcmp(pRecipInfo1->u1.u3.EphemeralAlgorithm.pszObjId,
  2125. pRecipInfo2->u1.u3.EphemeralAlgorithm.pszObjId) != 0) ||
  2126. (pRecipInfo1->u1.u3.EphemeralAlgorithm.Parameters.cbData !=
  2127. pRecipInfo2->u1.u3.EphemeralAlgorithm.Parameters.cbData) ||
  2128. (memcmp(pRecipInfo1->u1.u3.EphemeralAlgorithm.Parameters.pbData,
  2129. pRecipInfo2->u1.u3.EphemeralAlgorithm.Parameters.pbData,
  2130. pRecipInfo1->u1.u3.EphemeralAlgorithm.Parameters.cbData) != 0)){
  2131. return FALSE;
  2132. }
  2133. if ((pRecipInfo1->u1.u3.UserKeyingMaterial.cbData !=
  2134. pRecipInfo2->u1.u3.UserKeyingMaterial.cbData) ||
  2135. (memcmp(pRecipInfo1->u1.u3.UserKeyingMaterial.pbData,
  2136. pRecipInfo2->u1.u3.UserKeyingMaterial.pbData,
  2137. pRecipInfo1->u1.u3.UserKeyingMaterial.cbData) != 0)) {
  2138. return FALSE;
  2139. }
  2140. }
  2141. else if (pRecipInfo1->dwU1 == CMS_RECIPIENT_INFO_PUBKEY_STATIC_KEYAGREE) {
  2142. //
  2143. // We don't bother checking the sender cert id. I don't know of
  2144. // any reason why the same key would be encoded with different
  2145. // identifiers (issuer and serial vs subject key id)
  2146. //
  2147. if (pRecipInfo1->u1.u4.hprov != pRecipInfo2->u1.u4.hprov) return FALSE;
  2148. if (pRecipInfo1->u1.u4.dwKeySpec != pRecipInfo2->u1.u4.dwKeySpec) {
  2149. return FALSE;
  2150. }
  2151. if ((pRecipInfo1->u1.u3.UserKeyingMaterial.cbData !=
  2152. pRecipInfo2->u1.u3.UserKeyingMaterial.cbData) ||
  2153. (memcmp(pRecipInfo1->u1.u3.UserKeyingMaterial.pbData,
  2154. pRecipInfo2->u1.u3.UserKeyingMaterial.pbData,
  2155. pRecipInfo1->u1.u3.UserKeyingMaterial.cbData) != 0)) {
  2156. return FALSE;
  2157. }
  2158. }
  2159. else return FALSE;
  2160. return TRUE;
  2161. }
  2162. HRESULT ConvertEncryptionLayer(IMimeBody * pBody, IMimeSecurity2 * psm, SMIMEINFO * psi)
  2163. {
  2164. DWORD cAgree;
  2165. DWORD cRecipients;
  2166. HRESULT hr;
  2167. DWORD i;
  2168. DWORD i2;
  2169. DWORD iAgree;
  2170. DWORD iRecip;
  2171. CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO * pAgree = NULL;
  2172. CRYPT_ATTRIBUTE * pattr = NULL;
  2173. CMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO * pMailList = NULL;
  2174. PSECURITY_LAYER_DATA psld = NULL;
  2175. CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO * pTrans = NULL;
  2176. CMS_RECIPIENT_INFO * rgRecipInfo = NULL;
  2177. PROPVARIANT var;
  2178. PropVariantInit(&var);
  2179. //
  2180. // Create a layer to hold the encryption information
  2181. //
  2182. if (! (psld = new CSECURITY_LAYER_DATA)) {
  2183. hr = E_OUTOFMEMORY;
  2184. goto exit;
  2185. }
  2186. // Link together the different layers
  2187. if (psi->psldLayers == NULL) {
  2188. psi->psldLayers = psld;
  2189. }
  2190. psld->m_psldOuter = psi->psldInner;
  2191. if (psld->m_psldOuter != NULL) {
  2192. psld->m_psldOuter->m_psldInner = psld;
  2193. }
  2194. psi->psldInner = psld;
  2195. //
  2196. // Encryption layers must be blobed -- so or it in.
  2197. //
  2198. psi->dwMsgEnhancement |= MST_BLOB_FLAG;
  2199. psld->m_dwMsgEnhancement = psi->dwMsgEnhancement &
  2200. (MST_ENCRYPT_MASK | MST_BLOB_FLAG);
  2201. //
  2202. // The encryption algorithm may not be encoded the way we need it
  2203. // to be. The call will re-encode correctly for CMS.
  2204. //
  2205. // If we are encrypting, it is an error to not have an encryption
  2206. // algorithm.
  2207. //
  2208. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_ALG_BULK, &var)) &&
  2209. (0 != var.blob.cbSize)) {
  2210. Assert(VT_BLOB == var.vt);
  2211. hr = HrBuildContentEncryptionAlg(psld, &var.blob);
  2212. if (hr != S_OK) {
  2213. Assert(FALSE);
  2214. // goto exit;
  2215. }
  2216. }
  2217. else {
  2218. hr = E_INVALIDARG;
  2219. goto exit;
  2220. }
  2221. //
  2222. // The call may have provided a specific certificate to be used
  2223. // in decrypting the message. This functionality is now obsolete but
  2224. // still supported. If no certificate is provided then we will search
  2225. // for a valid decryption key.
  2226. //
  2227. PropVariantClear(&var);
  2228. #ifdef _WIN64
  2229. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_DECRYPTION_64, &var)) &&
  2230. (NULL != (PCCERT_CONTEXT *) var.pulVal))
  2231. {
  2232. Assert(VT_UI8 == var.vt);
  2233. // don't need to dupe the cert, been done in GetOption
  2234. psld->m_pccertDecrypt = (PCCERT_CONTEXT) var.pulVal;
  2235. #else // !_WIN64
  2236. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_DECRYPTION, &var)) &&
  2237. (NULL != (PCCERT_CONTEXT *) var.ulVal))
  2238. {
  2239. Assert(VT_UI4 == var.vt);
  2240. // don't need to dupe the cert, been done in GetOption
  2241. psld->m_pccertDecrypt = (PCCERT_CONTEXT) var.ulVal;
  2242. #endif // _WIN64
  2243. // Included a cert in this layer
  2244. psld->m_fCertInLayer = TRUE;
  2245. }
  2246. //
  2247. // Allocate the space to hold the Encryption structures we are going
  2248. // to pass into the CMS structures.
  2249. //
  2250. CHECKHR(hr = psm->GetRecipientCount(0, &cRecipients));
  2251. if (cRecipients == 0) {
  2252. hr = MIME_E_SECURITY_ENCRYPTNOSENDERCERT;
  2253. goto exit;
  2254. }
  2255. if (!MemAlloc((LPVOID *) &psld->m_rgRecipientInfo,
  2256. cRecipients * sizeof(CMSG_RECIPIENT_ENCODE_INFO))) {
  2257. hr = E_OUTOFMEMORY;
  2258. goto exit;
  2259. }
  2260. memset(psld->m_rgRecipientInfo, 0,
  2261. cRecipients*sizeof(CMSG_RECIPIENT_ENCODE_INFO));
  2262. //
  2263. // Allocate the space to hold the values we currently are holding
  2264. //
  2265. if (!MemAlloc((LPVOID *) &rgRecipInfo,
  2266. cRecipients * sizeof(rgRecipInfo[0]))) {
  2267. hr = E_OUTOFMEMORY;
  2268. goto exit;
  2269. }
  2270. memset(rgRecipInfo, 0, cRecipients*sizeof(rgRecipInfo[0]));
  2271. CHECKHR(hr = psm->GetRecipient(0, 0, cRecipients, rgRecipInfo));
  2272. //
  2273. // Walk through and process all of the recipients by copying data
  2274. // from the current structure into the CMS version of the structure.
  2275. //
  2276. // Note that we do no free any of the data allocated in the GetRecipient
  2277. // call. The data will be freed as part of freeing the CMS data
  2278. // structure instead. Ownership of all data is transfered.
  2279. //
  2280. for (i=0, iRecip = 0; i<cRecipients; i++) {
  2281. switch (rgRecipInfo[i].dwRecipientType) {
  2282. //
  2283. // If this is set then we must have already processed this item
  2284. //
  2285. case CMS_RECIPIENT_INFO_TYPE_UNKNOWN:
  2286. break;
  2287. //
  2288. // Key Transport items copy over one-for-one.
  2289. //
  2290. case CMS_RECIPIENT_INFO_TYPE_KEYTRANS:
  2291. // try and allocate the object to hold the data.
  2292. if (!MemAlloc((LPVOID *) &pTrans, sizeof (*pTrans))) {
  2293. hr = E_OUTOFMEMORY;
  2294. goto exit;
  2295. }
  2296. memset(pTrans, 0, sizeof(*pTrans));
  2297. //
  2298. // Copy the data over from the old to the new structure.
  2299. // Ownership of all data is transfered here.
  2300. //
  2301. pTrans->cbSize = sizeof(*pTrans);
  2302. pTrans->KeyEncryptionAlgorithm = rgRecipInfo[i].KeyEncryptionAlgorithm;
  2303. pTrans->pvKeyEncryptionAuxInfo = rgRecipInfo[i].pvKeyEncryptionAuxInfo;
  2304. Assert(rgRecipInfo[i].dwU1 == CMS_RECIPIENT_INFO_PUBKEY_KEYTRANS);
  2305. pTrans->RecipientPublicKey = rgRecipInfo[i].u1.SubjectPublicKey;
  2306. Assert((rgRecipInfo[i].dwU3 == CMS_RECIPIENT_INFO_KEYID_KEY_ID) ||
  2307. (rgRecipInfo[i].dwU3 == CMS_RECIPIENT_INFO_KEYID_ISSUERSERIAL));
  2308. if (rgRecipInfo[i].dwU3 == CMS_RECIPIENT_INFO_KEYID_KEY_ID) {
  2309. pTrans->RecipientId.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
  2310. pTrans->RecipientId.KeyId = rgRecipInfo[i].u3.KeyId;
  2311. }
  2312. else if (rgRecipInfo[i].dwU3 == CMS_RECIPIENT_INFO_KEYID_ISSUERSERIAL) {
  2313. pTrans->RecipientId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
  2314. pTrans->RecipientId.IssuerSerialNumber = rgRecipInfo[i].u3.IssuerSerial;
  2315. }
  2316. else {
  2317. hr = E_INVALIDARG;
  2318. goto exit;
  2319. }
  2320. //
  2321. // The copy has been sucessful so point to the new data.
  2322. //
  2323. psld->m_rgRecipientInfo[iRecip].dwRecipientChoice = CMSG_KEY_TRANS_RECIPIENT;
  2324. psld->m_rgRecipientInfo[iRecip].pKeyTrans = pTrans;
  2325. pTrans = NULL;
  2326. iRecip += 1;
  2327. if(rgRecipInfo[i].pccert)
  2328. CertFreeCertificateContext(rgRecipInfo[i].pccert);
  2329. break;
  2330. //
  2331. // Mail List items can also just be copied over from the source
  2332. // to the destination structures
  2333. //
  2334. case CMS_RECIPIENT_INFO_TYPE_MAIL_LIST:
  2335. // Allocate the CMS structure to hold this data
  2336. if (!MemAlloc((LPVOID *) &pMailList, sizeof(*pMailList))) {
  2337. hr = E_OUTOFMEMORY;
  2338. goto exit;
  2339. }
  2340. memset(pMailList, 0, sizeof(*pMailList));
  2341. //
  2342. // Copy the data over from the old to the new structure.
  2343. // Ownership of all data is transfered here.
  2344. //
  2345. pMailList->cbSize = sizeof(*pMailList);
  2346. pMailList->KeyEncryptionAlgorithm = rgRecipInfo[i].KeyEncryptionAlgorithm;
  2347. pMailList->pvKeyEncryptionAuxInfo = rgRecipInfo[i].pvKeyEncryptionAuxInfo;
  2348. Assert(rgRecipInfo[i].dwU1 == CMS_RECIPIENT_INFO_PUBKEY_PROVIDER);
  2349. pMailList->hCryptProv = rgRecipInfo[i].u1.u2.hprov;
  2350. pMailList->dwKeyChoice = CMSG_MAIL_LIST_HANDLE_KEY_CHOICE;
  2351. pMailList->hKeyEncryptionKey = rgRecipInfo[i].u1.u2.hkey;
  2352. Assert(rgRecipInfo[i].dwU3 == CMS_RECIPIENT_INFO_KEYID_KEY_ID);
  2353. pMailList->KeyId = rgRecipInfo[i].u3.KeyId;
  2354. pMailList->Date = rgRecipInfo[i].filetime;
  2355. pMailList->pOtherAttr = rgRecipInfo[i].pOtherAttr;
  2356. //
  2357. // Copy is successful so point to the data
  2358. //
  2359. psld->m_rgRecipientInfo[iRecip].dwRecipientChoice = CMSG_MAIL_LIST_RECIPIENT;
  2360. psld->m_rgRecipientInfo[iRecip].pMailList = pMailList;
  2361. iRecip += 1;
  2362. pMailList = NULL;
  2363. break;
  2364. //
  2365. // We need to do some magic with key agree structures.
  2366. // Specifically we want to do the following:
  2367. // - Combine together all key agrees with the same parameters
  2368. // into a single record to pass into the CMS code.
  2369. // -
  2370. case CMS_RECIPIENT_INFO_TYPE_KEYAGREE:
  2371. // allocate the CMS structure to hold this data
  2372. if (!MemAlloc((LPVOID *) &pAgree, sizeof(*pAgree))) {
  2373. hr = E_OUTOFMEMORY;
  2374. goto exit;
  2375. }
  2376. memset(pAgree, 0, sizeof(*pAgree));
  2377. //
  2378. // Start by setting up the common parameters used by all of the
  2379. // recipients in the common key set.
  2380. // Setup the key agreement parameters for encoding and
  2381. // so forth.
  2382. pAgree->cbSize = sizeof(*pAgree);
  2383. // Key Encryption Algorithm -
  2384. pAgree->KeyEncryptionAlgorithm = rgRecipInfo[i].KeyEncryptionAlgorithm;
  2385. pAgree->pvKeyEncryptionAuxInfo = rgRecipInfo[i].pvKeyEncryptionAuxInfo;
  2386. // Key Wrap Algorithm - Derive from the content algorithm
  2387. // if not already known.
  2388. if (rgRecipInfo[i].KeyWrapAlgorithm.pszObjId != NULL) {
  2389. pAgree->KeyWrapAlgorithm = rgRecipInfo[i].KeyWrapAlgorithm;
  2390. pAgree->pvKeyWrapAuxInfo = rgRecipInfo[i].pvKeyWrapAuxInfo;
  2391. }
  2392. else {
  2393. hr = HrDeriveKeyWrapAlg(psld, pAgree);
  2394. if (FAILED(hr)) {
  2395. goto exit;
  2396. }
  2397. }
  2398. // Items which are specificly located accroding to static or
  2399. // ephemeral key agreement.
  2400. if (rgRecipInfo[i].dwU1 == CMS_RECIPIENT_INFO_PUBKEY_EPHEMERAL_KEYAGREE) {
  2401. pAgree->UserKeyingMaterial = rgRecipInfo[i].u1.u3.UserKeyingMaterial;
  2402. if (!MemAlloc((LPVOID *) &pAgree->pEphemeralAlgorithm,
  2403. sizeof(CRYPT_ALGORITHM_IDENTIFIER))) {
  2404. hr = E_OUTOFMEMORY;
  2405. goto exit;
  2406. }
  2407. memset(pAgree->pEphemeralAlgorithm, 0,
  2408. sizeof(CRYPT_ALGORITHM_IDENTIFIER));
  2409. pAgree->dwKeyChoice = CMSG_KEY_AGREE_EPHEMERAL_KEY_CHOICE;
  2410. memcpy(pAgree->pEphemeralAlgorithm,
  2411. &rgRecipInfo[i].u1.u3.EphemeralAlgorithm,
  2412. sizeof(CRYPT_ALGORITHM_IDENTIFIER));
  2413. }
  2414. else {
  2415. Assert(rgRecipInfo[i].dwU1 == CMS_RECIPIENT_INFO_PUBKEY_STATIC_KEYAGREE);
  2416. pAgree->dwKeyChoice = CMSG_KEY_AGREE_STATIC_KEY_CHOICE;
  2417. pAgree->UserKeyingMaterial = rgRecipInfo[i].u1.u4.UserKeyingMaterial;
  2418. if (!MemAlloc((LPVOID *) &pAgree->pSenderId, sizeof(CERT_ID))) {
  2419. hr = E_OUTOFMEMORY;
  2420. goto exit;
  2421. }
  2422. memcpy(pAgree->pSenderId, &rgRecipInfo[i].u1.u4.senderCertId,
  2423. sizeof(CERT_ID));
  2424. pAgree->hCryptProv = rgRecipInfo[i].u1.u4.hprov;
  2425. pAgree->dwKeySpec = rgRecipInfo[i].u1.u4.dwKeySpec;
  2426. }
  2427. //
  2428. // We need to count of common items
  2429. //
  2430. for (i2=i+1, cAgree = 1; i2<cRecipients; i2++) {
  2431. cAgree += FSameAgreeParameters(&rgRecipInfo[i],
  2432. &rgRecipInfo[i2]);
  2433. }
  2434. //
  2435. //
  2436. //
  2437. // Allocate space to hold the set of common key agree recipients
  2438. //
  2439. if (!MemAlloc((LPVOID *) &pAgree->rgpRecipientEncryptedKeys,
  2440. cAgree * sizeof(LPVOID))) {
  2441. hr = E_OUTOFMEMORY;
  2442. goto exit;
  2443. }
  2444. pAgree->cRecipientEncryptedKeys = cAgree;
  2445. memset(pAgree->rgpRecipientEncryptedKeys, 0, cAgree * sizeof(LPVOID));
  2446. for (i2=i, iAgree = 0; i2<cRecipients; i2++) {
  2447. if ((i2 != i) && !FSameAgreeParameters(&rgRecipInfo[i],
  2448. &rgRecipInfo[i2])) {
  2449. continue;
  2450. }
  2451. if (!MemAlloc((LPVOID *) &pAgree->rgpRecipientEncryptedKeys[iAgree],
  2452. sizeof(CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO))) {
  2453. hr = E_OUTOFMEMORY;
  2454. goto exit;
  2455. }
  2456. memset(pAgree->rgpRecipientEncryptedKeys[iAgree], 0,
  2457. sizeof(CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO));
  2458. pAgree->rgpRecipientEncryptedKeys[iAgree]->cbSize = sizeof(CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO);
  2459. //
  2460. // Get the recipients Public Key value
  2461. //
  2462. if (rgRecipInfo[i2].dwU1 == CMS_RECIPIENT_INFO_PUBKEY_EPHEMERAL_KEYAGREE) {
  2463. pAgree->rgpRecipientEncryptedKeys[iAgree]->RecipientPublicKey = rgRecipInfo[i2].u1.u3.SubjectPublicKey;
  2464. }
  2465. else {
  2466. Assert(rgRecipInfo[i2].dwU1 == CMS_RECIPIENT_INFO_PUBKEY_STATIC_KEYAGREE);
  2467. pAgree->rgpRecipientEncryptedKeys[iAgree]->RecipientPublicKey = rgRecipInfo[i2].u1.u4.SubjectPublicKey;
  2468. }
  2469. //
  2470. // Get the recipients certificate ID
  2471. //
  2472. Assert((rgRecipInfo[i2].dwU3 == CMS_RECIPIENT_INFO_KEYID_KEY_ID) ||
  2473. (rgRecipInfo[i2].dwU3 == CMS_RECIPIENT_INFO_KEYID_ISSUERSERIAL));
  2474. if (rgRecipInfo[i2].dwU3 == CMS_RECIPIENT_INFO_KEYID_KEY_ID) {
  2475. pAgree->rgpRecipientEncryptedKeys[iAgree]->RecipientId.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
  2476. pAgree->rgpRecipientEncryptedKeys[iAgree]->RecipientId.KeyId = rgRecipInfo[i2].u3.KeyId;
  2477. pAgree->rgpRecipientEncryptedKeys[iAgree]->Date = rgRecipInfo[i2].filetime;
  2478. pAgree->rgpRecipientEncryptedKeys[iAgree]->pOtherAttr = rgRecipInfo[i2].pOtherAttr;
  2479. }
  2480. else if (rgRecipInfo[i2].dwU3 == CMS_RECIPIENT_INFO_KEYID_ISSUERSERIAL) {
  2481. pAgree->rgpRecipientEncryptedKeys[iAgree]->RecipientId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
  2482. pAgree->rgpRecipientEncryptedKeys[iAgree]->RecipientId.IssuerSerialNumber = rgRecipInfo[i2].u3.IssuerSerial;
  2483. }
  2484. else {
  2485. hr = E_INVALIDARG;
  2486. goto exit;
  2487. }
  2488. //
  2489. // Zero the data so it does not freed twice. (pointers are now
  2490. // in the CMS structure)
  2491. //
  2492. if (i != i2) {
  2493. memset(&rgRecipInfo[i2], 0, sizeof(rgRecipInfo[i2]));
  2494. }
  2495. iAgree += 1;
  2496. }
  2497. Assert(iAgree == cAgree);
  2498. //
  2499. // The copy has been successfully completed. We now move
  2500. // the data (and ownership) into new structure.
  2501. //
  2502. psld->m_rgRecipientInfo[iRecip].dwRecipientChoice = CMSG_KEY_AGREE_RECIPIENT;
  2503. psld->m_rgRecipientInfo[iRecip].pKeyAgree = pAgree;
  2504. iRecip += 1;
  2505. pAgree = NULL;
  2506. break;
  2507. }
  2508. //
  2509. // Zero the data so it does not freed twice. (pointers are now
  2510. // in the CMS structure)
  2511. //
  2512. memset(&rgRecipInfo[i], 0, sizeof(rgRecipInfo[i]));
  2513. }
  2514. psld->m_cEncryptItems = iRecip;
  2515. PropVariantClear(&var);
  2516. #ifndef _WIN64
  2517. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCRYPTPROV, &var)))
  2518. {
  2519. psi->hProv = (HCRYPTPROV) var.ulVal;
  2520. }
  2521. #else // _WIN64
  2522. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCRYPTPROV_64, &var)))
  2523. {
  2524. psi->hProv = (HCRYPTPROV) var.pulVal;
  2525. }
  2526. #endif // _WIN64
  2527. //
  2528. // Pickup the set of encryption certificate bag
  2529. //
  2530. PropVariantClear(&var);
  2531. #ifdef _WIN64
  2532. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_ENCRYPT_CERT_BAG_64, &var))) {
  2533. psld->m_hstoreEncrypt = (HCERTSTORE) var.pulVal;
  2534. #else
  2535. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_ENCRYPT_CERT_BAG, &var))) {
  2536. psld->m_hstoreEncrypt = (HCERTSTORE) var.ulVal;
  2537. #endif // _WIN64
  2538. }
  2539. //
  2540. // Pick up the unprotected attributes
  2541. //
  2542. if (g_FSupportV3) {
  2543. hr = psm->GetAttribute(0, 0, SMIME_ATTRIBUTE_SET_UNPROTECTED, 0, NULL,
  2544. &pattr);
  2545. if (FAILED(hr)) {
  2546. goto exit;
  2547. }
  2548. else if (hr == S_OK) {
  2549. Assert(pattr != NULL);
  2550. CHECKHR(hr = HrCopyCryptDataBlob(&pattr->rgValue[0],
  2551. &psld->m_blobUnprotectAttrs));
  2552. }
  2553. }
  2554. hr = S_OK;
  2555. exit:
  2556. PropVariantClear(&var);
  2557. if (rgRecipInfo != NULL) {
  2558. for (i=0; i<cRecipients; i++) {
  2559. FreeRecipientInfoContent(&rgRecipInfo[i]);
  2560. }
  2561. SafeMemFree(rgRecipInfo);
  2562. }
  2563. SafeMemFree(pTrans);
  2564. SafeMemFree(pMailList);
  2565. if (pAgree != NULL) {
  2566. for (i=0; pAgree->cRecipientEncryptedKeys; i++) {
  2567. SafeMemFree(pAgree->rgpRecipientEncryptedKeys[i]);
  2568. }
  2569. SafeMemFree(pAgree->pEphemeralAlgorithm);
  2570. SafeMemFree(pAgree->pSenderId);
  2571. SafeMemFree(pAgree->rgpRecipientEncryptedKeys);
  2572. SafeMemFree(pAgree);
  2573. }
  2574. SafeMemFree(pattr);
  2575. return hr;
  2576. }
  2577. /***************************************************************************
  2578. Name : OptionsToSMIMEINFO
  2579. Purpose : Fill the SMIMEINFO from the body properties
  2580. Parameters: fEncode = TRUE if encoding
  2581. pBody -> Body object
  2582. psi -> target SMIMEINFO
  2583. Returns : HRESULT
  2584. Comment :
  2585. ***************************************************************************/
  2586. HRESULT CSMime::OptionsToSMIMEINFO(
  2587. BOOL fEncode,
  2588. IMimeMessageTree *const pmm,
  2589. IMimeBody * pBody,
  2590. SMIMEINFO * psi)
  2591. {
  2592. CRYPT_ATTRIBUTE attr;
  2593. DWORD cb;
  2594. DWORD cAgree;
  2595. ULONG cCertBag = 0;
  2596. DWORD dwSecurity;
  2597. FILETIME ftSignTime;
  2598. HCERTSTORE hCertStore = NULL;
  2599. HRESULT hr = S_OK;
  2600. ULONG i;
  2601. DWORD i2;
  2602. DWORD iAgree;
  2603. ULONG iLayer;
  2604. DWORD iSigner;
  2605. PSECURITY_LAYER_DATA psld = NULL, psldTemp;
  2606. BYTE rgb[50];
  2607. PCCERT_CONTEXT * rgpccCertSigning = NULL;
  2608. PCCERT_CONTEXT * rgpcCertBag = NULL;
  2609. PROPVARIANT * rgpvAlgHash = NULL;
  2610. PROPVARIANT * rgpvAuthAttr = NULL;
  2611. PROPVARIANT * rgpvUnauthAttr = NULL;
  2612. IMimeSecurity2 * psm = NULL;
  2613. ULONG ulLayers = 0;
  2614. CRYPT_ATTR_BLOB valTime;
  2615. PROPVARIANT var;
  2616. Assert(pBody && psi);
  2617. //
  2618. // Pick up the security interface on the body. It makes life easier
  2619. //
  2620. hr = pBody->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &psm);
  2621. if (FAILED(hr)) {
  2622. goto exit;
  2623. }
  2624. //
  2625. // If we are going to encode the body, then see if the content type is
  2626. // "OID/xxx". In this case we encode the body specially and we need to
  2627. // get the size of the inner blob.
  2628. //
  2629. if (fEncode) {
  2630. // Must determine the body type to see if it needs special processing
  2631. if (pBody->IsContentType("OID", NULL) == S_OK) {
  2632. PROPVARIANT var;
  2633. var.vt = VT_LPSTR;
  2634. if (FAILED(pBody->GetProp(STR_ATT_SUBTYPE, 0, &var))) {
  2635. return TrapError(E_FAIL);
  2636. }
  2637. if (strcmp(var.pszVal, szOID_RSA_data) != 0) {
  2638. psi->pszInnerContent = var.pszVal;
  2639. if (FAILED(pBody->GetEstimatedSize(IET_BINARY, &psi->cbInnerContent))) {
  2640. return TrapError(E_FAIL);
  2641. }
  2642. }
  2643. }
  2644. }
  2645. if (FAILED(pBody->GetOption(OID_SECURITY_KEY_PROMPT, &var))) {
  2646. return TrapError(E_FAIL);
  2647. }
  2648. Assert(VT_LPWSTR == var.vt);
  2649. if (var.pwszVal != NULL) {
  2650. psi->pwszKeyPrompt = PszDupW(var.pwszVal);
  2651. if (psi->pwszKeyPrompt == NULL) {
  2652. return TrapError(E_OUTOFMEMORY);
  2653. }
  2654. }
  2655. //
  2656. // Get the security to be applied and put it into the security info layer
  2657. // structure
  2658. //
  2659. if (FAILED(pBody->GetOption(OID_SECURITY_TYPE, &var))) {
  2660. return TrapError(E_FAIL);
  2661. }
  2662. Assert(VT_UI4 == var.vt);
  2663. psi->dwMsgEnhancement = var.ulVal;
  2664. //
  2665. // Start doing the setup for encode operations.
  2666. //
  2667. if (fEncode) {
  2668. //
  2669. // We must be doing some type of encoding operation, or we should fail.
  2670. //
  2671. if (MST_NONE == var.ulVal) {
  2672. hr = TrapError(MIME_S_SECURITY_NOOP);
  2673. goto exit;
  2674. }
  2675. else if (!(MST_THIS_MASK & var.ulVal)) {
  2676. hr = TrapError(MIME_S_SECURITY_RECURSEONLY);
  2677. goto exit;
  2678. }
  2679. else if (MST_CLASS_SMIME_V1 != (var.ulVal & MST_CLASS_MASK)) {
  2680. hr = TrapError(MIME_E_SECURITY_CLASSNOTSUPPORTED);
  2681. goto exit;
  2682. }
  2683. //
  2684. // If we are doing multiple layers of encrption, then we require that
  2685. // the inner level be blobed and not clear.
  2686. //
  2687. if ((psi->pszInnerContent != NULL) && !(var.ulVal & MST_BLOB_FLAG)) {
  2688. hr = TrapError(E_INVALIDARG);
  2689. goto exit;
  2690. }
  2691. //
  2692. // Are we encrypting
  2693. //
  2694. if (psi->dwMsgEnhancement & MST_ENCRYPT_MASK) {
  2695. hr = ConvertEncryptionLayer(pBody, psm, psi);
  2696. if (FAILED(hr)) {
  2697. goto exit;
  2698. }
  2699. }
  2700. //
  2701. // Are we signing?
  2702. //
  2703. if (psi->dwMsgEnhancement & MST_SIGN_MASK) {
  2704. //
  2705. // Force in a a signing time
  2706. //
  2707. GetSystemTimeAsFileTime(&ftSignTime);
  2708. cb = sizeof(rgb);
  2709. if (CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CHOICE_OF_TIME,
  2710. &ftSignTime, 0, NULL, rgb, &cb)) {
  2711. attr.pszObjId = szOID_RSA_signingTime;
  2712. attr.cValue = 1;
  2713. attr.rgValue = &valTime;
  2714. valTime.pbData = rgb;
  2715. valTime.cbData = cb;
  2716. hr = psm->SetAttribute(SMIME_ATTR_ADD_IF_NOT_EXISTS,
  2717. (DWORD) -1, SMIME_ATTRIBUTE_SET_SIGNED,
  2718. &attr);
  2719. if (FAILED(hr)) {
  2720. goto exit;
  2721. }
  2722. }
  2723. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_SIGNATURE_COUNT, &var))) {
  2724. Assert(VT_UI4 == var.vt);
  2725. ulLayers = var.ulVal;
  2726. }
  2727. #ifdef _WIN64
  2728. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING_RG_64, &var))) {
  2729. Assert((VT_VECTOR | VT_UI8) == var.vt);
  2730. Assert(var.cauh.cElems == ulLayers);
  2731. rgpccCertSigning = (PCCERT_CONTEXT *) (var.cauh.pElems);
  2732. }
  2733. // These next two are optional
  2734. // Furthermore, if we get the first, we don't check the second. BJK - Huh?
  2735. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE_64, &var)))
  2736. {
  2737. Assert(VT_UI8 == var.vt);
  2738. hCertStore = (HCERTSTORE) var.pulVal;
  2739. #else
  2740. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING_RG, &var))) {
  2741. Assert((VT_VECTOR | VT_UI4) == var.vt);
  2742. Assert(var.caul.cElems == ulLayers);
  2743. rgpccCertSigning = (PCCERT_CONTEXT *)var.caul.pElems;
  2744. }
  2745. // These next two are optional
  2746. // Furthermore, if we get the first, we don't check the second. BJK - Huh?
  2747. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE, &var)))
  2748. {
  2749. Assert(VT_UI4 == var.vt);
  2750. hCertStore = (HCERTSTORE) var.ulVal;
  2751. #endif //_WIN64
  2752. }
  2753. // NOTE: OID_SECURITY_RG_CERT_BAG is not a per-layer array! It
  2754. // is an array of all the certs for the entire message.
  2755. #ifndef _WIN64
  2756. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_RG_CERT_BAG, &var))) {
  2757. Assert((VT_VECTOR | VT_UI4) == var.vt);
  2758. cCertBag = var.caul.cElems;
  2759. rgpcCertBag = (PCCERT_CONTEXT*)var.caul.pElems;
  2760. #else
  2761. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_RG_CERT_BAG_64, &var))) {
  2762. Assert((VT_VECTOR | VT_UI8) == var.vt);
  2763. cCertBag = var.cauh.cElems;
  2764. rgpcCertBag = (PCCERT_CONTEXT*)(var.cauh.pElems);
  2765. #endif //_WIN64
  2766. }
  2767. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_ALG_HASH_RG, &var))) {
  2768. Assert((VT_VECTOR | VT_VARIANT) == var.vt);
  2769. Assert(var.capropvar.cElems == ulLayers);
  2770. rgpvAlgHash = var.capropvar.pElems;
  2771. }
  2772. // Grab the unauthenicated attributes
  2773. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_UNAUTHATTR_RG, &var))) {
  2774. Assert((VT_VECTOR | VT_VARIANT) == var.vt);
  2775. Assert(var.capropvar.cElems == ulLayers);
  2776. rgpvUnauthAttr = var.capropvar.pElems;
  2777. }
  2778. // Grab the initial authenicated attributes
  2779. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_AUTHATTR_RG, &var))) {
  2780. Assert((VT_VECTOR | VT_VARIANT) == var.vt);
  2781. Assert(var.capropvar.cElems == ulLayers);
  2782. rgpvAuthAttr = var.capropvar.pElems;
  2783. }
  2784. // Create a layer to hold the signing information
  2785. if (! (psld = new CSECURITY_LAYER_DATA)) {
  2786. hr = E_OUTOFMEMORY;
  2787. goto exit;
  2788. }
  2789. // Link together the different layers
  2790. if (psi->psldLayers == NULL) {
  2791. psi->psldLayers = psld;
  2792. }
  2793. psld->m_psldOuter = psi->psldInner;
  2794. if (psld->m_psldOuter != NULL) {
  2795. psld->m_psldOuter->m_psldInner = psld;
  2796. }
  2797. psi->psldInner = psld;
  2798. //
  2799. psld->m_dwMsgEnhancement = psi->dwMsgEnhancement &
  2800. (MST_SIGN_MASK | MST_BLOB_FLAG);
  2801. // Fill in the signing information
  2802. if (!MemAlloc((LPVOID *) &psld->m_rgSigners,
  2803. sizeof(SignerData)*ulLayers)) {
  2804. hr = E_OUTOFMEMORY;
  2805. goto exit;
  2806. }
  2807. memset(psld->m_rgSigners, 0, sizeof(SignerData)*ulLayers);
  2808. psld->m_cSigners = ulLayers;
  2809. for (iSigner=0; iSigner < ulLayers; iSigner++) {
  2810. psld->m_rgSigners[iSigner].pccert = DupCert(rgpccCertSigning[iSigner]);
  2811. HrCopyBlob(&rgpvAlgHash[iSigner].blob,
  2812. &psld->m_rgSigners[iSigner].blobHashAlg);
  2813. HrCopyBlob(&rgpvUnauthAttr[iSigner].blob,
  2814. &psld->m_rgSigners[iSigner].blobUnauth);
  2815. HrCopyBlob(&rgpvAuthAttr[iSigner].blob,
  2816. &psld->m_rgSigners[iSigner].blobAuth);
  2817. }
  2818. #ifdef _WIN64
  2819. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE_64, &var)))
  2820. {
  2821. // Don't addref as we are just giving it to the sld object
  2822. psld->m_hcertstor = (HCERTSTORE) var.pulVal;
  2823. #else
  2824. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE, &var)))
  2825. {
  2826. // Don't addref as we are just giving it to the sld object
  2827. psld->m_hcertstor = (HCERTSTORE) var.ulVal;
  2828. #endif // _WIN64
  2829. }
  2830. }
  2831. //
  2832. // read these for both signing and encryption
  2833. //
  2834. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_REQUESTED_CTE, &var))) {
  2835. Assert(VT_I4 == var.vt);
  2836. psi->ietRequested = ENCODINGTYPE(var.lVal);
  2837. }
  2838. else {
  2839. psi->ietRequested = ENCODINGTYPE(-1);
  2840. }
  2841. }
  2842. //
  2843. // read these for both encoding and decoding
  2844. //
  2845. if (SUCCEEDED(pBody->GetOption(OID_SECURITY_SEARCHSTORES, &var)) &&
  2846. #ifdef _WIN64
  2847. (NULL != var.cauh.pElems)
  2848. #else
  2849. (NULL != var.caul.pElems)
  2850. #endif // _WIN64
  2851. ) {
  2852. #ifdef _WIN64
  2853. CAUH& caul = var.cauh; // On Win64, it's really a cauh
  2854. #else
  2855. CAUL& caul = var.caul;
  2856. #endif // _WIN64
  2857. psi->rgStores = (HCERTSTORE*)g_pMoleAlloc->Alloc(caul.cElems * sizeof(HCERTSTORE));
  2858. if (psi->rgStores) {
  2859. for (DWORD i = 0; i < caul.cElems; i++) {
  2860. // Shouldn't have to duplicate since we're not freeing them here
  2861. #ifdef _WIN64
  2862. psi->rgStores[i] = (HCERTSTORE)caul.pElems[i].QuadPart;
  2863. #else
  2864. psi->rgStores[i] = (HCERTSTORE)caul.pElems[i];
  2865. #endif // _WIN64
  2866. }
  2867. psi->cStores = caul.cElems;
  2868. }
  2869. SafeMemFree(caul.pElems);
  2870. }
  2871. else {
  2872. // if we were given no stores, open "My"
  2873. psi->rgStores = (HCERTSTORE*)g_pMoleAlloc->Alloc(sizeof(HCERTSTORE));
  2874. if (psi->rgStores) {
  2875. psi->rgStores[0] = OpenCachedMyStore();
  2876. if (psi->rgStores[0]) {
  2877. psi->cStores = 1;
  2878. } else {
  2879. g_pMoleAlloc->Free(psi->rgStores);
  2880. }
  2881. }
  2882. }
  2883. exit:
  2884. #ifdef SMIME_V3
  2885. if (psm != NULL) psm->Release();
  2886. #endif // SMIME_V3
  2887. #ifndef SMIME_V3
  2888. SafeMemFree(rgftSigningTime);
  2889. #endif // SMIME_V3
  2890. if (rgpccCertSigning) {
  2891. for (iLayer = 0; iLayer < ulLayers; iLayer++) {
  2892. if (rgpccCertSigning[iLayer]) {
  2893. CertFreeCertificateContext(rgpccCertSigning[iLayer]);
  2894. }
  2895. }
  2896. }
  2897. SafeMemFree(rgpccCertSigning);
  2898. if (hCertStore) {
  2899. CertCloseStore(hCertStore, 0);
  2900. }
  2901. if (rgpcCertBag) {
  2902. // NOTE: rgpcCertBag isn't indexed by layer!
  2903. for (i = 0; i < cCertBag; i++) {
  2904. if (rgpcCertBag[i]) {
  2905. CertFreeCertificateContext(rgpcCertBag[i]);
  2906. }
  2907. }
  2908. }
  2909. SafeMemFree(rgpcCertBag);
  2910. if (rgpvAlgHash) {
  2911. for (iLayer = 0; iLayer < ulLayers; iLayer++) {
  2912. SafeMemFree(rgpvAlgHash[iLayer].blob.pBlobData);
  2913. }
  2914. }
  2915. SafeMemFree(rgpvAlgHash);
  2916. if (rgpvUnauthAttr) {
  2917. for (iLayer = 0; iLayer < ulLayers; iLayer++) {
  2918. SafeMemFree(rgpvUnauthAttr[iLayer].blob.pBlobData);
  2919. }
  2920. }
  2921. SafeMemFree(rgpvUnauthAttr);
  2922. if (rgpvAuthAttr) {
  2923. for (iLayer = 0; iLayer < ulLayers; iLayer++) {
  2924. SafeMemFree(rgpvAuthAttr[iLayer].blob.pBlobData);
  2925. }
  2926. }
  2927. SafeMemFree(rgpvAuthAttr);
  2928. #ifndef SMIME_V3
  2929. if (rgpvSymcaps) {
  2930. for (iLayer = 0; iLayer < ulLayers; iLayer++) {
  2931. SafeMemFree(rgpvSymcaps[iLayer].blob.pBlobData);
  2932. }
  2933. }
  2934. SafeMemFree(rgpvSymcaps);
  2935. #endif // !SMIME_V3
  2936. return(hr);
  2937. }
  2938. /***************************************************************************
  2939. Name : SMIMEINFOToOptions
  2940. Purpose : set the body properties based on contents of the SMIMEINFO
  2941. Parameters: psi -> source SMIMEINFO
  2942. pBody -> target body object
  2943. Returns : void
  2944. Comment :
  2945. ***************************************************************************/
  2946. HRESULT CSMime::SMIMEINFOToOptions(
  2947. IMimeMessageTree * const pTree,
  2948. const SMIMEINFO * psi,
  2949. HBODY hBody)
  2950. {
  2951. DWORD dwSecurityType = 0;
  2952. HBODY hBody2;
  2953. HRESULT hr;
  2954. ULONG iLayer;
  2955. PCRYPT_ATTRIBUTES pattrsUnprot = NULL;
  2956. CMessageBody * pPrivBody = NULL;
  2957. PSECURITY_LAYER_DATA psldLoop;
  2958. IMimeSecurity2 * psm = NULL;
  2959. PROPVARIANT var;
  2960. #ifdef _WIN64
  2961. UNALIGNED CRYPT_ATTR_BLOB *pVal = NULL;
  2962. #endif
  2963. Assert(psi && hBody);
  2964. CHECKHR(hr = pTree->BindToObject(hBody, IID_CMessageBody, (void**)&pPrivBody));
  2965. Assert(pPrivBody);
  2966. pPrivBody->GetOption(OID_SECURITY_CERT_INCLUDED, &var);
  2967. Assert(VT_BOOL == var.vt);
  2968. if (!var.boolVal && psi->fCertWithMsg) {
  2969. var.boolVal = (VARIANT_BOOL) !!psi->fCertWithMsg;
  2970. pPrivBody->InternalSetOption(OID_SECURITY_CERT_INCLUDED, &var,
  2971. TRUE, TRUE);
  2972. }
  2973. pPrivBody->GetOption(OID_SECURITY_TYPE, &var);
  2974. dwSecurityType = var.ulVal;
  2975. // We could have been passed something like ROOT, move to a real handle
  2976. pPrivBody->GetHandle(&hBody2);
  2977. for (iLayer = 0, psldLoop = psi->psldLayers; psldLoop != NULL;
  2978. psldLoop = psldLoop->m_psldInner, iLayer++) {
  2979. // The rule here is: Always insert a new layer UNLESS:
  2980. // 1. this is an encrpytion layer and
  2981. // 2. the previous layer was a signing layer
  2982. if ((dwSecurityType != 0) &&
  2983. (!(dwSecurityType & MST_THIS_ENCRYPT) ||
  2984. !(psldLoop->m_dwMsgEnhancement & MST_THIS_SIGN))) {
  2985. /* ((dwSecurityType & MST_THIS_SIGN_ENCRYPT) != MST_THIS_SIGN) &&
  2986. ((psldLoop->m_dwMsgEnhancement & MST_THIS_SIGN_ENCRYPT) != MST_THIS_ENCRYPT)) {
  2987. */
  2988. if (psm != NULL) {
  2989. psm->Release();
  2990. psm = NULL;
  2991. }
  2992. pPrivBody->Release();
  2993. CHECKHR(hr = pTree->ToMultipart(hBody2, "y-security", NULL));
  2994. CHECKHR(hr = pTree->BindToObject(hBody2, IID_CMessageBody,
  2995. (void**)&pPrivBody));
  2996. }
  2997. // This must be after the above check for inserting a layer
  2998. dwSecurityType |= psldLoop->m_dwMsgEnhancement | MST_CLASS_SMIME_V1;
  2999. if (MST_SIGN_MASK & psldLoop->m_dwMsgEnhancement) {
  3000. DWORD cSigners = psldLoop->m_cSigners;
  3001. DWORD iSigner;
  3002. SignerData * pSigner;
  3003. // Allocate enough space in the option arrays for this layer
  3004. // OID_SECURITY_TYPE_RG // DWORD
  3005. // OID_SECURITY_ALG_HASH_RG // BLOB
  3006. // OID_SECURITY_CERT_SIGNING_RG // DWORD
  3007. // OID_SECURITY_HCERTSTORE_RG // DWORD
  3008. // OID_SECURITY_SYMCAPS_RG // BLOB
  3009. // OID_SECURITY_AUTHATTR_RG // BLOB
  3010. // OID_SECURITY_UNAUTHATTR_RG // BLOB
  3011. // OID_SECURITY_SIGNTIME_RG // FILETIME
  3012. // OID_SECURITY_USER_VALIDITY_RG // DWORD
  3013. // OID_SECURITY_RO_MSG_VALIDITY_RG // DWORD
  3014. #ifdef _WIN64
  3015. ULONG cbrgullCertSigning = cSigners * sizeof(ULONGLONG);
  3016. ULONGLONG * rgullCertSigning;
  3017. #else // !_WIN64
  3018. ULONG cbrgdwCertSigning = cSigners * sizeof(DWORD);
  3019. DWORD * rgdwCertSigning;
  3020. #endif // _WIN64
  3021. ULONG cbrgdwUserValidity = cSigners * sizeof(DWORD);
  3022. ULONG cbrgdwROMsgValidity = cSigners * sizeof(DWORD);
  3023. ULONG cbrgftSigntime = cSigners * sizeof(FILETIME);
  3024. ULONG cbrgpvAlgHash = cSigners * sizeof(PROPVARIANT);
  3025. ULONG cbrgpvSymcaps = cSigners * sizeof(PROPVARIANT);
  3026. ULONG cbrgpvAuthattr = cSigners * sizeof(PROPVARIANT);
  3027. ULONG cbrgpvUnauthattr = cSigners * sizeof(PROPVARIANT);
  3028. #ifdef SMIME_V3
  3029. ULONG cbrgpvReceipt = cSigners * sizeof(PROPVARIANT);
  3030. ULONG cbrgpvHash = cSigners * sizeof(PROPVARIANT);
  3031. #endif // SMIME_V3
  3032. #ifdef _WIN64
  3033. ULONG cbArrays = cbrgullCertSigning +
  3034. #else
  3035. ULONG cbArrays = cbrgdwCertSigning +
  3036. #endif
  3037. cbrgdwUserValidity + cbrgdwROMsgValidity +
  3038. cbrgftSigntime + cbrgpvAlgHash + cbrgpvSymcaps + cbrgpvAuthattr +
  3039. #ifdef SMIME_V3
  3040. cbrgpvReceipt + cbrgpvHash +
  3041. #endif // SMIME_V3
  3042. cbrgpvUnauthattr;
  3043. LPBYTE lpbArrays = NULL;
  3044. LPDWORD rgdwUserValidity;
  3045. LPDWORD rgdwROMsgValidity;
  3046. FILETIME * rgftSigntime;
  3047. PROPVARIANT * rgpvAlgHash;
  3048. PROPVARIANT * rgpvSymcaps;
  3049. PROPVARIANT * rgpvAuthattr;
  3050. PROPVARIANT * rgpvUnauthattr;
  3051. #ifdef SMIME_V3
  3052. PROPVARIANT * rgpvReceipt;
  3053. PROPVARIANT * rgpvHash;
  3054. #endif // SMIME_V3
  3055. // Allocate them all at once.
  3056. if (! MemAlloc((LPVOID *)&lpbArrays, cbArrays)) {
  3057. return E_OUTOFMEMORY;
  3058. }
  3059. ZeroMemory(lpbArrays, cbArrays);
  3060. // Set up the pointers
  3061. #ifdef _WIN64
  3062. rgullCertSigning = (ULONGLONG *) lpbArrays;
  3063. rgdwUserValidity = (LPDWORD)((LPBYTE)rgullCertSigning + cbrgullCertSigning);
  3064. #else // !_WIN64
  3065. rgdwCertSigning = (DWORD *) lpbArrays;
  3066. rgdwUserValidity = (LPDWORD)((LPBYTE)rgdwCertSigning + cbrgdwCertSigning);
  3067. #endif // _WIN64
  3068. rgdwROMsgValidity = (LPDWORD)((LPBYTE)rgdwUserValidity + cbrgdwUserValidity);
  3069. rgftSigntime = (FILETIME *)((LPBYTE)rgdwROMsgValidity + cbrgdwROMsgValidity);
  3070. rgpvAlgHash = (PROPVARIANT *)((LPBYTE)rgftSigntime + cbrgftSigntime);
  3071. rgpvSymcaps = (PROPVARIANT *)((LPBYTE)rgpvAlgHash + cbrgpvAlgHash);
  3072. rgpvAuthattr = (PROPVARIANT *)((LPBYTE)rgpvSymcaps + cbrgpvSymcaps);
  3073. rgpvUnauthattr = (PROPVARIANT *)((LPBYTE)rgpvAuthattr + cbrgpvAuthattr);
  3074. #ifdef SMIME_V3
  3075. rgpvReceipt = (PROPVARIANT *)((LPBYTE)rgpvUnauthattr + cbrgpvUnauthattr);
  3076. rgpvHash = (PROPVARIANT *)((LPBYTE)rgpvReceipt + cbrgpvReceipt);
  3077. #endif // SMIME_V3
  3078. for (iSigner=0, pSigner = psldLoop->m_rgSigners; iSigner<cSigners;
  3079. iSigner++, pSigner++) {
  3080. #ifdef _WIN64
  3081. rgullCertSigning[iSigner] = (ULONGLONG) pSigner->pccert;
  3082. #else // !_WIN64
  3083. rgdwCertSigning[iSigner] = (DWORD) pSigner->pccert;
  3084. #endif // _WIN64
  3085. if (pSigner->blobHashAlg.cbSize) {
  3086. rgpvAlgHash[iSigner].vt = VT_BLOB;
  3087. rgpvAlgHash[iSigner].blob.cbSize = pSigner->blobHashAlg.cbSize;
  3088. // Don't need to duplicate
  3089. rgpvAlgHash[iSigner].blob.pBlobData = pSigner->blobHashAlg.pBlobData;
  3090. }
  3091. if (pSigner->blobAuth.cbSize) {
  3092. rgpvAuthattr[iSigner].vt = VT_BLOB;
  3093. rgpvAuthattr[iSigner].blob.cbSize = pSigner->blobAuth.cbSize;
  3094. // Don't need to duplicate
  3095. rgpvAuthattr[iSigner].blob.pBlobData = pSigner->blobAuth.pBlobData;
  3096. // We want to break out two values from the authenticated blobs and put
  3097. // them into someplace easy to access
  3098. DWORD cbData = 0;
  3099. BOOL f;
  3100. DWORD i;
  3101. PCRYPT_ATTRIBUTES pattrs = NULL;
  3102. if ((! HrDecodeObject(pSigner->blobAuth.pBlobData,
  3103. pSigner->blobAuth.cbSize,
  3104. szOID_Microsoft_Attribute_Sequence, 0, &cbData,
  3105. (LPVOID *)&pattrs)) && pattrs) {
  3106. FILETIME * pSigningTime = NULL;
  3107. Assert(pattrs);
  3108. for (i = 0; i < pattrs->cAttr; i++) {
  3109. Assert(pattrs->rgAttr[i].cValue == 1);
  3110. if (lstrcmp(pattrs->rgAttr[i].pszObjId, szOID_RSA_signingTime) == 0) {
  3111. #ifndef _WIN64
  3112. if ((! HrDecodeObject(pattrs->rgAttr[i].rgValue[0].pbData,
  3113. pattrs->rgAttr[i].rgValue[0].cbData,
  3114. X509_CHOICE_OF_TIME, 0, &cbData, (LPVOID *)&pSigningTime)) && pSigningTime)
  3115. #else // _WIN64
  3116. pVal = &(pattrs->rgAttr[i].rgValue[0]);
  3117. if ((! HrDecodeObject(pVal->pbData,
  3118. pVal->cbData,
  3119. X509_CHOICE_OF_TIME, 0, &cbData, (LPVOID *)&pSigningTime)) && pSigningTime)
  3120. #endif //_WIN64
  3121. {
  3122. Assert(cbData == sizeof(FILETIME));
  3123. memcpy(&rgftSigntime[iSigner], pSigningTime, sizeof(FILETIME));
  3124. SafeMemFree(pSigningTime);
  3125. }
  3126. }
  3127. else if (lstrcmp(pattrs->rgAttr[i].pszObjId, szOID_RSA_SMIMECapabilities) == 0) {
  3128. rgpvSymcaps[iSigner].vt = VT_BLOB;
  3129. #ifndef _WIN64
  3130. rgpvSymcaps[iSigner].blob.cbSize = pattrs->rgAttr[i].rgValue[0].cbData;
  3131. // Duplicate the blob data since the MemFree(pattrs) will nuke this pointer.
  3132. rgpvSymcaps[iSigner].blob.pBlobData =
  3133. DuplicateMemory(pattrs->rgAttr[i].rgValue[0].pbData, rgpvSymcaps[iSigner].blob.cbSize);
  3134. #else // _WIN64
  3135. pVal = &(pattrs->rgAttr[i].rgValue[0]);
  3136. rgpvSymcaps[iSigner].blob.cbSize = pVal->cbData;
  3137. // Duplicate the blob data since the MemFree(pattrs) will nuke this pointer.
  3138. rgpvSymcaps[iSigner].blob.pBlobData =
  3139. DuplicateMemory(pVal->pbData, rgpvSymcaps[iSigner].blob.cbSize);
  3140. #endif //_WIN64
  3141. }
  3142. }
  3143. MemFree(pattrs);
  3144. }
  3145. }
  3146. if (pSigner->blobUnauth.cbSize) {
  3147. rgpvUnauthattr[iSigner].vt = VT_BLOB;
  3148. rgpvUnauthattr[iSigner].blob.cbSize = pSigner->blobUnauth.cbSize;
  3149. // Don't need to duplicate
  3150. rgpvUnauthattr[iSigner].blob.pBlobData = pSigner->blobUnauth.pBlobData;
  3151. }
  3152. #ifdef SMIME_V3
  3153. if (pSigner->blobReceipt.cbSize) {
  3154. rgpvReceipt[iSigner].vt = VT_BLOB;
  3155. rgpvReceipt[iSigner].blob.cbSize = pSigner->blobReceipt.cbSize;
  3156. // Don't need to duplicate
  3157. rgpvReceipt[iSigner].blob.pBlobData = pSigner->blobReceipt.pBlobData;
  3158. dwSecurityType |= MST_RECEIPT_REQUEST;
  3159. }
  3160. if (pSigner->blobHash.cbSize) {
  3161. rgpvHash[iSigner].vt = VT_BLOB;
  3162. rgpvHash[iSigner].blob.cbSize = pSigner->blobHash.cbSize;
  3163. // Don't need to duplicate
  3164. rgpvHash[iSigner].blob.pBlobData = pSigner->blobHash.pBlobData;
  3165. }
  3166. #endif // SMIME_V3
  3167. // Signature validity
  3168. rgdwROMsgValidity[iSigner] = pSigner->ulValidity;
  3169. }
  3170. #ifdef SMIME_V3
  3171. var.vt = VT_VECTOR | VT_VARIANT;
  3172. var.capropvar.pElems = rgpvReceipt;
  3173. var.capropvar.cElems = cSigners;
  3174. pPrivBody->InternalSetOption(OID_SECURITY_RECEIPT_RG, &var, TRUE, TRUE);
  3175. var.vt = VT_VECTOR | VT_VARIANT;
  3176. var.capropvar.pElems = rgpvHash;
  3177. var.capropvar.cElems = cSigners;
  3178. pPrivBody->InternalSetOption(OID_SECURITY_MESSAGE_HASH_RG, &var, TRUE, TRUE);
  3179. #endif // SMIME_V3
  3180. // Set the array options
  3181. #ifdef _WIN64
  3182. var.vt = VT_VECTOR | VT_UI8;
  3183. var.cauh.pElems = (ULARGE_INTEGER *)(rgullCertSigning);
  3184. var.cauh.cElems = cSigners;
  3185. pPrivBody->InternalSetOption(OID_SECURITY_CERT_SIGNING_RG_64, &var, TRUE, TRUE);
  3186. #else
  3187. var.vt = VT_VECTOR | VT_UI4;
  3188. var.caul.pElems = rgdwCertSigning;
  3189. var.caul.cElems = cSigners;
  3190. pPrivBody->InternalSetOption(OID_SECURITY_CERT_SIGNING_RG, &var, TRUE, TRUE);
  3191. #endif // _WIN64
  3192. var.vt = VT_VECTOR | VT_UI4;
  3193. var.caul.pElems = rgdwUserValidity;
  3194. var.caul.cElems = cSigners;
  3195. pPrivBody->InternalSetOption(OID_SECURITY_USER_VALIDITY_RG, &var, TRUE, TRUE);
  3196. var.vt = VT_VECTOR | VT_UI4;
  3197. var.caul.pElems = rgdwROMsgValidity;
  3198. var.caul.cElems = cSigners;
  3199. pPrivBody->InternalSetOption(OID_SECURITY_RO_MSG_VALIDITY_RG, &var, TRUE, TRUE);
  3200. var.vt = VT_VECTOR | VT_FILETIME;
  3201. var.cafiletime.pElems = rgftSigntime;
  3202. var.cafiletime.cElems = cSigners;
  3203. pPrivBody->InternalSetOption(OID_SECURITY_SIGNTIME_RG, &var, TRUE, TRUE);
  3204. var.vt = VT_VECTOR | VT_VARIANT;
  3205. var.capropvar.pElems = rgpvAlgHash;
  3206. var.capropvar.cElems = cSigners;
  3207. pPrivBody->InternalSetOption(OID_SECURITY_ALG_HASH_RG, &var, TRUE, TRUE);
  3208. var.vt = VT_VECTOR | VT_VARIANT;
  3209. var.capropvar.pElems = rgpvSymcaps;
  3210. var.capropvar.cElems = cSigners;
  3211. pPrivBody->InternalSetOption(OID_SECURITY_SYMCAPS_RG, &var, TRUE, TRUE);
  3212. var.vt = VT_VECTOR | VT_VARIANT;
  3213. var.capropvar.pElems = rgpvAuthattr;
  3214. var.capropvar.cElems = cSigners;
  3215. pPrivBody->InternalSetOption(OID_SECURITY_AUTHATTR_RG, &var, TRUE, TRUE);
  3216. var.vt = VT_VECTOR | VT_VARIANT;
  3217. var.capropvar.pElems = rgpvUnauthattr;
  3218. var.capropvar.cElems = cSigners;
  3219. pPrivBody->InternalSetOption(OID_SECURITY_UNAUTHATTR_RG, &var, TRUE, TRUE);
  3220. // clean up the duplicated rgpvSymcaps
  3221. if (rgpvSymcaps) {
  3222. for (iSigner = 0; iSigner < cSigners; iSigner++) {
  3223. SafeMemFree(rgpvSymcaps[iSigner].blob.pBlobData);
  3224. }
  3225. }
  3226. // Free the arrays
  3227. SafeMemFree(lpbArrays);
  3228. }
  3229. if (MST_THIS_ENCRYPT & psldLoop->m_dwMsgEnhancement) {
  3230. Assert(psldLoop->m_pccertDecrypt != NULL);
  3231. if (psldLoop->m_pccertDecrypt != NULL) {
  3232. #ifdef _WIN64
  3233. var.vt = VT_UI8;
  3234. var.pulVal = (ULONG *) (psldLoop->m_pccertDecrypt);
  3235. pPrivBody->InternalSetOption(OID_SECURITY_CERT_DECRYPTION_64, &var,
  3236. TRUE, TRUE);
  3237. #else // !_WIN64
  3238. var.vt = VT_UI4;
  3239. var.ulVal = (ULONG) psldLoop->m_pccertDecrypt;
  3240. pPrivBody->InternalSetOption(OID_SECURITY_CERT_DECRYPTION, &var,
  3241. TRUE, TRUE);
  3242. #endif // _WIN64
  3243. }
  3244. //N TODO: convert oids to symcaps
  3245. //BruceK: Why? Does this make sense on an encrypted layer? Maybe Erik is
  3246. // suggesting that we put can gather a little bit of information about
  3247. // the sender's capabilities from the encryption method he used. At any
  3248. // rate, it isn't nearly as important as the signed message case.
  3249. Assert(psldLoop->m_blobDecAlg.cbSize != 0);
  3250. if (psldLoop->m_blobDecAlg.cbSize) {
  3251. var.vt = VT_BLOB;
  3252. var.blob.cbSize = psldLoop->m_blobDecAlg.cbSize;
  3253. var.blob.pBlobData = psldLoop->m_blobDecAlg.pBlobData;
  3254. pPrivBody->InternalSetOption(OID_SECURITY_ALG_BULK, &var,
  3255. TRUE, TRUE);
  3256. }
  3257. if (g_FSupportV3 && (psldLoop->m_blobUnprotectAttrs.cbData > 0)) {
  3258. DWORD iAttr;
  3259. DWORD cbData = 0;
  3260. if (psm == NULL) {
  3261. CHECKHR(hr = pPrivBody->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &psm));
  3262. }
  3263. CHECKHR(hr = HrDecodeObject(psldLoop->m_blobUnprotectAttrs.pbData,
  3264. psldLoop->m_blobUnprotectAttrs.cbData,
  3265. szOID_Microsoft_Attribute_Sequence, 0,
  3266. &cbData, (LPVOID *) &pattrsUnprot));
  3267. for (iAttr = 0; iAttr < pattrsUnprot->cAttr; iAttr++) {
  3268. CHECKHR(hr = psm->SetAttribute(0, 0, SMIME_ATTRIBUTE_SET_UNPROTECTED,
  3269. &pattrsUnprot->rgAttr[iAttr]));
  3270. }
  3271. }
  3272. }
  3273. var.vt = VT_UI4;
  3274. var.ulVal = dwSecurityType;
  3275. pPrivBody->InternalSetOption(OID_SECURITY_TYPE, &var, TRUE, TRUE);
  3276. // M00BUG -- must deal with two?
  3277. #ifdef _WIN64
  3278. if (psldLoop->m_hcertstor != NULL) {
  3279. var.vt = VT_UI8;
  3280. var.pulVal = (ULONG *) (psldLoop->m_hcertstor);
  3281. pPrivBody->InternalSetOption(OID_SECURITY_HCERTSTORE_64, &var, TRUE, TRUE);
  3282. }
  3283. #else
  3284. if (psldLoop->m_hcertstor != NULL)
  3285. {
  3286. var.vt = VT_UI4;
  3287. var.ulVal = (ULONG)psldLoop->m_hcertstor;
  3288. pPrivBody->InternalSetOption(OID_SECURITY_HCERTSTORE, &var, TRUE, TRUE);
  3289. }
  3290. #endif // _WIN64
  3291. }
  3292. hr = S_OK;
  3293. exit:
  3294. if (psm != NULL) psm->Release();
  3295. SafeMemFree(pattrsUnprot);
  3296. if (pPrivBody != NULL) pPrivBody->Release();
  3297. return hr;
  3298. }
  3299. /***************************************************************************
  3300. Name : MergeSMIMEINFO
  3301. Purpose :
  3302. Parameters: psiOuter -> Object to be merged into
  3303. psiInner -> Object to merge from
  3304. Returns : HRESULT of errors
  3305. Comment :
  3306. ***************************************************************************/
  3307. HRESULT CSMime::MergeSMIMEINFO(SMIMEINFO *psiOuter, SMIMEINFO * psiInner)
  3308. {
  3309. PSECURITY_LAYER_DATA psld;
  3310. psiOuter->fCertWithMsg |= psiInner->fCertWithMsg;
  3311. // Just stick the inner data at the inner most point in the outer data
  3312. // and the clear out the inner data structure.
  3313. if (psiInner->psldLayers != NULL) {
  3314. for (psld = psiOuter->psldLayers; psld->m_psldInner != NULL;
  3315. psld = psld->m_psldInner);
  3316. psld->m_psldInner = psiInner->psldLayers;
  3317. psiInner->psldLayers = NULL;
  3318. }
  3319. return S_OK;
  3320. }
  3321. /***************************************************************************
  3322. Name : FreeSMIMEINFO
  3323. Purpose : Free and Release the memory and objects stored in the
  3324. SMIMEINFO.
  3325. Parameters: psi -> SMIMEINFO
  3326. Returns : none
  3327. Comment :
  3328. ***************************************************************************/
  3329. void CSMime::FreeSMIMEINFO(SMIMEINFO *psi)
  3330. {
  3331. register DWORD i;
  3332. if (psi->psldLayers) {
  3333. psi->psldLayers->Release();
  3334. }
  3335. for (i = 0; i < psi->cStores; i++) {
  3336. CertCloseStore(psi->rgStores[i], 0);
  3337. }
  3338. if (psi->rgStores) {
  3339. g_pMoleAlloc->Free(psi->rgStores);
  3340. }
  3341. if (psi->hProv) {
  3342. CryptReleaseContext(psi->hProv, 0);
  3343. }
  3344. #ifdef SMIME_V3
  3345. MemFree(psi->pszInnerContent);
  3346. SafeMemFree(psi->pwszKeyPrompt);
  3347. #endif // SMIME_V3
  3348. return;
  3349. }
  3350. #ifdef KILL_THIS
  3351. /***************************************************************************
  3352. Name : MergeSMIMEINFOs
  3353. Purpose : Merge two SMIMEINFO structures into one
  3354. Parameters: psiOuter -> Source structure
  3355. psiInner -> Destination structure
  3356. Returns : void
  3357. Comment :
  3358. ***************************************************************************/
  3359. void CSMime::MergeSMIMEINFOs(const SMIMEINFO *const psiOuter, SMIMEINFO *const psiInner)
  3360. {
  3361. PSECURITY_LAYER_DATA psldLoopOuter;
  3362. PSECURITY_LAYER_DATA psldLoopInner;
  3363. psiInner->fCertWithMsg |= psiOuter->fCertWithMsg;
  3364. Assert(0 == (psiOuter->ulMsgValidity & psiInner->ulMsgValidity));
  3365. psiInner->ulMsgValidity |= psiOuter->ulMsgValidity;
  3366. if (psiOuter->dwMsgEnhancement & MST_SIGN_MASK) {
  3367. // Duplicate the stores
  3368. if (psiOuter->cStores) {
  3369. psiInner->rgStores = (HCERTSTORE*)
  3370. g_pMoleAlloc->Alloc(psiOuter->cStores * sizeof(HCERTSTORE));
  3371. if (psiOuter->rgStores) {
  3372. for (DWORD i = 0; i < psiOuter->cStores; i++) {
  3373. psiInner->rgStores[i] = CertDuplicateStore(psiOuter->rgStores[i]);
  3374. }
  3375. psiInner->cStores = psiOuter->cStores;
  3376. }
  3377. }
  3378. }
  3379. psiInner->dwMsgEnhancement |= psiOuter->dwMsgEnhancement;
  3380. // Before I link in this new list, I'd like to do some error checking. In particular, I
  3381. // want to aviod loops and duplicates in my linked list.
  3382. psldLoopOuter = psiOuter->psldLayers;
  3383. while (psldLoopOuter) {
  3384. psldLoopInner = psiInner->psldLayers;
  3385. while (psldLoopInner) {
  3386. if (psldLoopInner == psldLoopOuter) {
  3387. AssertSz(FALSE, "MergeSMIMEINFOs found duplicate layer data");
  3388. // OK, we'll just ignore the outer layer data.
  3389. goto exit;
  3390. }
  3391. psldLoopInner = psldLoopInner->m_psldInner;
  3392. }
  3393. psldLoopOuter = psldLoopOuter->m_psldInner;
  3394. }
  3395. // Insert the outer layer data list at the head of the inner list.
  3396. psldLoopInner = psiInner->psldLayers;
  3397. psldLoopOuter = psiOuter->psldLayers;
  3398. psiInner->psldLayers = psldLoopOuter;
  3399. if (psldLoopOuter) {
  3400. // We've linked it into another SMIMEINFO, AddRef.
  3401. psldLoopOuter->AddRef();
  3402. // Walk the Outer list to find the end.
  3403. while (psldLoopOuter) {
  3404. if (! psldLoopOuter->m_psldInner) {
  3405. // Found end of list. Tack on original inner list here.
  3406. psldLoopOuter->m_psldInner = psldLoopInner;
  3407. // Hook up the Outer link
  3408. Assert(! psldLoopInner->m_psldOuter);
  3409. psldLoopInner->m_psldOuter = psldLoopOuter;
  3410. break;
  3411. }
  3412. psldLoopOuter = psldLoopOuter->m_psldInner;
  3413. }
  3414. }
  3415. // Make sure we bring the encryption layer with us.
  3416. if (psiOuter->psldEncrypt) {
  3417. Assert(! psiInner->psldEncrypt);
  3418. if (! psiInner->psldEncrypt) {
  3419. psiInner->psldEncrypt = psiOuter->psldEncrypt;
  3420. }
  3421. }
  3422. // Update the inner layer pointer (in case there was none before)
  3423. if (! psiInner->psldInner) {
  3424. psiInner->psldInner = psiOuter->psldInner;
  3425. }
  3426. psiInner->ulLayers += psiOuter->ulLayers;
  3427. exit:
  3428. return;
  3429. }
  3430. #endif // KILL_THIS?
  3431. #ifndef SMIME_V3
  3432. // Bitfield for dw below
  3433. #define CAA_SIGNING_TIME 1
  3434. #define CAA_SMIME_CAPABILITIES 2
  3435. #define CAA_ALL (CAA_SIGNING_TIME | CAA_SMIME_CAPABILITIES)
  3436. /***************************************************************************
  3437. Name : ConstructAuthAttributes
  3438. Purpose : crack open the authenticated attributes blobs and check
  3439. if there is a signing time specified. If not, we must
  3440. add one. Ditto with the S/Mime Capabilities.
  3441. Parameters: pblEncoded -> return blob of encoded Authenticated Attributes
  3442. pblAuthAttr -> authenticated attribute blob
  3443. data pointer may be replaced
  3444. pftSigntime -> signing time
  3445. pblSymcaps -> symcaps blob
  3446. Returns : HRESULT
  3447. Comment : The caller should be careful not to cache the
  3448. data pointer within the authenticated attributes blob since
  3449. it may be freed in here and replaced with a different one.
  3450. ***************************************************************************/
  3451. static HRESULT ConstructAuthAttributes(BLOB * pblEncoded, BLOB * pblAuthAttr, FILETIME * pftSigntime, BLOB * pblSymcaps)
  3452. {
  3453. HRESULT hr = S_OK;
  3454. ULONG cbData;
  3455. ULONG i;
  3456. DWORD dw; // bitfield: CAA_SIGNING_TIME, CAA_SMIME_CAPABILITIES
  3457. PCRYPT_ATTRIBUTES pattrs = NULL;
  3458. BOOL fpattrs = FALSE;
  3459. PCRYPT_ATTRIBUTE pattr = NULL;
  3460. LPBYTE pbSignTime = NULL;
  3461. LPBYTE pbAttr = NULL;
  3462. CRYPT_ATTRIBUTES attrs;
  3463. CRYPT_ATTR_BLOB valCaps;
  3464. CRYPT_ATTR_BLOB valTime;
  3465. Assert(pblAuthAttr);
  3466. Assert(pftSigntime);
  3467. Assert(pblSymcaps);
  3468. Assert(pblEncoded);
  3469. if ((pblAuthAttr->cbSize > 0) &&
  3470. ((! HrDecodeObject(pblAuthAttr->pBlobData, pblAuthAttr->cbSize,
  3471. szOID_Microsoft_Attribute_Sequence,
  3472. 0, &cbData, (LPVOID *)&pattrs)) && pattrs)) {
  3473. fpattrs = TRUE; // don't forget to free pattrs!
  3474. for (i = 0, dw = CAA_ALL; i < pattrs->cAttr; i++) {
  3475. if (lstrcmp(pattrs->rgAttr[i].pszObjId, szOID_RSA_signingTime) == 0) {
  3476. dw &= ~CAA_SIGNING_TIME;
  3477. }
  3478. else if (lstrcmp(pattrs->rgAttr[i].pszObjId, szOID_RSA_SMIMECapabilities) == 0) {
  3479. dw &= ~CAA_SMIME_CAPABILITIES;
  3480. }
  3481. }
  3482. } else {
  3483. // BUGBUG: Should probably report the error if MemAlloc failed. As it sits, there is no
  3484. // real harm except that the message will go out without a signing time and symcaps.
  3485. dw = CAA_ALL;
  3486. pattrs = &attrs;
  3487. attrs.cAttr = 0;
  3488. attrs.rgAttr = NULL;
  3489. }
  3490. if (MemAlloc((LPVOID *)&pattr, (pattrs->cAttr + 2) * sizeof(CRYPT_ATTRIBUTE))) {
  3491. memcpy(pattr, pattrs->rgAttr, pattrs->cAttr * sizeof(CRYPT_ATTRIBUTE));
  3492. pattrs->rgAttr = pattr;
  3493. //
  3494. // The default answer does not have a signing time in it. We are going
  3495. // to create and add a signing time. This may come from either
  3496. // a passed in parameter, or from the system.
  3497. if (dw & CAA_SIGNING_TIME) {
  3498. if ((pftSigntime->dwLowDateTime == 0) &&
  3499. (pftSigntime->dwHighDateTime == 0)) {
  3500. GetSystemTimeAsFileTime(pftSigntime); // caller sees it now!
  3501. }
  3502. cbData = 0;
  3503. if (CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CHOICE_OF_TIME,
  3504. pftSigntime, CRYPT_ENCODE_ALLOC_FLAG,
  3505. &CryptEncodeAlloc, &pbSignTime, &cbData)) {
  3506. // BUGBUG: Should probably report the error if MemAlloc failed. As it sits, there is no
  3507. // real harm except that the message will go out without a signing time and symcaps.
  3508. pattr[pattrs->cAttr].pszObjId = szOID_RSA_signingTime;
  3509. pattr[pattrs->cAttr].cValue = 1;
  3510. pattr[pattrs->cAttr].rgValue = &valTime;
  3511. pattr[pattrs->cAttr].rgValue[0].pbData = pbSignTime;
  3512. pattr[pattrs->cAttr].rgValue[0].cbData = cbData;
  3513. pattrs->cAttr += 1;
  3514. }
  3515. }
  3516. if (dw & CAA_SMIME_CAPABILITIES) {
  3517. if (pblSymcaps->cbSize > 0) {
  3518. pattr[pattrs->cAttr].pszObjId = szOID_RSA_SMIMECapabilities;
  3519. pattr[pattrs->cAttr].cValue = 1;
  3520. pattr[pattrs->cAttr].rgValue = &valCaps;
  3521. pattr[pattrs->cAttr].rgValue[0].pbData = pblSymcaps->pBlobData;
  3522. pattr[pattrs->cAttr].rgValue[0].cbData = pblSymcaps->cbSize;
  3523. pattrs->cAttr += 1;
  3524. }
  3525. }
  3526. cbData = 0;
  3527. if (CryptEncodeObjectEx(X509_ASN_ENCODING, szOID_Microsoft_Attribute_Sequence,
  3528. pattrs, CRYPT_ENCODE_ALLOC_FLAG,
  3529. &CryptEncodeAlloc, &pbAttr, &cbData)) {
  3530. hr = HrGetLastError();
  3531. goto exit;
  3532. }
  3533. pblEncoded->cbSize = cbData;
  3534. pblEncoded->pBlobData = pbAttr;
  3535. pbAttr = NULL; // Drop this pointer so that it won't be freed below
  3536. } else {
  3537. hr = E_OUTOFMEMORY;
  3538. }
  3539. exit:
  3540. SafeMemFree(pattr);
  3541. if (fpattrs) {
  3542. SafeMemFree(pattrs);
  3543. }
  3544. SafeMemFree(pbSignTime);
  3545. return(hr);
  3546. }
  3547. #endif // !SMIME_V3
  3548. /***************************************************************************
  3549. Name : IsSMimeProtocol
  3550. Purpose : Test if the protocol type of this root message body is
  3551. application/x-pkcs7-signature
  3552. Parameters: lpPropSet -> Property set of message
  3553. Returns : TRUE if this is an S/MIME protocol message
  3554. Comment : Used to differentiate between S/MIME and PGP signatures.
  3555. ***************************************************************************/
  3556. BOOL IsSMimeProtocol(LPMIMEPROPERTYSET lpPropSet) {
  3557. PROPVARIANT var;
  3558. BOOL fReturn = FALSE;
  3559. var.vt = VT_LPSTR;
  3560. if (SUCCEEDED(lpPropSet->GetProp(
  3561. STR_PAR_PROTOCOL,
  3562. 0, // [in] DWORD dwFlags,
  3563. &var))) {
  3564. if (var.pszVal) {
  3565. fReturn = (! lstrcmpi(var.pszVal, STR_MIME_APPL_PKCS7SIG)) ||
  3566. (! lstrcmpi(var.pszVal, STR_MIME_APPL_PKCS7SIG_1));
  3567. SafeMemFree(var.pszVal);
  3568. }
  3569. }
  3570. return(fReturn);
  3571. }
  3572. /***************************************************************************
  3573. Name : DuplicateMemory
  3574. Purpose : Allocate a new buffer and copy the old one into it.
  3575. Parameters: lpbIn -> Existing buffer
  3576. cbIn = size of lpvIn
  3577. Returns : new MemAlloc'ed buffer
  3578. Comment : Caller is responsible for MemFree'ing the returned buffer.
  3579. ***************************************************************************/
  3580. LPBYTE DuplicateMemory(LPBYTE lpvIn, ULONG cbIn) {
  3581. LPBYTE lpbReturn = NULL;
  3582. if (MemAlloc((void**)&lpbReturn, cbIn)) {
  3583. memcpy(lpbReturn, lpvIn, cbIn);
  3584. }
  3585. return(lpbReturn);
  3586. }
  3587. //*************************************************************************
  3588. // CSECURITY_LAYER_DATA
  3589. //*************************************************************************
  3590. ///////////////////////////////////////////////////////////////////////////
  3591. //
  3592. // ctor/dtor
  3593. //
  3594. CSECURITY_LAYER_DATA::CSECURITY_LAYER_DATA(void)
  3595. {
  3596. m_cRef = 1;
  3597. DOUT("CSECURITY_LAYER_DATA::constructor() %#x -> %d", this, m_cRef);
  3598. m_dwMsgEnhancement = MST_NONE;
  3599. m_fCertInLayer = FALSE;
  3600. m_cSigners = 0;
  3601. m_rgSigners = NULL;
  3602. m_cEncryptItems = 0;
  3603. #ifdef SMIME_V3
  3604. m_rgRecipientInfo = NULL;
  3605. m_ContentEncryptAlgorithm.pszObjId = NULL;
  3606. m_ContentEncryptAlgorithm.Parameters.cbData = 0;
  3607. m_ContentEncryptAlgorithm.Parameters.pbData = NULL;
  3608. m_pvEncryptAuxInfo = NULL;
  3609. m_blobUnprotectAttrs.pbData = NULL;
  3610. m_blobUnprotectAttrs.cbData = 0;
  3611. m_hstoreEncrypt = NULL;
  3612. #else // !SMIME_V3
  3613. m_rgEncryptItems = NULL;
  3614. #endif // SMIME_V3
  3615. m_ulDecValidity = 0;
  3616. m_blobDecAlg.cbSize = 0;
  3617. m_blobDecAlg.pBlobData = NULL;
  3618. m_pccertDecrypt = NULL;
  3619. m_hcertstor = NULL;
  3620. m_psldInner = NULL;
  3621. m_psldOuter = NULL;
  3622. }
  3623. CSECURITY_LAYER_DATA::~CSECURITY_LAYER_DATA(void)
  3624. {
  3625. DWORD i;
  3626. DWORD i1;
  3627. DWORD iSigner;
  3628. DOUT("CSECURITY_LAYER_DATA::destructor() %#x -> %d", this, m_cRef);
  3629. if (m_psldInner != NULL) {
  3630. m_psldInner->Release();
  3631. }
  3632. if (m_hcertstor != NULL) CertCloseStore(m_hcertstor, 0);
  3633. if (m_pccertDecrypt != NULL) CertFreeCertificateContext(m_pccertDecrypt);
  3634. SafeMemFree(m_blobDecAlg.pBlobData);
  3635. for (iSigner=0; iSigner<m_cSigners; iSigner++) {
  3636. if (m_rgSigners[iSigner].pccert != NULL)
  3637. CertFreeCertificateContext(m_rgSigners[iSigner].pccert);
  3638. SafeMemFree(m_rgSigners[iSigner].blobHashAlg.pBlobData);
  3639. SafeMemFree(m_rgSigners[iSigner].blobAuth.pBlobData);
  3640. SafeMemFree(m_rgSigners[iSigner].blobUnauth.pBlobData);
  3641. #ifdef SMIME_V3
  3642. SafeMemFree(m_rgSigners[iSigner].blobReceipt.pBlobData);
  3643. SafeMemFree(m_rgSigners[iSigner].blobHash.pBlobData);
  3644. #endif // SMIME_V3
  3645. }
  3646. SafeMemFree(m_rgSigners);
  3647. for (i=0; i<m_cEncryptItems; i++) {
  3648. #ifdef SMIME_V3
  3649. switch (m_rgRecipientInfo[i].dwRecipientChoice) {
  3650. case CMSG_KEY_TRANS_RECIPIENT:
  3651. if (m_rgRecipientInfo[i].pKeyTrans->KeyEncryptionAlgorithm.pszObjId != 0) {
  3652. MemFree(m_rgRecipientInfo[i].pKeyTrans->KeyEncryptionAlgorithm.pszObjId);
  3653. MemFree(m_rgRecipientInfo[i].pKeyTrans->KeyEncryptionAlgorithm.Parameters.pbData);
  3654. }
  3655. if (m_rgRecipientInfo[i].pKeyTrans->pvKeyEncryptionAuxInfo != NULL) {
  3656. MemFree(m_rgRecipientInfo[i].pKeyTrans->pvKeyEncryptionAuxInfo);
  3657. }
  3658. if (m_rgRecipientInfo[i].pKeyTrans->RecipientPublicKey.cbData != 0) {
  3659. MemFree(m_rgRecipientInfo[i].pKeyTrans->RecipientPublicKey.pbData);
  3660. }
  3661. if (m_rgRecipientInfo[i].pKeyTrans->RecipientId.dwIdChoice == CERT_ID_KEY_IDENTIFIER)
  3662. {
  3663. if (m_rgRecipientInfo[i].pKeyTrans->RecipientId.KeyId.cbData != 0) {
  3664. MemFree(m_rgRecipientInfo[i].pKeyTrans->RecipientId.KeyId.pbData);
  3665. }
  3666. }
  3667. else if (m_rgRecipientInfo[i].pKeyTrans->RecipientId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
  3668. {
  3669. if (m_rgRecipientInfo[i].pKeyTrans->RecipientId.IssuerSerialNumber.Issuer.cbData != 0) {
  3670. MemFree(m_rgRecipientInfo[i].pKeyTrans->RecipientId.IssuerSerialNumber.Issuer.pbData);
  3671. }
  3672. if (m_rgRecipientInfo[i].pKeyTrans->RecipientId.IssuerSerialNumber.SerialNumber.cbData != 0) {
  3673. MemFree(m_rgRecipientInfo[i].pKeyTrans->RecipientId.IssuerSerialNumber.SerialNumber.pbData);
  3674. }
  3675. }
  3676. SafeMemFree(m_rgRecipientInfo[i].pKeyTrans);
  3677. break;
  3678. case CMSG_MAIL_LIST_RECIPIENT:
  3679. if (m_rgRecipientInfo[i].pMailList->KeyEncryptionAlgorithm.pszObjId != 0) {
  3680. MemFree(m_rgRecipientInfo[i].pMailList->KeyEncryptionAlgorithm.pszObjId);
  3681. MemFree(m_rgRecipientInfo[i].pMailList->KeyEncryptionAlgorithm.Parameters.pbData);
  3682. }
  3683. if (m_rgRecipientInfo[i].pMailList->pvKeyEncryptionAuxInfo != NULL) {
  3684. MemFree(m_rgRecipientInfo[i].pMailList->pvKeyEncryptionAuxInfo);
  3685. }
  3686. if (m_rgRecipientInfo[i].pMailList->pOtherAttr != NULL) {
  3687. MemFree(m_rgRecipientInfo[i].pMailList->pOtherAttr->pszObjId);
  3688. MemFree(m_rgRecipientInfo[i].pMailList->pOtherAttr->Value.pbData);
  3689. }
  3690. SafeMemFree(m_rgRecipientInfo[i].pMailList);
  3691. break;
  3692. case CMSG_KEY_AGREE_RECIPIENT:
  3693. if (m_rgRecipientInfo[i].pKeyAgree->KeyEncryptionAlgorithm.pszObjId != 0) {
  3694. MemFree(m_rgRecipientInfo[i].pKeyAgree->KeyEncryptionAlgorithm.pszObjId);
  3695. MemFree(m_rgRecipientInfo[i].pKeyAgree->KeyEncryptionAlgorithm.Parameters.pbData);
  3696. }
  3697. if (m_rgRecipientInfo[i].pKeyAgree->pvKeyEncryptionAuxInfo != NULL) {
  3698. MemFree(m_rgRecipientInfo[i].pKeyAgree->pvKeyEncryptionAuxInfo);
  3699. }
  3700. SafeMemFree(m_rgRecipientInfo[i].pKeyAgree);
  3701. break;
  3702. default:
  3703. Assert(FALSE);
  3704. break;
  3705. }
  3706. #else // SMIME_V3
  3707. SafeMemFree(m_rgEncryptItems[i].Transport.blobAlg.pBlobData);
  3708. switch (m_rgEncryptItems[i].dwTagType) {
  3709. case ENCRYPT_ITEM_TRANSPORT:
  3710. for (i1=0; i1<m_rgEncryptItems[i].Transport.cCert; i1++) {
  3711. CertFreeCertificateContext(m_rgEncryptItems[i].Transport.rgpccert[i1]);
  3712. }
  3713. SafeMemFree(m_rgEncryptItems[i].Transport.rgpccert);
  3714. break;
  3715. default:
  3716. Assert(FALSE);
  3717. break;
  3718. }
  3719. #endif // SMIME_V3
  3720. }
  3721. #ifdef SMIME_V3
  3722. SafeMemFree(m_rgRecipientInfo);
  3723. SafeMemFree(m_pvEncryptAuxInfo);
  3724. SafeMemFree(m_ContentEncryptAlgorithm.pszObjId);
  3725. SafeMemFree(m_ContentEncryptAlgorithm.Parameters.pbData);
  3726. SafeMemFree(m_blobUnprotectAttrs.pbData);
  3727. CertCloseStore(m_hstoreEncrypt, 0);
  3728. #else // SMIME_V3
  3729. SafeMemFree(m_rgEncryptItems);
  3730. #endif // SMIME_V3
  3731. }
  3732. ///////////////////////////////////////////////////////////////////////////
  3733. //
  3734. // IUnknown methods
  3735. //
  3736. STDMETHODIMP CSECURITY_LAYER_DATA::QueryInterface(REFIID riid, LPVOID *ppv)
  3737. {
  3738. if (!ppv)
  3739. return TrapError(E_INVALIDARG);
  3740. // Find IID
  3741. if (IID_IUnknown == riid) {
  3742. *ppv = THIS_AS_UNK;
  3743. }
  3744. else if (IID_IStream == riid) {
  3745. *ppv = (IStream *)this;
  3746. }
  3747. else {
  3748. *ppv = NULL;
  3749. return E_NOINTERFACE;
  3750. }
  3751. ((IUnknown *)*ppv)->AddRef();
  3752. return S_OK;
  3753. }
  3754. STDMETHODIMP_(ULONG) CSECURITY_LAYER_DATA::AddRef(void)
  3755. {
  3756. DOUT("CSECURITY_LAYER_DATA::AddRef() %#x -> %d", this, m_cRef+1);
  3757. InterlockedIncrement((LPLONG)&m_cRef);
  3758. return m_cRef;
  3759. }
  3760. STDMETHODIMP_(ULONG) CSECURITY_LAYER_DATA::Release(void)
  3761. {
  3762. DOUT("CSECURITY_LAYER_DATA::Release() %#x -> %d", this, m_cRef-1);
  3763. if (0 == InterlockedDecrement((LPLONG)&m_cRef)) {
  3764. delete this;
  3765. return 0;
  3766. }
  3767. return m_cRef;
  3768. }
  3769. #ifdef SMIME_V3
  3770. /*** HrCopyOID
  3771. *
  3772. * Description:
  3773. * General utility function to make copying of recipient info objects much easier
  3774. */
  3775. HRESULT HrCopyOID(LPCSTR psz, LPSTR * ppsz)
  3776. {
  3777. DWORD cb;
  3778. HRESULT hr = S_OK;
  3779. cb = strlen(psz) + 1;
  3780. CHECKHR(hr = HrAlloc((void **) ppsz, cb));
  3781. memcpy(*ppsz, psz, cb);
  3782. exit:
  3783. return hr;
  3784. }
  3785. /*** HrCopyCryptDataBlob
  3786. *
  3787. * Description:
  3788. * General utility function to make copying of recipient info objects much easier
  3789. */
  3790. HRESULT HrCopyCryptDataBlob(const CRYPT_DATA_BLOB * pblobSrc, PCRYPT_DATA_BLOB pblobDst)
  3791. {
  3792. HRESULT hr = S_OK;
  3793. if (pblobSrc->cbData == 0) {
  3794. Assert(pblobDst->pbData == NULL);
  3795. Assert(pblobDst->cbData == 0);
  3796. goto exit;
  3797. }
  3798. CHECKHR(hr = HrAlloc((void **) &pblobDst->pbData, pblobSrc->cbData));
  3799. memcpy(pblobDst->pbData, pblobSrc->pbData, pblobSrc->cbData);
  3800. pblobDst->cbData = pblobSrc->cbData;
  3801. exit:
  3802. return hr;
  3803. }
  3804. /*** HrCopyCryptDataBlob
  3805. *
  3806. * Description:
  3807. * General utility function to make copying of recipient info objects much easier
  3808. */
  3809. HRESULT HrCopyCryptBitBlob(const CRYPT_BIT_BLOB * pblobSrc, PCRYPT_BIT_BLOB pblobDst)
  3810. {
  3811. HRESULT hr = S_OK;
  3812. if (pblobSrc->cbData == 0) {
  3813. Assert(pblobDst->pbData == NULL);
  3814. Assert(pblobDst->cbData == 0);
  3815. goto exit;
  3816. }
  3817. CHECKHR(hr = HrAlloc((void **) &pblobDst->pbData, pblobSrc->cbData));
  3818. memcpy(pblobDst->pbData, pblobSrc->pbData, pblobSrc->cbData);
  3819. pblobDst->cbData = pblobSrc->cbData;
  3820. pblobDst->cUnusedBits = pblobSrc->cUnusedBits;
  3821. exit:
  3822. return hr;
  3823. }
  3824. HRESULT HrCopyCryptAlgorithm(const CRYPT_ALGORITHM_IDENTIFIER * pAlgSrc,
  3825. PCRYPT_ALGORITHM_IDENTIFIER pAlgDst)
  3826. {
  3827. HRESULT hr = S_OK;
  3828. CHECKHR(hr = HrCopyOID(pAlgSrc->pszObjId, &pAlgDst->pszObjId));
  3829. if (pAlgSrc->Parameters.cbData != 0) {
  3830. CHECKHR(hr = HrCopyCryptDataBlob(&pAlgSrc->Parameters, &pAlgDst->Parameters));
  3831. }
  3832. exit:
  3833. return hr;
  3834. }
  3835. HRESULT HrCopyCertId(const CERT_ID * pcertidSrc, PCERT_ID pcertidDst)
  3836. {
  3837. HRESULT hr = S_OK;
  3838. pcertidDst->dwIdChoice = pcertidSrc->dwIdChoice;
  3839. switch (pcertidSrc->dwIdChoice) {
  3840. case CERT_ID_ISSUER_SERIAL_NUMBER:
  3841. hr = HrCopyCryptDataBlob(&pcertidSrc->IssuerSerialNumber.Issuer,
  3842. &pcertidDst->IssuerSerialNumber.Issuer);
  3843. hr = HrCopyCryptDataBlob(&pcertidSrc->IssuerSerialNumber.SerialNumber,
  3844. &pcertidDst->IssuerSerialNumber.SerialNumber);
  3845. break;
  3846. case CERT_ID_KEY_IDENTIFIER:
  3847. hr = HrCopyCryptDataBlob(&pcertidSrc->HashId, &pcertidDst->HashId);
  3848. break;
  3849. case CERT_ID_SHA1_HASH:
  3850. hr = HrCopyCryptDataBlob(&pcertidSrc->HashId, &pcertidDst->HashId);
  3851. break;
  3852. default:
  3853. return E_FAIL;
  3854. }
  3855. return hr;
  3856. }
  3857. /*** FreeRecipientInfo
  3858. *
  3859. * Description:
  3860. * Free all of the data pointed to by the recipient info as well as the recipient
  3861. * info object itself.
  3862. */
  3863. void FreeRecipientInfoContent(PCMS_RECIPIENT_INFO pRecipInfo)
  3864. {
  3865. if (pRecipInfo->pccert != NULL) {
  3866. CertFreeCertificateContext(pRecipInfo->pccert);
  3867. }
  3868. if (pRecipInfo->KeyEncryptionAlgorithm.pszObjId != 0) {
  3869. MemFree(pRecipInfo->KeyEncryptionAlgorithm.pszObjId);
  3870. MemFree(pRecipInfo->KeyEncryptionAlgorithm.Parameters.pbData);
  3871. }
  3872. if (pRecipInfo->pvKeyEncryptionAuxInfo != NULL) {
  3873. MemFree(pRecipInfo->pvKeyEncryptionAuxInfo);
  3874. }
  3875. if ((pRecipInfo->dwU1 == CMS_RECIPIENT_INFO_PUBKEY_KEYTRANS) &&
  3876. (pRecipInfo->u1.SubjectPublicKey.cbData != 0)) {
  3877. MemFree(pRecipInfo->u1.SubjectPublicKey.pbData);
  3878. }
  3879. if (pRecipInfo->dwU1 == CMS_RECIPIENT_INFO_PUBKEY_PROVIDER) {
  3880. Assert(FALSE);
  3881. }
  3882. if (pRecipInfo->dwU3 == CMS_RECIPIENT_INFO_KEYID_ISSUERSERIAL) {
  3883. if (pRecipInfo->u3.IssuerSerial.Issuer.cbData != 0) {
  3884. MemFree(pRecipInfo->u3.IssuerSerial.Issuer.pbData);
  3885. }
  3886. if (pRecipInfo->u3.IssuerSerial.SerialNumber.cbData != 0) {
  3887. MemFree(pRecipInfo->u3.IssuerSerial.SerialNumber.pbData);
  3888. }
  3889. }
  3890. if (pRecipInfo->dwU3 == CMS_RECIPIENT_INFO_KEYID_KEY_ID) {
  3891. if (pRecipInfo->u3.KeyId.cbData != 0) {
  3892. MemFree(pRecipInfo->u3.KeyId.pbData);
  3893. }
  3894. }
  3895. if (pRecipInfo->pOtherAttr != NULL) {
  3896. MemFree(pRecipInfo->pOtherAttr->pszObjId);
  3897. MemFree(pRecipInfo->pOtherAttr->Value.pbData);
  3898. }
  3899. return;
  3900. }
  3901. #endif // SMIME_V3
  3902. /* * * END --- SMIME.CPP --- END * * */