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.

1874 lines
52 KiB

  1. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
  3. File: EnvelopedData.cpp
  4. Content: Implementation of CEnvelopedData.
  5. History: 11-15-99 dsie created
  6. ------------------------------------------------------------------------------*/
  7. #include "StdAfx.h"
  8. #include "CAPICOM.h"
  9. #include "EnvelopedData.h"
  10. #include "Common.h"
  11. #include "Convert.h"
  12. #include "CertHlpr.h"
  13. #include "MsgHlpr.h"
  14. #include "SignHlpr.h"
  15. #include "Settings.h"
  16. ////////////////////////////////////////////////////////////////////////////////
  17. //
  18. // Local functions.
  19. //
  20. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  21. Function : SelectRecipientCertCallback
  22. Synopsis : Callback routine for CryptUIDlgSelectCertificateW() API for
  23. recipient's cert selection.
  24. Parameter: See CryptUI.h for defination.
  25. Remark : Filter out any cert that is not time valid.
  26. ------------------------------------------------------------------------------*/
  27. static BOOL WINAPI SelectRecipientCertCallback (PCCERT_CONTEXT pCertContext,
  28. BOOL * pfInitialSelectedCert,
  29. void * pvCallbackData)
  30. {
  31. int nValidity = 0;
  32. //
  33. // Check cert time validity.
  34. //
  35. if (0 != (nValidity = ::CertVerifyTimeValidity(NULL, pCertContext->pCertInfo)))
  36. {
  37. DebugTrace("Info: SelectRecipientCertCallback() - invalid time (%s).\n",
  38. nValidity < 0 ? "not yet valid" : "expired");
  39. return FALSE;
  40. }
  41. return TRUE;
  42. }
  43. ////////////////////////////////////////////////////////////////////////////////
  44. //
  45. // CEnvelopedData
  46. //
  47. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  48. Function : SetKeyLength
  49. Synopsis : Setup the symetric encryption key length.
  50. Parameter: HCRYPTPROV hCryptProv - CSP handle.
  51. CRYPT_ALGORITHM_IDENTIFIER EncryptAlgorithm - Encryption algorithm.
  52. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength - Key length.
  53. void ** pAuxInfo - Receive NULL or allocated and initialized
  54. aux info structure.
  55. Remark :
  56. ------------------------------------------------------------------------------*/
  57. static HRESULT SetKeyLength (
  58. HCRYPTPROV hCryptProv,
  59. CRYPT_ALGORITHM_IDENTIFIER EncryptAlgorithm,
  60. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength,
  61. void ** ppAuxInfo)
  62. {
  63. HRESULT hr = S_OK;
  64. ALG_ID AlgID = 0;
  65. PROV_ENUMALGS_EX peex;
  66. CMSG_RC2_AUX_INFO * pRC2AuxInfo = NULL;
  67. CMSG_RC4_AUX_INFO * pRC4AuxInfo = NULL;
  68. DebugTrace("Entering SetKeyLength().\n");
  69. //
  70. // Sanity check.
  71. //
  72. ATLASSERT(hCryptProv);
  73. ATLASSERT(ppAuxInfo);
  74. //
  75. // Initialize.
  76. //
  77. *ppAuxInfo = (void *) NULL;
  78. //
  79. // Get ALG_ID.
  80. //
  81. if (FAILED(hr = ::OIDToAlgID(EncryptAlgorithm.pszObjId, &AlgID)))
  82. {
  83. DebugTrace("Error [%#x]: OIDToAlgID() failed.\n", hr);
  84. goto ErrorExit;
  85. }
  86. //
  87. // Get algorithm capability from CSP.
  88. //
  89. if (FAILED(::IsAlgSupported(hCryptProv, AlgID, &peex)))
  90. {
  91. hr = CAPICOM_E_NOT_SUPPORTED;
  92. DebugTrace("Error: requested encryption algorithm is not available.\n");
  93. goto ErrorExit;
  94. }
  95. //
  96. // Setup AuxInfo for RC2.
  97. //
  98. if (CALG_RC2 == AlgID)
  99. {
  100. //
  101. // Allocate and intialize memory for RC2 AuxInfo structure.
  102. //
  103. if (!(pRC2AuxInfo = (CMSG_RC2_AUX_INFO *) ::CoTaskMemAlloc(sizeof(CMSG_RC2_AUX_INFO))))
  104. {
  105. hr = E_OUTOFMEMORY;
  106. DebugTrace("Error: out of memory.\n");
  107. goto ErrorExit;
  108. }
  109. ::ZeroMemory(pRC2AuxInfo, sizeof(CMSG_RC2_AUX_INFO));
  110. pRC2AuxInfo->cbSize = sizeof(CMSG_RC2_AUX_INFO);
  111. //
  112. // Determine key length requested.
  113. //
  114. if (CAPICOM_ENCRYPTION_KEY_LENGTH_MAXIMUM == KeyLength)
  115. {
  116. pRC2AuxInfo->dwBitLen = peex.dwMaxLen;
  117. }
  118. else if (CAPICOM_ENCRYPTION_KEY_LENGTH_40_BITS == KeyLength)
  119. {
  120. if (peex.dwMinLen <= 40 && 40 <= peex.dwMaxLen)
  121. {
  122. pRC2AuxInfo->dwBitLen = 40;
  123. }
  124. else
  125. {
  126. hr = CAPICOM_E_NOT_SUPPORTED;
  127. DebugTrace("Error [%#x]: 40-bits encryption is not available.\n", hr);
  128. goto ErrorExit;
  129. }
  130. }
  131. else if (CAPICOM_ENCRYPTION_KEY_LENGTH_56_BITS == KeyLength)
  132. {
  133. if (peex.dwMinLen <= 56 && 56 <= peex.dwMaxLen)
  134. {
  135. pRC2AuxInfo->dwBitLen = 56;
  136. }
  137. else
  138. {
  139. hr = CAPICOM_E_NOT_SUPPORTED;
  140. DebugTrace("Error [%#x]: 56-bits encryption is not available.\n", hr);
  141. goto ErrorExit;
  142. }
  143. }
  144. else if (CAPICOM_ENCRYPTION_KEY_LENGTH_128_BITS == KeyLength)
  145. {
  146. if (peex.dwMinLen <= 128 && 128 <= peex.dwMaxLen)
  147. {
  148. pRC2AuxInfo->dwBitLen = 128;
  149. }
  150. else
  151. {
  152. hr = CAPICOM_E_NOT_SUPPORTED;
  153. DebugTrace("Error [%#x]: 128-bits encryption is not available.\n", hr);
  154. goto ErrorExit;
  155. }
  156. }
  157. else
  158. {
  159. //
  160. // Should never get to here.
  161. //
  162. hr = CAPICOM_E_INTERNAL;
  163. DebugTrace("Error [%#x]: Unknown key length (%d).\n", hr, KeyLength);
  164. goto ErrorExit;
  165. }
  166. //
  167. // Return RC2 AuxInfo pointer to caller.
  168. //
  169. *ppAuxInfo = (void *) pRC2AuxInfo;
  170. }
  171. else if (CALG_RC4 == AlgID)
  172. {
  173. //
  174. // Allocate and intialize memory for RC4 AuxInfo structure.
  175. //
  176. if (!(pRC4AuxInfo = (CMSG_RC4_AUX_INFO *) ::CoTaskMemAlloc(sizeof(CMSG_RC4_AUX_INFO))))
  177. {
  178. hr = E_OUTOFMEMORY;
  179. DebugTrace("Error: out of memory.\n");
  180. goto ErrorExit;
  181. }
  182. ::ZeroMemory(pRC4AuxInfo, sizeof(CMSG_RC4_AUX_INFO));
  183. pRC4AuxInfo->cbSize = sizeof(CMSG_RC4_AUX_INFO);
  184. //
  185. // Determine key length requested.
  186. //
  187. if (CAPICOM_ENCRYPTION_KEY_LENGTH_MAXIMUM == KeyLength)
  188. {
  189. pRC4AuxInfo->dwBitLen = peex.dwMaxLen;
  190. }
  191. else if (CAPICOM_ENCRYPTION_KEY_LENGTH_40_BITS == KeyLength)
  192. {
  193. if (peex.dwMinLen <= 40 && 40 <= peex.dwMaxLen)
  194. {
  195. pRC4AuxInfo->dwBitLen = 40;
  196. }
  197. else
  198. {
  199. hr = CAPICOM_E_NOT_SUPPORTED;
  200. DebugTrace("Error [%#x]: 40-bits encryption is not available.\n", hr);
  201. goto ErrorExit;
  202. }
  203. }
  204. else if (CAPICOM_ENCRYPTION_KEY_LENGTH_56_BITS == KeyLength)
  205. {
  206. if (peex.dwMinLen <= 56 && 56 <= peex.dwMaxLen)
  207. {
  208. pRC4AuxInfo->dwBitLen = 56;
  209. }
  210. else
  211. {
  212. hr = CAPICOM_E_NOT_SUPPORTED;
  213. DebugTrace("Error [%#x]: 56-bits encryption is not available.\n", hr);
  214. goto ErrorExit;
  215. }
  216. }
  217. else if (CAPICOM_ENCRYPTION_KEY_LENGTH_128_BITS == KeyLength)
  218. {
  219. if (peex.dwMinLen <= 128 && 128 <= peex.dwMaxLen)
  220. {
  221. pRC4AuxInfo->dwBitLen = 128;
  222. }
  223. else
  224. {
  225. hr = CAPICOM_E_NOT_SUPPORTED;
  226. DebugTrace("Error [%#x]: 128-bits encryption is not available.\n", hr);
  227. goto ErrorExit;
  228. }
  229. }
  230. else
  231. {
  232. //
  233. // Should never get to here.
  234. //
  235. hr = CAPICOM_E_INTERNAL;
  236. DebugTrace("Error [%#x]: Unknown key length (%d).\n", hr, KeyLength);
  237. goto ErrorExit;
  238. }
  239. //
  240. // Return RC4 AuxInfo pointer to caller.
  241. //
  242. *ppAuxInfo = (void *) pRC4AuxInfo;
  243. }
  244. CommonExit:
  245. DebugTrace("Leaving SetKeyLength().\n");
  246. return hr;
  247. ErrorExit:
  248. //
  249. // Sanity check.
  250. //
  251. ATLASSERT(FAILED(hr));
  252. //
  253. // Free resource.
  254. //
  255. if (pRC2AuxInfo)
  256. {
  257. ::CoTaskMemFree(pRC2AuxInfo);
  258. }
  259. if (pRC4AuxInfo)
  260. {
  261. ::CoTaskMemFree(pRC4AuxInfo);
  262. }
  263. goto CommonExit;
  264. }
  265. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  266. Function : SetEncryptionAlgorithm
  267. Synopsis : Setup the encryption algorithm structure.
  268. Parameter: CAPICOM_ENCRYPTION_ALGORITHM AlgoName - Algorithm ID enum name.
  269. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength - Key length enum name.
  270. CRYPT_ALGORITHM_IDENTIFIER * pEncryptAlgorithm - Pointer to the
  271. structure.
  272. Remark :
  273. ------------------------------------------------------------------------------*/
  274. static HRESULT SetEncryptionAlgorithm (CAPICOM_ENCRYPTION_ALGORITHM AlgoName,
  275. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength,
  276. CRYPT_ALGORITHM_IDENTIFIER * pEncryptAlgorithm)
  277. {
  278. HRESULT hr = S_OK;
  279. ALG_ID AlgID = 0;
  280. DebugTrace("Entering SetEncryptionAlgorithm().\n");
  281. //
  282. // Sanity check.
  283. //
  284. ATLASSERT(pEncryptAlgorithm);
  285. //
  286. // Initialize structure.
  287. //
  288. ::ZeroMemory(pEncryptAlgorithm, sizeof(CRYPT_ALGORITHM_IDENTIFIER));
  289. //
  290. // Convert to LPSTR.
  291. //
  292. if (FAILED(hr = ::EnumNameToAlgID(AlgoName, KeyLength, &AlgID)))
  293. {
  294. DebugTrace("Error: EnumNameToAlgID() failed.\n");
  295. goto ErrorExit;
  296. }
  297. if (FAILED(hr = ::AlgIDToOID(AlgID, &pEncryptAlgorithm->pszObjId)))
  298. {
  299. DebugTrace("Error: AlgIDToOID() failed.\n");
  300. goto ErrorExit;
  301. }
  302. CommonExit:
  303. DebugTrace("Leaving SetEncryptionAlgorithm().\n");
  304. return hr;
  305. ErrorExit:
  306. //
  307. // Sanity check.
  308. //
  309. ATLASSERT(FAILED(hr));
  310. //
  311. // Free resource.
  312. //
  313. if (pEncryptAlgorithm->pszObjId)
  314. {
  315. ::CoTaskMemFree(pEncryptAlgorithm->pszObjId);
  316. }
  317. goto CommonExit;
  318. }
  319. ////////////////////////////////////////////////////////////////////////////////
  320. //
  321. // CEnvelopedData
  322. //
  323. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  324. Function : CEnvelopedData::get_Content
  325. Synopsis : Return the content.
  326. Parameter: BSTR * pVal - Pointer to BSTR to receive the content.
  327. Remark :
  328. ------------------------------------------------------------------------------*/
  329. STDMETHODIMP CEnvelopedData::get_Content (BSTR * pVal)
  330. {
  331. HRESULT hr = S_OK;
  332. DebugTrace("Entering CEnvelopedData::get_Content().\n");
  333. //
  334. // Lock access to this object.
  335. //
  336. m_Lock.Lock();
  337. try
  338. {
  339. //
  340. // Check parameters.
  341. //
  342. if (NULL == pVal)
  343. {
  344. hr = E_INVALIDARG;
  345. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  346. goto ErrorExit;
  347. }
  348. //
  349. // Make sure content is already initialized.
  350. //
  351. if (0 == m_ContentBlob.cbData)
  352. {
  353. hr = CAPICOM_E_ENVELOP_NOT_INITIALIZED;
  354. DebugTrace("Error [%#x]: Enveloped object has not been initialized.\n", hr);
  355. goto ErrorExit;
  356. }
  357. //
  358. // Sanity check.
  359. //
  360. ATLASSERT(m_ContentBlob.pbData);
  361. //
  362. // Return content.
  363. //
  364. if (FAILED(hr = ::BlobToBstr(&m_ContentBlob, pVal)))
  365. {
  366. DebugTrace("Error [%#x]: BlobToBstr() failed.\n", hr);
  367. goto ErrorExit;
  368. }
  369. }
  370. catch(...)
  371. {
  372. hr = E_POINTER;
  373. DebugTrace("Exception: invalid parameter.\n");
  374. goto ErrorExit;
  375. }
  376. UnlockExit:
  377. //
  378. // Unlock access to this object.
  379. //
  380. m_Lock.Unlock();
  381. DebugTrace("Leaving CEnvelopedData::get_Content().\n");
  382. return hr;
  383. ErrorExit:
  384. //
  385. // Sanity check.
  386. //
  387. ATLASSERT(FAILED(hr));
  388. ReportError(hr);
  389. goto UnlockExit;
  390. }
  391. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  392. Function : CEnvelopedData::put_Content
  393. Synopsis : Initialize the object with content to be enveloped.
  394. Parameter: BSTR newVal - BSTR containing the content to be enveloped.
  395. Remark :
  396. ------------------------------------------------------------------------------*/
  397. STDMETHODIMP CEnvelopedData::put_Content (BSTR newVal)
  398. {
  399. HRESULT hr = S_OK;
  400. DebugTrace("Entering CEnvelopedData::put_Content().\n");
  401. //
  402. // Lock access to this object.
  403. //
  404. m_Lock.Lock();
  405. try
  406. {
  407. //
  408. // Make sure parameters are valid.
  409. //
  410. if (0 == ::SysStringByteLen(newVal))
  411. {
  412. hr = E_INVALIDARG;
  413. DebugTrace("Error [%#x]: Parameter newVal is NULL or empty.\n", hr);
  414. goto ErrorExit;
  415. }
  416. //
  417. // Update content.
  418. //
  419. if (FAILED(hr = ::BstrToBlob(newVal, &m_ContentBlob)))
  420. {
  421. DebugTrace("Error [%#x]: BstrToBlob() failed.\n", hr);
  422. goto ErrorExit;
  423. }
  424. }
  425. catch(...)
  426. {
  427. hr = E_POINTER;
  428. DebugTrace("Exception: invalid parameter.\n");
  429. goto ErrorExit;
  430. }
  431. UnlockExit:
  432. //
  433. // Unlock access to this object.
  434. //
  435. m_Lock.Unlock();
  436. DebugTrace("Leaving CEnvelopedData::put_Content().\n");
  437. return hr;
  438. ErrorExit:
  439. //
  440. // Sanity check.
  441. //
  442. ATLASSERT(FAILED(hr));
  443. ReportError(hr);
  444. goto UnlockExit;
  445. }
  446. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  447. Function : CEnvelopedData::get_Algorithm
  448. Synopsis : Property to return the algorithm object.
  449. Parameter: IAlgorithm ** pVal - Pointer to pointer to IAlgorithm to receive
  450. the interfcae pointer.
  451. Remark :
  452. ------------------------------------------------------------------------------*/
  453. STDMETHODIMP CEnvelopedData::get_Algorithm (IAlgorithm ** pVal)
  454. {
  455. HRESULT hr = S_OK;
  456. DebugTrace("Entering CEnvelopedData::get_Algorithm().\n");
  457. //
  458. // Lock access to this object.
  459. //
  460. m_Lock.Lock();
  461. try
  462. {
  463. //
  464. // Check parameters.
  465. //
  466. if (NULL == pVal)
  467. {
  468. hr = E_INVALIDARG;
  469. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  470. goto ErrorExit;
  471. }
  472. //
  473. // Sanity check.
  474. //
  475. ATLASSERT(m_pIAlgorithm);
  476. //
  477. // Return interface pointer to caller.
  478. //
  479. if (FAILED(hr = m_pIAlgorithm->QueryInterface(pVal)))
  480. {
  481. DebugTrace("Unexpected error [%#x]: m_pIAlgorithm->QueryInterface() failed.\n", hr);
  482. goto ErrorExit;
  483. }
  484. }
  485. catch(...)
  486. {
  487. hr = E_POINTER;
  488. DebugTrace("Exception: invalid parameter.\n");
  489. goto ErrorExit;
  490. }
  491. UnlockExit:
  492. //
  493. // Unlock access to this object.
  494. //
  495. m_Lock.Unlock();
  496. DebugTrace("Leaving CEnvelopedData::get_Algorithm().\n");
  497. return hr;
  498. ErrorExit:
  499. //
  500. // Sanity check.
  501. //
  502. ATLASSERT(FAILED(hr));
  503. ReportError(hr);
  504. goto UnlockExit;
  505. }
  506. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  507. Function : CEnvelopedData::get_Recipients
  508. Synopsis : Property to return the IRecipients collection object.
  509. Parameter: IRecipients ** pVal - Pointer to pointer to IRecipietns to receive
  510. the interface pointer.
  511. Remark :
  512. ------------------------------------------------------------------------------*/
  513. STDMETHODIMP CEnvelopedData::get_Recipients (IRecipients ** pVal)
  514. {
  515. HRESULT hr = S_OK;
  516. DebugTrace("Entering CEnvelopedData::get_Recipients().\n");
  517. //
  518. // Lock access to this object.
  519. //
  520. m_Lock.Lock();
  521. try
  522. {
  523. //
  524. // Check parameters.
  525. //
  526. if (NULL == pVal)
  527. {
  528. hr = E_INVALIDARG;
  529. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  530. goto ErrorExit;
  531. }
  532. //
  533. // Sanity check.
  534. //
  535. ATLASSERT(m_pIRecipients);
  536. //
  537. // Return interface pointer to caller.
  538. //
  539. if (FAILED(hr = m_pIRecipients->QueryInterface(pVal)))
  540. {
  541. DebugTrace("Unexpected error [%#x]: m_pIRecipients->QueryInterface() failed.\n", hr);
  542. goto ErrorExit;
  543. }
  544. }
  545. catch(...)
  546. {
  547. hr = E_POINTER;
  548. DebugTrace("Exception: invalid parameter.\n");
  549. goto ErrorExit;
  550. }
  551. UnlockExit:
  552. //
  553. // Unlock access to this object.
  554. //
  555. m_Lock.Unlock();
  556. DebugTrace("Leaving CEnvelopedData::get_Recipients().\n");
  557. return hr;
  558. ErrorExit:
  559. //
  560. // Sanity check.
  561. //
  562. ATLASSERT(FAILED(hr));
  563. ReportError(hr);
  564. goto UnlockExit;
  565. }
  566. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  567. Function : CEnvelopedData::Encrypt
  568. Synopsis : Envelop the content.
  569. Parameter: CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
  570. BSTR * pVal - Pointer to BSTR to receive the enveloped message.
  571. Remark :
  572. ------------------------------------------------------------------------------*/
  573. STDMETHODIMP CEnvelopedData::Encrypt (CAPICOM_ENCODING_TYPE EncodingType,
  574. BSTR * pVal)
  575. {
  576. HRESULT hr = S_OK;
  577. HCRYPTMSG hMsg = NULL;
  578. HCRYPTPROV hCryptProv = NULL;
  579. CRYPT_DATA_BLOB MessageBlob = {0, NULL};
  580. DebugTrace("Entering CEnvelopedData::Encrypt().\n");
  581. //
  582. // Lock access to this object.
  583. //
  584. m_Lock.Lock();
  585. try
  586. {
  587. //
  588. // Check parameters.
  589. //
  590. if (NULL == pVal)
  591. {
  592. hr = E_INVALIDARG;
  593. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  594. goto ErrorExit;
  595. }
  596. //
  597. // Make sure we do have content to envelop.
  598. //
  599. if (0 == m_ContentBlob.cbData)
  600. {
  601. hr = CAPICOM_E_ENVELOP_NOT_INITIALIZED;
  602. DebugTrace("Error [%#x]: envelop object has not been initialized.\n", hr);
  603. goto ErrorExit;
  604. }
  605. //
  606. // Open a new message to encode.
  607. //
  608. if (FAILED(hr = OpenToEncode(&hMsg, &hCryptProv)))
  609. {
  610. DebugTrace("Error [%#x]: CEnvelopedData::OpenToEncode() failed.\n", hr);
  611. goto ErrorExit;
  612. }
  613. //
  614. // Update envelop content.
  615. //
  616. if(!::CryptMsgUpdate(hMsg,
  617. m_ContentBlob.pbData,
  618. m_ContentBlob.cbData,
  619. TRUE))
  620. {
  621. hr = HRESULT_FROM_WIN32(::GetLastError());
  622. DebugTrace("Error [%#x]: CryptMsgUpdate() failed.\n", hr);
  623. goto ErrorExit;
  624. }
  625. //
  626. // Retrieve enveloped message.
  627. //
  628. if (FAILED(hr = ::GetMsgParam(hMsg,
  629. CMSG_CONTENT_PARAM,
  630. 0,
  631. (void **) &MessageBlob.pbData,
  632. &MessageBlob.cbData)))
  633. {
  634. hr = HRESULT_FROM_WIN32(::GetLastError());
  635. DebugTrace("Error [%#x]: GetMsgParam() failed to get message content.\n", hr);
  636. goto ErrorExit;
  637. }
  638. //
  639. // Now export the enveloped message.
  640. //
  641. if (FAILED(hr = ::ExportData(MessageBlob, EncodingType, pVal)))
  642. {
  643. DebugTrace("Error [%#x]: ExportData() failed.\n", hr);
  644. goto ErrorExit;
  645. }
  646. //
  647. // Write encoded blob to file, so we can use offline tool such as
  648. // ASN parser to analyze message.
  649. //
  650. // The following line will resolve to void for non debug build, and
  651. // thus can be safely removed if desired.
  652. //
  653. DumpToFile("Enveloped.asn", MessageBlob.pbData, MessageBlob.cbData);
  654. }
  655. catch(...)
  656. {
  657. hr = E_POINTER;
  658. DebugTrace("Exception: invalid parameter.\n");
  659. goto ErrorExit;
  660. }
  661. UnlockExit:
  662. //
  663. // Free resource.
  664. //
  665. if (MessageBlob.pbData)
  666. {
  667. ::CoTaskMemFree(MessageBlob.pbData);
  668. }
  669. if (hCryptProv)
  670. {
  671. ::ReleaseContext(hCryptProv);
  672. }
  673. if (hMsg)
  674. {
  675. ::CryptMsgClose(hMsg);
  676. }
  677. //
  678. // Unlock access to this object.
  679. //
  680. m_Lock.Unlock();
  681. DebugTrace("Leaving CEnvelopedData::Encrypt().\n");
  682. return hr;
  683. ErrorExit:
  684. //
  685. // Sanity check.
  686. //
  687. ATLASSERT(FAILED(hr));
  688. ReportError(hr);
  689. goto UnlockExit;
  690. }
  691. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  692. Function : CEnvelopedData::Decrypt
  693. Synopsis : Decrypt the enveloped message.
  694. Parameter: BSTR EnvelopedMessage - BSTR containing the enveloped message.
  695. Remark : If called from web environment, UI will be displayed, if has
  696. not been prevously disabled, to warn the user of accessing the
  697. private key for decrypting.
  698. ------------------------------------------------------------------------------*/
  699. STDMETHODIMP CEnvelopedData::Decrypt (BSTR EnvelopedMessage)
  700. {
  701. HRESULT hr = S_OK;
  702. HRESULT hr2 = S_OK;
  703. HCERTSTORE hCertStores[2] = {NULL, NULL};
  704. HCRYPTMSG hMsg = NULL;
  705. PCCERT_CONTEXT pCertContext = NULL;
  706. HCRYPTPROV hCryptProv = NULL;
  707. DWORD dwKeySpec = 0;
  708. BOOL bReleaseContext = FALSE;
  709. BOOL bUserPrompted = FALSE;
  710. DWORD dwNumRecipients = 0;
  711. DWORD cbNumRecipients = sizeof(dwNumRecipients);
  712. CRYPT_DATA_BLOB ContentBlob = {0, NULL};
  713. DWORD dwIndex;
  714. CComBSTR bstrContent;
  715. DebugTrace("Entering CEnvelopedData::Decrypt().\n");
  716. //
  717. // Lock access to this object.
  718. //
  719. m_Lock.Lock();
  720. try
  721. {
  722. //
  723. // Reset member variables.
  724. //
  725. if (FAILED(hr = m_pIRecipients->Clear()))
  726. {
  727. DebugTrace("Error [%#x]: m_pIRecipients->Clear() failed.\n", hr);
  728. goto ErrorExit;
  729. }
  730. //
  731. // Make sure parameters are valid.
  732. //
  733. if (0 == ::SysStringByteLen(EnvelopedMessage))
  734. {
  735. hr = E_INVALIDARG;
  736. DebugTrace("Error [%#x]: Parameter EnvelopedMessage is NULL or empty.\n", hr);
  737. goto ErrorExit;
  738. }
  739. //
  740. // Open current user and local machine MY stores.
  741. //
  742. hCertStores[0] = ::CertOpenStore(CERT_STORE_PROV_SYSTEM,
  743. CAPICOM_ASN_ENCODING,
  744. NULL,
  745. CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG,
  746. L"My");
  747. hCertStores[1] = ::CertOpenStore(CERT_STORE_PROV_SYSTEM,
  748. CAPICOM_ASN_ENCODING,
  749. NULL,
  750. CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_OPEN_EXISTING_FLAG,
  751. L"My");
  752. //
  753. // Did we manage to open any of the MY store?
  754. //
  755. if (NULL == hCertStores[0] && NULL == hCertStores[1])
  756. {
  757. hr = HRESULT_FROM_WIN32(::GetLastError());
  758. DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
  759. goto ErrorExit;
  760. }
  761. //
  762. // Open the message for decode.
  763. //
  764. if (FAILED(hr = OpenToDecode(NULL, EnvelopedMessage, &hMsg)))
  765. {
  766. DebugTrace("Error [%#x]: CEnvelopedData::OpenToDecode() failed.\n", hr);
  767. goto ErrorExit;
  768. }
  769. //
  770. // Determine number of recipients.
  771. //
  772. if (!::CryptMsgGetParam(hMsg,
  773. CMSG_RECIPIENT_COUNT_PARAM,
  774. 0,
  775. (void *) &dwNumRecipients,
  776. &cbNumRecipients))
  777. {
  778. hr = HRESULT_FROM_WIN32(::GetLastError());
  779. DebugTrace("Error [%#x]: CryptMsgGetParam() failed for CMSG_RECIPIENT_COUNT_PARAM.\n", hr);
  780. goto ErrorExit;
  781. }
  782. //
  783. // Find recipient.
  784. //
  785. for (dwIndex = 0; dwIndex < dwNumRecipients; dwIndex++)
  786. {
  787. BOOL bFound = FALSE;
  788. DATA_BLOB CertInfoBlob = {0, NULL};
  789. //
  790. // Get RecipientInfo.
  791. //
  792. if (FAILED(hr = ::GetMsgParam(hMsg,
  793. CMSG_RECIPIENT_INFO_PARAM,
  794. dwIndex,
  795. (void **) &CertInfoBlob.pbData,
  796. &CertInfoBlob.cbData)))
  797. {
  798. DebugTrace("Error [%#x]: GetMsgParam() failed for CMSG_RECIPIENT_INFO_PARAM.\n", hr);
  799. goto ErrorExit;
  800. }
  801. //
  802. // Find recipient's cert in store.
  803. //
  804. if ((hCertStores[0] && (pCertContext = ::CertGetSubjectCertificateFromStore(hCertStores[0],
  805. CAPICOM_ASN_ENCODING,
  806. (CERT_INFO *) CertInfoBlob.pbData))) ||
  807. (hCertStores[1] && (pCertContext = ::CertGetSubjectCertificateFromStore(hCertStores[1],
  808. CAPICOM_ASN_ENCODING,
  809. (CERT_INFO *) CertInfoBlob.pbData))))
  810. {
  811. bFound = TRUE;
  812. }
  813. //
  814. // Free memory.
  815. //
  816. ::CoTaskMemFree(CertInfoBlob.pbData);
  817. //
  818. // Did we find the recipient?
  819. //
  820. if (bFound)
  821. {
  822. CMSG_CTRL_DECRYPT_PARA DecryptPara;
  823. //
  824. // If we are called from a web page, we need to pop up UI
  825. // to get user permission to perform decrypt operation.
  826. //
  827. if (!bUserPrompted)
  828. {
  829. if (m_dwCurrentSafety &&
  830. FAILED(hr = OperationApproved(IDD_DECRYPT_SECURITY_ALERT_DLG)))
  831. {
  832. DebugTrace("Error [%#x]: OperationApproved() failed.\n", hr);
  833. goto ErrorExit;
  834. }
  835. bUserPrompted = TRUE;
  836. }
  837. //
  838. // Acquire CSP context.
  839. //
  840. if (S_OK == ::AcquireContext(pCertContext, &hCryptProv, &dwKeySpec, &bReleaseContext))
  841. {
  842. //
  843. // Decypt the message.
  844. //
  845. ::ZeroMemory(&DecryptPara, sizeof(DecryptPara));
  846. DecryptPara.cbSize = sizeof(DecryptPara);
  847. DecryptPara.hCryptProv = hCryptProv;
  848. DecryptPara.dwKeySpec = dwKeySpec;
  849. DecryptPara.dwRecipientIndex = dwIndex;
  850. if(::CryptMsgControl(hMsg,
  851. 0,
  852. CMSG_CTRL_DECRYPT,
  853. &DecryptPara))
  854. {
  855. //
  856. // Get decrypted content.
  857. //
  858. if (FAILED(hr = ::GetMsgParam(hMsg,
  859. CMSG_CONTENT_PARAM,
  860. 0,
  861. (void **) &ContentBlob.pbData,
  862. &ContentBlob.cbData)))
  863. {
  864. DebugTrace("Error [%#x]: GetMsgParam() failed to get CMSG_CONTENT_PARAM.\n", hr);
  865. goto ErrorExit;
  866. }
  867. //
  868. // Update member variables.
  869. //
  870. m_ContentBlob = ContentBlob;
  871. //
  872. // We are all done, so break out of loop.
  873. //
  874. break;
  875. }
  876. else
  877. {
  878. //
  879. // Keep copy of error code.
  880. //
  881. hr2 = HRESULT_FROM_WIN32(::GetLastError());
  882. DebugTrace("Info [%#x]: CryptMsgControl() failed to decrypt.\n", hr2);
  883. }
  884. if (bReleaseContext)
  885. {
  886. ::ReleaseContext(hCryptProv), hCryptProv = NULL;
  887. }
  888. }
  889. ::CertFreeCertificateContext(pCertContext), pCertContext = NULL;
  890. }
  891. }
  892. //
  893. // Did we find the recipient?
  894. //
  895. if (dwIndex == dwNumRecipients)
  896. {
  897. //
  898. // Retrieve previous error if any.
  899. //
  900. if (FAILED(hr2))
  901. {
  902. hr = hr2;
  903. DebugTrace("Error [%#x]: CryptMsgControl() failed to decrypt.\n", hr);
  904. }
  905. else
  906. {
  907. hr = CAPICOM_E_ENVELOP_RECIPIENT_NOT_FOUND;
  908. DebugTrace("Error [%#x]: recipient not found.\n", hr);
  909. }
  910. goto ErrorExit;
  911. }
  912. }
  913. catch(...)
  914. {
  915. hr = E_POINTER;
  916. DebugTrace("Exception: invalid parameter.\n");
  917. goto ErrorExit;
  918. }
  919. UnlockExit:
  920. //
  921. // Free resource.
  922. //
  923. if (hCryptProv && bReleaseContext)
  924. {
  925. ::ReleaseContext(hCryptProv);
  926. }
  927. if (pCertContext)
  928. {
  929. ::CertFreeCertificateContext(pCertContext);
  930. }
  931. if(hMsg)
  932. {
  933. ::CryptMsgClose(hMsg);
  934. }
  935. if (hCertStores[0])
  936. {
  937. ::CertCloseStore(hCertStores[0], 0);
  938. }
  939. if (hCertStores[1])
  940. {
  941. ::CertCloseStore(hCertStores[1], 0);
  942. }
  943. //
  944. // Unlock access to this object.
  945. //
  946. m_Lock.Unlock();
  947. DebugTrace("Leaving CEnvelopedData::Decrypt().\n");
  948. return hr;
  949. ErrorExit:
  950. //
  951. // Sanity check.
  952. //
  953. ATLASSERT(FAILED(hr));
  954. //
  955. // Free resources.
  956. //
  957. if (ContentBlob.pbData)
  958. {
  959. ::CoTaskMemFree(ContentBlob.pbData);
  960. }
  961. ReportError(hr);
  962. goto UnlockExit;
  963. }
  964. ////////////////////////////////////////////////////////////////////////////////
  965. //
  966. // Private member functions.
  967. //
  968. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  969. Function : CEnvelopedData::Init
  970. Synopsis : Initialize the object.
  971. Parameter: None.
  972. Remark : This method is not part of the COM interface (it is a normal C++
  973. member function). We need it to initialize the object created
  974. internally by us.
  975. Since it is only a normal C++ member function, this function can
  976. only be called from a C++ class pointer, not an interface pointer.
  977. ------------------------------------------------------------------------------*/
  978. STDMETHODIMP CEnvelopedData::Init ()
  979. {
  980. HRESULT hr = S_OK;
  981. CComPtr<IAlgorithm> pIAlgorithm = NULL;
  982. CComPtr<IRecipients> pIRecipients = NULL;
  983. DebugTrace("Entering CEnvelopedData::Init().\n");
  984. //
  985. // Create embeded IAlgorithm.
  986. //
  987. if (FAILED(hr = ::CreateAlgorithmObject(FALSE, FALSE, &pIAlgorithm)))
  988. {
  989. DebugTrace("Error [%#x]: CreateAlgorithmObject() failed.\n", hr);
  990. goto CommonExit;
  991. }
  992. //
  993. // Create embeded IRecipients.
  994. //
  995. if (FAILED(hr = ::CreateRecipientsObject(&pIRecipients)))
  996. {
  997. DebugTrace("Error [%#x]: CreateRecipientsObject() failed.\n", hr);
  998. goto CommonExit;
  999. }
  1000. //
  1001. // Update member variables.
  1002. //
  1003. m_bEnveloped = FALSE;
  1004. m_ContentBlob.cbData = 0;
  1005. m_ContentBlob.pbData = NULL;
  1006. m_pIAlgorithm = pIAlgorithm;
  1007. m_pIRecipients = pIRecipients;
  1008. CommonExit:
  1009. DebugTrace("Leaving CEnvelopedData::Init().\n");
  1010. return hr;
  1011. }
  1012. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1013. Function : CEnvelopedData::OpenToEncode
  1014. Synopsis : Create and initialize an envelop message for encoding.
  1015. Parameter: HCRYPTMSG * phMsg - Pointer to HCRYPTMSG to receive message
  1016. handler.
  1017. HCRYPTPROV * phCryptProv - Pointer to HCRYPTPROV to receive CSP
  1018. handler.
  1019. Remark :
  1020. ------------------------------------------------------------------------------*/
  1021. STDMETHODIMP CEnvelopedData::OpenToEncode (HCRYPTMSG * phMsg,
  1022. HCRYPTPROV * phCryptProv)
  1023. {
  1024. HRESULT hr = S_OK;
  1025. DWORD dwNumRecipients = 0;
  1026. PCCERT_CONTEXT * pCertContexts = NULL;
  1027. PCERT_INFO * pCertInfos = NULL;
  1028. HCRYPTPROV hCryptProv = NULL;
  1029. void * pEncryptionAuxInfo = NULL;
  1030. CAPICOM_STORE_INFO StoreInfo = {0, L"AddressBook"};
  1031. CComPtr<ICertificate> pIRecipient = NULL;
  1032. CComPtr<ICertificate2> pICertificate2 = NULL;
  1033. DWORD dwIndex;
  1034. CAPICOM_ENCRYPTION_ALGORITHM AlgoName;
  1035. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength;
  1036. CMSG_ENVELOPED_ENCODE_INFO EnvelopInfo;
  1037. CRYPT_ALGORITHM_IDENTIFIER EncryptionAlgorithm;
  1038. DebugTrace("Entering CEnvelopedData::OpenToEncode().\n");
  1039. //
  1040. // Sanity check.
  1041. //
  1042. ATLASSERT(phMsg);
  1043. ATLASSERT(phCryptProv);
  1044. ATLASSERT(m_ContentBlob.cbData && m_ContentBlob.pbData);
  1045. ATLASSERT(m_pIRecipients);
  1046. //
  1047. // Initialize.
  1048. //
  1049. ::ZeroMemory(&EnvelopInfo, sizeof(EnvelopInfo));
  1050. ::ZeroMemory(&EncryptionAlgorithm, sizeof(EncryptionAlgorithm));
  1051. //
  1052. // Make sure we do have at least 1 recipient.
  1053. //
  1054. if (FAILED(hr = m_pIRecipients->get_Count((long *) &dwNumRecipients)))
  1055. {
  1056. DebugTrace("Error [%#x]: m_pIRecipients->get_Count() failed.\n", hr);
  1057. goto ErrorExit;
  1058. }
  1059. if (0 == dwNumRecipients)
  1060. {
  1061. //
  1062. // Prompt user to add a recipient.
  1063. //
  1064. if (FAILED(hr = ::SelectCertificate(StoreInfo,
  1065. SelectRecipientCertCallback,
  1066. &pICertificate2)))
  1067. {
  1068. if (hr == CAPICOM_E_STORE_EMPTY)
  1069. {
  1070. hr = CAPICOM_E_ENVELOP_NO_RECIPIENT;
  1071. }
  1072. DebugTrace("Error [%#x]: SelectCertificate() failed.\n", hr);
  1073. goto ErrorExit;
  1074. }
  1075. if (FAILED(hr = pICertificate2->QueryInterface(__uuidof(ICertificate), (void **) &pIRecipient)))
  1076. {
  1077. DebugTrace("Unexpected error [%#x]: pICertificate2->QueryInterface() failed.\n", hr);
  1078. goto ErrorExit;
  1079. }
  1080. //
  1081. // Add to collection.
  1082. //
  1083. if (FAILED (hr = m_pIRecipients->Add(pIRecipient)))
  1084. {
  1085. DebugTrace("Error [%#x]: m_pIRecipients->Add() failed.\n", hr);
  1086. goto ErrorExit;
  1087. }
  1088. //
  1089. // Make sure count is 1.
  1090. //
  1091. if (FAILED(hr = m_pIRecipients->get_Count((long *) &dwNumRecipients)))
  1092. {
  1093. DebugTrace("Error [%#x]: m_pIRecipients->get_Count() failed.\n", hr);
  1094. goto ErrorExit;
  1095. }
  1096. //
  1097. // Sanity check.
  1098. //
  1099. ATLASSERT(1 == dwNumRecipients);
  1100. }
  1101. //
  1102. // Allocate memory for CERT_CONTEXT array.
  1103. //
  1104. if (!(pCertContexts = (PCCERT_CONTEXT *) ::CoTaskMemAlloc(sizeof(PCCERT_CONTEXT) * dwNumRecipients)))
  1105. {
  1106. hr = E_OUTOFMEMORY;
  1107. DebugTrace("Error: out of memory.\n");
  1108. goto ErrorExit;
  1109. }
  1110. ::ZeroMemory(pCertContexts, sizeof(PCCERT_CONTEXT) * dwNumRecipients);
  1111. //
  1112. // Allocate memory for CERT_INFO array.
  1113. //
  1114. if (!(pCertInfos = (PCERT_INFO *) ::CoTaskMemAlloc(sizeof(PCERT_INFO) * dwNumRecipients)))
  1115. {
  1116. hr = E_OUTOFMEMORY;
  1117. DebugTrace("Error: out of memory.\n");
  1118. goto ErrorExit;
  1119. }
  1120. ::ZeroMemory(pCertInfos, sizeof(PCERT_INFO) * dwNumRecipients);
  1121. //
  1122. // Set CERT_INFO array.
  1123. //
  1124. for (dwIndex = 0; dwIndex < dwNumRecipients; dwIndex++)
  1125. {
  1126. CComVariant varRecipient;
  1127. CComPtr<ICertificate> pIRecipient2 = NULL;
  1128. //
  1129. // Get next recipient.
  1130. //
  1131. if (FAILED(hr = m_pIRecipients->get_Item((long) (dwIndex + 1),
  1132. &varRecipient)))
  1133. {
  1134. DebugTrace("Error [%#x]: m_pIRecipients->get_Item() failed.\n", hr);
  1135. goto ErrorExit;
  1136. }
  1137. //
  1138. // Get custom interface.
  1139. //
  1140. if (FAILED(hr = varRecipient.pdispVal->QueryInterface(IID_ICertificate,
  1141. (void **) &pIRecipient2)))
  1142. {
  1143. DebugTrace("Error [%#x]: varRecipient.pdispVal->QueryInterface() failed.\n", hr);
  1144. goto ErrorExit;
  1145. }
  1146. //
  1147. // Get CERT_CONTEXT.
  1148. //
  1149. if (FAILED(hr = ::GetCertContext(pIRecipient2, &pCertContexts[dwIndex])))
  1150. {
  1151. DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
  1152. goto ErrorExit;
  1153. }
  1154. //
  1155. // Set CERT_INFO.
  1156. //
  1157. pCertInfos[dwIndex] = pCertContexts[dwIndex]->pCertInfo;
  1158. }
  1159. //
  1160. // Get algorithm ID enum name.
  1161. //
  1162. if (FAILED(hr = m_pIAlgorithm->get_Name(&AlgoName)))
  1163. {
  1164. DebugTrace("Error [%#x]: m_pIAlgorithm->get_Name() failed.\n", hr);
  1165. goto ErrorExit;
  1166. }
  1167. //
  1168. // Get key length enum name.
  1169. //
  1170. if (FAILED(hr = m_pIAlgorithm->get_KeyLength(&KeyLength)))
  1171. {
  1172. DebugTrace("Error [%#x]: m_pIAlgorithm->get_KeyLength() failed.\n", hr);
  1173. goto ErrorExit;
  1174. }
  1175. //
  1176. // Get CSP context.
  1177. //
  1178. if (FAILED(hr = ::AcquireContext(AlgoName,
  1179. KeyLength,
  1180. &hCryptProv)))
  1181. {
  1182. DebugTrace("Error [%#x]: AcquireContext() failed.\n", hr);
  1183. goto ErrorExit;
  1184. }
  1185. //
  1186. // Set algorithm.
  1187. //
  1188. if (FAILED(hr = ::SetEncryptionAlgorithm(AlgoName,
  1189. KeyLength,
  1190. &EncryptionAlgorithm)))
  1191. {
  1192. DebugTrace("Error [%#x]: SetEncryptionAlgorithm() failed.\n", hr);
  1193. goto ErrorExit;
  1194. }
  1195. //
  1196. // Set key length.
  1197. //
  1198. if (FAILED(hr = ::SetKeyLength(hCryptProv,
  1199. EncryptionAlgorithm,
  1200. KeyLength,
  1201. &pEncryptionAuxInfo)))
  1202. {
  1203. DebugTrace("Error [%#x]: SetKeyLength() failed.\n", hr);
  1204. goto ErrorExit;
  1205. }
  1206. //
  1207. // Set CMSG_ENVELOPED_ENCODE_INFO.
  1208. //
  1209. EnvelopInfo.cbSize = sizeof(EnvelopInfo);
  1210. EnvelopInfo.ContentEncryptionAlgorithm = EncryptionAlgorithm;
  1211. EnvelopInfo.hCryptProv = hCryptProv;
  1212. EnvelopInfo.cRecipients = dwNumRecipients;
  1213. EnvelopInfo.rgpRecipients = pCertInfos;
  1214. EnvelopInfo.pvEncryptionAuxInfo = pEncryptionAuxInfo;
  1215. //
  1216. // Open the message for encoding.
  1217. //
  1218. if(!(*phMsg = ::CryptMsgOpenToEncode(CAPICOM_ASN_ENCODING, // ASN encoding type
  1219. 0, // Flags
  1220. CMSG_ENVELOPED, // Message type
  1221. &EnvelopInfo, // Pointer to structure
  1222. NULL, // Inner content OID
  1223. NULL))) // Stream information (not used)
  1224. {
  1225. hr = HRESULT_FROM_WIN32(::GetLastError());
  1226. DebugTrace("Error [%#x]: CryptMsgOpenToEncode() failed.\n", hr);
  1227. goto ErrorExit;
  1228. }
  1229. //
  1230. // Return HCRYPTPROV to caller.
  1231. //
  1232. *phCryptProv = hCryptProv;
  1233. CommonExit:
  1234. //
  1235. // Free resource.
  1236. //
  1237. if (pEncryptionAuxInfo)
  1238. {
  1239. ::CoTaskMemFree(pEncryptionAuxInfo);
  1240. }
  1241. if (EncryptionAlgorithm.pszObjId)
  1242. {
  1243. ::CoTaskMemFree(EncryptionAlgorithm.pszObjId);
  1244. }
  1245. if (EncryptionAlgorithm.Parameters.pbData)
  1246. {
  1247. ::CoTaskMemFree(EncryptionAlgorithm.Parameters.pbData);
  1248. }
  1249. if (pCertInfos)
  1250. {
  1251. ::CoTaskMemFree(pCertInfos);
  1252. }
  1253. if (pCertContexts)
  1254. {
  1255. for (dwIndex = 0; dwIndex < dwNumRecipients; dwIndex++)
  1256. {
  1257. if (pCertContexts[dwIndex])
  1258. {
  1259. ::CertFreeCertificateContext(pCertContexts[dwIndex]);
  1260. }
  1261. }
  1262. ::CoTaskMemFree(pCertContexts);
  1263. }
  1264. DebugTrace("Leaving CEnvelopedData::OpenToEncode().\n");
  1265. return hr;
  1266. ErrorExit:
  1267. //
  1268. // Sanity check.
  1269. //
  1270. ATLASSERT(FAILED(hr));
  1271. //
  1272. // Free resource.
  1273. //
  1274. if (hCryptProv)
  1275. {
  1276. ::ReleaseContext(hCryptProv);
  1277. }
  1278. goto CommonExit;
  1279. }
  1280. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1281. Function : CEnvelopedData::OpenToDeccode
  1282. Synopsis : Open an enveloped message for decoding.
  1283. Parameter: HCRYPTPROV hCryptProv - CSP handle.
  1284. BSTR EnvelopMessage - Enveloped message.
  1285. HCRYPTMSG * phMsg - Pointer to HCRYPTMSG.
  1286. Remark :
  1287. ------------------------------------------------------------------------------*/
  1288. STDMETHODIMP CEnvelopedData::OpenToDecode (HCRYPTPROV hCryptProv,
  1289. BSTR EnvelopedMessage,
  1290. HCRYPTMSG * phMsg)
  1291. {
  1292. HRESULT hr = S_OK;
  1293. HCRYPTMSG hMsg = NULL;
  1294. DWORD dwMsgType = 0;
  1295. DWORD cbMsgType = sizeof(dwMsgType);
  1296. DATA_BLOB MessageBlob = {0, NULL};
  1297. DATA_BLOB AlgorithmBlob = {0, NULL};
  1298. DATA_BLOB ParametersBlob = {0, NULL};
  1299. DebugTrace("Leaving CEnvelopedData::OpenToDecode().\n");
  1300. // Sanity check.
  1301. //
  1302. ATLASSERT(phMsg);
  1303. ATLASSERT(EnvelopedMessage);
  1304. try
  1305. {
  1306. //
  1307. // Open the message for decoding.
  1308. //
  1309. if (!(hMsg = ::CryptMsgOpenToDecode(CAPICOM_ASN_ENCODING,
  1310. 0,
  1311. 0,
  1312. hCryptProv,
  1313. NULL,
  1314. NULL)))
  1315. {
  1316. hr = HRESULT_FROM_WIN32(::GetLastError());
  1317. DebugTrace("Error [%#x]: CryptMsgOpenToDecode() failed.\n", hr);
  1318. goto CommonExit;
  1319. }
  1320. //
  1321. // Import the message.
  1322. //
  1323. if (FAILED(hr = ::ImportData(EnvelopedMessage, CAPICOM_ENCODE_ANY, &MessageBlob)))
  1324. {
  1325. DebugTrace("Error [%#x]: ImportData() failed.\n", hr);
  1326. goto ErrorExit;
  1327. }
  1328. //
  1329. // Update message with enveloped content.
  1330. //
  1331. if (!::CryptMsgUpdate(hMsg,
  1332. MessageBlob.pbData,
  1333. MessageBlob.cbData,
  1334. TRUE))
  1335. {
  1336. hr = HRESULT_FROM_WIN32(::GetLastError());
  1337. DebugTrace("Error [%#x]: CryptMsgUpdate() failed.\n", hr);
  1338. goto ErrorExit;
  1339. }
  1340. //
  1341. // Check message type.
  1342. //
  1343. if (!::CryptMsgGetParam(hMsg,
  1344. CMSG_TYPE_PARAM,
  1345. 0,
  1346. (void *) &dwMsgType,
  1347. &cbMsgType))
  1348. {
  1349. hr = HRESULT_FROM_WIN32(::GetLastError());
  1350. DebugTrace("Error [%#x]: CryptMsgGetParam() failed for CMSG_TYPE_PARAM.\n", hr);
  1351. goto ErrorExit;
  1352. }
  1353. if (CMSG_ENVELOPED != dwMsgType)
  1354. {
  1355. hr = CAPICOM_E_ENVELOP_INVALID_TYPE;
  1356. DebugTrace("Error [%#x]: Enveloped message's dwMsgType (%#x) is not CMSG_ENVELOPED.\n", hr, dwMsgType);
  1357. goto ErrorExit;
  1358. }
  1359. //
  1360. // Get algorithm ID.
  1361. //
  1362. if (FAILED(hr = ::GetMsgParam(hMsg,
  1363. CMSG_ENVELOPE_ALGORITHM_PARAM,
  1364. 0,
  1365. (void **) &AlgorithmBlob.pbData,
  1366. &AlgorithmBlob.cbData)))
  1367. {
  1368. DebugTrace("Error [%#x]: GetMsgParam() failed for CMSG_ENVELOPE_ALGORITHM_PARAM.\n", hr);
  1369. goto ErrorExit;
  1370. }
  1371. //
  1372. // Restore encryption algorithm state, as much as we can.
  1373. //
  1374. if (0 == lstrcmpA(szOID_RSA_RC2CBC, ((CRYPT_ALGORITHM_IDENTIFIER *) AlgorithmBlob.pbData)->pszObjId))
  1375. {
  1376. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength;
  1377. DebugTrace("INFO: Envelop encryption algorithm was RC2.\n");
  1378. //
  1379. // Set encryption algorithm name.
  1380. //
  1381. if (FAILED(hr = m_pIAlgorithm->put_Name(CAPICOM_ENCRYPTION_ALGORITHM_RC2)))
  1382. {
  1383. DebugTrace("Error [%#x]: m_pIAlgorithm->put_Name() failed.\n", hr);
  1384. goto ErrorExit;
  1385. }
  1386. //
  1387. // Determine encryption key length.
  1388. //
  1389. if (((CRYPT_ALGORITHM_IDENTIFIER *) AlgorithmBlob.pbData)->Parameters.cbData)
  1390. {
  1391. if (FAILED(hr = ::DecodeObject(PKCS_RC2_CBC_PARAMETERS,
  1392. ((CRYPT_ALGORITHM_IDENTIFIER *) AlgorithmBlob.pbData)->Parameters.pbData,
  1393. ((CRYPT_ALGORITHM_IDENTIFIER *) AlgorithmBlob.pbData)->Parameters.cbData,
  1394. &ParametersBlob)))
  1395. {
  1396. DebugTrace("Error [%#x]: DecodeObject() failed for PKCS_RC2_CBC_PARAMETERS.\n", hr);
  1397. goto ErrorExit;
  1398. }
  1399. }
  1400. //
  1401. // Set encryption key length.
  1402. //
  1403. switch (((CRYPT_RC2_CBC_PARAMETERS *) ParametersBlob.pbData)->dwVersion)
  1404. {
  1405. case CRYPT_RC2_40BIT_VERSION:
  1406. {
  1407. KeyLength = CAPICOM_ENCRYPTION_KEY_LENGTH_40_BITS;
  1408. DebugTrace("INFO: Envelop encryption key length was 40-bits.\n");
  1409. break;
  1410. }
  1411. case CRYPT_RC2_56BIT_VERSION:
  1412. {
  1413. KeyLength = CAPICOM_ENCRYPTION_KEY_LENGTH_56_BITS;
  1414. DebugTrace("INFO: Envelop encryption key length was 56-bits.\n");
  1415. break;
  1416. }
  1417. case CRYPT_RC2_128BIT_VERSION:
  1418. {
  1419. KeyLength = CAPICOM_ENCRYPTION_KEY_LENGTH_128_BITS;
  1420. DebugTrace("INFO: Envelop encryption key length was 128-bits.\n");
  1421. break;
  1422. }
  1423. default:
  1424. {
  1425. //
  1426. // Unknown key length, so arbitrary choose one.
  1427. //
  1428. KeyLength = CAPICOM_ENCRYPTION_KEY_LENGTH_MAXIMUM;
  1429. DebugTrace("INFO: Unknown envelop encryption key length.\n");
  1430. break;
  1431. }
  1432. }
  1433. //
  1434. // Set key length.
  1435. //
  1436. if (FAILED(hr = m_pIAlgorithm->put_KeyLength(KeyLength)))
  1437. {
  1438. DebugTrace("Error [%#x]: m_pIAlgorithm->put_KeyLength() failed.\n", hr);
  1439. goto ErrorExit;
  1440. }
  1441. }
  1442. else if (0 == lstrcmpA(szOID_RSA_RC4, ((CRYPT_ALGORITHM_IDENTIFIER *) AlgorithmBlob.pbData)->pszObjId))
  1443. {
  1444. DebugTrace("INFO: Envelop encryption algorithm was RC4.\n");
  1445. //
  1446. // Set encryption algorithm name.
  1447. //
  1448. if (FAILED(hr = m_pIAlgorithm->put_Name(CAPICOM_ENCRYPTION_ALGORITHM_RC4)))
  1449. {
  1450. DebugTrace("Error [%#x]: m_pIAlgorithm->put_Name() failed.\n", hr);
  1451. goto ErrorExit;
  1452. }
  1453. //
  1454. // For RC4, CAPI simply does not provide a way to retrieve the
  1455. // encryption key length, so we will have to leave it alone!!!
  1456. //
  1457. }
  1458. else if (0 == lstrcmpA(szOID_OIWSEC_desCBC, ((CRYPT_ALGORITHM_IDENTIFIER *) AlgorithmBlob.pbData)->pszObjId))
  1459. {
  1460. DebugTrace("INFO: Envelop encryption algorithm was DES.\n");
  1461. //
  1462. // Set encryption algorithm name.
  1463. //
  1464. if (FAILED(hr = m_pIAlgorithm->put_Name(CAPICOM_ENCRYPTION_ALGORITHM_DES)))
  1465. {
  1466. DebugTrace("Error [%#x]: m_pIAlgorithm->put_Name() failed.\n", hr);
  1467. goto ErrorExit;
  1468. }
  1469. //
  1470. // For DES, key length is fixed at 56, and should be ignored.
  1471. //
  1472. }
  1473. else if (0 == lstrcmpA(szOID_RSA_DES_EDE3_CBC, ((CRYPT_ALGORITHM_IDENTIFIER *) AlgorithmBlob.pbData)->pszObjId))
  1474. {
  1475. DebugTrace("INFO: Envelop encryption algorithm was 3DES.\n");
  1476. //
  1477. // Set encryption algorithm name.
  1478. //
  1479. if (FAILED(hr = m_pIAlgorithm->put_Name(CAPICOM_ENCRYPTION_ALGORITHM_3DES)))
  1480. {
  1481. DebugTrace("Error [%#x]: m_pIAlgorithm->put_Name() failed.\n", hr);
  1482. goto ErrorExit;
  1483. }
  1484. //
  1485. // For 3DES, key length is fixed at 168, and should be ignored.
  1486. //
  1487. }
  1488. else
  1489. {
  1490. DebugTrace("INFO: Unknown envelop encryption algorithm.\n");
  1491. }
  1492. //
  1493. // Return msg handler to caller.
  1494. //
  1495. *phMsg = hMsg;
  1496. }
  1497. catch(...)
  1498. {
  1499. hr = E_POINTER;
  1500. DebugTrace("Exception: invalid parameter.\n");
  1501. goto ErrorExit;
  1502. }
  1503. CommonExit:
  1504. //
  1505. // Free resource.
  1506. //
  1507. if (ParametersBlob.pbData)
  1508. {
  1509. ::CoTaskMemFree(ParametersBlob.pbData);
  1510. }
  1511. if (AlgorithmBlob.pbData)
  1512. {
  1513. ::CoTaskMemFree(AlgorithmBlob.pbData);
  1514. }
  1515. if (MessageBlob.pbData)
  1516. {
  1517. ::CoTaskMemFree(MessageBlob.pbData);
  1518. }
  1519. DebugTrace("Leaving CEnvelopedData::OpenToDecode().\n");
  1520. return hr;
  1521. ErrorExit:
  1522. //
  1523. // Sanity check.
  1524. //
  1525. ATLASSERT(FAILED(hr));
  1526. if (hMsg)
  1527. {
  1528. ::CryptMsgClose(hMsg);
  1529. }
  1530. goto CommonExit;
  1531. }