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.

3910 lines
132 KiB

  1. /*
  2. ** capistm.cpp
  3. **
  4. ** Purpose:
  5. ** Implementation of a class to wrap around CAPI functionality
  6. **
  7. ** History
  8. ** 1/26/98; (brucek) triple wrap support
  9. ** 2/07/97: (t-erikne) multipart/signed
  10. ** 1/06/97: (t-erikne) Moved into MimeOLE
  11. ** 11/14/96: (t-erikne) CAPI Post-SDR work
  12. ** 8/27/96: (t-erikne) Created.
  13. **
  14. ** Copyright (C) Microsoft Corp. 1996-1998.
  15. */
  16. ///////////////////////////////////////////////////////////////////////////
  17. //
  18. // Depends on
  19. //
  20. #include "pch.hxx"
  21. #include <wincrypt.h>
  22. #include "olealloc.h"
  23. #include "containx.h"
  24. #include "smime.h"
  25. #include "capistm.h"
  26. #include "mimeapi.h"
  27. #include "inetconv.h"
  28. #include <capiutil.h>
  29. #ifndef MAC
  30. #include <shlwapi.h>
  31. #endif // !MAC
  32. #include <demand.h>
  33. #include "strconst.h"
  34. #include "smimepol.h"
  35. BOOL FHideMsgWithDifferentLabels();
  36. enum ECertErrorProcessLabel {
  37. CertErrorProcessLabelAnyway = 0,
  38. CertErrorProcessLabelGrant = 1,
  39. CertErrorProcessLabelDeny = 2
  40. };
  41. DWORD DwProcessLabelWithCertError();
  42. HRESULT HrCheckLabelAccess(const DWORD dwFlags, const HWND hwnd,
  43. PSMIME_SECURITY_LABEL plabel, const PCCERT_CONTEXT pccertDecrypt,
  44. const PCCERT_CONTEXT pccertSigner, const HCERTSTORE hcertstor);
  45. #ifdef MAC
  46. #undef CertOpenStore
  47. EXTERN_C WINCRYPT32API HCERTSTORE WINAPI MacCertOpenStore(LPCSTR lpszStoreProvider,
  48. DWORD dwEncodingType,
  49. HCRYPTPROV hCryptProv,
  50. DWORD dwFlags,
  51. const void *pvPara);
  52. #define CertOpenStore MacCertOpenStore
  53. #endif // MAC
  54. // from dllmain.h
  55. extern DWORD g_dwSysPageSize;
  56. extern CMimeAllocator * g_pMoleAlloc;
  57. extern ULONG DllAddRef(void);
  58. extern ULONG DllRelease(void);
  59. extern void DebugDumpStreamToFile(LPSTREAM pstm, LPSTR lpszFile);
  60. // From smime.cpp
  61. extern HRESULT HrGetLastError(void);
  62. extern BOOL FIsMsasn1Loaded();
  63. #ifdef WIN16
  64. #define CRYPT_ACQUIRE_CONTEXT CryptAcquireContextA
  65. #else
  66. #define CRYPT_ACQUIRE_CONTEXT CryptAcquireContextW
  67. #endif
  68. ///////////////////////////////////////////////////////////////////////////
  69. //
  70. // defines
  71. //
  72. #define THIS_AS_UNK ((IUnknown *)(IStream *)this)
  73. #define CS_E_CANT_DECRYPT MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x2414)
  74. #define CS_E_MSG_INVALID MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x2415)
  75. const int CbCacheBufferSize = 4 * 1024;
  76. ///////////////////////////////////////////////////////////////////////////
  77. //
  78. // inlines
  79. //
  80. static INLINE void ReleaseCert(PCCERT_CONTEXT pc)
  81. { if (pc) CertFreeCertificateContext(pc); }
  82. // Streaming state diagram
  83. //
  84. // SF GT SD-FW-TN-SO-SF
  85. // | | /[encryption]
  86. // SO QT-------------------
  87. // [op encode] \ / [opaque decode] \[signed]
  88. // ------NB------ (FW-TN)-SO-SF
  89. // [det encode] / \ [detached decode]
  90. // DO DO
  91. // | \
  92. // SF DF
  93. // |
  94. // SO
  95. // |
  96. // SF
  97. //
  98. //
  99. // New state diagram:
  100. // encrypt
  101. // SD--SO
  102. // opaque encode opaque decode /
  103. // SO QT--------------------[QTF]---
  104. // \ / \
  105. // ---NB----- SO signed
  106. // / \
  107. // SO---DO DO ------------------ SO
  108. // detach encode detach decode
  109. //
  110. //
  111. #ifndef WIN16
  112. enum CSstate {
  113. STREAM_NOT_BEGUN,
  114. STREAM_QUESTION_TIME,
  115. STREAM_QUESTION_TIME_FINAL,
  116. STREAM_SETUP_DECRYPT,
  117. STREAM_DETACHED_OCCURING,
  118. STREAM_OCCURING, // must be +1 of DF
  119. STREAM_ERROR,
  120. STREAM_GOTTYPE,
  121. CSTM_FIRST_WRITE = 32,
  122. CSTM_TEST_NESTING,
  123. CSTM_STREAMING,
  124. CSTM_STREAMING_DONE,
  125. CSTM_GOTTYPE,
  126. };
  127. #endif // !WIN16
  128. // low word is public. see .h file.
  129. #define CSTM_DECODE 0x00010000
  130. #define CSTM_DONTRELEASEPROV 0x00020000
  131. #define CSTM_RECURSED 0x00040000
  132. #define CSTM_HAVECR 0x10000000
  133. #define CSTM_HAVEEOL 0x20000000
  134. static const char s_cszMy[] = "My";
  135. static const char s_cszWABCertStore[] = "AddressBook";
  136. static const char s_cszCA[] = "CA";
  137. static const char s_cszMimeHeader[] = "Content-Type: application/x-pkcs7-mime"
  138. "; name=smime.p7m; smime-type=";
  139. static const char s_cszMimeHeader2[] = "Content-Disposition: attachment; "
  140. "filename=smime.p7m";
  141. static const char s_cszOIDMimeHeader1[] = "Content-Type: oid/";
  142. static const char s_cszOIDMimeHeader2[] = "\nContent-Transfer-Encoding: binary\n\n";
  143. ///////////////////////////////////////////////////////////////////////////
  144. //
  145. // static prototypes
  146. //
  147. #if 0
  148. #define IV_LENGTH 8
  149. static BOOL _GetIV(BYTE rgbIV[IV_LENGTH]);
  150. static PBYTE _PVEncodeObject(
  151. LPCSTR lpszStructType,
  152. const void *pvStructInfo,
  153. DWORD *pcbEncoded);
  154. #endif
  155. static HRESULT _InitEncodedCert(IN HCERTSTORE hcertstor,
  156. OUT PCERT_BLOB * rgblobCert, OUT DWORD * pcCerts,
  157. OUT PCRL_BLOB * rgblobCRL, OUT DWORD * pcCrl);
  158. static HRESULT _InitEncodedCertIncludingSigners(IN HCERTSTORE hcertstor,
  159. DWORD cSigners, SignerData rgSigners[],
  160. PCERT_BLOB * prgblobCerts, DWORD * pcCerts,
  161. PCRL_BLOB * prgblobCrls, DWORD * pcCrl);
  162. static void _SMimeCapsFromHMsg(HCRYPTMSG, DWORD id, LPBYTE * ppb, DWORD * pcb);
  163. // ---------------------------- UTILITY FUNCTIONS --------------------------
  164. HRESULT GetParameters(PCCERT_CONTEXT pccert, HCERTSTORE hstoreMsg,
  165. HCERTSTORE hstoreAll)
  166. {
  167. CRYPT_DATA_BLOB blob;
  168. DWORD dw;
  169. HRESULT hr = CRYPT_E_MISSING_PUBKEY_PARA;
  170. PCCERT_CONTEXT pccertX;
  171. //
  172. // Start by looking for the issuer certificate on your own. All that
  173. // matters is that we find a certificate which claims to be the issuer
  174. // and has parameters -- they will need to verify the parameters are
  175. // correct at a later date.
  176. //
  177. pccertX = NULL;
  178. while (hstoreMsg != NULL) {
  179. //
  180. // Find certificates by matching issuers -- ok for now as PKIX requires
  181. // all issuers to have DNs
  182. //
  183. dw = CERT_STORE_SIGNATURE_FLAG;
  184. pccertX = CertGetIssuerCertificateFromStore(hstoreMsg, pccert, pccertX,
  185. &dw);
  186. if (pccertX == NULL) {
  187. if (::GetLastError() == CRYPT_E_SELF_SIGNED) {
  188. return S_OK;
  189. }
  190. break;
  191. }
  192. //
  193. // Only accept the item if we manage a signature validation on it.
  194. //
  195. if ((dw & CERT_STORE_SIGNATURE_FLAG)) {
  196. //
  197. // We can't verify the signature, so get the issuers paramters and try again
  198. //
  199. hr = GetParameters(pccertX, hstoreMsg, hstoreAll);
  200. if (FAILED(hr)) {
  201. continue;
  202. }
  203. //
  204. // The issuing cert has parameters, try the signature check again againist it.
  205. //
  206. dw = CERT_STORE_SIGNATURE_FLAG;
  207. if (CertVerifySubjectCertificateContext(pccert, pccertX, &dw) && (dw == 0)) {
  208. break;
  209. }
  210. hr = CRYPT_E_MISSING_PUBKEY_PARA;
  211. }
  212. else {
  213. if (pccertX->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData != 0) {
  214. hr = 0;
  215. break;
  216. }
  217. //
  218. // If we found one but it does not have the parameters, it must be
  219. // inheriting from it's issuer as well.
  220. //
  221. dw = CERT_STORE_SIGNATURE_FLAG;
  222. if (CertVerifySubjectCertificateContext(pccert, pccertX, &dw) && (dw == 0)) {
  223. hr = 0;
  224. break;
  225. }
  226. }
  227. }
  228. //
  229. // If we still do not have a certificate, then search all of the system stores
  230. // for an isuer.
  231. //
  232. if (pccertX == NULL) {
  233. while (hstoreAll != NULL) {
  234. //
  235. // Find certificates by matching issuers -- ok for now as PKIX requires
  236. // all issuers to have DNs
  237. //
  238. dw = CERT_STORE_SIGNATURE_FLAG;
  239. pccertX = CertGetIssuerCertificateFromStore(hstoreAll, pccert, pccertX,
  240. &dw);
  241. if (pccertX == NULL) {
  242. if (::GetLastError() == CRYPT_E_SELF_SIGNED) {
  243. return S_OK;
  244. }
  245. break;
  246. }
  247. //
  248. // Only accept the item if we manage a signature validation on it.
  249. //
  250. if ((dw & CERT_STORE_SIGNATURE_FLAG)) {
  251. //
  252. // We can't verify the signature, so get the issuers paramters and try again
  253. //
  254. hr = GetParameters(pccertX, hstoreMsg, hstoreAll);
  255. if (FAILED(hr)) {
  256. continue;
  257. }
  258. //
  259. // The issuing cert has parameters, try the signature check again againist it.
  260. //
  261. dw = CERT_STORE_SIGNATURE_FLAG;
  262. if (CertVerifySubjectCertificateContext(pccert, pccertX, &dw) && (dw == 0)) {
  263. break;
  264. }
  265. hr = CRYPT_E_MISSING_PUBKEY_PARA;
  266. }
  267. else {
  268. if (pccertX->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters.cbData != 0) {
  269. hr = 0;
  270. break;
  271. }
  272. //
  273. // If we found one but it does not have the parameters, it must be inheriting
  274. // from it's issuer as well.
  275. //
  276. dw = CERT_STORE_SIGNATURE_FLAG;
  277. if (CertVerifySubjectCertificateContext(pccert, pccertX, &dw) && (dw == 0)) {
  278. hr = 0;
  279. break;
  280. }
  281. }
  282. }
  283. }
  284. #if 0
  285. //
  286. // We found a certificate, set the parameters onto the context so that we
  287. // can successfully manage to validate the signature
  288. //
  289. if (pccertX != NULL) {
  290. CRYPT_DATA_BLOB * pdata = NULL;
  291. hr = HrGetCertificateParam(pccert, CERT_PUBKEY_ALG_PARA_PROP_ID, (LPVOID *) &pdata, NULL);
  292. if (FAILED(hr)) {
  293. CertFreeCertificateContext(pccertX);
  294. return hr;
  295. }
  296. CertSetCertificateContextProperty(pccert, CERT_PUBKEY_ALG_PARA_PROP_ID, 0, pdata);
  297. ReleaseMem(pdata);
  298. CertFreeCertificateContext(pccertX);
  299. return S_OK;
  300. }
  301. //
  302. // if we still have not found anything, then let the caller have a chance
  303. // to tell us what the parameters ought to be.
  304. //
  305. if (m_pSmimeCallback != NULL) {
  306. hr = m_pSmimeCallback->GetParameters(pSignerCert, NULL,
  307. &blob.cbData, &blob.pbData);
  308. if (SUCCEEDED(hr)) {
  309. if (!CertSetCertificateContextProperty(pccert, CERT_PUBKEY_ALG_PARA_PROP_ID, 0, &blob) {
  310. hr = HrGetLastError();
  311. }
  312. }
  313. if (pb != NULL) {
  314. LocalFree(blob.pbData);
  315. }
  316. if (SUCCEEDED(hr)) {
  317. goto retry;
  318. }
  319. }
  320. #endif // 0
  321. return hr;
  322. }
  323. //*************************************************************************
  324. // CCAPIStm
  325. //*************************************************************************
  326. ///////////////////////////////////////////////////////////////////////////
  327. //
  328. // ctor/dtor
  329. //
  330. /***************************************************************************
  331. Name : constructor
  332. Purpose :
  333. Parameters: lpstmOut -> Output stream or NULL
  334. psld -> SECURITY_LAYER_DATA or NULL. If NULL, one will be
  335. created.
  336. Returns : void
  337. Comment :
  338. ***************************************************************************/
  339. CCAPIStm::CCAPIStm(LPSTREAM lpstmOut) :
  340. m_pstmOut(lpstmOut), m_cRef(1)
  341. {
  342. DOUT("CCAPIStm::constructor() %#x -> %d", this, m_cRef);
  343. if (m_pstmOut)
  344. m_pstmOut->AddRef();
  345. m_hProv = NULL;
  346. m_hMsg = NULL;
  347. // m_buffer = NULL;
  348. m_csStatus = STREAM_NOT_BEGUN;
  349. m_csStream = CSTM_FIRST_WRITE;
  350. m_rgStores = NULL;
  351. m_cStores = 0;
  352. m_pUserCertDecrypt = NULL;
  353. m_pCapiInner = NULL;
  354. m_pConverter = NULL;
  355. m_psldData = NULL;
  356. m_pattrAuth = NULL;
  357. #if defined(DEBUG) && !defined(MAC)
  358. {
  359. char szFileName[MAX_PATH + 1];
  360. m_pstmDebugFile = NULL;
  361. // Create a debug output file name based on the CAPIStm pointer
  362. wnsprintfA(szFileName, ARRAYSIZE(szFileName), "c:\\capidump%08x.txt", this);
  363. OpenFileStream(szFileName, CREATE_ALWAYS, GENERIC_WRITE, &m_pstmDebugFile);
  364. }
  365. #endif
  366. m_hwnd = NULL;
  367. m_pSmimeCallback = NULL;
  368. m_dwFlagsSEF = 0;
  369. m_pwszKeyPrompt = NULL;
  370. m_pbBuffer = NULL;
  371. m_cbBuffer = 0;
  372. // m_dwFlags set in HrInitialize
  373. // m_cbBeginWrite initialized before use
  374. // m_cbBufUsed handled in the Begin* functions
  375. // m_cbBufAlloc handled in the Begin* functions
  376. }
  377. CCAPIStm::~CCAPIStm()
  378. {
  379. DOUT("CCAPIStm::destructor() %#x -> %d", this, m_cRef);
  380. if (m_hMsg) {
  381. CryptMsgClose(m_hMsg);
  382. }
  383. if (m_hProv)
  384. {
  385. CryptReleaseContext(m_hProv, 0);
  386. }
  387. m_hProv = NULL;
  388. ReleaseObj(m_pCapiInner);
  389. ReleaseObj(m_pstmOut);
  390. ReleaseObj(m_pConverter);
  391. if (m_pattrAuth) {
  392. MemFree(m_pattrAuth);
  393. }
  394. if (m_pUserCertDecrypt) {
  395. CertFreeCertificateContext(m_pUserCertDecrypt);
  396. }
  397. if (m_cStores) {
  398. Assert(m_rgStores);
  399. for (DWORD i=0; i<m_cStores; i++) {
  400. CertCloseStore(m_rgStores[i], 0);
  401. }
  402. MemFree(m_rgStores);
  403. }
  404. // Fix: Releasing hProv is caller responcibility
  405. //if (m_hProv && !(m_dwFlagsStm & CSTM_DONTRELEASEPROV)) {
  406. // CryptReleaseContext(m_hProv, 0);
  407. //}
  408. #if defined(DEBUG) && !defined(MAC)
  409. SafeRelease(m_pstmDebugFile);
  410. #endif
  411. if (m_psldData) {
  412. m_psldData->Release();
  413. }
  414. if (m_pbBuffer != NULL) {
  415. MemFree(m_pbBuffer);
  416. }
  417. SafeMemFree(m_pwszKeyPrompt);
  418. ReleaseObj(m_pSmimeCallback);
  419. }
  420. ///////////////////////////////////////////////////////////////////////////
  421. //
  422. // IUnknown methods
  423. //
  424. STDMETHODIMP CCAPIStm::QueryInterface(REFIID riid, LPVOID *ppv)
  425. {
  426. if (!ppv) {
  427. return TrapError(E_INVALIDARG);
  428. }
  429. // Find IID
  430. if (IID_IUnknown == riid) {
  431. *ppv = THIS_AS_UNK;
  432. }
  433. else if (IID_IStream == riid) {
  434. *ppv = (IStream *)this;
  435. }
  436. else {
  437. *ppv = NULL;
  438. return E_NOINTERFACE;
  439. }
  440. ((IUnknown *)*ppv)->AddRef();
  441. return S_OK;
  442. }
  443. STDMETHODIMP_(ULONG) CCAPIStm::AddRef(void)
  444. {
  445. DOUT("CCAPIStm::AddRef() %#x -> %d", this, m_cRef+1);
  446. InterlockedIncrement((LPLONG)&m_cRef);
  447. return m_cRef;
  448. }
  449. STDMETHODIMP_(ULONG) CCAPIStm::Release(void)
  450. {
  451. DOUT("CCAPIStm::Release() %#x -> %d", this, m_cRef-1);
  452. if (0 == InterlockedDecrement((LPLONG)&m_cRef)) {
  453. delete this;
  454. return 0;
  455. }
  456. return m_cRef;
  457. }
  458. ///////////////////////////////////////////////////////////////////////////
  459. //
  460. // IStream methods
  461. //
  462. STDMETHODIMP CCAPIStm::Seek(LARGE_INTEGER, DWORD, ULARGE_INTEGER *plibNewPosition)
  463. {
  464. if (!plibNewPosition) {
  465. return E_POINTER;
  466. }
  467. else {
  468. plibNewPosition->HighPart = 0;
  469. plibNewPosition->LowPart = 0;
  470. }
  471. return S_OK;
  472. }
  473. //// CCAPIStm::Write
  474. //
  475. // Description:
  476. // This function is called with the original message as the buffer
  477. // being written into this stream object. We then make the appropriate
  478. // calls into the NT Crypto system in order to encrypt/decrypt the message.
  479. //
  480. // Part of what this function needs to do is to interact with the
  481. // Crypto system in order to cause decryption of message to occur.
  482. #ifndef WIN16
  483. STDMETHODIMP CCAPIStm::Write(const void *pv, ULONG cb, ULONG *pcbActual)
  484. #else
  485. STDMETHODIMP CCAPIStm::Write(const void HUGEP *pv, ULONG cb, ULONG *pcbActual)
  486. #endif // !WIN16
  487. {
  488. HRESULT hr;
  489. //
  490. // Reset the return arg just incase
  491. //
  492. if (pcbActual != NULL) {
  493. *pcbActual = 0;
  494. }
  495. //
  496. // If the CMS object is not still open, then we are dead and need to return an error.
  497. //
  498. if (!m_hMsg) {
  499. hr = CAPISTM_E_MSG_CLOSED;
  500. goto exit;
  501. }
  502. //
  503. // Are we in the correct state to take anything.
  504. //
  505. switch (m_csStatus) {
  506. case STREAM_NOT_BEGUN:
  507. Assert(FALSE); // Should never get here
  508. hr = CAPISTM_E_NOT_BEGUN;
  509. goto exit;
  510. case STREAM_DETACHED_OCCURING:
  511. case STREAM_QUESTION_TIME:
  512. case STREAM_SETUP_DECRYPT:
  513. case STREAM_OCCURING:
  514. break;
  515. case STREAM_ERROR:
  516. Assert(FALSE); // Should never get here
  517. hr = CAPISTM_E_OVERDONE;
  518. goto exit;
  519. case STREAM_GOTTYPE:
  520. hr = CAPISTM_E_GOTTYPE;
  521. goto exit;
  522. // We should go from QT to QTF in this function, and never come back
  523. // until we have changed the state again.
  524. default:
  525. Assert(FALSE);
  526. case STREAM_QUESTION_TIME_FINAL:
  527. hr = E_UNEXPECTED;
  528. goto exit;
  529. }
  530. #if defined(DEBUG) && !defined(MAC)
  531. //
  532. // Flush the input buffer to disk so that we can debug it later if necessary
  533. //
  534. if (!m_pCapiInner && m_pstmDebugFile) {
  535. m_pstmDebugFile->Write((BYTE *)pv, cb, NULL);
  536. }
  537. #endif
  538. //
  539. // We need to start buffering data to make our messages shorter. The output
  540. // from the save code comes in one and two byte chucks often, we need to put
  541. // the data out in larger blocks
  542. //
  543. if (m_pbBuffer != NULL) {
  544. //
  545. // If we would overflow the buffer, then dump the cached buffer out
  546. //
  547. if (m_cbBuffer + cb > CbCacheBufferSize) {
  548. if (!CryptMsgUpdate(m_hMsg, m_pbBuffer, m_cbBuffer, FALSE)) {
  549. // CryptMsgUpdate failed
  550. Assert(S_OK != HrGetLastError());
  551. hr = HrGetLastError();
  552. if (FAILED(hr)) {
  553. m_csStatus = STREAM_ERROR;
  554. }
  555. goto exit;
  556. }
  557. m_cbBuffer = 0;
  558. }
  559. //
  560. // If this buffer will over flow, then dump out just that item. Otherwise
  561. // we are just going to cache the buffer.
  562. //
  563. if (cb >= CbCacheBufferSize) {
  564. if (!CryptMsgUpdate(m_hMsg, (BYTE *) pv, cb, FALSE)) {
  565. // CryptMsgUpdate failed
  566. Assert(S_OK != HrGetLastError());
  567. hr = HrGetLastError();
  568. if (FAILED(hr)) {
  569. m_csStatus = STREAM_ERROR;
  570. }
  571. goto exit;
  572. }
  573. }
  574. else {
  575. memcpy(m_pbBuffer + m_cbBuffer, pv, cb);
  576. m_cbBuffer += cb;
  577. }
  578. if (pcbActual != NULL) {
  579. *pcbActual = cb;
  580. }
  581. //
  582. // The only time we should be here is when we are creating a new CMS object
  583. // and thus all of the code below this is not relavent as we don't ever
  584. // need to ask questions about what type of this message.
  585. //
  586. hr = S_OK;
  587. goto exit;
  588. }
  589. else {
  590. //
  591. // Push the input buffer into the Crypto system. On failures from the
  592. // system we need to propigate the correct error state into our structure
  593. // and into the return value.
  594. //
  595. if (!CryptMsgUpdate(m_hMsg, (BYTE *)pv, cb, FALSE)) {
  596. // CryptMsgUpdate failed
  597. Assert(S_OK != HrGetLastError());
  598. hr = HrGetLastError();
  599. if (FAILED(hr)) {
  600. m_csStatus = STREAM_ERROR;
  601. }
  602. goto exit;
  603. }
  604. }
  605. //
  606. // Since the CryptMsgUpdate call succeeded, return
  607. // a nice out param (specifically that we have consumed all of the passed
  608. // in bytes)
  609. //
  610. if (pcbActual) {
  611. *pcbActual = cb;
  612. }
  613. hr = S_OK;
  614. //
  615. // If we are in a state where we need to ask questions about the message,
  616. // then proceed to do so.
  617. //
  618. if ((STREAM_QUESTION_TIME == m_csStatus) ||
  619. (STREAM_QUESTION_TIME_FINAL == m_csStatus)) {
  620. DWORD cbDWORD, dwMsgType;
  621. // We should never be asking questions if encoding.
  622. Assert(m_dwFlagsStm & CSTM_DECODE);
  623. //
  624. // Find out what security services have been placed onto this
  625. // message object (if any). If not enough bytes have been processed
  626. // to find out what the encoding of the message is, then return
  627. // success so we can get more bytes and get the question answered
  628. // at a later date.
  629. //
  630. cbDWORD = sizeof(DWORD);
  631. if (!CryptMsgGetParam(m_hMsg, CMSG_TYPE_PARAM, 0, &dwMsgType, &cbDWORD)) {
  632. hr = HrGetLastError();
  633. Assert (S_OK != hr);
  634. if (CRYPT_E_STREAM_MSG_NOT_READY == hr) {
  635. hr = S_OK;
  636. }
  637. goto exit;
  638. }
  639. // Since we are here, we must have a V1 type S/MIME message
  640. Assert(m_psldData);
  641. m_psldData->m_dwMsgEnhancement = MST_CLASS_SMIME_V1;
  642. hr = S_OK;
  643. //
  644. // Set the correct flags based on the message type of the object we are
  645. // decoding.
  646. //
  647. switch (dwMsgType) {
  648. case CMSG_ENVELOPED:
  649. m_psldData->m_dwMsgEnhancement |= MST_THIS_ENCRYPT;
  650. break;
  651. case CMSG_SIGNED:
  652. m_psldData->m_dwMsgEnhancement |= MST_THIS_BLOBSIGN;
  653. break;
  654. case CMSG_SIGNED_AND_ENVELOPED:
  655. m_psldData->m_dwMsgEnhancement |= MST_THIS_BLOBSIGN | MST_THIS_ENCRYPT;
  656. break;
  657. default:
  658. // K this is a little rude. not my iface error.
  659. hr = MIME_E_SECURITY_BADSECURETYPE;
  660. // just return the CAPI type if we don't recognize
  661. m_psldData->m_dwMsgEnhancement = dwMsgType;
  662. break;
  663. }
  664. //
  665. // If all we are asking for is a type and we don't have any other errors,
  666. // mark the fact that we got the type and return that fact as the
  667. // error (to prevent futher buffers being written into us.)
  668. //
  669. if (CSTM_TYPE_ONLY & m_dwFlagsStm) {
  670. CSSDOUT("Got Type on typeonly call.");
  671. CSSDOUT("You will now see 80041417 failures; they're okay.");
  672. m_csStatus = STREAM_GOTTYPE;
  673. if (SUCCEEDED(hr)) {
  674. hr = CAPISTM_E_GOTTYPE;
  675. }
  676. goto exit;
  677. }
  678. //
  679. // Change the object state based on the message type. If we need to
  680. // setup a decryption, then we need to mark the state for that.
  681. // If we are just signing, then we can just let the rest of the
  682. // streaming occur.
  683. //
  684. if (CMSG_ENVELOPED == dwMsgType) {
  685. m_csStatus = STREAM_SETUP_DECRYPT;
  686. }
  687. else {
  688. m_csStatus = STREAM_OCCURING;
  689. }
  690. }
  691. //
  692. // If we need to set-up the message for decryption, then do so at this
  693. // point.
  694. //
  695. Assert(SUCCEEDED(hr));
  696. if (STREAM_SETUP_DECRYPT == m_csStatus) {
  697. // Can't decrypt detached messages
  698. Assert(!(m_dwFlagsStm & CSTM_DETACHED));
  699. // We are now streaming the data out, on the assumption that the
  700. // decryption stats.
  701. m_csStatus = STREAM_OCCURING;
  702. hr = HandleEnveloped();
  703. // If we failed to decrypt, then re-map some errors and change the
  704. // state back in the event that not all of the lock boxes have
  705. // been seen yet.
  706. if (FAILED(hr)) {
  707. if (CRYPT_E_STREAM_MSG_NOT_READY == hr) {
  708. m_csStatus = STREAM_SETUP_DECRYPT;
  709. hr = S_OK;
  710. }
  711. else if (CS_E_CANT_DECRYPT == hr) {
  712. hr = MIME_E_SECURITY_CANTDECRYPT;
  713. // m_csStatus = STREAM_FINAL; // M00QUEST
  714. }
  715. else {
  716. if (CS_E_MSG_INVALID == hr) {
  717. hr = MIME_E_SECURITY_CANTDECRYPT;
  718. }
  719. m_csStatus = STREAM_ERROR;
  720. }
  721. goto exit;
  722. }
  723. }
  724. hr = S_OK;
  725. exit:
  726. #ifdef DEBUG
  727. if (CAPISTM_E_GOTTYPE != hr) {
  728. return TrapError(hr);
  729. }
  730. else {
  731. return hr; // don't spew this
  732. }
  733. #else
  734. return hr;
  735. #endif
  736. }
  737. ///////////////////////////////////////////////////////////////////////////
  738. //
  739. // CCAPIStm public methods
  740. //
  741. /* HrInnerInitialize:
  742. **
  743. ** Purpose:
  744. ** the standard "my constructor can't return errors" function
  745. ** Takes:
  746. ** dwFlagsSEF - Control Flags
  747. ** hwndParent - modal UI parents to this
  748. ** dwFlagsStm - see capistm.h
  749. ** Returns:
  750. ** OLE_E_INVALIDHWND if you give me a bad window
  751. ** MIME_E_SECURITY_NOOP if MST_NONE is the current psi type
  752. ** Notes:
  753. ** dwFlags is currently 0 for encode. do it this way.
  754. */
  755. HRESULT CCAPIStm::HrInnerInitialize(DWORD dwFlagsSEF, const HWND hwndParent,
  756. DWORD dwFlagsStm, IMimeSecurityCallback * pCallback,
  757. PSECURITY_LAYER_DATA psld)
  758. {
  759. HRESULT hr = S_OK;
  760. //
  761. // Save the security layer data
  762. //
  763. if (psld)
  764. {
  765. psld->AddRef();
  766. m_psldData = psld;
  767. }
  768. else
  769. {
  770. IF_NULLEXIT(m_psldData = new(SECURITY_LAYER_DATA));
  771. }
  772. //
  773. // Save the flags
  774. //
  775. m_dwFlagsSEF = dwFlagsSEF;
  776. m_dwFlagsStm = dwFlagsStm;
  777. if (pCallback != NULL)
  778. {
  779. m_pSmimeCallback = pCallback;
  780. pCallback->AddRef();
  781. }
  782. //
  783. // Make sure that if we have a window, it is a real window.
  784. //
  785. IF_TRUEEXIT((hwndParent && !IsWindow(hwndParent)), OLE_E_INVALIDHWND);
  786. //
  787. // Shove the hwnd into any crypto provider we openned up.
  788. //
  789. CryptSetProvParam(NULL, PP_CLIENT_HWND, (BYTE *)&hwndParent, 0);
  790. m_hwnd = hwndParent;
  791. exit:
  792. return hr;
  793. }
  794. /* HrInitialize:
  795. **
  796. ** Purpose:
  797. ** the standard "my constructor can't return errors" function
  798. ** Takes:
  799. ** dwFlagsSEF - Control Flags
  800. ** hwndParent - modal UI parents to this
  801. ** fEncode - trivial
  802. ** psi - message state information. see smime.h
  803. ** dwFlagsStm - see capistm.h
  804. ** Returns:
  805. ** OLE_E_INVALIDHWND if you give me a bad window
  806. ** MIME_E_SECURITY_NOOP if MST_NONE is the current psi type
  807. ** Notes:
  808. ** dwFlags is currently 0 for encode. do it this way.
  809. */
  810. HRESULT CCAPIStm::HrInitialize(DWORD dwFlagsSEF, const HWND hwndParent,
  811. const BOOL fEncode, SMIMEINFO *const psi,
  812. DWORD dwFlagsStm, IMimeSecurityCallback * pCallback,
  813. PSECURITY_LAYER_DATA psld)
  814. {
  815. HRESULT hr;
  816. // do the initialization common to all capi stream objects.
  817. CHECKHR(hr = HrInnerInitialize(dwFlagsSEF, hwndParent, dwFlagsStm, pCallback, psld));
  818. if (fEncode) {
  819. hr = BeginEncodeStreaming(psi);
  820. }
  821. else {
  822. hr = BeginDecodeStreaming(psi);
  823. }
  824. exit:
  825. return TrapError(hr);
  826. }
  827. /* EndStreaming:
  828. **
  829. ** Purpose:
  830. ** Push CAPI's message state forward a notch
  831. ** Returns:
  832. ** HRESULT
  833. */
  834. HRESULT CCAPIStm::EndStreaming()
  835. {
  836. DWORD dwMsgEnhancement = m_psldData->m_dwMsgEnhancement;
  837. HRESULT hr = S_OK;
  838. PCMSG_ATTR pUnprotectedAttrs = NULL;
  839. Assert(m_hMsg);
  840. // If we are crurent in an error state then return
  841. if ((STREAM_ERROR == m_csStatus) || STREAM_GOTTYPE == m_csStatus) {
  842. goto exit;
  843. }
  844. //
  845. // If we are decoding -- and we are doing a detached message we need
  846. // to jump from the sign object to the real body here.
  847. //
  848. if ((CSTM_DECODE & m_dwFlagsStm) && (STREAM_DETACHED_OCCURING == m_csStatus)) {
  849. Assert(m_csStream == CSTM_STREAMING_DONE);
  850. // client has finished giving us the signature block
  851. m_csStatus = STREAM_OCCURING;
  852. m_csStream = CSTM_STREAMING;
  853. m_psldData->m_dwMsgEnhancement = MST_THIS_SIGN;
  854. CSSDOUT("Signature streaming finished.");
  855. if (! CryptMsgUpdate(m_hMsg, m_pbBuffer, m_cbBuffer, TRUE)) {
  856. if ((hr = HrGetLastError()) == 0x80070000) { // CAPI sometimes doesn't SetLastError
  857. hr = 0x80070000 | ERROR_ACCESS_DENIED;
  858. }
  859. }
  860. m_cbBuffer = 0;
  861. goto exit;
  862. }
  863. if (! CryptMsgUpdate(m_hMsg, m_pbBuffer, m_cbBuffer, TRUE)) {
  864. if ((hr = HrGetLastError()) == 0x80070000) { // CAPI sometimes doesn't SetLastError
  865. hr = 0x80070000 | ERROR_ACCESS_DENIED;
  866. }
  867. goto exit;
  868. }
  869. m_cbBuffer = 0;
  870. if (m_dwFlagsStm & CSTM_DETACHED) {
  871. m_csStatus = STREAM_OCCURING;
  872. }
  873. //
  874. // do final streaming and verification
  875. //
  876. if (CSTM_DECODE & m_dwFlagsStm) {
  877. if (MST_THIS_SIGN & dwMsgEnhancement) {
  878. hr = VerifySignedMessage();
  879. if (FAILED(hr)) {
  880. goto exit;
  881. }
  882. } else {
  883. Assert(STREAM_OCCURING == m_csStatus);
  884. Assert(CSTM_STREAMING_DONE == m_csStream);
  885. if (g_FSupportV3 && (MST_THIS_ENCRYPT & dwMsgEnhancement)) {
  886. BOOL f;
  887. DWORD cbData = 0;
  888. LPBYTE pb = NULL;
  889. f = CryptMsgGetParam(m_hMsg, CMSG_UNPROTECTED_ATTR_PARAM, 0, NULL, &cbData);
  890. if (!f) {
  891. // Probably, message doesn't have a CMSG_UNPROTECTED_ATTR_PARAM
  892. hr = HrGetLastError();
  893. if(hr != CRYPT_E_ATTRIBUTES_MISSING)
  894. goto exit;
  895. else
  896. {
  897. hr = S_OK;
  898. cbData = 0;
  899. }
  900. }
  901. if (cbData != 0) {
  902. if (!MemAlloc((LPVOID *) &pUnprotectedAttrs, cbData)) {
  903. hr = E_OUTOFMEMORY;
  904. goto exit;
  905. }
  906. f = CryptMsgGetParam(m_hMsg, CMSG_UNPROTECTED_ATTR_PARAM, 0, pUnprotectedAttrs, &cbData);
  907. Assert(f);
  908. if (!CryptEncodeObjectEx(X509_ASN_ENCODING, szOID_Microsoft_Attribute_Sequence,
  909. pUnprotectedAttrs, CRYPT_ENCODE_ALLOC_FLAG,
  910. &CryptEncodeAlloc, &pb, &cbData)) {
  911. hr = HrGetLastError();
  912. goto exit;
  913. }
  914. m_psldData->m_blobUnprotectAttrs.cbData = cbData;
  915. m_psldData->m_blobUnprotectAttrs.pbData = pb;
  916. }
  917. }
  918. }
  919. }
  920. //
  921. // fill in some more of the data structure
  922. //
  923. if ((CSTM_DECODE & m_dwFlagsStm) &&
  924. (dwMsgEnhancement & MST_THIS_ENCRYPT)) {
  925. _SMimeCapsFromHMsg(m_hMsg, CMSG_ENVELOPE_ALGORITHM_PARAM,
  926. &m_psldData->m_blobDecAlg.pBlobData,
  927. &m_psldData->m_blobDecAlg.cbSize);
  928. }
  929. if (m_pCapiInner) {
  930. hr = m_pCapiInner->EndStreaming();
  931. }
  932. exit:
  933. SafeMemFree(pUnprotectedAttrs);
  934. if (hr == ERROR_ACCESS_DENIED) {
  935. hr = E_ACCESSDENIED; // convert CAPI error to OLE HRESULT
  936. }
  937. return(hr);
  938. }
  939. PSECURITY_LAYER_DATA CCAPIStm::GetSecurityLayerData() const
  940. {
  941. if (m_psldData) {
  942. m_psldData->AddRef();
  943. }
  944. return(m_psldData);
  945. }
  946. ///////////////////////////////////////////////////////////////////////////
  947. //
  948. // Implementation methods
  949. //
  950. ///////////////////////////////////////////////////////////////////////////
  951. ///////////////////////////////////////////////////////////////////////////
  952. //
  953. // Encode / Decode
  954. //
  955. HRESULT CCAPIStm::BeginEncodeStreaming(SMIMEINFO *const psi)
  956. {
  957. DWORD cb;
  958. DWORD cbData;
  959. DWORD cCrls = 0;
  960. DWORD cCerts = 0;
  961. DWORD cSigners = 0;
  962. HRESULT hr;
  963. DWORD i;
  964. DWORD dwMsgType;
  965. DWORD dwFlags = 0;
  966. PCRYPT_KEY_PROV_INFO pKPI;
  967. CMSG_STREAM_INFO cmsi;
  968. DWORD dwPsiType;
  969. DWORD iSigner;
  970. PCRYPT_ATTRIBUTES pattrsUnprot = NULL;
  971. PCRYPT_ATTRIBUTES * rgpattrAuth = NULL;
  972. PCRYPT_ATTRIBUTES * rgpattrUnauth = NULL;
  973. #ifndef SMIME_V3
  974. PCRYPT_SMIME_CAPABILITIES pcaps = NULL;
  975. #endif // SMIME_V3
  976. CMSG_RC2_AUX_INFO rc2Aux;
  977. CRL_BLOB* rgCrlBlob;
  978. PCRYPT_SMIME_CAPABILITIES * rgpcaps = NULL;
  979. CMSG_SIGNER_ENCODE_INFO * rgSigner;
  980. // #ifndef _WIN64
  981. union {
  982. struct {
  983. // #endif
  984. // anything that comes first must be common (in size)
  985. // to both structures
  986. CERT_INFO** rgpCertInfo;
  987. CMSG_ENVELOPED_ENCODE_INFO ceei;
  988. // #ifndef _WIN64
  989. };
  990. struct {
  991. // #endif
  992. CERT_BLOB* rgCertBlob;
  993. CMSG_SIGNED_ENCODE_INFO csei;
  994. // #ifndef _WIN64
  995. };
  996. };
  997. // #endif
  998. ////////////
  999. // can only return from here down
  1000. m_csStatus = STREAM_ERROR;
  1001. rgSigner = NULL;
  1002. if (!psi) {
  1003. return E_POINTER;
  1004. }
  1005. //
  1006. // Get the security operations to be performed on this body layer.
  1007. // we only care about the current body properties so mask out
  1008. // other layers.
  1009. // If we don't have any security to perform, then get out of here
  1010. //
  1011. dwPsiType = m_psldData->m_dwMsgEnhancement & MST_THIS_MASK;
  1012. if (MST_NONE == dwPsiType) {
  1013. AssertSz(dwPsiType != MST_NONE, "Why are we here if we have no security to apply?");
  1014. return TrapError(MIME_E_SECURITY_NOOP);
  1015. }
  1016. //
  1017. // detached is the only allowed user settable flag
  1018. //
  1019. if ((m_dwFlagsStm & CSTM_ALLFLAGS) & ~CSTM_DETACHED) {
  1020. return TrapError(E_INVALIDARG);
  1021. }
  1022. rgCertBlob = NULL;
  1023. rgCrlBlob = NULL;
  1024. pKPI = NULL;
  1025. ////////////
  1026. // can goto end from here down
  1027. //
  1028. // We should never be in a situation where we are going to both encrypt and sign
  1029. // a message.
  1030. //
  1031. AssertSz((!!(dwPsiType & MST_THIS_SIGN) +
  1032. !!(dwPsiType & MST_THIS_ENCRYPT)) == 1,
  1033. "Encrypt and Sign Same Layer is not legal");
  1034. if (dwPsiType & MST_THIS_SIGN) {
  1035. dwMsgType = CMSG_SIGNED;
  1036. if (!(m_psldData->m_dwMsgEnhancement & MST_BLOB_FLAG)) {
  1037. dwFlags |= CMSG_DETACHED_FLAG;
  1038. }
  1039. cSigners = m_psldData->m_cSigners;
  1040. if (m_psldData->m_hcertstor != NULL) {
  1041. hr = _InitEncodedCertIncludingSigners(m_psldData->m_hcertstor,
  1042. cSigners, m_psldData->m_rgSigners,
  1043. &rgCertBlob, &cCerts,
  1044. &rgCrlBlob, &cCrls);
  1045. if (FAILED(hr)) {
  1046. goto exit;
  1047. }
  1048. }
  1049. cb = sizeof(CMSG_SIGNER_ENCODE_INFO) * cSigners;
  1050. if (!MemAlloc((LPVOID *) &rgSigner, cb)) {
  1051. hr = E_OUTOFMEMORY;
  1052. goto exit;
  1053. }
  1054. memset(rgSigner, 0, cb);
  1055. cb = sizeof(PCRYPT_SMIME_CAPABILITIES) * cSigners;
  1056. if (!MemAlloc((LPVOID *) &rgpcaps, cb)) {
  1057. hr = E_OUTOFMEMORY;
  1058. goto exit;
  1059. }
  1060. memset(rgpcaps, 0, cb);
  1061. if (!MemAlloc((LPVOID *) &rgpattrAuth, cSigners*sizeof(PCRYPT_ATTRIBUTES))) {
  1062. hr = E_OUTOFMEMORY;
  1063. goto exit;
  1064. }
  1065. memset(rgpattrAuth, 0, cSigners*sizeof(PCRYPT_ATTRIBUTES));
  1066. if (!MemAlloc((LPVOID *) &rgpattrUnauth, cSigners*sizeof(PCRYPT_ATTRIBUTES))) {
  1067. hr = E_OUTOFMEMORY;
  1068. goto exit;
  1069. }
  1070. memset(rgpattrUnauth, 0, cSigners*sizeof(PCRYPT_ATTRIBUTES));
  1071. for (iSigner=0; iSigner<cSigners; iSigner++) {
  1072. rgSigner[iSigner].cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
  1073. rgSigner[iSigner].pvHashAuxInfo = NULL;
  1074. // We need to pull apart the algorithm used to sign the message so
  1075. // we can pass it down to the crypt32 code
  1076. hr = HrDecodeObject(m_psldData->m_rgSigners[iSigner].blobHashAlg.pBlobData,
  1077. m_psldData->m_rgSigners[iSigner].blobHashAlg.cbSize,
  1078. PKCS_SMIME_CAPABILITIES, 0, &cbData,
  1079. (LPVOID *)&rgpcaps[iSigner]);
  1080. if (FAILED(hr)) {
  1081. goto exit;
  1082. }
  1083. // MOOBUG -- MEMORY LEAK ON PCAPS!!!!
  1084. Assert(rgpcaps[iSigner] != NULL);
  1085. Assert(rgpcaps[iSigner]->cCapability == 1);
  1086. rgSigner[iSigner].HashAlgorithm.pszObjId = rgpcaps[iSigner]->rgCapability[0].pszObjId;
  1087. rgSigner[iSigner].HashAlgorithm.Parameters.cbData = rgpcaps[iSigner]->rgCapability[0].Parameters.cbData;
  1088. rgSigner[iSigner].HashAlgorithm.Parameters.pbData = rgpcaps[iSigner]->rgCapability[0].Parameters.pbData;
  1089. //
  1090. // Need to setup the attributes to attach to the signed message
  1091. //
  1092. if (m_psldData->m_rgSigners[iSigner].blobAuth.cbSize != 0) {
  1093. cbData = 0;
  1094. hr = HrDecodeObject(m_psldData->m_rgSigners[iSigner].blobAuth.pBlobData,
  1095. m_psldData->m_rgSigners[iSigner].blobAuth.cbSize,
  1096. szOID_Microsoft_Attribute_Sequence, 0,
  1097. &cbData, (LPVOID *)&rgpattrAuth[iSigner]);
  1098. if (FAILED(hr)) {
  1099. goto exit;
  1100. }
  1101. if (rgpattrAuth[iSigner] != NULL) {
  1102. rgSigner[iSigner].cAuthAttr = rgpattrAuth[iSigner]->cAttr;
  1103. rgSigner[iSigner].rgAuthAttr = rgpattrAuth[iSigner]->rgAttr;
  1104. Assert(m_pattrAuth == NULL);
  1105. if (!g_FSupportV3) {
  1106. // This code exists for old versions of crypt32. Prior to
  1107. // the NT5 re-write the capi code did not copy the attributes
  1108. // but assumed that we must have done so.
  1109. m_pattrAuth = rgpattrAuth[iSigner];
  1110. rgpattrAuth[iSigner] = NULL;
  1111. }
  1112. } else {
  1113. Assert(rgSigner[iSigner].cAuthAttr == 0);
  1114. Assert(rgSigner[iSigner].rgAuthAttr == NULL);
  1115. }
  1116. }
  1117. if (m_psldData->m_rgSigners[iSigner].blobUnauth.cbSize != 0) {
  1118. cbData = 0;
  1119. HrDecodeObject(m_psldData->m_rgSigners[iSigner].blobUnauth.pBlobData,
  1120. m_psldData->m_rgSigners[iSigner].blobUnauth.cbSize,
  1121. szOID_Microsoft_Attribute_Sequence, 0,
  1122. &cbData, (LPVOID *)&rgpattrUnauth[iSigner]);
  1123. if (FAILED(hr)) {
  1124. goto exit;
  1125. }
  1126. if (rgpattrUnauth[iSigner] != NULL) {
  1127. rgSigner[iSigner].cUnauthAttr = rgpattrUnauth[iSigner]->cAttr;
  1128. rgSigner[iSigner].rgUnauthAttr = rgpattrUnauth[iSigner]->rgAttr;
  1129. } else {
  1130. Assert(rgSigner[iSigner].cUnauthAttr == 0);
  1131. Assert(rgSigner[iSigner].rgUnauthAttr == NULL);
  1132. }
  1133. }
  1134. // load the provider information from the signing cert and then
  1135. // acquire that provider with the appropriate key container
  1136. hr = HrGetCertificateParam(m_psldData->m_rgSigners[iSigner].pccert,
  1137. CERT_KEY_PROV_INFO_PROP_ID,
  1138. (LPVOID *) &pKPI, NULL);
  1139. if (FAILED(hr)) {
  1140. goto gle;
  1141. }
  1142. if (!m_hProv && ! CRYPT_ACQUIRE_CONTEXT(&m_hProv, pKPI->pwszContainerName,
  1143. pKPI->pwszProvName, pKPI->dwProvType,
  1144. pKPI->dwFlags)) {
  1145. goto gle;
  1146. }
  1147. Assert(0 == pKPI->cProvParam);
  1148. #ifdef SMIME_V3
  1149. if (psi->pwszKeyPrompt != NULL) {
  1150. CryptSetProvParam(m_hProv, PP_UI_PROMPT, (LPBYTE) psi->pwszKeyPrompt, 0);
  1151. }
  1152. #endif // SMIME_V3
  1153. rgSigner[iSigner].pCertInfo = m_psldData->m_rgSigners[iSigner].pccert->pCertInfo;
  1154. rgSigner[iSigner].hCryptProv = m_hProv;
  1155. rgSigner[iSigner].dwKeySpec = pKPI->dwKeySpec;
  1156. //
  1157. // Need to change dsa to dsa-with-sha1
  1158. //
  1159. if (strcmp(rgSigner[iSigner].pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_OIWSEC_dsa) == 0) {
  1160. rgSigner[iSigner].HashEncryptionAlgorithm.pszObjId = szOID_OIWSEC_dsaSHA1;
  1161. }
  1162. }
  1163. csei.cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO);
  1164. csei.cSigners = m_psldData->m_cSigners;
  1165. csei.rgSigners = rgSigner;
  1166. csei.cCertEncoded = cCerts;
  1167. csei.rgCertEncoded = rgCertBlob;
  1168. csei.cCrlEncoded = cCrls;
  1169. csei.rgCrlEncoded = rgCrlBlob;
  1170. }
  1171. //
  1172. // If it is not signed, then it must be encrypted. Setup the calls for
  1173. // performing an encryption operation.
  1174. //
  1175. else {
  1176. Assert((dwPsiType & MST_THIS_ENCRYPT) != 0);
  1177. dwMsgType = CMSG_ENVELOPED;
  1178. //
  1179. // If we are given a CSP, then we are going to pass it on to the Crypt32 code,
  1180. // However it turns out that we are the ones who release the CSP so store it
  1181. // locally into the class object.
  1182. //
  1183. Assert(m_hProv == NULL);
  1184. m_hProv = psi->hProv;
  1185. psi->hProv = NULL;
  1186. //
  1187. // Extract out the bulk encryption algorithm we are going to apply to
  1188. // the body of the message. This algorithm is the same across all
  1189. // the different key transfer algorthms.
  1190. //
  1191. //
  1192. // Setup the structure containing all of the encryption parameters for the
  1193. // Message Encode function. This structure gets setup differently
  1194. // depending on the version of Crypt32 which we are running on.
  1195. //
  1196. memset(&ceei, 0, sizeof(ceei));
  1197. ceei.cbSize = sizeof(CMSG_ENVELOPED_ENCODE_INFO);
  1198. ceei.hCryptProv = m_hProv;
  1199. ceei.ContentEncryptionAlgorithm = m_psldData->m_ContentEncryptAlgorithm;
  1200. ceei.pvEncryptionAuxInfo = m_psldData->m_pvEncryptAuxInfo;
  1201. if (g_FSupportV3) {
  1202. ceei.cRecipients = m_psldData->m_cEncryptItems;
  1203. ceei.rgCmsRecipients = m_psldData->m_rgRecipientInfo;
  1204. if (m_psldData->m_blobUnprotectAttrs.cbData > 0) {
  1205. CHECKHR(hr = HrDecodeObject(m_psldData->m_blobUnprotectAttrs.pbData,
  1206. m_psldData->m_blobUnprotectAttrs.cbData,
  1207. szOID_Microsoft_Attribute_Sequence, 0,
  1208. &cbData, (LPVOID *) &pattrsUnprot));
  1209. ceei.cUnprotectedAttr = pattrsUnprot->cAttr;
  1210. ceei.rgUnprotectedAttr = pattrsUnprot->rgAttr;
  1211. }
  1212. //
  1213. // Allow for certificates to be carried on the encryption package now
  1214. // need this for Fortezza static-static implementation.
  1215. //
  1216. if (m_psldData->m_hstoreEncrypt != NULL) {
  1217. hr = _InitEncodedCert(m_psldData->m_hstoreEncrypt, &rgCertBlob, &cCerts,
  1218. &rgCrlBlob, &cCrls);
  1219. if (FAILED(hr)) {
  1220. goto exit;
  1221. }
  1222. ceei.cCertEncoded = cCerts;
  1223. ceei.rgCertEncoded = rgCertBlob;
  1224. ceei.cCrlEncoded = cCrls;
  1225. ceei.rgCrlEncoded = rgCrlBlob;
  1226. }
  1227. }
  1228. else {
  1229. PCERT_INFO pinfo;
  1230. if (!MemAlloc((LPVOID *) &ceei.rgpRecipients,
  1231. (sizeof(CERT_INFO) + sizeof(PCERT_INFO)) * m_psldData->m_cEncryptItems)) {
  1232. hr = E_OUTOFMEMORY;
  1233. goto exit;
  1234. }
  1235. memset(ceei.rgpRecipients, 0,
  1236. (sizeof(CERT_INFO) + sizeof(PCERT_INFO)) * m_psldData->m_cEncryptItems);
  1237. ceei.cRecipients = m_psldData->m_cEncryptItems;
  1238. pinfo = (PCERT_INFO) ((ceei.cRecipients * sizeof(PCERT_INFO)) +
  1239. (LPBYTE) ceei.rgpRecipients);
  1240. for (i=0; i<ceei.cRecipients; i++, pinfo++) {
  1241. ceei.rgpRecipients[i] = pinfo;
  1242. Assert(m_psldData->m_rgRecipientInfo[i].dwRecipientChoice == CMSG_KEY_TRANS_RECIPIENT);
  1243. pinfo->SubjectPublicKeyInfo.Algorithm = m_psldData->m_rgRecipientInfo[i].pKeyTrans->KeyEncryptionAlgorithm;
  1244. pinfo->SubjectPublicKeyInfo.PublicKey = m_psldData->m_rgRecipientInfo[i].pKeyTrans->RecipientPublicKey;
  1245. Assert(m_psldData->m_rgRecipientInfo[i].pKeyTrans->RecipientId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER);
  1246. pinfo->Issuer = m_psldData->m_rgRecipientInfo[i].pKeyTrans->RecipientId.IssuerSerialNumber.Issuer;
  1247. pinfo->SerialNumber = m_psldData->m_rgRecipientInfo[i].pKeyTrans->RecipientId.IssuerSerialNumber.SerialNumber;
  1248. }
  1249. }
  1250. }
  1251. // Do we need to recurse and wrap ourselves in an Outer Layer?
  1252. if (m_psldData->m_psldOuter) {
  1253. CSSDOUT("Streaming wrapped message (type: %x)", m_psldData->m_psldOuter->m_dwMsgEnhancement);
  1254. hr = InitInner(psi, NULL, m_psldData->m_psldOuter);
  1255. if (FAILED(hr)) {
  1256. goto exit;
  1257. }
  1258. // This will write the header to the new inner CAPI stream
  1259. if (m_pstmOut) {
  1260. CONVINITINFO ci = {0};
  1261. // Create a conversion stream
  1262. ci.ietEncoding = IET_BASE64;
  1263. ci.fEncoder = TRUE;
  1264. TrapError(HrCreateInternetConverter(&ci, &m_pConverter));
  1265. m_pstmOut->Write(s_cszMimeHeader, sizeof(s_cszMimeHeader)-1, NULL);
  1266. if (m_psldData->m_dwMsgEnhancement & MST_THIS_ENCRYPT) {
  1267. m_pstmOut->Write(STR_SMT_ENVELOPEDDATA,
  1268. lstrlen(STR_SMT_ENVELOPEDDATA), NULL);
  1269. }
  1270. else {
  1271. if ((psi->pszInnerContent != NULL) &&
  1272. (strcmp(psi->pszInnerContent,
  1273. szOID_SMIME_ContentType_Receipt) == 0)) {
  1274. m_pstmOut->Write(STR_SMT_SIGNEDRECEIPT,
  1275. lstrlen(STR_SMT_SIGNEDRECEIPT), NULL);
  1276. }
  1277. else {
  1278. m_pstmOut->Write(STR_SMT_SIGNEDDATA,
  1279. lstrlen(STR_SMT_SIGNEDDATA), NULL);
  1280. }
  1281. }
  1282. m_pstmOut->Write(c_szCRLF, lstrlen(c_szCRLF), NULL);
  1283. m_pstmOut->Write(STR_HDR_CNTXFER, lstrlen(STR_HDR_CNTXFER), NULL);
  1284. m_pstmOut->Write(c_szColonSpace, lstrlen(c_szColonSpace), NULL);
  1285. if (m_pConverter) {
  1286. m_pstmOut->Write(STR_ENC_BASE64, lstrlen(STR_ENC_BASE64), NULL);
  1287. } else {
  1288. // Failed to create the conversion stream. Try sending binary anyway.
  1289. // (Netscape can't read it, but most others can.)
  1290. m_pstmOut->Write(STR_ENC_BINARY, lstrlen(STR_ENC_BINARY), NULL);
  1291. }
  1292. m_pstmOut->Write(c_szCRLF, lstrlen(c_szCRLF), NULL);
  1293. m_pstmOut->Write(s_cszMimeHeader2, sizeof(s_cszMimeHeader2)-1, NULL);
  1294. m_pstmOut->Write(c_szCRLFCRLF, lstrlen(c_szCRLFCRLF), NULL);
  1295. }
  1296. }
  1297. //
  1298. // Since the write code is so bad for buffering, lets do the buffering here.
  1299. // Ignore all errors on return, if the buffer is not allocated then we just
  1300. // get the same poor performance as before.
  1301. //
  1302. MemAlloc((LPVOID *) &m_pbBuffer, CbCacheBufferSize);
  1303. //
  1304. //
  1305. if (psi->pszInnerContent != NULL) {
  1306. cmsi.cbContent = psi->cbInnerContent;
  1307. }
  1308. else {
  1309. cmsi.cbContent = (DWORD) -1; // indefinite-lenght BER encoding
  1310. }
  1311. cmsi.pfnStreamOutput = CBStreamOutput;
  1312. cmsi.pvArg = (void *)this;
  1313. m_hMsg = CryptMsgOpenToEncode(
  1314. CRYPT_ASN_ENCODING|PKCS_7_ASN_ENCODING,
  1315. CMSG_CMS_ENCAPSULATED_CONTENT_FLAG | dwFlags,
  1316. dwMsgType,
  1317. // (dwMsgType == CMSG_SIGNED) ? ((void *) &csei) : ((void *) &ceei), // really depends on the union
  1318. &ceei,
  1319. psi->pszInnerContent,
  1320. &cmsi);
  1321. if (! m_hMsg) {
  1322. goto gle;
  1323. }
  1324. //
  1325. // Put the top level into either DETACHED or STREAM based on if we are
  1326. // doing detached signing or blob signing/encryption.
  1327. //
  1328. // Put the low level stream into the write through state so it moves all
  1329. // data out to the output stream. (If no output stream then mark as no
  1330. // output streaming.)
  1331. //
  1332. m_csStatus = (m_dwFlagsStm & CSTM_DETACHED) ? STREAM_DETACHED_OCCURING : STREAM_OCCURING;
  1333. m_csStream = m_pstmOut ? CSTM_STREAMING : CSTM_GOTTYPE;
  1334. hr = S_OK;
  1335. exit:
  1336. if (!g_FSupportV3 && (dwPsiType & MST_THIS_ENCRYPT)) {
  1337. MemFree(ceei.rgpRecipients);
  1338. }
  1339. ReleaseMem(pKPI);
  1340. if (rgCertBlob) {
  1341. g_pMoleAlloc->Free(rgCertBlob); //also rgpCertInfo
  1342. }
  1343. if (rgCrlBlob) {
  1344. g_pMoleAlloc->Free(rgCrlBlob);
  1345. }
  1346. if (rgpcaps != NULL) {
  1347. for (iSigner=0; iSigner<cSigners; iSigner++) {
  1348. MemFree(rgpcaps[iSigner]);
  1349. }
  1350. MemFree(rgpcaps);
  1351. }
  1352. SafeMemFree(rgSigner);
  1353. SafeMemFree(pattrsUnprot);
  1354. for (iSigner=0; iSigner<cSigners; iSigner++) {
  1355. SafeMemFree(rgpattrAuth[iSigner]);
  1356. SafeMemFree(rgpattrUnauth[iSigner]);
  1357. }
  1358. SafeMemFree(rgpattrAuth);
  1359. SafeMemFree(rgpattrUnauth);
  1360. Assert(m_hMsg || S_OK != hr);
  1361. return TrapError(hr);
  1362. gle:
  1363. hr = HrGetLastError();
  1364. goto exit;
  1365. }
  1366. HRESULT CCAPIStm::BeginDecodeStreaming(
  1367. SMIMEINFO *const psi)
  1368. {
  1369. CMSG_STREAM_INFO cmsi;
  1370. if (CSTM_TYPE_ONLY & m_dwFlagsStm) {
  1371. if (CSTM_DETACHED & m_dwFlagsStm) {
  1372. return E_INVALIDARG;
  1373. }
  1374. }
  1375. m_dwFlagsStm |= CSTM_DECODE;
  1376. if (psi) {
  1377. // SMIME3: if there is a cert in the associated layer data, duplicate it up here.
  1378. // BUGBUG: NYI
  1379. m_hProv = psi->hProv;
  1380. psi->hProv = NULL;
  1381. // Copy the array of cert stores up here
  1382. if (psi->cStores) {
  1383. m_rgStores = (HCERTSTORE*)g_pMalloc->Alloc(psi->cStores * sizeof(HCERTSTORE));
  1384. if (! m_rgStores) {
  1385. return(E_OUTOFMEMORY);
  1386. }
  1387. for (DWORD i = 0; i < psi->cStores; i++) {
  1388. m_rgStores[i] = CertDuplicateStore(psi->rgStores[i]);
  1389. }
  1390. m_cStores = psi->cStores;
  1391. }
  1392. // HACK!!! HACK!!!! for WIN64
  1393. #ifndef _WIN64
  1394. #ifdef SMIME_V3
  1395. UNALIGNED WCHAR *wsz = psi->pwszKeyPrompt;
  1396. if (wsz != NULL) {
  1397. m_pwszKeyPrompt = PszDupW((LPCWSTR) wsz);
  1398. if (m_pwszKeyPrompt == NULL) {
  1399. return(E_OUTOFMEMORY);
  1400. }
  1401. }
  1402. #endif // SMIME_V3
  1403. #endif //_WIN64
  1404. }
  1405. cmsi.cbContent = (DWORD)-1; // indefinite-length BER encoding
  1406. cmsi.pfnStreamOutput = CBStreamOutput;
  1407. cmsi.pvArg = (void *)this;
  1408. m_hMsg = CryptMsgOpenToDecode(
  1409. CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1410. (m_dwFlagsStm & CSTM_DETACHED) ? CMSG_DETACHED_FLAG : 0,
  1411. 0, // don't know the type
  1412. m_hProv, // needed for verify, but not decrypt
  1413. NULL, // pRecipientInfo
  1414. &cmsi);
  1415. if (m_hMsg) {
  1416. m_csStatus = (m_dwFlagsStm & CSTM_DETACHED) ? STREAM_DETACHED_OCCURING : STREAM_QUESTION_TIME;
  1417. } else {
  1418. m_csStatus = STREAM_ERROR;
  1419. }
  1420. Assert(m_hMsg || S_OK != HrGetLastError());
  1421. return m_hMsg ? S_OK : HrGetLastError();
  1422. }
  1423. ///////////////////////////////////////////////////////////////////////////
  1424. //
  1425. // Callback and helpers/crackers
  1426. //
  1427. BOOL WINAPI CCAPIStm::CBStreamOutput(
  1428. const void *pvArg,
  1429. BYTE *pbData,
  1430. DWORD cbData,
  1431. BOOL fFinal)
  1432. {
  1433. Assert(pvArg);
  1434. return((CCAPIStm*)pvArg)->StreamOutput(pbData, cbData, fFinal);
  1435. }
  1436. BOOL CCAPIStm::StreamOutput(
  1437. BYTE * pbData,
  1438. DWORD cbData,
  1439. BOOL fFinal)
  1440. {
  1441. HRESULT hr = S_OK;
  1442. int iEOH;
  1443. #ifdef SMIME_V3
  1444. LPSTR szContentType = NULL;
  1445. #endif // SMIME_V3
  1446. // m_csStream should be one of the CSTM states at this point, if not then
  1447. // we are in error.
  1448. Assert((m_csStream == CSTM_GOTTYPE) || (m_csStream == CSTM_FIRST_WRITE) ||
  1449. (m_csStream == CSTM_TEST_NESTING) || (m_csStream == CSTM_STREAMING));
  1450. // If all we are doing is looking for the type, then we know that
  1451. // we already have one at this point. There is no need to put the
  1452. // output of the Crypto code anyplace as it is not part of what we
  1453. // are looking for.
  1454. if (CSTM_GOTTYPE == m_csStream) {
  1455. return TRUE;
  1456. }
  1457. // If we have no output stream, then all we need to do is the state
  1458. // transistion on fFinal being true.
  1459. if (m_pstmOut == NULL) {
  1460. if (fFinal) {
  1461. m_csStream = CSTM_STREAMING_DONE;
  1462. }
  1463. return TRUE;
  1464. }
  1465. //
  1466. // Test for an enclosed opaque S/MIME message
  1467. // the client doesn't care about this level of goo, so hide it and
  1468. // stream this data into a new CAPIStm, letting it stream out the
  1469. // real stuff.
  1470. //
  1471. if (CSTM_FIRST_WRITE == m_csStream) {
  1472. // this is the position of the beginning of any
  1473. // possible MIME header
  1474. if (FAILED(HrGetStreamPos(m_pstmOut, &m_cbBeginWrite)) ||
  1475. FAILED(HrGetStreamSize(m_pstmOut, &m_cbBeginSize))) {
  1476. m_cbBeginWrite = 0;
  1477. m_cbBeginSize = 0;
  1478. } else {
  1479. // reset position
  1480. HrStreamSeekSet(m_pstmOut, m_cbBeginWrite);
  1481. }
  1482. m_csStream = CSTM_TEST_NESTING;
  1483. #ifdef SMIME_V3
  1484. if (szContentType = (LPSTR)PVGetMsgParam(m_hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, NULL, NULL)) {
  1485. if (lstrcmp(szOID_PKCS_7_DATA, szContentType)) {
  1486. hr = m_pstmOut->Write(s_cszOIDMimeHeader1, strlen(s_cszOIDMimeHeader1), NULL);
  1487. if (SUCCEEDED(hr)) {
  1488. hr = m_pstmOut->Write(szContentType, strlen(szContentType), NULL);
  1489. }
  1490. if (SUCCEEDED(hr)) {
  1491. hr = m_pstmOut->Write(s_cszOIDMimeHeader2, strlen(s_cszOIDMimeHeader2), NULL);
  1492. }
  1493. if (FAILED(hr)) {
  1494. return FALSE;
  1495. }
  1496. m_csStream = CSTM_STREAMING;
  1497. }
  1498. }
  1499. #endif // SMIME_V3
  1500. }
  1501. if (CSTM_TEST_NESTING == m_csStream &&
  1502. (-1 != (iEOH = SniffForEndOfHeader(pbData, cbData)))) {
  1503. CMimePropertyContainer *pContHeader;
  1504. // get the position of the first char of the body
  1505. iEOH = cbData - iEOH + 1;
  1506. pContHeader = new CMimePropertyContainer;
  1507. if (pContHeader) {
  1508. hr = pContHeader->InitNew();
  1509. if (SUCCEEDED(hr)) {
  1510. ULONG posCurrent;
  1511. // write out the last bit of the header data
  1512. // then move back to the header's start after
  1513. // saving our current position
  1514. hr = m_pstmOut->Write(pbData, iEOH, NULL);
  1515. if (SUCCEEDED(hr)) {
  1516. // fixup the amount of data in pbData so
  1517. // only body stuff gets written to the stream
  1518. // . . . we've already written the header
  1519. pbData += iEOH;
  1520. cbData -= iEOH;
  1521. HrGetStreamPos(m_pstmOut, &posCurrent);
  1522. HrStreamSeekSet(m_pstmOut, m_cbBeginWrite);
  1523. hr = pContHeader->Load(m_pstmOut);
  1524. #ifdef DEBUG
  1525. BYTE *pbHeader;
  1526. DWORD cbHeader;
  1527. HrStreamToByte(m_pstmOut, &pbHeader, &cbHeader);
  1528. SafeMemFree(pbHeader);
  1529. #endif
  1530. // if we don't have an inner message, need to reset
  1531. // the stream back to where we were
  1532. HrStreamSeekSet(m_pstmOut, posCurrent);
  1533. }
  1534. }
  1535. if (SUCCEEDED(hr)) {
  1536. CSSDOUT("Loaded an inner header.");
  1537. if (IsOpaqueSecureContentType(pContHeader)) {
  1538. CSSDOUT("Sniffed an inner PKCS#7.");
  1539. // the HandleNesting call will reset m_pstmOut
  1540. TrapError(HandleNesting(pContHeader));
  1541. }
  1542. m_csStream = CSTM_STREAMING;
  1543. }
  1544. #ifdef DEBUG
  1545. else {
  1546. CSSDOUT("Load of inner header failed.");
  1547. }
  1548. #endif
  1549. pContHeader->Release();
  1550. }
  1551. }
  1552. if (fFinal) {
  1553. m_csStream = CSTM_STREAMING_DONE;
  1554. }
  1555. if (m_pConverter) {
  1556. BLOB blob;
  1557. blob.pBlobData = pbData;
  1558. blob.cbSize = cbData;
  1559. hr = m_pConverter->HrFillAppend(&blob);
  1560. if (SUCCEEDED(hr)) {
  1561. if (m_dwFlagsStm & CSTM_DECODE) {
  1562. hr = m_pConverter->HrInternetDecode(fFinal);
  1563. }
  1564. else {
  1565. hr = m_pConverter->HrInternetEncode(fFinal);
  1566. }
  1567. }
  1568. if (SUCCEEDED(hr)) {
  1569. hr = m_pConverter->HrWriteConverted(m_pstmOut);
  1570. }
  1571. else {
  1572. hr = m_pstmOut->Write(pbData, cbData, NULL);
  1573. }
  1574. }
  1575. else {
  1576. hr = m_pstmOut->Write(pbData, cbData, NULL);
  1577. }
  1578. #ifdef SMIME_V3
  1579. MemFree(szContentType);
  1580. #endif // SMIME_V3
  1581. return SUCCEEDED(hr) ? TRUE : FALSE;
  1582. }
  1583. /* SniffForEndOfHeader:
  1584. **
  1585. ** Purpose:
  1586. ** see if we have accumulated two blank lines in a row
  1587. ** Takes:
  1588. ** a buffer to scan and size of the buffer
  1589. ** Returns:
  1590. ** number of characters from the end of the second \n
  1591. */
  1592. int CCAPIStm::SniffForEndOfHeader(
  1593. BYTE * pbData,
  1594. DWORD cbData)
  1595. {
  1596. BOOL fCR, fEOL;
  1597. // state is saved b/c the double blank could cross
  1598. // a buffer chunk's boundary
  1599. // restore old state and also reset
  1600. fCR = m_dwFlagsStm & CSTM_HAVECR;
  1601. fEOL = m_dwFlagsStm & CSTM_HAVEEOL;
  1602. if (fCR || fEOL) {
  1603. m_dwFlagsStm &= ~(CSTM_HAVECR | CSTM_HAVEEOL);
  1604. }
  1605. while (cbData) {
  1606. if (chCR == *pbData) {
  1607. fCR = TRUE;
  1608. }
  1609. else if (fCR && (chLF == *pbData)) {
  1610. if (fEOL) {
  1611. // double blank line
  1612. return cbData;
  1613. }
  1614. fCR = FALSE;
  1615. fEOL = TRUE;
  1616. }
  1617. else {
  1618. fCR = FALSE;
  1619. fEOL = FALSE;
  1620. }
  1621. pbData++;
  1622. cbData--;
  1623. }
  1624. // state was reset above. persist if we need to.
  1625. if (fCR || fEOL) {
  1626. m_dwFlagsStm |= (fCR ? CSTM_HAVECR : 0) | (fEOL ? CSTM_HAVEEOL : 0);
  1627. }
  1628. return -1;
  1629. }
  1630. HRESULT CCAPIStm::HandleNesting(CMimePropertyContainer *pContHeader)
  1631. {
  1632. ENCODINGTYPE iet;
  1633. iet = pContHeader->GetEncodingType();
  1634. if (!(IET_BINARY == iet || IET_7BIT == iet || IET_8BIT == iet)) {
  1635. CONVINITINFO ciiDecode;
  1636. // we actually need to decode
  1637. ciiDecode.dwFlags = 0;
  1638. ciiDecode.ietEncoding = iet;
  1639. ciiDecode.fEncoder = FALSE;
  1640. TrapError(HrCreateInternetConverter(&ciiDecode, &m_pConverter));
  1641. }
  1642. return InitInner();
  1643. }
  1644. HRESULT CCAPIStm::InitInner()
  1645. {
  1646. SMIMEINFO siBuilt;
  1647. ULARGE_INTEGER liSize;
  1648. // Init siBuilt
  1649. memset(&siBuilt, 0, sizeof(siBuilt));
  1650. // now also fixup the stream back to a near original
  1651. // state. if for some reason the data written after
  1652. // now is smaller than the header is, this
  1653. // work will make sure we don't keep bits of the header
  1654. HrStreamSeekSet(m_pstmOut, m_cbBeginWrite);
  1655. liSize.LowPart = m_cbBeginSize;
  1656. liSize.HighPart = m_cbBeginWrite;
  1657. m_pstmOut->SetSize(liSize);
  1658. siBuilt.hProv = m_hProv;
  1659. #ifdef OLD_STUFF
  1660. // BUGBUG: Is something like this needed?
  1661. siBuilt.ssEncrypt.pcDecryptionCert = m_pUserCertDecrypt;
  1662. #endif // OLD_STUFF
  1663. siBuilt.cStores = m_cStores;
  1664. siBuilt.rgStores = m_rgStores;
  1665. return InitInner(&siBuilt);
  1666. }
  1667. HRESULT CCAPIStm::InitInner(
  1668. SMIMEINFO *const psi,
  1669. CCAPIStm * pOuter,
  1670. PSECURITY_LAYER_DATA psldOuter)
  1671. {
  1672. HRESULT hr;
  1673. if (! pOuter) {
  1674. m_pCapiInner = new CCAPIStm(m_pstmOut);
  1675. CHECKHR(hr = m_pCapiInner-> HrInnerInitialize(m_dwFlagsSEF, m_hwnd, m_dwFlagsStm, m_pSmimeCallback, psldOuter));
  1676. if (!psldOuter) {
  1677. // Hook up the chain of Security Layer Data objects.
  1678. Assert(! m_psldData->m_psldInner);
  1679. m_pCapiInner->m_psldData->AddRef();
  1680. m_psldData->m_psldInner = m_pCapiInner->m_psldData;
  1681. if (m_pCapiInner->m_psldData) {
  1682. // Init the Up pointer of the new layer data
  1683. m_pCapiInner->m_psldData->m_psldOuter = m_psldData;
  1684. }
  1685. }
  1686. // recurse
  1687. return m_pCapiInner->InitInner(psi, this, psldOuter);
  1688. }
  1689. Assert(!m_pCapiInner);
  1690. Assert(pOuter);
  1691. Assert(psi);
  1692. m_dwFlagsStm = pOuter->m_dwFlagsStm & CSTM_ALLFLAGS;
  1693. // This will get me involved
  1694. ReleaseObj(pOuter->m_pstmOut);
  1695. pOuter->m_pstmOut = (IStream*)this;
  1696. AddRef(); // outer is holding 1
  1697. m_dwFlagsStm |= CSTM_RECURSED;
  1698. if (pOuter->m_dwFlagsStm & CSTM_DECODE) {
  1699. hr = BeginDecodeStreaming(psi);
  1700. }
  1701. else {
  1702. // don't support detached inner CRYPTMSGs
  1703. m_dwFlagsStm &= ~CSTM_DETACHED;
  1704. hr = BeginEncodeStreaming(psi);
  1705. }
  1706. m_dwFlagsStm &= ~CSTM_RECURSED;
  1707. exit:
  1708. return hr;
  1709. }
  1710. //
  1711. // Gets the immediate outermost decryption cert (if any).
  1712. //
  1713. PCCERT_CONTEXT CCAPIStm::GetOuterDecryptCert()
  1714. {
  1715. PCCERT_CONTEXT pccertDecrypt = NULL;
  1716. PSECURITY_LAYER_DATA psldOuter = NULL;
  1717. Assert(NULL != m_psldData);
  1718. if (NULL != m_psldData) {
  1719. psldOuter = m_psldData->m_psldOuter;
  1720. }
  1721. while (NULL != psldOuter) {
  1722. if (NULL != psldOuter->m_pccertDecrypt) {
  1723. Assert( MST_ENCRYPT_MASK & (psldOuter->m_dwMsgEnhancement) );
  1724. pccertDecrypt = psldOuter->m_pccertDecrypt;
  1725. break;
  1726. }
  1727. psldOuter = psldOuter->m_psldOuter;
  1728. }
  1729. return pccertDecrypt;
  1730. }
  1731. HCERTSTORE
  1732. OpenAllStore(
  1733. IN DWORD cStores,
  1734. IN HCERTSTORE rgStores[],
  1735. IN OUT HCERTSTORE *phCertStoreAddr,
  1736. IN OUT HCERTSTORE *phCertStoreCA,
  1737. IN OUT HCERTSTORE *phCertStoreMy,
  1738. IN OUT HCERTSTORE *phCertStoreRoot
  1739. )
  1740. {
  1741. HCERTSTORE hstoreAll;
  1742. DWORD i;
  1743. hstoreAll = CertOpenStore(CERT_STORE_PROV_COLLECTION, X509_ASN_ENCODING,
  1744. NULL, 0, NULL);
  1745. if (hstoreAll == NULL) {
  1746. return NULL;
  1747. }
  1748. for (i=0; i<cStores; i++) {
  1749. CertAddStoreToCollection(hstoreAll, rgStores[i], 0, 0);
  1750. }
  1751. // Open the standard system stores
  1752. *phCertStoreAddr = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING,
  1753. NULL, CERT_SYSTEM_STORE_CURRENT_USER,
  1754. s_cszWABCertStore);
  1755. if (*phCertStoreAddr != NULL) {
  1756. CertAddStoreToCollection(hstoreAll, *phCertStoreAddr, 0, 0);
  1757. }
  1758. *phCertStoreMy = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, NULL,
  1759. CERT_SYSTEM_STORE_CURRENT_USER, s_cszMy);
  1760. if (*phCertStoreMy != NULL) {
  1761. CertAddStoreToCollection(hstoreAll, *phCertStoreMy, 0, 0);
  1762. }
  1763. *phCertStoreCA = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, NULL,
  1764. CERT_SYSTEM_STORE_CURRENT_USER, s_cszCA);
  1765. if (*phCertStoreCA != NULL) {
  1766. CertAddStoreToCollection(hstoreAll, *phCertStoreCA, 0, 0);
  1767. }
  1768. *phCertStoreRoot = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, NULL,
  1769. CERT_SYSTEM_STORE_CURRENT_USER, "Root");
  1770. if (*phCertStoreRoot != NULL) {
  1771. CertAddStoreToCollection(hstoreAll, *phCertStoreRoot, 0, 0);
  1772. }
  1773. return hstoreAll;
  1774. }
  1775. ///////////////////////////////////////////////////////////////////////////
  1776. //
  1777. // The enveloped and signed message parsers
  1778. //
  1779. /* VerifySignedMessage:
  1780. **
  1781. ** Purpose:
  1782. ** Using CAPI, this loads the certs from the message and tests to find
  1783. ** the one hopefully used to sign the message. CAPI builds a new hash
  1784. ** using this cert and compares it with the hash from the SignerInfo.
  1785. ** Takes:
  1786. ** IN hMsg - built CAPI message containing cyphertext
  1787. ** OUT psi - certificate used for signing, and if it was part of hMsg
  1788. ** OUT OPTIONAL pPlain - blob containing cleartext
  1789. ** Returns:
  1790. ** MIME_E_SECURITY_MULTSIGNERS if cSigners > 1. We can't deal.
  1791. ** MIME_E_SECURITY_BADCONTENT if I don't understand the message type of the
  1792. ** inner data
  1793. ** else S_OK or E_FAIL
  1794. */
  1795. HRESULT CCAPIStm::VerifySignedMessage()
  1796. {
  1797. CRYPT_SMIME_CAPABILITIES cap;
  1798. DWORD cbData = 0;
  1799. DWORD cCerts;
  1800. DWORD cSigners = 0;
  1801. DWORD dexStore;
  1802. BOOL f;
  1803. #ifdef SMIME_V3
  1804. BOOL fLookForReceiptRequest = TRUE;
  1805. #endif // SMIME_V3
  1806. HCERTSTORE hCertStoreAddr = NULL;
  1807. HCERTSTORE hCertStoreCA = NULL;
  1808. HCERTSTORE hCertStoreMy = NULL;
  1809. HCERTSTORE hCertStoreRoot = NULL;
  1810. HCERTSTORE hMsgCertStore = NULL;
  1811. HRESULT hr = S_OK;
  1812. DWORD i;
  1813. DWORD iSigner;
  1814. #ifdef SMIME_V3
  1815. DWORD iSignData;
  1816. CRYPT_ATTR_BLOB attrReceiptReq = {0};
  1817. CRYPT_ATTR_BLOB attrSecLabel = {0};
  1818. DWORD cblabel;
  1819. CMSG_CMS_SIGNER_INFO cmsSignerInfo;
  1820. DWORD dwCtrl;
  1821. HCERTSTORE hstoreAll = NULL;
  1822. PSMIME_RECEIPT_REQUEST preq = NULL;
  1823. PSMIME_SECURITY_LABEL plabel = NULL;
  1824. CMSG_CMS_SIGNER_INFO * pCmsSignerInfo = NULL;
  1825. LPVOID pv;
  1826. CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA verifySignature;
  1827. #endif // SMIME_V3
  1828. PCCERT_CONTEXT pccertSigner = NULL;
  1829. SignerData * pSignerData = NULL;
  1830. PCMSG_SIGNER_INFO pSignerInfo = NULL;
  1831. CERT_INFO SignerId;
  1832. LPSTR szContentType = NULL;
  1833. Assert(m_hMsg);
  1834. Assert(m_psldData->m_fCertInLayer == FALSE);
  1835. // Get the number of signers
  1836. cbData = sizeof(cSigners);
  1837. f = CryptMsgGetParam(m_hMsg, CMSG_SIGNER_COUNT_PARAM, 0, &cSigners, &cbData);
  1838. if (!f) {
  1839. goto CryptoError;
  1840. }
  1841. if (cSigners == 0) {
  1842. hr = MIME_E_NO_SIGNER;
  1843. goto ErrorReturn;
  1844. }
  1845. // Allocate space to hold the signer information
  1846. if (!MemAlloc((LPVOID *) &pSignerData, cSigners * sizeof(SignerData))) {
  1847. hr = E_OUTOFMEMORY;
  1848. goto ErrorReturn;
  1849. }
  1850. m_psldData->m_rgSigners = pSignerData;
  1851. m_psldData->m_cSigners = cSigners;
  1852. // Initialized to a known state
  1853. memset(pSignerData, 0, cSigners * sizeof(SignerData));
  1854. for (i=0; i<cSigners; i++) {
  1855. pSignerData[i].ulValidity = MSV_UNVERIFIABLE;
  1856. }
  1857. // If there are certificates in the message, get a store provider which
  1858. // maps to the certificates in the message for later lookup.
  1859. Assert(sizeof(cCerts) == cbData);
  1860. f = CryptMsgGetParam(m_hMsg, CMSG_CERT_COUNT_PARAM, 0, &cCerts, &cbData);
  1861. Assert(f);
  1862. if (f && cCerts) {
  1863. // since there are certs included, let's try them first when matching
  1864. // certs with signers.
  1865. // get the store set
  1866. // make sure we keep hold of our provider
  1867. hMsgCertStore = CertOpenStore(CERT_STORE_PROV_MSG, X509_ASN_ENCODING,
  1868. m_hProv, 0, m_hMsg);
  1869. if (hMsgCertStore) {
  1870. m_dwFlagsStm |= CSTM_DONTRELEASEPROV; // given unto the store
  1871. }
  1872. // if it failed, we just don't have a store then
  1873. Assert(hMsgCertStore != NULL);
  1874. m_psldData->m_hcertstor = CertDuplicateStore(hMsgCertStore);
  1875. }
  1876. //
  1877. // Walk through each and every signature attempting to verify each signature
  1878. //
  1879. for (iSigner=0; iSigner<cSigners; iSigner++, pSignerData++) {
  1880. // Preconditions
  1881. Assert(pccertSigner == NULL);
  1882. // release the signer info from the previous iteration.
  1883. SafeMemFree(pSignerInfo);
  1884. if (pCmsSignerInfo != &cmsSignerInfo) {
  1885. SafeMemFree(pCmsSignerInfo);
  1886. }
  1887. // get the issuer and serial number from the ith SignerInfo
  1888. if (g_FSupportV3) {
  1889. hr = HrGetMsgParam(m_hMsg, CMSG_CMS_SIGNER_INFO_PARAM, iSigner,
  1890. (LPVOID *) &pCmsSignerInfo, NULL);
  1891. if (FAILED(hr)) {
  1892. goto ErrorReturn;
  1893. }
  1894. }
  1895. else {
  1896. hr = HrGetMsgParam(m_hMsg, CMSG_SIGNER_INFO_PARAM, iSigner,
  1897. (LPVOID *) &pSignerInfo, NULL);
  1898. if (FAILED(hr))
  1899. {
  1900. goto ErrorReturn;
  1901. }
  1902. cmsSignerInfo.dwVersion = pSignerInfo->dwVersion;
  1903. cmsSignerInfo.SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
  1904. cmsSignerInfo.SignerId.IssuerSerialNumber.Issuer = pSignerInfo->Issuer;
  1905. cmsSignerInfo.SignerId.IssuerSerialNumber.SerialNumber = pSignerInfo->SerialNumber;
  1906. cmsSignerInfo.HashAlgorithm = pSignerInfo->HashAlgorithm;
  1907. cmsSignerInfo.HashEncryptionAlgorithm = pSignerInfo->HashEncryptionAlgorithm;
  1908. cmsSignerInfo.EncryptedHash = pSignerInfo->EncryptedHash;
  1909. cmsSignerInfo.AuthAttrs = pSignerInfo->AuthAttrs;
  1910. cmsSignerInfo.UnauthAttrs = pSignerInfo->UnauthAttrs;
  1911. pCmsSignerInfo = &cmsSignerInfo;
  1912. // (post-SDR)
  1913. // Build up IASN
  1914. SignerId.Issuer = pSignerInfo->Issuer;
  1915. SignerId.SerialNumber = pSignerInfo->SerialNumber;
  1916. }
  1917. // Our best bet to easily find a certificate is in the message provided
  1918. // list of certificates.
  1919. if (hMsgCertStore) {
  1920. if (g_FSupportV3) {
  1921. pccertSigner = CertFindCertificateInStore(hMsgCertStore, X509_ASN_ENCODING, 0,
  1922. CERT_FIND_CERT_ID,
  1923. &pCmsSignerInfo->SignerId, NULL);
  1924. }
  1925. else {
  1926. pccertSigner = CertGetSubjectCertificateFromStore(hMsgCertStore,
  1927. X509_ASN_ENCODING, &SignerId);
  1928. }
  1929. if (pccertSigner != NULL) {
  1930. m_psldData->m_fCertInLayer = TRUE;
  1931. }
  1932. }
  1933. if (pccertSigner == NULL) {
  1934. if (g_FSupportV3) {
  1935. hstoreAll = OpenAllStore(
  1936. m_cStores,
  1937. m_rgStores,
  1938. &hCertStoreAddr,
  1939. &hCertStoreCA,
  1940. &hCertStoreMy,
  1941. &hCertStoreRoot
  1942. );
  1943. if (hstoreAll == NULL)
  1944. goto CryptoError;
  1945. pccertSigner = CertFindCertificateInStore(hstoreAll, X509_ASN_ENCODING, 0,
  1946. CERT_FIND_CERT_ID,
  1947. &pCmsSignerInfo->SignerId, NULL);
  1948. }
  1949. else {
  1950. Assert(!g_FSupportV3);
  1951. CSSDOUT("Couldn't find cert in message store");
  1952. // Look in the caller specified cert store before the hard coded stores.
  1953. for (dexStore=0; dexStore<m_cStores; dexStore++) {
  1954. if (m_rgStores[dexStore]) {
  1955. if (pccertSigner = CertGetSubjectCertificateFromStore(
  1956. m_rgStores[dexStore], X509_ASN_ENCODING, &SignerId)) {
  1957. break;
  1958. }
  1959. }
  1960. }
  1961. if (!pccertSigner) {
  1962. // Look in the "Address Book" store
  1963. if (hCertStoreAddr == NULL) {
  1964. hCertStoreAddr = CertOpenStore(CERT_STORE_PROV_SYSTEM_A,
  1965. X509_ASN_ENCODING, NULL, CERT_SYSTEM_STORE_CURRENT_USER,
  1966. s_cszWABCertStore);
  1967. }
  1968. if (hCertStoreAddr != NULL) {
  1969. pccertSigner = CertGetSubjectCertificateFromStore(
  1970. hCertStoreAddr, X509_ASN_ENCODING, &SignerId);
  1971. }
  1972. }
  1973. if (!pccertSigner) {
  1974. // Look in the "My" store
  1975. if (hCertStoreMy == NULL) {
  1976. hCertStoreMy = CertOpenStore(CERT_STORE_PROV_SYSTEM_A,
  1977. X509_ASN_ENCODING, NULL,
  1978. CERT_SYSTEM_STORE_CURRENT_USER,
  1979. s_cszMy);
  1980. }
  1981. if (hCertStoreMy != NULL) {
  1982. pccertSigner = CertGetSubjectCertificateFromStore(
  1983. hCertStoreMy, X509_ASN_ENCODING, &SignerId);
  1984. }
  1985. }
  1986. if (!pccertSigner) {
  1987. // Look in the "CA" store
  1988. if (hCertStoreCA == NULL) {
  1989. hCertStoreCA = CertOpenStore(CERT_STORE_PROV_SYSTEM_A,
  1990. X509_ASN_ENCODING, NULL,
  1991. CERT_SYSTEM_STORE_CURRENT_USER, s_cszCA);
  1992. }
  1993. if (hCertStoreCA) {
  1994. pccertSigner = CertGetSubjectCertificateFromStore(
  1995. hCertStoreCA, X509_ASN_ENCODING, &SignerId);
  1996. }
  1997. }
  1998. }
  1999. }
  2000. //
  2001. // By now we should have a certificate to verify with, if we don't then
  2002. // we need to say we can't do anything with it.
  2003. //
  2004. if (!pccertSigner) {
  2005. // we still can't find the cert. Therefore, cannot verify signer
  2006. CSSDOUT("Cannot verify signer");
  2007. pSignerData->ulValidity = MSV_UNVERIFIABLE;
  2008. } else {
  2009. pSignerData->pccert = CertDuplicateCertificateContext(pccertSigner);
  2010. if (g_FSupportV3) {
  2011. dwCtrl = CMSG_CTRL_VERIFY_SIGNATURE_EX;
  2012. pv = &verifySignature;
  2013. verifySignature.cbSize = sizeof(verifySignature);
  2014. verifySignature.hCryptProv = NULL;
  2015. verifySignature.dwSignerIndex = iSigner;
  2016. verifySignature.dwSignerType = CMSG_VERIFY_SIGNER_CERT;
  2017. verifySignature.pvSigner = (LPVOID) pccertSigner;
  2018. }
  2019. else {
  2020. dwCtrl = CMSG_CTRL_VERIFY_SIGNATURE;
  2021. pv = pccertSigner->pCertInfo;
  2022. }
  2023. retry:
  2024. if (!CryptMsgControl(m_hMsg, 0, dwCtrl, pv)) {
  2025. HRESULT hr2 = HrGetLastError();
  2026. CSSDOUT("Failed signer verify --> %lx", hr2);
  2027. if (hr2 == CRYPT_E_MISSING_PUBKEY_PARA) {
  2028. if (NULL == hstoreAll && g_FSupportV3) {
  2029. hstoreAll = OpenAllStore(
  2030. m_cStores,
  2031. m_rgStores,
  2032. &hCertStoreAddr,
  2033. &hCertStoreCA,
  2034. &hCertStoreMy,
  2035. &hCertStoreRoot
  2036. );
  2037. if (NULL == hstoreAll)
  2038. goto CryptoError;
  2039. }
  2040. hr2 = GetParameters(pccertSigner, hMsgCertStore, hstoreAll);
  2041. if (hr2 == S_OK) {
  2042. goto retry;
  2043. }
  2044. pSignerData->ulValidity = MSV_UNVERIFIABLE;
  2045. }
  2046. else if (NTE_BAD_SIGNATURE == hr2 || CRYPT_E_HASH_VALUE == hr2) {
  2047. pSignerData->ulValidity = MSV_BADSIGNATURE;
  2048. } else if (NTE_BAD_ALGID == hr2) {
  2049. pSignerData->ulValidity = MSV_UNKHASH;
  2050. } else if (CRYPT_E_SIGNER_NOT_FOUND == hr2) {
  2051. pSignerData->ulValidity = MSV_UNVERIFIABLE;
  2052. } else if (NTE_FAIL == hr2) {
  2053. // RSABASE returns errors. This might
  2054. // be a failure or the hash might be changed.
  2055. // Have to be cautious -> make it bad.
  2056. pSignerData->ulValidity = MSV_BADSIGNATURE;
  2057. } else {
  2058. pSignerData->ulValidity = MSV_MALFORMEDSIG;
  2059. }
  2060. } else {
  2061. CSSDOUT("Verify of signature succeeded.");
  2062. pSignerData->ulValidity &=
  2063. ~(MSV_SIGNATURE_MASK|MSV_SIGNING_MASK);
  2064. }
  2065. // Determine if certificate is expired
  2066. if (0 != CertVerifyTimeValidityWithDelta(NULL, pccertSigner->pCertInfo, TIME_DELTA_SECONDS)) {
  2067. pSignerData->ulValidity |= MSV_EXPIRED_SIGNINGCERT;
  2068. }
  2069. }
  2070. if (szContentType = (LPSTR)PVGetMsgParam(m_hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, NULL, NULL)) {
  2071. if (lstrcmp(szOID_PKCS_7_DATA, szContentType)) {
  2072. CSSDOUT("Guess what, we have nested PKCS7 data types (maybe).");
  2073. }
  2074. } else {
  2075. // CAPI failed... we are in trouble...
  2076. pSignerData->ulValidity |= MSV_INVALID;
  2077. hr = MIME_E_SECURITY_BADCONTENT;
  2078. goto ErrorReturn;
  2079. }
  2080. // Grab the hashing alg
  2081. cap.cCapability = 1;
  2082. cap.rgCapability = (CRYPT_SMIME_CAPABILITY *) &pCmsSignerInfo->HashAlgorithm;
  2083. if (!CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_SMIME_CAPABILITIES,
  2084. &cap, CRYPT_ENCODE_ALLOC_FLAG, &CryptEncodeAlloc,
  2085. &pSignerData->blobHashAlg.pBlobData,
  2086. &pSignerData->blobHashAlg.cbSize)) {
  2087. Assert(FALSE);
  2088. }
  2089. //
  2090. // Get the attributes, authenicated and unauthenicated, and put into the
  2091. // structure so we can push them back to the user later
  2092. if (pCmsSignerInfo->AuthAttrs.cAttr != 0) {
  2093. #ifdef SMIME_V3
  2094. for (i=0; i<pCmsSignerInfo->AuthAttrs.cAttr; i++) {
  2095. // If we have a security label in this message, then we need to
  2096. // perform access validation.
  2097. if (g_FSupportV3 && FIsMsasn1Loaded()) {
  2098. if (strcmp(pCmsSignerInfo->AuthAttrs.rgAttr[i].pszObjId,
  2099. szOID_SMIME_Security_Label) == 0) {
  2100. if ((pSignerData->ulValidity & MSV_SIGNATURE_MASK) != MSV_OK) {
  2101. DWORD dw = DwProcessLabelWithCertError();
  2102. if (CertErrorProcessLabelGrant == dw) {
  2103. hr = S_OK;
  2104. continue;
  2105. }
  2106. else if (CertErrorProcessLabelDeny == dw) {
  2107. hr = MIME_E_SECURITY_LABELACCESSDENIED;
  2108. goto ErrorReturn;
  2109. }
  2110. // else continue processing the label.
  2111. }
  2112. if (pCmsSignerInfo->AuthAttrs.rgAttr[i].cValue != 1) {
  2113. hr = MIME_E_SECURITY_LABELCORRUPT;
  2114. goto ErrorReturn;
  2115. }
  2116. // Have we already seen a label?
  2117. if (attrSecLabel.pbData != NULL) {
  2118. // Check that the one we saw matches this one
  2119. if ((attrSecLabel.cbData !=
  2120. pCmsSignerInfo->AuthAttrs.rgAttr[i].rgValue[0].cbData) ||
  2121. memcmp(attrSecLabel.pbData,
  2122. pCmsSignerInfo->AuthAttrs.rgAttr[i].rgValue[0].pbData,
  2123. attrSecLabel.cbData)) {
  2124. if (FHideMsgWithDifferentLabels()) {
  2125. hr = MIME_E_SECURITY_LABELCORRUPT;
  2126. goto ErrorReturn;
  2127. }
  2128. else {
  2129. continue;
  2130. }
  2131. }
  2132. else {
  2133. continue;
  2134. }
  2135. }
  2136. else {
  2137. // Save label.
  2138. attrSecLabel.cbData = pCmsSignerInfo->AuthAttrs.rgAttr[i].rgValue[0].cbData;
  2139. if (!MemAlloc((LPVOID*) (& attrSecLabel.pbData), attrSecLabel.cbData)) {
  2140. hr = MIME_E_SECURITY_LABELCORRUPT;
  2141. goto ErrorReturn;
  2142. }
  2143. memcpy(attrSecLabel.pbData, pCmsSignerInfo->AuthAttrs.rgAttr[i].rgValue[0].pbData,
  2144. attrSecLabel.cbData);
  2145. }
  2146. // Clean-up from last loop
  2147. if (plabel != NULL) CryptDecodeAlloc.pfnFree(plabel);
  2148. // Crack the contents of the label
  2149. if (!CryptDecodeObjectEx(X509_ASN_ENCODING,
  2150. szOID_SMIME_Security_Label,
  2151. pCmsSignerInfo->AuthAttrs.rgAttr[i].rgValue[0].pbData,
  2152. pCmsSignerInfo->AuthAttrs.rgAttr[i].rgValue[0].cbData,
  2153. CRYPT_ENCODE_ALLOC_FLAG, &CryptDecodeAlloc,
  2154. &plabel, &cblabel)) {
  2155. goto CryptoError;
  2156. }
  2157. // Query the policy.
  2158. hr = HrCheckLabelAccess((m_dwFlagsSEF & SEF_NOUI) ?
  2159. SMIME_POLICY_MODULE_NOUI: 0,
  2160. m_hwnd, plabel, GetOuterDecryptCert(),
  2161. pccertSigner, hMsgCertStore);
  2162. // If security policy returned an error, then abort.
  2163. if (FAILED(hr)) {
  2164. goto ErrorReturn;
  2165. }
  2166. }
  2167. }
  2168. if (g_FSupportV3 && FIsMsasn1Loaded() && (fLookForReceiptRequest) &&
  2169. ((pSignerData->ulValidity & (MSV_SIGNATURE_MASK | MSV_SIGNING_MASK)) == MSV_OK)) {
  2170. // If we have a receipt request in this message than we need to build
  2171. // the receipt body now while we have a chance.
  2172. if (strcmp(pCmsSignerInfo->AuthAttrs.rgAttr[i].pszObjId,
  2173. szOID_SMIME_Receipt_Request) == 0) {
  2174. if (pCmsSignerInfo->AuthAttrs.rgAttr[i].cValue != 1) {
  2175. if (attrReceiptReq.pbData != NULL) {
  2176. StopSendOfReceipt:
  2177. for (iSignData=0; iSignData < iSigner; iSignData++) {
  2178. SafeMemFree(m_psldData->m_rgSigners[iSignData].blobReceipt.pBlobData);
  2179. SafeMemFree(m_psldData->m_rgSigners[iSignData].blobHash.pBlobData);
  2180. m_psldData->m_rgSigners[iSignData].blobReceipt.cbSize = 0;
  2181. m_psldData->m_rgSigners[iSignData].blobHash.cbSize = 0;
  2182. }
  2183. }
  2184. fLookForReceiptRequest = FALSE;
  2185. continue;
  2186. }
  2187. DWORD cb;
  2188. DWORD cbReceipt;
  2189. DWORD cbHash = 0;
  2190. LPBYTE pbReceipt = NULL;
  2191. LPBYTE pbHash = NULL;
  2192. SMIME_RECEIPT receipt = {0};
  2193. // Clean-up from last loop
  2194. if (preq != NULL) free(preq);
  2195. // Have we already seen a receipt?
  2196. if (attrReceiptReq.pbData != NULL) {
  2197. // Check that the one we saw matches this one
  2198. if ((attrReceiptReq.cbData !=
  2199. pCmsSignerInfo->AuthAttrs.rgAttr[i].rgValue[0].cbData) ||
  2200. memcmp(attrReceiptReq.pbData,
  2201. pCmsSignerInfo->AuthAttrs.rgAttr[i].rgValue[0].pbData,
  2202. attrReceiptReq.cbData)) {
  2203. goto StopSendOfReceipt;
  2204. }
  2205. }
  2206. else {
  2207. // Save receipt request
  2208. attrReceiptReq.cbData = pCmsSignerInfo->AuthAttrs.rgAttr[i].rgValue[0].cbData;
  2209. if (!MemAlloc((LPVOID*) (& attrReceiptReq.pbData), attrReceiptReq.cbData)) {
  2210. // abort looking for receipt requests.
  2211. goto StopSendOfReceipt;
  2212. }
  2213. memcpy(attrReceiptReq.pbData, pCmsSignerInfo->AuthAttrs.rgAttr[i].rgValue[0].pbData,
  2214. attrReceiptReq.cbData);
  2215. }
  2216. // Crack the contents of the receipt
  2217. if (!CryptDecodeObjectEx(X509_ASN_ENCODING,
  2218. szOID_SMIME_Receipt_Request,
  2219. pCmsSignerInfo->AuthAttrs.rgAttr[i].rgValue[0].pbData,
  2220. pCmsSignerInfo->AuthAttrs.rgAttr[i].rgValue[0].cbData,
  2221. CRYPT_ENCODE_ALLOC_FLAG, &CryptDecodeAlloc,
  2222. &preq, &cb)) {
  2223. goto StopSendOfReceipt;
  2224. }
  2225. // Encode the receipt
  2226. receipt.Version = 1;
  2227. receipt.pszOIDContent = szContentType;
  2228. receipt.ContentIdentifier = preq->ContentIdentifier;
  2229. receipt.OriginatorSignature.cbData = pCmsSignerInfo->EncryptedHash.cbData;
  2230. receipt.OriginatorSignature.pbData = pCmsSignerInfo->EncryptedHash.pbData;
  2231. if (!CryptEncodeObjectEx(X509_ASN_ENCODING,
  2232. szOID_SMIME_ContentType_Receipt,
  2233. &receipt, CRYPT_ENCODE_ALLOC_FLAG,
  2234. &CryptEncodeAlloc, &pbReceipt,
  2235. &cbReceipt)) {
  2236. goto StopSendOfReceipt;
  2237. }
  2238. pSignerData->blobReceipt.cbSize = cbReceipt;
  2239. pSignerData->blobReceipt.pBlobData = pbReceipt;
  2240. pbHash = (LPBYTE)PVGetMsgParam(m_hMsg, CMSG_COMPUTED_HASH_PARAM,
  2241. NULL, &cbHash);
  2242. if (pbHash == NULL) {
  2243. goto CryptoError;
  2244. }
  2245. pSignerData->blobHash.cbSize = cbHash;
  2246. pSignerData->blobHash.pBlobData = pbHash;
  2247. }
  2248. }
  2249. }
  2250. #endif // SMIME_V3
  2251. //
  2252. cbData = 0;
  2253. LPBYTE pb;
  2254. if (!CryptEncodeObjectEx(X509_ASN_ENCODING, szOID_Microsoft_Attribute_Sequence,
  2255. &pCmsSignerInfo->AuthAttrs, CRYPT_ENCODE_ALLOC_FLAG,
  2256. &CryptEncodeAlloc, &pb, &cbData)) {
  2257. goto CryptoError;
  2258. }
  2259. pSignerData->blobAuth.cbSize = cbData;
  2260. pSignerData->blobAuth.pBlobData = pb;
  2261. }
  2262. if (pCmsSignerInfo->UnauthAttrs.cAttr != 0) {
  2263. LPBYTE pb;
  2264. if (!CryptEncodeObjectEx(X509_ASN_ENCODING, szOID_Microsoft_Attribute_Sequence,
  2265. &pCmsSignerInfo->UnauthAttrs,
  2266. CRYPT_ENCODE_ALLOC_FLAG, &CryptEncodeAlloc,
  2267. &pb, &cbData)) {
  2268. goto CryptoError;
  2269. }
  2270. pSignerData->blobUnauth.cbSize = cbData;
  2271. pSignerData->blobUnauth.pBlobData = pb;
  2272. }
  2273. CertFreeCertificateContext(pccertSigner);
  2274. pccertSigner = NULL;
  2275. }
  2276. exit:
  2277. #ifdef SMIME_V3
  2278. if (preq != NULL) CryptDecodeAlloc.pfnFree(preq);
  2279. if (plabel != NULL) CryptDecodeAlloc.pfnFree(plabel);
  2280. SafeMemFree(attrReceiptReq.pbData);
  2281. SafeMemFree(attrSecLabel.pbData);
  2282. #endif // SMIME_V3
  2283. if (hCertStoreAddr != NULL) CertCloseStore(hCertStoreAddr, 0);
  2284. if (hCertStoreMy != NULL) CertCloseStore(hCertStoreMy, 0);
  2285. if (hCertStoreCA != NULL) CertCloseStore(hCertStoreCA, 0);
  2286. if (hCertStoreRoot != NULL) CertCloseStore(hCertStoreRoot, 0);
  2287. if (hMsgCertStore != NULL) CertCloseStore(hMsgCertStore, 0);
  2288. MemFree(szContentType);
  2289. ReleaseMem(pSignerInfo);
  2290. #ifdef SMIME_V3
  2291. if (pCmsSignerInfo != &cmsSignerInfo) {
  2292. ReleaseMem(pCmsSignerInfo);
  2293. }
  2294. if (hstoreAll != NULL) CertCloseStore(hstoreAll, 0);
  2295. #endif // SMIME_V3
  2296. ReleaseCert(pccertSigner);
  2297. return hr;
  2298. CryptoError:
  2299. hr = HrGetLastError();
  2300. ErrorReturn:
  2301. // On error, release the cert store
  2302. if (m_psldData->m_hcertstor != NULL) {
  2303. CertCloseStore(m_psldData->m_hcertstor, 0);
  2304. m_psldData->m_hcertstor = NULL;
  2305. }
  2306. if (S_OK == hr)
  2307. // our generic error message
  2308. hr = TrapError(MIME_E_SECURITY_BADMESSAGE);
  2309. goto exit;
  2310. }
  2311. static HRESULT GetCSP(PCCERT_CONTEXT pccert, HCRYPTPROV * phprov, DWORD * pdwKeyId)
  2312. {
  2313. HRESULT hr;
  2314. PCRYPT_KEY_PROV_INFO pKPI = NULL;
  2315. Assert(*phprov == NULL);
  2316. Assert(*pdwKeyId == 0);
  2317. //
  2318. //
  2319. hr = HrGetCertificateParam(pccert, CERT_KEY_PROV_INFO_PROP_ID,
  2320. (LPVOID *) &pKPI, NULL);
  2321. if (FAILED(hr)) {
  2322. goto exit;
  2323. }
  2324. *pdwKeyId = pKPI->dwKeySpec;
  2325. // If the cert specifies the base provider OR has no specification,
  2326. // then try to acquire RSAENH, else get RSABASE.
  2327. if ((PROV_RSA_FULL == pKPI->dwProvType) &&
  2328. (UnlocStrEqNW(pKPI->pwszProvName, MS_DEF_PROV_W,
  2329. sizeof(MS_DEF_PROV_W)/sizeof(WCHAR)-5) ||
  2330. (*pKPI->pwszProvName == 0))) {
  2331. if (!CRYPT_ACQUIRE_CONTEXT(phprov, pKPI->pwszContainerName,
  2332. MS_ENHANCED_PROV_W, PROV_RSA_FULL,
  2333. pKPI->dwFlags)) {
  2334. CSSDOUT("CryptAcquireContext -> %x\n", HrGetLastError());
  2335. }
  2336. }
  2337. if (*phprov == NULL) {
  2338. if (! CRYPT_ACQUIRE_CONTEXT(phprov, pKPI->pwszContainerName,
  2339. pKPI->pwszProvName, pKPI->dwProvType,
  2340. pKPI->dwFlags)) {
  2341. CSSDOUT("CryptAcquireContext -> %x\n", HrGetLastError());
  2342. hr = HrGetLastError();
  2343. goto exit;
  2344. }
  2345. }
  2346. hr = S_OK;
  2347. exit:
  2348. ReleaseMem(pKPI);
  2349. return hr;
  2350. }
  2351. HRESULT CCAPIStm::FindKeyFor(HWND hwnd, DWORD dwFlags, DWORD dwRecipientIndex,
  2352. const CMSG_CMS_RECIPIENT_INFO * pRecipInfo,
  2353. HCERTSTORE hcertstore, DWORD * pdwCtrl,
  2354. CMS_CTRL_DECRYPT_INFO * pDecryptInfo,
  2355. PCCERT_CONTEXT * ppCertDecrypt)
  2356. {
  2357. HRESULT hr;
  2358. HCRYPTPROV hProv = NULL;
  2359. DWORD i;
  2360. PCMSG_CTRL_DECRYPT_PARA pccdp;
  2361. PCCERT_CONTEXT pCertDecrypt = NULL;
  2362. PCCERT_CONTEXT pCertOrig = NULL;
  2363. if (g_FSupportV3) {
  2364. switch (pRecipInfo->dwRecipientChoice) {
  2365. //
  2366. // Given the certificate reference, see if we can find it in
  2367. // the passed in certificate stores, if yes then we will attempt
  2368. // to decrypt using that certificate
  2369. //
  2370. // This is a Key Transport recipient info object. The CAPI 2.0
  2371. // code can deal with both SKI and Issuer/Serial Number references
  2372. //
  2373. case CMSG_KEY_TRANS_RECIPIENT:
  2374. pCertDecrypt = CertFindCertificateInStore(hcertstore, X509_ASN_ENCODING,
  2375. 0, CERT_FIND_CERT_ID,
  2376. &pRecipInfo->pKeyTrans->RecipientId, NULL);
  2377. if (pCertDecrypt != NULL) {
  2378. hr = GetCSP(pCertDecrypt, &pDecryptInfo->trans.hCryptProv,
  2379. &pDecryptInfo->trans.dwKeySpec);
  2380. if (SUCCEEDED(hr)) {
  2381. //
  2382. // We find a certificate for this lock box. Setup the
  2383. // structure to be used in decrypting the message.
  2384. //
  2385. *pdwCtrl = CMSG_CTRL_KEY_TRANS_DECRYPT;
  2386. pDecryptInfo->trans.cbSize = sizeof(pDecryptInfo->trans);
  2387. // pDecryptInfo->trans.hCryptProv = hProv;
  2388. // pDecryptInfo->trans.dwKeySpec = pKPI->dwKeySpec;
  2389. pDecryptInfo->trans.pKeyTrans = pRecipInfo->pKeyTrans;
  2390. pDecryptInfo->trans.dwRecipientIndex = dwRecipientIndex;
  2391. }
  2392. else {
  2393. ReleaseCert(pCertDecrypt);
  2394. pCertDecrypt = NULL;
  2395. }
  2396. }
  2397. break;
  2398. //
  2399. // Given the certificate reference, see if we can find it in
  2400. // the passed in certificate stores, if yes then we will attempt
  2401. // to decrypt using that certificate
  2402. //
  2403. // This is a Key Agreement recipient info object. The CAPI 2.0
  2404. // code can deal with both SKI and Issuer/Serial Number references
  2405. //
  2406. // There may be multiple certificate references within a single
  2407. // recipient info object
  2408. //
  2409. case CMSG_KEY_AGREE_RECIPIENT:
  2410. for (i=0; i<pRecipInfo->pKeyAgree->cRecipientEncryptedKeys; i++) {
  2411. pCertDecrypt = CertFindCertificateInStore(
  2412. hcertstore, X509_ASN_ENCODING, 0,
  2413. CERT_FIND_CERT_ID,
  2414. &pRecipInfo->pKeyAgree->rgpRecipientEncryptedKeys[i]->RecipientId,
  2415. NULL);
  2416. if (pCertDecrypt != NULL) {
  2417. hr = GetCSP(pCertDecrypt, &pDecryptInfo->agree.hCryptProv,
  2418. &pDecryptInfo->agree.dwKeySpec);
  2419. if (SUCCEEDED(hr)) {
  2420. //
  2421. // We find a certificate for this lock box. Setup the
  2422. // structure to be used in decrypting the message.
  2423. //
  2424. *pdwCtrl = CMSG_CTRL_KEY_AGREE_DECRYPT;
  2425. pDecryptInfo->agree.cbSize = sizeof(pDecryptInfo->agree);
  2426. pDecryptInfo->agree.pKeyAgree = pRecipInfo->pKeyAgree;
  2427. pDecryptInfo->agree.dwRecipientIndex = dwRecipientIndex;
  2428. pDecryptInfo->agree.dwRecipientEncryptedKeyIndex = i;
  2429. //
  2430. // Need to find the originator information
  2431. //
  2432. switch(pRecipInfo->pKeyAgree->dwOriginatorChoice) {
  2433. case CMSG_KEY_AGREE_ORIGINATOR_CERT:
  2434. pCertOrig = CertFindCertificateInStore( hcertstore, X509_ASN_ENCODING, 0, CERT_FIND_CERT_ID, &pRecipInfo->pKeyAgree->OriginatorCertId, NULL);
  2435. if (pCertOrig == NULL) {
  2436. hr = S_FALSE;
  2437. goto exit;
  2438. }
  2439. hr = HrCopyCryptBitBlob(&pCertOrig->pCertInfo->SubjectPublicKeyInfo.PublicKey,
  2440. &pDecryptInfo->agree.OriginatorPublicKey);
  2441. if (FAILED(hr)) {
  2442. goto exit;
  2443. }
  2444. break;
  2445. case CMSG_KEY_AGREE_ORIGINATOR_PUBLIC_KEY:
  2446. hr = HrCopyCryptBitBlob(&pRecipInfo->pKeyAgree->OriginatorPublicKeyInfo.PublicKey,
  2447. &pDecryptInfo->agree.OriginatorPublicKey);
  2448. if (FAILED(hr)) {
  2449. goto exit;
  2450. }
  2451. break;
  2452. default:
  2453. hr = NTE_FAIL;
  2454. goto exit;
  2455. }
  2456. break;
  2457. }
  2458. else {
  2459. ReleaseCert(pCertDecrypt);
  2460. pCertDecrypt = NULL;
  2461. }
  2462. }
  2463. }
  2464. break;
  2465. //
  2466. // We can't find this from a certificate
  2467. //
  2468. case CMSG_MAIL_LIST_RECIPIENT:
  2469. break;
  2470. default:
  2471. hr = NTE_FAIL;
  2472. goto exit;
  2473. }
  2474. }
  2475. else {
  2476. CERT_INFO * pCertInfo = (CERT_INFO *) pRecipInfo;
  2477. for (i=0; i<m_cStores; i++) {
  2478. pCertDecrypt = CertGetSubjectCertificateFromStore(m_rgStores[i],
  2479. X509_ASN_ENCODING, pCertInfo);
  2480. if (pCertDecrypt != NULL) {
  2481. pccdp = (PCMSG_CTRL_DECRYPT_PARA) pDecryptInfo;
  2482. hr = GetCSP(pCertDecrypt, &pccdp->hCryptProv, &pccdp->dwKeySpec);
  2483. if (SUCCEEDED(hr)) {
  2484. //
  2485. // We find a certificate for this lock box. Setup the
  2486. // structure to be used in decrypting the message.
  2487. //
  2488. *pdwCtrl = CMSG_CTRL_DECRYPT;
  2489. pccdp->cbSize = sizeof(CMSG_CTRL_DECRYPT_PARA);
  2490. pccdp->dwRecipientIndex = dwRecipientIndex;
  2491. }
  2492. else {
  2493. ReleaseCert(pCertDecrypt);
  2494. pCertDecrypt = NULL;
  2495. }
  2496. break;
  2497. }
  2498. }
  2499. }
  2500. //
  2501. // If we did not find a certificate, then return a failure code
  2502. //
  2503. if (pCertDecrypt == NULL) {
  2504. hr = S_FALSE;
  2505. goto exit;
  2506. }
  2507. //
  2508. // If we have a certificate, then return it for the user to examine.
  2509. //
  2510. if (pCertDecrypt != NULL) {
  2511. *ppCertDecrypt = pCertDecrypt;
  2512. pCertDecrypt = NULL;
  2513. }
  2514. hProv = NULL;
  2515. hr = S_OK;
  2516. exit:
  2517. ReleaseCert(pCertDecrypt);
  2518. ReleaseCert(pCertOrig);
  2519. if (hProv != NULL) CryptReleaseContext(hProv, 0);
  2520. return hr;
  2521. }
  2522. BOOL CCAPIStm::HandleEnveloped()
  2523. {
  2524. DWORD cbData;
  2525. DWORD cCerts;
  2526. DWORD cRecips;
  2527. CMS_CTRL_DECRYPT_INFO decryptInfo = {0};
  2528. DWORD dexRecip;
  2529. DWORD dwCtrl;
  2530. BOOL f;
  2531. BOOL fGotoUser = FALSE;
  2532. HCERTSTORE hcertstore = NULL;
  2533. HCERTSTORE hMsgCertStore = NULL;
  2534. HRESULT hr;
  2535. DWORD i;
  2536. PCCERT_CONTEXT pCertDecrypt = NULL;
  2537. CMSG_CMS_RECIPIENT_INFO * pCmsCertInfo;
  2538. LPVOID pv = NULL;
  2539. //
  2540. // If we are not suppose to display UI -- return an error about displaying UI now.
  2541. //
  2542. ////////////////////////////////////////////////////////////////////////////////////////
  2543. // 591349 - Compiler Bug For Zero Initialization of Data Structure. Active WinNT 5.1 (Whistler) 1 Server RC1
  2544. // the line above doesn't zero the structure due to this compiler bug
  2545. memset(&decryptInfo, 0, sizeof(decryptInfo));
  2546. if (m_dwFlagsSEF & SEF_NOUI) {
  2547. return MIME_E_SECURITY_UIREQUIRED;
  2548. }
  2549. //
  2550. // this call exists for one and only one purpose. We must
  2551. // be sure that we have read and parsed all of the RecipientInfo structures
  2552. // before we start processing them. Since the algorithm parameter is after
  2553. // the last of the last of the recipient structures, this make sure of that.
  2554. //
  2555. pv = PVGetMsgParam(m_hMsg, CMSG_ENVELOPE_ALGORITHM_PARAM, 0, NULL);
  2556. if (pv == NULL) {
  2557. goto gle;
  2558. }
  2559. MemFree(pv); pv = NULL;
  2560. //
  2561. // Fetch the set of certificates on the message object
  2562. //
  2563. cbData = sizeof(cCerts);
  2564. f = CryptMsgGetParam(m_hMsg, CMSG_CERT_COUNT_PARAM, 0, &cCerts, &cbData);
  2565. Assert(f);
  2566. if (f && (cCerts > 0)) {
  2567. // since there are certs included, let's try them first when matching
  2568. // certs with enryptors.
  2569. // get the store set
  2570. // make sure we keep hold of our provider
  2571. hMsgCertStore = CertOpenStore(CERT_STORE_PROV_MSG, X509_ASN_ENCODING,
  2572. m_hProv, 0, m_hMsg);
  2573. if (hMsgCertStore) {
  2574. m_dwFlagsStm |= CSTM_DONTRELEASEPROV; // given unto the store
  2575. }
  2576. // if it failed, we just don't have a store then
  2577. Assert(hMsgCertStore != NULL);
  2578. m_psldData->m_hstoreEncrypt = CertDuplicateStore(hMsgCertStore);
  2579. }
  2580. //
  2581. // Retrieve the count of recipient infos on the message
  2582. //
  2583. cbData = sizeof(cRecips);
  2584. if (!CryptMsgGetParam(m_hMsg, g_FSupportV3 ? CMSG_CMS_RECIPIENT_COUNT_PARAM :
  2585. CMSG_RECIPIENT_COUNT_PARAM, 0, &cRecips, &cbData)) {
  2586. goto gle;
  2587. }
  2588. //
  2589. // If we were provided an actual certificate, see if this is it...
  2590. // We will either search for the provided certificate or in the provided
  2591. // certificate stores, but not both.
  2592. //
  2593. if (m_pUserCertDecrypt != NULL) {
  2594. hcertstore = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING,
  2595. NULL, 0, NULL);
  2596. if (hcertstore == NULL) {
  2597. hr = HrGetLastError();
  2598. goto exit;
  2599. }
  2600. if (!CertAddCertificateContextToStore(hcertstore, m_pUserCertDecrypt,
  2601. CERT_STORE_ADD_ALWAYS, NULL)) {
  2602. hr = HrGetLastError();
  2603. goto exit;
  2604. }
  2605. }
  2606. else {
  2607. if (g_FSupportV3) {
  2608. hcertstore = CertOpenStore(CERT_STORE_PROV_COLLECTION, X509_ASN_ENCODING,
  2609. NULL, 0, NULL);
  2610. if (hcertstore == NULL) {
  2611. hr = HrGetLastError();
  2612. goto exit;
  2613. }
  2614. for (i=0; i<m_cStores; i++) {
  2615. CertAddStoreToCollection(hcertstore, m_rgStores[i], 0, 0);
  2616. }
  2617. if (hMsgCertStore != NULL) {
  2618. CertAddStoreToCollection(hcertstore, hMsgCertStore, 0, 0);
  2619. }
  2620. }
  2621. }
  2622. // For each possible recipient
  2623. tryAgain:
  2624. for (dexRecip=0; dexRecip<cRecips; dexRecip++) {
  2625. //
  2626. // Retrieve the desciption of the i-th recipient's lockbox
  2627. //
  2628. hr = HrGetMsgParam(m_hMsg, g_FSupportV3 ? CMSG_CMS_RECIPIENT_INFO_PARAM :
  2629. CMSG_RECIPIENT_INFO_PARAM, dexRecip, (LPVOID *) &pv, NULL);
  2630. if (FAILED(hr)) {
  2631. goto exit;
  2632. }
  2633. //
  2634. // Look to see if there is a decrypt item we can fill in here.
  2635. //
  2636. if (fGotoUser) {
  2637. //
  2638. // Look to see if there is a decrypt item that the user can fill in.
  2639. //
  2640. hr = m_pSmimeCallback->FindKeyFor(m_hwnd, 0, dexRecip,
  2641. (CMSG_CMS_RECIPIENT_INFO *) pv,
  2642. &dwCtrl, &decryptInfo, &pCertDecrypt);
  2643. }
  2644. else {
  2645. hr = FindKeyFor(m_hwnd, 0, dexRecip, (CMSG_CMS_RECIPIENT_INFO *) pv,
  2646. hcertstore, &dwCtrl, &decryptInfo, &pCertDecrypt);
  2647. }
  2648. if (FAILED(hr)) {
  2649. goto exit;
  2650. }
  2651. if (hr == S_OK) {
  2652. #ifdef SMIME_V3
  2653. if (m_pwszKeyPrompt != NULL) {
  2654. PCMSG_CTRL_DECRYPT_PARA pccdp;
  2655. switch (dwCtrl) {
  2656. case CMSG_CTRL_KEY_TRANS_DECRYPT:
  2657. CryptSetProvParam(decryptInfo.trans.hCryptProv,
  2658. PP_UI_PROMPT, (LPBYTE) m_pwszKeyPrompt, 0);
  2659. break;
  2660. case CMSG_CTRL_KEY_AGREE_DECRYPT:
  2661. CryptSetProvParam(decryptInfo.agree.hCryptProv,
  2662. PP_UI_PROMPT, (LPBYTE) m_pwszKeyPrompt, 0);
  2663. break;
  2664. case CMSG_CTRL_DECRYPT:
  2665. pccdp = (PCMSG_CTRL_DECRYPT_PARA) &decryptInfo;
  2666. CryptSetProvParam(pccdp->hCryptProv,
  2667. PP_UI_PROMPT, (LPBYTE) m_pwszKeyPrompt, 0);
  2668. break;
  2669. }
  2670. }
  2671. #endif // SMIME_V3
  2672. if (!CryptMsgControl(m_hMsg, CMSG_CRYPT_RELEASE_CONTEXT_FLAG,
  2673. dwCtrl, &decryptInfo)) {
  2674. hr = HrGetLastError();
  2675. //
  2676. // Force any cleanups in the event of an error
  2677. //
  2678. switch (dwCtrl) {
  2679. case CMSG_CTRL_KEY_TRANS_DECRYPT:
  2680. CryptReleaseContext(decryptInfo.trans.hCryptProv, 0);
  2681. break;
  2682. case CMSG_CTRL_KEY_AGREE_DECRYPT:
  2683. CryptReleaseContext(decryptInfo.agree.hCryptProv, 0);
  2684. break;
  2685. case CMSG_CTRL_MAIL_LIST_DECRYPT:
  2686. Assert(FALSE);
  2687. break;
  2688. case CMSG_CTRL_DECRYPT:
  2689. CryptReleaseContext(((PCMSG_CTRL_DECRYPT_PARA) &decryptInfo)->hCryptProv, 0);
  2690. break;
  2691. }
  2692. goto exit;
  2693. }
  2694. goto DecryptDone;
  2695. }
  2696. //
  2697. // Clean up the object returned describing the lock box, if we
  2698. // were unsuccessful in finding a decryption key.
  2699. //
  2700. MemFree(pv); pv = NULL;
  2701. }
  2702. //
  2703. // If we are completely unsuccessful and the user has provided
  2704. // us a callback to play with, then give the user a shot at finding
  2705. // the correct decryption parameters.
  2706. //
  2707. if (!fGotoUser && g_FSupportV3 && (m_pSmimeCallback != NULL)) {
  2708. fGotoUser = TRUE;
  2709. goto tryAgain;
  2710. }
  2711. CSSDOUT("Could not decrypt the message");
  2712. m_psldData->m_ulDecValidity = MSV_CANTDECRYPT;
  2713. hr = CS_E_CANT_DECRYPT;
  2714. goto exit;
  2715. //
  2716. // If we get here, then we
  2717. // 1) found some parameters and
  2718. // 2) the worked.
  2719. //
  2720. DecryptDone:
  2721. Assert(m_psldData && (m_psldData->m_pccertDecrypt == NULL));
  2722. if (pCertDecrypt != NULL) {
  2723. m_psldData->m_pccertDecrypt = CertDuplicateCertificateContext(pCertDecrypt);
  2724. // Determine if certificate is expired
  2725. if (0 != CertVerifyTimeValidityWithDelta(NULL, pCertDecrypt->pCertInfo,
  2726. TIME_DELTA_SECONDS)) {
  2727. m_psldData->m_ulDecValidity |= MSV_ENC_FOR_EXPIREDCERT;
  2728. }
  2729. }
  2730. hr = S_OK;
  2731. exit:
  2732. if (pv != NULL) MemFree(pv);
  2733. CertFreeCertificateContext(pCertDecrypt);
  2734. if (hMsgCertStore != NULL) {
  2735. CertCloseStore(hMsgCertStore, 0);
  2736. }
  2737. if (hcertstore != NULL) {
  2738. CertCloseStore(hcertstore, 0);
  2739. }
  2740. if (FAILED(hr)) {
  2741. #ifdef DEBUG
  2742. if (NTE_BAD_DATA == hr) {
  2743. CSSDOUT("Could not decrypt. Maybe due to ImportKeyError since");
  2744. CSSDOUT("NTE_BAD_DATA is the result.");
  2745. // If this happens then it is somewhat likely that PKCS2Decrypt
  2746. // failed inside the CSP. (assuming rsabase, rsaenh)
  2747. }
  2748. #endif
  2749. switch (hr) {
  2750. case CS_E_CANT_DECRYPT:
  2751. case CRYPT_E_STREAM_MSG_NOT_READY:
  2752. case HRESULT_FROM_WIN32(ERROR_CANCELLED):
  2753. break;
  2754. default:
  2755. // I suppose many things could have gone wrong. We thought
  2756. // we had a cert, though, so let's just say the message itself
  2757. // is bogus.
  2758. //N8 this is a bad idea if we are wrapping a signature
  2759. // should be able to tell if the sig failed and display
  2760. // a better error message.
  2761. //N8 CAPI is simply going to return NTE_FAIL b/c they
  2762. // are failing because our callback failed. the
  2763. // innerCAPI should have some failure state in it.
  2764. // Maybe we could use this to set MSV_BADINNERSIG or something.
  2765. // It would be an encryption error (inside that mask)
  2766. //N8 also this is not being used well enough, even for
  2767. // decryption. the secUI should test this bit and
  2768. // say something intelligent about the message. NS does.
  2769. m_psldData->m_ulDecValidity = MSV_INVALID;
  2770. hr = CS_E_MSG_INVALID;
  2771. break;
  2772. }
  2773. }
  2774. #ifdef DEBUG
  2775. if (CRYPT_E_STREAM_MSG_NOT_READY != hr) {
  2776. return TrapError(hr);
  2777. } else {
  2778. return hr;
  2779. }
  2780. #else
  2781. return hr;
  2782. #endif
  2783. gle:
  2784. hr = HrGetLastError();
  2785. Assert(S_OK != hr);
  2786. goto exit;
  2787. }
  2788. ///////////////////////////////////////////////////////////////////////////
  2789. //
  2790. // Class-static utility functions
  2791. //
  2792. HRESULT CCAPIStm::DuplicateSecurityLayerData(const PSECURITY_LAYER_DATA psldIn, PSECURITY_LAYER_DATA *const ppsldOut)
  2793. {
  2794. if (!psldIn || !ppsldOut) {
  2795. return E_POINTER;
  2796. }
  2797. // Just addref the original and return it
  2798. psldIn->AddRef();
  2799. *ppsldOut = psldIn;
  2800. return(S_OK);
  2801. }
  2802. void CCAPIStm::FreeSecurityLayerData(PSECURITY_LAYER_DATA psld)
  2803. {
  2804. if (! psld) {
  2805. return;
  2806. }
  2807. psld->Release();
  2808. }
  2809. ///////////////////////////////////////////////////////////////////////////
  2810. //
  2811. // Statics to file
  2812. //
  2813. static HRESULT _InitEncodedCert(IN HCERTSTORE hcertstor,
  2814. PCERT_BLOB * prgblobCerts, DWORD * pcCerts,
  2815. PCRL_BLOB * prgblobCrls, DWORD * pcCrl)
  2816. {
  2817. DWORD cbCerts = 0;
  2818. DWORD cbCRLs = 0;
  2819. DWORD cCerts = 0;
  2820. DWORD cCRLs = 0;
  2821. DWORD i;
  2822. LPBYTE pbCert = NULL;
  2823. LPBYTE pbCRL = NULL;
  2824. PCCERT_CONTEXT pccert = NULL;
  2825. PCCRL_CONTEXT pccrl = NULL;
  2826. PCERT_BLOB rgblobCerts = NULL;
  2827. PCRL_BLOB rgblobCRLs = NULL;
  2828. while ((pccert = CertEnumCertificatesInStore(hcertstor, pccert)) != NULL) {
  2829. cbCerts += LcbAlignLcb(pccert->cbCertEncoded);
  2830. cCerts += 1;
  2831. }
  2832. while ((pccrl = CertEnumCRLsInStore(hcertstor, pccrl)) != NULL) {
  2833. cbCRLs += LcbAlignLcb(pccrl->cbCrlEncoded);
  2834. cCRLs += 1;
  2835. }
  2836. if (cCerts > 0) {
  2837. rgblobCerts = (PCERT_BLOB) g_pMoleAlloc->Alloc(LcbAlignLcb(sizeof(CERT_BLOB) * cCerts + cbCerts));
  2838. if (rgblobCerts == NULL) {
  2839. return E_OUTOFMEMORY;
  2840. }
  2841. }
  2842. if (cCRLs > 0) {
  2843. rgblobCRLs = (PCRL_BLOB) g_pMoleAlloc->Alloc(LcbAlignLcb(sizeof(CRL_BLOB) * cCRLs + cbCRLs));
  2844. if (rgblobCRLs == NULL) {
  2845. g_pMoleAlloc->Free(rgblobCerts);
  2846. return E_OUTOFMEMORY;
  2847. }
  2848. }
  2849. if (cCerts > 0) {
  2850. pbCert = (LPBYTE) &rgblobCerts[cCerts];
  2851. i = 0;
  2852. while ((pccert = CertEnumCertificatesInStore(hcertstor, pccert)) != NULL) {
  2853. memcpy(pbCert, pccert->pbCertEncoded, pccert->cbCertEncoded);
  2854. rgblobCerts[i].pbData = pbCert;
  2855. rgblobCerts[i].cbData = pccert->cbCertEncoded;
  2856. pbCert += LcbAlignLcb(pccert->cbCertEncoded);
  2857. i++;
  2858. }
  2859. Assert(i == cCerts);
  2860. }
  2861. if (cCRLs > 0) {
  2862. pbCRL = (LPBYTE) &rgblobCRLs[cCRLs];
  2863. i = 0;
  2864. while ((pccrl = CertEnumCRLsInStore(hcertstor, pccrl)) != NULL) {
  2865. memcpy(pbCRL, pccrl->pbCrlEncoded, pccrl->cbCrlEncoded);
  2866. rgblobCRLs[i].pbData = pbCRL;
  2867. rgblobCRLs[i].cbData = pccrl->cbCrlEncoded;
  2868. pbCRL += LcbAlignLcb(pccrl->cbCrlEncoded);
  2869. i++;
  2870. }
  2871. Assert(i == cCRLs);
  2872. }
  2873. *prgblobCerts = rgblobCerts;
  2874. *pcCerts = cCerts;
  2875. *prgblobCrls = rgblobCRLs;
  2876. *pcCrl = cCRLs;
  2877. return S_OK;
  2878. }
  2879. // Ensures that the signer certificates are included in the returned
  2880. // array of blobs.
  2881. static HRESULT _InitEncodedCertIncludingSigners(IN HCERTSTORE hcertstor,
  2882. DWORD cSigners, SignerData rgSigners[],
  2883. PCERT_BLOB * prgblobCerts, DWORD * pcCerts,
  2884. PCRL_BLOB * prgblobCrls, DWORD * pcCrl)
  2885. {
  2886. HRESULT hr;
  2887. HCERTSTORE hCollection = NULL;
  2888. DWORD i;
  2889. // Loop through signers. Check that they are already included in the
  2890. // certificate store. If not, then, create a collection and memory store
  2891. // to include.
  2892. for (i = 0; i < cSigners; i++) {
  2893. PCCERT_CONTEXT pSignerCert = rgSigners[i].pccert;
  2894. PCCERT_CONTEXT pStoreCert = NULL;
  2895. while (NULL != (pStoreCert = CertEnumCertificatesInStore(
  2896. hcertstor, pStoreCert))) {
  2897. if (pSignerCert->cbCertEncoded == pStoreCert->cbCertEncoded &&
  2898. 0 == memcmp(pSignerCert->pbCertEncoded,
  2899. pStoreCert->pbCertEncoded,
  2900. pSignerCert->cbCertEncoded))
  2901. break;
  2902. }
  2903. if (pStoreCert)
  2904. // Signer cert is already included in the store
  2905. CertFreeCertificateContext(pStoreCert);
  2906. else {
  2907. if (NULL == hCollection) {
  2908. // Create collection and memory store to contain the
  2909. // signer certificate
  2910. HCERTSTORE hMemory = NULL;
  2911. BOOL fResult;
  2912. hCollection = CertOpenStore(
  2913. CERT_STORE_PROV_COLLECTION,
  2914. X509_ASN_ENCODING,
  2915. NULL,
  2916. 0,
  2917. NULL
  2918. );
  2919. if (NULL == hCollection)
  2920. goto CommonReturn;
  2921. if (!CertAddStoreToCollection(
  2922. hCollection,
  2923. hcertstor,
  2924. 0, // dwUpdateFlags
  2925. 0 // dwPriority
  2926. ))
  2927. goto CommonReturn;
  2928. hMemory = CertOpenStore(
  2929. CERT_STORE_PROV_MEMORY,
  2930. X509_ASN_ENCODING,
  2931. NULL,
  2932. 0,
  2933. NULL
  2934. );
  2935. if (NULL == hMemory)
  2936. goto CommonReturn;
  2937. fResult = CertAddStoreToCollection(
  2938. hCollection,
  2939. hMemory,
  2940. CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
  2941. 1 // dwPriority
  2942. );
  2943. CertCloseStore(hMemory, 0);
  2944. if (!fResult)
  2945. goto CommonReturn;
  2946. hcertstor = hCollection;
  2947. }
  2948. CertAddEncodedCertificateToStore(
  2949. hCollection,
  2950. pSignerCert->dwCertEncodingType,
  2951. pSignerCert->pbCertEncoded,
  2952. pSignerCert->cbCertEncoded,
  2953. CERT_STORE_ADD_ALWAYS,
  2954. NULL
  2955. );
  2956. }
  2957. }
  2958. CommonReturn:
  2959. hr = _InitEncodedCert(hcertstor, prgblobCerts, pcCerts, prgblobCrls, pcCrl);
  2960. if (hCollection)
  2961. CertCloseStore(hCollection, 0);
  2962. return hr;
  2963. }
  2964. #ifndef SMIME_V3
  2965. static HRESULT _InitCertInfo(
  2966. IN PCCERT_CONTEXT * rgpCerts,
  2967. IN DWORD cCerts,
  2968. OUT PCERT_INFO ** prgpCertInfo)
  2969. {
  2970. PCERT_INFO* rgpCertInfo = NULL;
  2971. DWORD dwIdx;
  2972. HRESULT hr = S_OK;
  2973. Assert(prgpCertInfo);
  2974. if (cCerts) {
  2975. rgpCertInfo = (PCERT_INFO*)g_pMoleAlloc->Alloc(sizeof(CERT_BLOB) * cCerts);
  2976. if (NULL == rgpCertInfo) {
  2977. hr = E_OUTOFMEMORY;
  2978. goto exit;
  2979. }
  2980. for (dwIdx = 0; dwIdx < cCerts; dwIdx++) {
  2981. rgpCertInfo[dwIdx] = rgpCerts[dwIdx]->pCertInfo;
  2982. }
  2983. }
  2984. exit:
  2985. *prgpCertInfo = rgpCertInfo;
  2986. return hr;
  2987. }
  2988. #endif // !SMIME_V3
  2989. void _SMimeCapsFromHMsg(HCRYPTMSG hMsg, DWORD idParam, LPBYTE * ppb, DWORD * pcb)
  2990. {
  2991. DWORD cbData = 0;
  2992. CRYPT_SMIME_CAPABILITY cap;
  2993. CRYPT_SMIME_CAPABILITIES caps;
  2994. BOOL f;
  2995. PCRYPT_ALGORITHM_IDENTIFIER paid = NULL;
  2996. LPBYTE pb = NULL;
  2997. f = CryptMsgGetParam(hMsg, idParam, 0, NULL, &cbData);
  2998. if ((cbData == 0) || ! MemAlloc((LPVOID *) &paid, cbData)) {
  2999. Assert(FALSE);
  3000. goto error;
  3001. }
  3002. f = CryptMsgGetParam(hMsg, idParam, 0, paid, &cbData);
  3003. Assert(f);
  3004. caps.cCapability = 1;
  3005. caps.rgCapability = &cap;
  3006. cap.pszObjId = paid->pszObjId;
  3007. cap.Parameters.cbData = paid->Parameters.cbData;
  3008. cap.Parameters.pbData = paid->Parameters.pbData;
  3009. cbData = 0;
  3010. if (!CryptEncodeObjectEx(X509_ASN_ENCODING, szOID_RSA_SMIMECapabilities,
  3011. &caps, CRYPT_ENCODE_ALLOC_FLAG, &CryptEncodeAlloc,
  3012. &pb, &cbData)) {
  3013. Assert(FALSE);
  3014. goto error;
  3015. }
  3016. *ppb = pb;
  3017. *pcb = cbData;
  3018. exit:
  3019. SafeMemFree(paid);
  3020. return;
  3021. error:
  3022. *ppb = NULL;
  3023. *pcb = 0;
  3024. goto exit;
  3025. }
  3026. #ifdef SMIME_V3
  3027. //// HrBuildContentEncryptionAlg
  3028. //
  3029. // Description:
  3030. // This function is used to decode a smime capability and build the
  3031. // structure we need to pass into the Crypt32 code.
  3032. //
  3033. HRESULT HrBuildContentEncryptionAlg(PSECURITY_LAYER_DATA psld, BLOB * pblob)
  3034. {
  3035. DWORD cbData;
  3036. HRESULT hr;
  3037. PCRYPT_SMIME_CAPABILITIES pcaps = NULL;
  3038. CMSG_RC2_AUX_INFO * prc2Aux;
  3039. //
  3040. // Decode the capability which is the bulk encryption algorithm
  3041. //
  3042. hr = HrDecodeObject(pblob->pBlobData, pblob->cbSize, PKCS_SMIME_CAPABILITIES,
  3043. 0, &cbData, (LPVOID *)&pcaps);
  3044. if (FAILED(hr)) {
  3045. goto exit;
  3046. }
  3047. Assert(pcaps->cCapability == 1);
  3048. DWORD cchSize = (lstrlen(pcaps->rgCapability[0].pszObjId) + 1);
  3049. if (!MemAlloc((LPVOID *) &psld->m_ContentEncryptAlgorithm.pszObjId, cchSize * sizeof(psld->m_ContentEncryptAlgorithm.pszObjId[0])))
  3050. {
  3051. hr = E_OUTOFMEMORY;
  3052. goto exit;
  3053. }
  3054. StrCpyN(psld->m_ContentEncryptAlgorithm.pszObjId, pcaps->rgCapability[0].pszObjId, cchSize);
  3055. //
  3056. // If this is the RC/2 algorithm, then we need to setup the aux info
  3057. // to pass in the algorithm size.
  3058. //
  3059. if (lstrcmp(pcaps->rgCapability[0].pszObjId, szOID_RSA_RC2CBC) == 0) {
  3060. psld->m_ContentEncryptAlgorithm.Parameters.cbData = 0;
  3061. psld->m_ContentEncryptAlgorithm.Parameters.pbData = NULL;
  3062. if (!MemAlloc((LPVOID *) &(psld->m_pvEncryptAuxInfo), sizeof(*prc2Aux))) {
  3063. hr = E_OUTOFMEMORY;
  3064. goto exit;
  3065. }
  3066. prc2Aux = (CMSG_RC2_AUX_INFO *) psld->m_pvEncryptAuxInfo;
  3067. prc2Aux->cbSize = sizeof(*prc2Aux);
  3068. if (pcaps->rgCapability[0].Parameters.cbData == 0) {
  3069. prc2Aux->dwBitLen = 40;
  3070. }
  3071. else {
  3072. switch(pcaps->rgCapability[0].Parameters.pbData[pcaps->rgCapability[0].Parameters.cbData-1]) {
  3073. case 128:
  3074. case 58:
  3075. prc2Aux->dwBitLen = 128;
  3076. break;
  3077. case 64:
  3078. case 120:
  3079. prc2Aux->dwBitLen = 64;
  3080. break;
  3081. case 40:
  3082. case 160:
  3083. default:
  3084. prc2Aux->dwBitLen = 40;
  3085. break;
  3086. }
  3087. }
  3088. }
  3089. else if (pcaps->rgCapability[0].Parameters.cbData != 0) {
  3090. if (!MemAlloc((LPVOID *) &psld->m_ContentEncryptAlgorithm.Parameters.pbData,
  3091. pcaps->rgCapability[0].Parameters.cbData)) {
  3092. hr = E_OUTOFMEMORY;
  3093. goto exit;
  3094. }
  3095. memcpy(psld->m_ContentEncryptAlgorithm.Parameters.pbData,
  3096. pcaps->rgCapability[0].Parameters.pbData,
  3097. pcaps->rgCapability[0].Parameters.cbData);
  3098. psld->m_ContentEncryptAlgorithm.Parameters.cbData =
  3099. pcaps->rgCapability[0].Parameters.cbData;
  3100. }
  3101. hr = S_OK;
  3102. exit:
  3103. if (pcaps != NULL) MemFree(pcaps);
  3104. return hr;
  3105. }
  3106. HRESULT HrDeriveKeyWrapAlg(PSECURITY_LAYER_DATA psld, CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO * pAgree)
  3107. {
  3108. LPCSTR pszObjId = psld->m_ContentEncryptAlgorithm.pszObjId;
  3109. if (lstrcmp(pszObjId, szOID_RSA_RC2CBC) == 0) {
  3110. pAgree->KeyWrapAlgorithm.pszObjId = szOID_RSA_SMIMEalgCMSRC2wrap;
  3111. pAgree->pvKeyWrapAuxInfo = psld->m_pvEncryptAuxInfo;
  3112. }
  3113. else if (lstrcmp(pszObjId, szOID_RSA_DES_EDE3_CBC) == 0) {
  3114. pAgree->KeyWrapAlgorithm.pszObjId = szOID_RSA_SMIMEalgCMS3DESwrap;
  3115. pAgree->pvKeyWrapAuxInfo = NULL;
  3116. }
  3117. else if (lstrcmp(pszObjId, szOID_INFOSEC_mosaicConfidentiality) == 0) {
  3118. pAgree->KeyWrapAlgorithm.pszObjId = "2.16.840.1.101.2.1.1.24";
  3119. pAgree->pvKeyWrapAuxInfo = NULL;
  3120. }
  3121. else {
  3122. return NTE_NOT_FOUND;
  3123. }
  3124. return S_OK;
  3125. }
  3126. #endif // SMIME_V3
  3127. #ifdef SMIME_V3
  3128. //
  3129. // Read in admin option that determines whether a msg with disparate
  3130. // Labels is shown or not.
  3131. //
  3132. BOOL FHideMsgWithDifferentLabels()
  3133. {
  3134. DWORD cbData = 0;
  3135. DWORD dwType = 0;
  3136. DWORD dwValue = 0;
  3137. BOOL fHideMsg = FALSE;
  3138. HKEY hkey = NULL;
  3139. LONG lRes;
  3140. // Open the security label admin defaults key.
  3141. lRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szSecLabelAdminRegKey, 0,
  3142. KEY_READ, &hkey);
  3143. if ( (ERROR_SUCCESS != lRes) || (NULL == hkey) ) {
  3144. // No admin label options were found.
  3145. goto exit;
  3146. }
  3147. cbData = sizeof(dwValue);
  3148. lRes = RegQueryValueEx(hkey, c_szHideMsgWithDifferentLabels, NULL,
  3149. &dwType, (LPBYTE) &dwValue, &cbData);
  3150. if (ERROR_SUCCESS != lRes) {
  3151. goto exit;
  3152. }
  3153. if (0x01 == dwValue) {
  3154. fHideMsg = TRUE;
  3155. }
  3156. exit:
  3157. if (NULL != hkey) RegCloseKey(hkey);
  3158. return fHideMsg;
  3159. }
  3160. //
  3161. // Read in admin option that determines how to process a label in a
  3162. // signture with errors.
  3163. // Returns 0, 1, 2 for ProcessAnyway, Grant, Deny(default).
  3164. //
  3165. DWORD DwProcessLabelWithCertError()
  3166. {
  3167. DWORD cbData = 0;
  3168. DWORD dwType = 0;
  3169. DWORD dwValue = CertErrorProcessLabelDeny;
  3170. BOOL dwProcessMsg = 0;
  3171. HKEY hkey = NULL;
  3172. LONG lRes;
  3173. // Open the security label admin defaults key.
  3174. lRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szSecLabelAdminRegKey, 0,
  3175. KEY_READ, &hkey);
  3176. if ( (ERROR_SUCCESS != lRes) || (NULL == hkey) ) {
  3177. // No admin label options were found.
  3178. goto exit;
  3179. }
  3180. // Read in the admin option.
  3181. cbData = sizeof(dwValue);
  3182. lRes = RegQueryValueEx(hkey, c_szCertErrorWithLabel, NULL,
  3183. &dwType, (LPBYTE) &dwValue, &cbData);
  3184. if (ERROR_SUCCESS != lRes) {
  3185. dwValue = CertErrorProcessLabelDeny;
  3186. goto exit;
  3187. }
  3188. // If the value isn't one of the known ones, force it to the default value.
  3189. if ( (CertErrorProcessLabelAnyway != dwValue) && (CertErrorProcessLabelGrant != dwValue) &&
  3190. (CertErrorProcessLabelDeny != dwValue) ) {
  3191. dwValue = CertErrorProcessLabelDeny;
  3192. }
  3193. exit:
  3194. if (NULL != hkey) RegCloseKey(hkey);
  3195. return dwValue;
  3196. }
  3197. //
  3198. // Given a label, queries the policy whether access is to be granted.
  3199. // (If reqd policy doesn't exist, it also tries to query the default
  3200. // policy, if one exists).
  3201. //
  3202. HRESULT HrCheckLabelAccess(const DWORD dwFlags, const HWND hwnd,
  3203. PSMIME_SECURITY_LABEL plabel, const PCCERT_CONTEXT pccertDecrypt,
  3204. const PCCERT_CONTEXT pccertSigner, const HCERTSTORE hcertstor)
  3205. {
  3206. HRESULT hr = MIME_E_SECURITY_LABELACCESSDENIED;
  3207. HKEY hkey = NULL;
  3208. HKEY hkeySub = NULL;
  3209. HINSTANCE hinstDll = NULL;
  3210. PFNGetSMimePolicy pfnGetSMimePolicy = NULL;
  3211. ISMimePolicyCheckAccess *pspca = NULL;
  3212. LONG lRes;
  3213. DWORD dwType;
  3214. DWORD cbData;
  3215. CHAR szDllPath[MAX_PATH];
  3216. CHAR szExpandedDllPath[MAX_PATH];
  3217. CHAR szFuncName[MAX_FUNC_NAME];
  3218. if ((NULL == plabel) || (NULL == plabel->pszObjIdSecurityPolicy)) {
  3219. hr = S_OK; // No label/policyoid => access granted.
  3220. goto exit;
  3221. }
  3222. // Open the security policies key.
  3223. lRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szSecLabelPoliciesRegKey, 0,
  3224. KEY_READ, &hkey);
  3225. if ( (ERROR_SUCCESS != lRes) || (NULL == hkey) ) {
  3226. // No security policies are registered. Deny access.
  3227. goto ErrorReturn;
  3228. }
  3229. // Open the security policy (or default policy regkey).
  3230. lRes = RegOpenKeyEx(hkey, plabel->pszObjIdSecurityPolicy, 0, KEY_READ, &hkeySub);
  3231. if ((ERROR_SUCCESS != lRes) || (NULL == hkeySub)) {
  3232. if (hkeySub != NULL) {
  3233. RegCloseKey(hkeySub);
  3234. hkeySub = NULL;
  3235. }
  3236. // Try opening the default policy, if one exists.
  3237. lRes = RegOpenKeyEx(hkey, c_szDefaultPolicyOid, 0, KEY_READ, &hkeySub);
  3238. if ((ERROR_SUCCESS != lRes) || (NULL == hkeySub)) {
  3239. // couldn't find specified_and_default policy. deny access.
  3240. goto ErrorReturn;
  3241. }
  3242. }
  3243. Assert(NULL != hkeySub);
  3244. // get the path to the policy dll, and load it.
  3245. cbData = sizeof(szDllPath);
  3246. lRes = RegQueryValueEx(hkeySub, c_szSecurityPolicyDllPath, NULL,
  3247. &dwType, (LPBYTE)szDllPath, &cbData);
  3248. if (ERROR_SUCCESS != lRes) {
  3249. // policy not correctly registered. deny access.
  3250. goto ErrorReturn;
  3251. }
  3252. szDllPath[ ARRAYSIZE(szDllPath) - 1 ] = '\0';
  3253. // expand environment strings (if any) in the dll path we read in.
  3254. if (REG_EXPAND_SZ == dwType)
  3255. {
  3256. ZeroMemory(szExpandedDllPath, ARRAYSIZE(szExpandedDllPath));
  3257. ExpandEnvironmentStrings(szDllPath, szExpandedDllPath, ARRAYSIZE(szExpandedDllPath));
  3258. szExpandedDllPath[ARRAYSIZE(szExpandedDllPath) - 1] = '\0';
  3259. StrCpyN(szDllPath, szExpandedDllPath, ARRAYSIZE(szDllPath));
  3260. }
  3261. hinstDll = LoadLibraryEx(szDllPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  3262. if (NULL == hinstDll) {
  3263. // couldn't load policy. deny access.
  3264. goto ErrorReturn;
  3265. }
  3266. // get the entry func name.
  3267. cbData = sizeof(szFuncName);
  3268. lRes = RegQueryValueEx(hkeySub, c_szSecurityPolicyFuncName, NULL,
  3269. &dwType, (LPBYTE)szFuncName, &cbData);
  3270. if (ERROR_SUCCESS != lRes) {
  3271. // policy not correctly registered. deny access.
  3272. goto ErrorReturn;
  3273. }
  3274. pfnGetSMimePolicy = (PFNGetSMimePolicy) GetProcAddress(hinstDll, szFuncName);
  3275. if (NULL == pfnGetSMimePolicy) {
  3276. // couldn't get proc address. deny access.
  3277. goto ErrorReturn;
  3278. }
  3279. hr = (pfnGetSMimePolicy) (0, plabel->pszObjIdSecurityPolicy, GetACP(),
  3280. IID_ISMimePolicyCheckAccess, (LPUNKNOWN *) &pspca);
  3281. if (FAILED(hr) || (NULL == pspca)) {
  3282. // couldn't get required interface,
  3283. goto ErrorReturn;
  3284. }
  3285. // Call into the policy module to find out if access is to be denied/granted.
  3286. hr = pspca->IsAccessGranted(dwFlags, hwnd, plabel, pccertDecrypt,
  3287. pccertSigner, hcertstor);
  3288. // fall through to exit.
  3289. exit:
  3290. if (pspca) pspca->Release();
  3291. if (hinstDll) FreeLibrary(hinstDll);
  3292. if (hkeySub) RegCloseKey(hkeySub);
  3293. if (hkey) RegCloseKey(hkey);
  3294. return hr;
  3295. ErrorReturn:
  3296. if (! FAILED(hr)) {
  3297. // If we had an error, but didn't get a failure code, force a failure.
  3298. hr |= 0x80000000;
  3299. }
  3300. goto exit;
  3301. }
  3302. #endif // SMIME_V3
  3303. /* * * END --- CAPISTM.CPP --- END * * */