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.

2278 lines
64 KiB

  1. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
  3. File: SignedData.cpp
  4. Content: Implementation of CSignedData.
  5. History: 11-15-99 dsie created
  6. ------------------------------------------------------------------------------*/
  7. #include "StdAfx.h"
  8. #include "CAPICOM.h"
  9. #include "SignedData.h"
  10. #include "Certificates.h"
  11. #include "Chain.h"
  12. #include "Common.h"
  13. #include "Convert.h"
  14. #include "CertHlpr.h"
  15. #include "MsgHlpr.h"
  16. #include "Policy.h"
  17. #include "Settings.h"
  18. #include "Signer2.h"
  19. #include "Signers.h"
  20. #include "SignHlpr.h"
  21. ////////////////////////////////////////////////////////////////////////////////
  22. //
  23. // Local functions.
  24. //
  25. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  26. Function : FreeCertificateChain
  27. Synopsis : Free resources allocated for the chain built with
  28. InitCertificateChain.
  29. Parameter: CRYPT_DATA_BLOB * pChainBlob - Pointer to chain blob.
  30. Remark :
  31. ------------------------------------------------------------------------------*/
  32. static void FreeCertificateChain (CRYPT_DATA_BLOB * pChainBlob)
  33. {
  34. DWORD i;
  35. PCCERT_CONTEXT * rgCertContext;
  36. DebugTrace("Entering FreeCertificateChain().\n");
  37. //
  38. // Sanity check.
  39. //
  40. ATLASSERT(pChainBlob);
  41. //
  42. // Free all allocated memory for the chain.
  43. //
  44. ;
  45. for (i = 0, rgCertContext = (PCCERT_CONTEXT *) pChainBlob->pbData; i < pChainBlob->cbData; i++)
  46. {
  47. ATLASSERT(rgCertContext[i]);
  48. ::CertFreeCertificateContext(rgCertContext[i]);
  49. }
  50. ::CoTaskMemFree((LPVOID) pChainBlob->pbData);
  51. return;
  52. }
  53. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  54. Function : AddCertificateChain
  55. Synopsis : Add the chain of certificates to the bag of certs.
  56. Parameter: HCRYPTMSG hMsg - Message handle.
  57. DATA_BLOB * pChainBlob - Pointer chain blob of PCCERT_CONTEXT.
  58. CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption - Include option.
  59. Remark :
  60. ------------------------------------------------------------------------------*/
  61. static HRESULT AddCertificateChain (HCRYPTMSG hMsg,
  62. DATA_BLOB * pChainBlob,
  63. CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption)
  64. {
  65. HRESULT hr = S_OK;
  66. DebugTrace("Entering AddCertificateChain().\n");
  67. //
  68. // Sanity check.
  69. //
  70. ATLASSERT(hMsg);
  71. ATLASSERT(pChainBlob);
  72. ATLASSERT(pChainBlob->cbData);
  73. ATLASSERT(pChainBlob->pbData);
  74. DWORD cCertContext = pChainBlob->cbData;
  75. PCERT_CONTEXT * rgCertContext = (PCERT_CONTEXT *) pChainBlob->pbData;
  76. //
  77. // Determine number of cert(s) to include in the bag.
  78. //
  79. switch (IncludeOption)
  80. {
  81. case CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY:
  82. {
  83. cCertContext = 1;
  84. break;
  85. }
  86. case CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN:
  87. {
  88. break;
  89. }
  90. case CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT:
  91. {
  92. //
  93. // <<< Falling thru to default >>>
  94. //
  95. }
  96. default:
  97. {
  98. if (1 < cCertContext)
  99. {
  100. cCertContext--;
  101. }
  102. break;
  103. }
  104. }
  105. //
  106. // Add all certs from the chain to message.
  107. //
  108. for (DWORD i = 0; i < cCertContext; i++)
  109. {
  110. //
  111. // Is this cert already in the bag of certs?
  112. //
  113. if (FAILED(hr =::FindSignerCertInMessage(hMsg,
  114. &rgCertContext[i]->pCertInfo->Issuer,
  115. &rgCertContext[i]->pCertInfo->SerialNumber,
  116. NULL)))
  117. {
  118. //
  119. // No, so add to bag of certs.
  120. //
  121. DATA_BLOB CertBlob = {rgCertContext[i]->cbCertEncoded,
  122. rgCertContext[i]->pbCertEncoded};
  123. if (!::CryptMsgControl(hMsg,
  124. 0,
  125. CMSG_CTRL_ADD_CERT,
  126. &CertBlob))
  127. {
  128. hr = HRESULT_FROM_WIN32(::GetLastError());
  129. DebugTrace("Error [%#x]: CryptMsgControl() failed for CMSG_CTRL_ADD_CERT.\n", hr);
  130. break;
  131. }
  132. hr = S_OK;
  133. }
  134. }
  135. DebugTrace("Leaving AddCertificateChain().\n");
  136. return hr;
  137. }
  138. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  139. Function : InitCertificateChain
  140. Synopsis : Allocate and initialize a certificate chain for the specified
  141. certificate, and return the chain in an array of PCERT_CONTEXT.
  142. Parameter: ICertificate * pICertificate - Pointer to ICertificate for which
  143. the chain will be built.
  144. HCERTSTORE hAdditionalStore - Additional store handle.
  145. CRYPT_DATA_BLOB * pChainBlob - Pointer to blob to recevie the
  146. size and array of PCERT_CONTEXT
  147. for the chain.
  148. Remark :
  149. ------------------------------------------------------------------------------*/
  150. static HRESULT InitCertificateChain (ICertificate * pICertificate,
  151. HCERTSTORE hAdditionalStore,
  152. CRYPT_DATA_BLOB * pChainBlob)
  153. {
  154. HRESULT hr = S_OK;
  155. CComPtr<IChain> pIChain = NULL;
  156. VARIANT_BOOL bResult = VARIANT_FALSE;
  157. DebugTrace("Entering InitCertificateChain().\n");
  158. //
  159. // Sanity checks.
  160. //
  161. ATLASSERT(pICertificate);
  162. ATLASSERT(pChainBlob);
  163. //
  164. // Create a chain object.
  165. //
  166. if (FAILED(hr = ::CreateChainObject(pICertificate,
  167. hAdditionalStore,
  168. &bResult,
  169. &pIChain)))
  170. {
  171. DebugTrace("Error [%#x]: CreateChainObject() failed.\n", hr);
  172. goto CommonExit;
  173. }
  174. //
  175. // Get the chain of certs.
  176. //
  177. if (FAILED(hr = ::GetChainContext(pIChain, pChainBlob)))
  178. {
  179. DebugTrace("Error [%#x]: GetChainContext() failed.\n", hr);
  180. }
  181. CommonExit:
  182. DebugTrace("Leaving InitCertificateChain().\n");
  183. return hr;
  184. }
  185. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  186. Function : FreeSignerEncodeInfo
  187. Synopsis : Free all memory allocated for the CMSG_SIGNER_ENCODE_INFO
  188. structure, including any memory allocated for members of the
  189. structure.
  190. Parameter: CMSG_SIGNER_ENCODE_INFO * pSignerEncodeInfo - Pointer to the
  191. structure.
  192. Remark :
  193. ------------------------------------------------------------------------------*/
  194. static void FreeSignerEncodeInfo (CMSG_SIGNER_ENCODE_INFO * pSignerEncodeInfo)
  195. {
  196. DebugTrace("Entering FreeSignerEncodeInfo().\n");
  197. //
  198. // Sanity check.
  199. //
  200. ATLASSERT(pSignerEncodeInfo);
  201. //
  202. // First free the authenticated attributes array, if present.
  203. //
  204. if (pSignerEncodeInfo->rgAuthAttr)
  205. {
  206. ::FreeAttributes(pSignerEncodeInfo->cAuthAttr, pSignerEncodeInfo->rgAuthAttr);
  207. ::CoTaskMemFree(pSignerEncodeInfo->rgAuthAttr);
  208. }
  209. ::ZeroMemory(pSignerEncodeInfo, sizeof(CMSG_SIGNER_ENCODE_INFO));
  210. DebugTrace("Leaving FreeSignerEncodeInfo().\n");
  211. return;
  212. }
  213. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  214. Function : InitSignerEncodeInfo
  215. Synopsis : Allocate a CMSG_SIGNER_ENCODE_INFO structure, and initialize it
  216. with values passed in through parameters.
  217. Parameter: ISigner * pISigner - Pointer to ISigner.
  218. PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT of cert.
  219. HCRYPTPROV phCryptProv - CSP handle.
  220. DWORD dwKeySpec - Key spec, AT_KEYEXCHANGE or AT_SIGNATURE.
  221. CMSG_SIGNER_ENCODE_INFO * pSignerEncodeInfo - Structure to be
  222. initialized.
  223. Return : Pointer to an initialized CMSG_SIGNER_ENCODE_INFO structure if
  224. success, otherwise NULL (out of memory).
  225. Remark : Must call FreeSignerEncodeInfo to free resources allocated.
  226. ------------------------------------------------------------------------------*/
  227. static HRESULT InitSignerEncodeInfo (ISigner * pISigner,
  228. PCCERT_CONTEXT pCertContext,
  229. HCRYPTPROV hCryptProv,
  230. DWORD dwKeySpec,
  231. CMSG_SIGNER_ENCODE_INFO * pSignerEncodeInfo)
  232. {
  233. HRESULT hr = S_OK;
  234. CRYPT_ATTRIBUTES AuthAttr;
  235. DebugTrace("Entering InitSignerEncodeInfo().\n");
  236. //
  237. // Sanity check.
  238. //
  239. ATLASSERT(pISigner);
  240. ATLASSERT(pCertContext);
  241. ATLASSERT(hCryptProv);
  242. ATLASSERT(pSignerEncodeInfo);
  243. //
  244. // Initialize.
  245. //
  246. ::ZeroMemory(&AuthAttr, sizeof(AuthAttr));
  247. //
  248. // Get authenticated attributes.
  249. //
  250. if (FAILED(hr = ::GetAuthenticatedAttributes(pISigner, &AuthAttr)))
  251. {
  252. DebugTrace("Error [%#x]: GetAuthenticatedAttributes() failed.\n", hr);
  253. goto ErrorExit;
  254. }
  255. //
  256. // Setup CMSG_SIGNER_ENCODE_INFO structure.
  257. //
  258. ::ZeroMemory(pSignerEncodeInfo, sizeof(CMSG_SIGNER_ENCODE_INFO));
  259. pSignerEncodeInfo->cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
  260. pSignerEncodeInfo->pCertInfo = pCertContext->pCertInfo;
  261. pSignerEncodeInfo->hCryptProv = hCryptProv;
  262. pSignerEncodeInfo->dwKeySpec = dwKeySpec;
  263. pSignerEncodeInfo->HashAlgorithm.pszObjId = szOID_OIWSEC_sha1;
  264. pSignerEncodeInfo->cAuthAttr = AuthAttr.cAttr;
  265. pSignerEncodeInfo->rgAuthAttr = AuthAttr.rgAttr;
  266. CommonExit:
  267. DebugTrace("Leaving InitSignerEncodeInfo().\n");
  268. return hr;
  269. ErrorExit:
  270. //
  271. // Sanity check.
  272. //
  273. ATLASSERT(FAILED(hr));
  274. //
  275. // Free resources.
  276. //
  277. ::FreeAttributes(&AuthAttr);
  278. goto CommonExit;
  279. }
  280. ////////////////////////////////////////////////////////////////////////////////
  281. //
  282. // CSignedData
  283. //
  284. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  285. Function : CSignedData::get_Content
  286. Synopsis : Return the content.
  287. Parameter: BSTR * pVal - Pointer to BSTR to receive the content.
  288. Remark :
  289. ------------------------------------------------------------------------------*/
  290. STDMETHODIMP CSignedData::get_Content (BSTR * pVal)
  291. {
  292. HRESULT hr = S_OK;
  293. DebugTrace("Entering CSignedData::get_Content().\n");
  294. try
  295. {
  296. //
  297. // Lock access to this object.
  298. //
  299. m_Lock.Lock();
  300. //
  301. // Make sure parameter is valid.
  302. //
  303. if (NULL == pVal)
  304. {
  305. hr = E_POINTER;
  306. DebugTrace("Error: invalid parameter, pVal is NULL.\n");
  307. goto ErrorExit;
  308. }
  309. //
  310. // Make sure content is already initialized.
  311. //
  312. if (0 == m_ContentBlob.cbData)
  313. {
  314. hr = CAPICOM_E_SIGN_NOT_INITIALIZED;
  315. DebugTrace("Error: SignedData object has not been initialized.\n");
  316. goto ErrorExit;
  317. }
  318. //
  319. // Sanity check.
  320. //
  321. ATLASSERT(m_ContentBlob.pbData);
  322. //
  323. // Return content.
  324. //
  325. if (FAILED(hr = ::BlobToBstr(&m_ContentBlob, pVal)))
  326. {
  327. DebugTrace("Error [%#x]: BlobToBstr() failed.\n", hr);
  328. goto ErrorExit;
  329. }
  330. }
  331. catch(...)
  332. {
  333. hr = E_INVALIDARG;
  334. DebugTrace("Exception: invalid parameter.\n");
  335. goto ErrorExit;
  336. }
  337. UnlockExit:
  338. //
  339. // Unlock access to this object.
  340. //
  341. m_Lock.Unlock();
  342. DebugTrace("Leaving CSignedData::get_Content().\n");
  343. return hr;
  344. ErrorExit:
  345. //
  346. // Sanity check.
  347. //
  348. ATLASSERT(FAILED(hr));
  349. ReportError(hr);
  350. goto UnlockExit;
  351. }
  352. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  353. Function : CSignedData::put_Content
  354. Synopsis : Initialize the object with content to be signed.
  355. Parameter: BSTR newVal - BSTR containing the content to be signed.
  356. Remark : Note that this property should not be changed once a signature
  357. is created, as it will re-initialize the object even in error
  358. condition, unless that's your intention.
  359. ------------------------------------------------------------------------------*/
  360. STDMETHODIMP CSignedData::put_Content (BSTR newVal)
  361. {
  362. HRESULT hr = S_OK;
  363. DebugTrace("Entering CSignedData::put_Content().\n");
  364. try
  365. {
  366. //
  367. // Lock access to this object.
  368. //
  369. m_Lock.Lock();
  370. //
  371. // Reset member variables.
  372. //
  373. if (m_ContentBlob.pbData)
  374. {
  375. ::CoTaskMemFree(m_ContentBlob.pbData);
  376. }
  377. if (m_MessageBlob.pbData)
  378. {
  379. ::CoTaskMemFree(m_MessageBlob.pbData);
  380. }
  381. m_bSigned = FALSE;
  382. m_bDetached = VARIANT_FALSE;
  383. m_ContentBlob.cbData = 0;
  384. m_ContentBlob.pbData = NULL;
  385. m_MessageBlob.cbData = 0;
  386. m_MessageBlob.pbData = NULL;
  387. //
  388. // Make sure parameters are valid.
  389. //
  390. if (NULL == newVal)
  391. {
  392. hr = E_INVALIDARG;
  393. DebugTrace("Error [%#x]: Parameter newVal is NULL.\n", hr);
  394. goto ErrorExit;
  395. }
  396. if (0 == ::SysStringByteLen(newVal))
  397. {
  398. hr = E_INVALIDARG;
  399. DebugTrace("Error [%#x]: Parameter newVal is empty.\n", hr);
  400. goto ErrorExit;
  401. }
  402. //
  403. // Update content.
  404. //
  405. if (FAILED(hr = ::BstrToBlob(newVal, &m_ContentBlob)))
  406. {
  407. DebugTrace("Error [%#x]: BstrToBlob() failed.\n", hr);
  408. goto ErrorExit;
  409. }
  410. }
  411. catch(...)
  412. {
  413. hr = E_INVALIDARG;
  414. DebugTrace("Exception: invalid parameter.\n");
  415. goto ErrorExit;
  416. }
  417. UnlockExit:
  418. //
  419. // Unlock access to this object.
  420. //
  421. m_Lock.Unlock();
  422. DebugTrace("Leaving CSignedData::put_Content().\n");
  423. return hr;
  424. ErrorExit:
  425. //
  426. // Sanity check.
  427. //
  428. ATLASSERT(FAILED(hr));
  429. ReportError(hr);
  430. goto UnlockExit;
  431. }
  432. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  433. Function : CSignedData::get_Signers
  434. Synopsis : Return all the content signers as an ISigners collection object.
  435. Parameter: ISigner * pVal - Pointer to pointer to ISigners to receive
  436. interface pointer.
  437. Remark :
  438. ------------------------------------------------------------------------------*/
  439. STDMETHODIMP CSignedData::get_Signers (ISigners ** pVal)
  440. {
  441. HRESULT hr = S_OK;
  442. HCRYPTMSG hMsg = NULL;
  443. HCERTSTORE hStore = NULL;
  444. DebugTrace("Entering CSignedData::get_Signers().\n");
  445. try
  446. {
  447. //
  448. // Lock access to this object.
  449. //
  450. m_Lock.Lock();
  451. //
  452. // Make sure the messages is already signed.
  453. //
  454. if (!m_bSigned)
  455. {
  456. hr = CAPICOM_E_SIGN_NOT_SIGNED;
  457. DebugTrace("Error: content was not signed.\n");
  458. goto ErrorExit;
  459. }
  460. //
  461. // Open the encoded message for decode.
  462. //
  463. if (FAILED(hr = OpenToDecode(NULL,
  464. &hMsg)))
  465. {
  466. DebugTrace("Error [%#x]: OpenToDecode() failed.\n", hr);
  467. goto ErrorExit;
  468. }
  469. //
  470. // Open the PKCS7 store.
  471. //
  472. if (!(hStore = ::CertOpenStore(CERT_STORE_PROV_PKCS7,
  473. CAPICOM_ASN_ENCODING,
  474. NULL,
  475. CERT_STORE_OPEN_EXISTING_FLAG,
  476. &m_MessageBlob)))
  477. {
  478. DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
  479. goto ErrorExit;
  480. }
  481. //
  482. // Create the ISigners collection object.
  483. //
  484. if (FAILED(hr = ::CreateSignersObject(hMsg, 1, hStore, m_dwCurrentSafety, pVal)))
  485. {
  486. DebugTrace("Error [%#x]: CreateSignersObject() failed.\n", hr);
  487. goto ErrorExit;
  488. }
  489. }
  490. catch(...)
  491. {
  492. hr = E_INVALIDARG;
  493. DebugTrace("Exception: invalid parameter.\n");
  494. goto ErrorExit;
  495. }
  496. UnlockExit:
  497. //
  498. // Free resource.
  499. //
  500. if (hMsg)
  501. {
  502. ::CryptMsgClose(hMsg);
  503. }
  504. //
  505. // Unlock access to this object.
  506. //
  507. m_Lock.Unlock();
  508. DebugTrace("Leaving CSignedData::get_Signers().\n");
  509. return hr;
  510. ErrorExit:
  511. //
  512. // Sanity check.
  513. //
  514. ATLASSERT(FAILED(hr));
  515. ReportError(hr);
  516. goto UnlockExit;
  517. }
  518. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  519. Function : CSignedData::get_Certificates
  520. Synopsis : Return all certificates found in the message as an non-ordered
  521. ICertificates collection object.
  522. Parameter: ICertificates ** pVal - Pointer to pointer to ICertificates
  523. to receive the interface pointer.
  524. Remark :
  525. ------------------------------------------------------------------------------*/
  526. STDMETHODIMP CSignedData::get_Certificates (ICertificates ** pVal)
  527. {
  528. HRESULT hr = S_OK;
  529. CComPtr<ICertificates2> pICertificates = NULL;
  530. CAPICOM_CERTIFICATES_SOURCE ccs = {CAPICOM_CERTIFICATES_LOAD_FROM_MESSAGE, 0};
  531. DebugTrace("Entering CSignedData::get_Certificates().\n");
  532. try
  533. {
  534. //
  535. // Lock access to this object.
  536. //
  537. m_Lock.Lock();
  538. //
  539. // Make sure the messages is already signed.
  540. //
  541. if (!m_bSigned)
  542. {
  543. hr = CAPICOM_E_SIGN_NOT_SIGNED;
  544. DebugTrace("Error: content was not signed.\n");
  545. goto ErrorExit;
  546. }
  547. //
  548. // Open the encoded message for decode.
  549. //
  550. if (FAILED(hr = OpenToDecode(NULL, &ccs.hCryptMsg)))
  551. {
  552. DebugTrace("Error [%#x]: OpenToDecode() failed.\n", hr);
  553. goto ErrorExit;
  554. }
  555. //
  556. // Create the ICertificates2 collection object.
  557. //
  558. if (FAILED(hr = ::CreateCertificatesObject(ccs, m_dwCurrentSafety, TRUE, &pICertificates)))
  559. {
  560. DebugTrace("Error [%#x]: CreateCertificatesObject() failed.\n", hr);
  561. goto ErrorExit;
  562. }
  563. //
  564. // Return ICertificates collection object to user.
  565. //
  566. if (FAILED(hr = pICertificates->QueryInterface(__uuidof(ICertificates), (void **) pVal)))
  567. {
  568. DebugTrace("Error [%#x]: pICertificates->QueryInterface() failed.\n", hr);
  569. goto ErrorExit;
  570. }
  571. }
  572. catch(...)
  573. {
  574. hr = E_INVALIDARG;
  575. DebugTrace("Exception: invalid parameter.\n");
  576. goto ErrorExit;
  577. }
  578. UnlockExit:
  579. //
  580. // Free resource.
  581. //
  582. if (ccs.hCryptMsg)
  583. {
  584. ::CryptMsgClose(ccs.hCryptMsg);
  585. }
  586. //
  587. // Unlock access to this object.
  588. //
  589. m_Lock.Unlock();
  590. DebugTrace("Leaving CSignedData::get_Certificates().\n");
  591. return hr;
  592. ErrorExit:
  593. //
  594. // Sanity check.
  595. //
  596. ATLASSERT(FAILED(hr));
  597. ReportError(hr);
  598. goto UnlockExit;
  599. }
  600. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  601. Function : CSignedData::Sign
  602. Synopsis : Sign the content and produce a signed message.
  603. Parameter: ISigner * pSigner - Pointer to ISigner.
  604. VARIANT_BOOL bDetached - TRUE if content is to be detached, else
  605. FALSE.
  606. CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
  607. BSTR * pVal - Pointer to BSTR to receive the signed message.
  608. Remark : The certificate selection dialog will be launched
  609. (CryptUIDlgSelectCertificate API) to display a list of certificates
  610. from the Current User\My store for selecting a signer's certificate,
  611. for the following conditions:
  612. 1) A signer is not specified (pVal is NULL) or the ICertificate
  613. property of the ISigner is not set
  614. 2) There is more than 1 cert in the store, and
  615. 3) The Settings::EnablePromptForIdentityUI property is not disabled.
  616. Also if called from web environment, UI will be displayed, if has
  617. not been prevously disabled, to warn the user of accessing the
  618. private key for signing.
  619. ------------------------------------------------------------------------------*/
  620. STDMETHODIMP CSignedData::Sign (ISigner * pISigner,
  621. VARIANT_BOOL bDetached,
  622. CAPICOM_ENCODING_TYPE EncodingType,
  623. BSTR * pVal)
  624. {
  625. HRESULT hr = S_OK;
  626. CComPtr<ISigner2> pISigner2 = NULL;
  627. CComPtr<ISigner2> pISelectedSigner2 = NULL;
  628. CComPtr<ICertificate> pISelectedCertificate = NULL;
  629. PCCERT_CONTEXT pSelectedCertContext = NULL;
  630. HCRYPTPROV hCryptProv = NULL;
  631. HCERTSTORE hAdditionalStore = NULL;
  632. DWORD dwKeySpec = 0;
  633. BOOL bReleaseContext = FALSE;
  634. DATA_BLOB ChainBlob = {0, NULL};
  635. CAPICOM_STORE_INFO StoreInfo = {CAPICOM_STORE_INFO_STORENAME, L"My"};
  636. CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo = {0};
  637. DebugTrace("Entering CSignedData::Sign().\n");
  638. try
  639. {
  640. //
  641. // Lock access to this object.
  642. //
  643. m_Lock.Lock();
  644. //
  645. // Make sure parameter is valid.
  646. //
  647. if (NULL == pVal)
  648. {
  649. hr = E_POINTER;
  650. DebugTrace("Error: invalid parameter, pVal is NULL.\n");
  651. goto ErrorExit;
  652. }
  653. //
  654. // Make sure content is already initialized.
  655. //
  656. if (0 == m_ContentBlob.cbData)
  657. {
  658. hr = CAPICOM_E_SIGN_NOT_INITIALIZED;
  659. DebugTrace("Error: SignedData object has not been initialized.\n");
  660. goto ErrorExit;
  661. }
  662. //
  663. // Sanity check.
  664. //
  665. ATLASSERT(m_ContentBlob.pbData);
  666. //
  667. // QI for ISigner2 if user passed in an ISigner.
  668. //
  669. if (pISigner)
  670. {
  671. if (FAILED(hr = pISigner->QueryInterface(__uuidof(ISigner2), (void **) &pISigner2)))
  672. {
  673. DebugTrace("Internal error [%#x]: pISigner->QueryInterface() failed.\n", hr);
  674. goto ErrorExit;
  675. }
  676. }
  677. //
  678. // Get the signer's cert (may prompt user to select signer's cert).
  679. //
  680. if (FAILED(hr = ::GetSignerCert(pISigner2,
  681. CERT_CHAIN_POLICY_BASE,
  682. StoreInfo,
  683. FindDataSigningCertCallback,
  684. &pISelectedSigner2,
  685. &pISelectedCertificate,
  686. &pSelectedCertContext)))
  687. {
  688. DebugTrace("Error [%#x]: GetSignerCert() failed.\n", hr);
  689. goto ErrorExit;
  690. }
  691. //
  692. // If we are called from a web page, we need to pop up UI
  693. // to get user permission to perform signing operation.
  694. //
  695. if (m_dwCurrentSafety &&
  696. FAILED(hr = OperationApproved(IDD_SIGN_SECURITY_ALERT_DLG)))
  697. {
  698. DebugTrace("Error [%#x]: OperationApproved() failed.\n", hr);
  699. goto ErrorExit;
  700. }
  701. //
  702. // Acquire CSP context and access to private key.
  703. //
  704. if (FAILED(hr = ::AcquireContext(pSelectedCertContext,
  705. &hCryptProv,
  706. &dwKeySpec,
  707. &bReleaseContext)))
  708. {
  709. DebugTrace("Error [%#x]: AcquireContext() failed.\n", hr);
  710. goto ErrorExit;
  711. }
  712. //
  713. // Get additional store handle.
  714. //
  715. if (FAILED(hr = ::GetSignerAdditionalStore(pISelectedSigner2, &hAdditionalStore)))
  716. {
  717. DebugTrace("Error [%#x]: GetSignerAdditionalStore() failed.\n", hr);
  718. goto ErrorExit;
  719. }
  720. //
  721. // Build the bag of certs to be included into the message.
  722. //
  723. if (FAILED(hr = InitCertificateChain(pISelectedCertificate,
  724. hAdditionalStore,
  725. &ChainBlob)))
  726. {
  727. DebugTrace("Error [%#x]: InitCertificateChain() failed.\n", hr);
  728. goto ErrorExit;
  729. }
  730. //
  731. // Allocate and initialize a CMSG_SIGNER_ENCODE_INFO structure.
  732. //
  733. if (FAILED(hr = ::InitSignerEncodeInfo(pISelectedSigner2,
  734. pSelectedCertContext,
  735. hCryptProv,
  736. dwKeySpec,
  737. &SignerEncodeInfo)))
  738. {
  739. DebugTrace("Error [%#x]: InitSignerEncodeInfo() failed.\n", hr);
  740. goto ErrorExit;
  741. }
  742. //
  743. // Now sign the content.
  744. //
  745. if (FAILED(hr = SignContent(pISelectedSigner2,
  746. &SignerEncodeInfo,
  747. &ChainBlob,
  748. bDetached,
  749. EncodingType,
  750. pVal)))
  751. {
  752. DebugTrace("Error [%#x]: CSignedData::SignContent() failed.\n", hr);
  753. goto ErrorExit;
  754. }
  755. }
  756. catch(...)
  757. {
  758. hr = E_INVALIDARG;
  759. DebugTrace("Exception: invalid parameter.\n");
  760. goto ErrorExit;
  761. }
  762. UnlockExit:
  763. //
  764. // Free resources.
  765. //
  766. ::FreeSignerEncodeInfo(&SignerEncodeInfo);
  767. if (ChainBlob.pbData)
  768. {
  769. ::FreeCertificateChain(&ChainBlob);
  770. }
  771. if (hCryptProv && bReleaseContext)
  772. {
  773. ::CryptReleaseContext(hCryptProv, 0);
  774. }
  775. if (pSelectedCertContext)
  776. {
  777. ::CertFreeCertificateContext(pSelectedCertContext);
  778. }
  779. if (hAdditionalStore)
  780. {
  781. ::CertCloseStore(hAdditionalStore, 0);
  782. }
  783. //
  784. // Unlock access to this object.
  785. //
  786. m_Lock.Unlock();
  787. DebugTrace("Leaving CSignedData::Sign().\n");
  788. return hr;
  789. ErrorExit:
  790. //
  791. // Sanity check.
  792. //
  793. ATLASSERT(FAILED(hr));
  794. ReportError(hr);
  795. goto UnlockExit;
  796. }
  797. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  798. Function : CSignedData::CoSign
  799. Synopsis : CoSign the content and produce a signed message. This method will
  800. behaves the same as the Sign method as a non-detached message if
  801. the messge currently does not already have a signature.
  802. Parameter: ISigner * pSigner - Pointer to ISigner.
  803. CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
  804. BSTR * pVal - Pointer to BSTR to receive the signed message.
  805. Remark : The certificate selection dialog will be launched
  806. (CryptUIDlgSelectCertificate API) to display a list of certificates
  807. from the Current User\My store for selecting a signer's certificate,
  808. for the following conditions:
  809. 1) A signer is not specified (pVal is NULL) or the ICertificate
  810. property of the ISigner is not set
  811. 2) There is more than 1 cert in the store, and
  812. 3) The Settings::EnablePromptForIdentityUI property is not disabled.
  813. Also if called from web environment, UI will be displayed, if has
  814. not been prevously disabled, to warn the user of accessing the
  815. private key for signing.
  816. ------------------------------------------------------------------------------*/
  817. STDMETHODIMP CSignedData::CoSign (ISigner * pISigner,
  818. CAPICOM_ENCODING_TYPE EncodingType,
  819. BSTR * pVal)
  820. {
  821. HRESULT hr = S_OK;
  822. CComPtr<ISigner2> pISigner2 = NULL;
  823. CComPtr<ISigner2> pISelectedSigner2 = NULL;
  824. CComPtr<ICertificate> pISelectedCertificate = NULL;
  825. PCCERT_CONTEXT pSelectedCertContext = NULL;
  826. HCRYPTPROV hCryptProv = NULL;
  827. HCERTSTORE hAdditionalStore = NULL;
  828. DWORD dwKeySpec = 0;
  829. BOOL bReleaseContext = FALSE;
  830. DATA_BLOB ChainBlob = {0, NULL};
  831. CAPICOM_STORE_INFO StoreInfo = {CAPICOM_STORE_INFO_STORENAME, L"My"};
  832. CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo;
  833. DebugTrace("Entering CSignedData::CoSign().\n");
  834. //
  835. // Initialize.
  836. //
  837. ::ZeroMemory(&SignerEncodeInfo, sizeof(SignerEncodeInfo));
  838. try
  839. {
  840. //
  841. // Lock access to this object.
  842. //
  843. m_Lock.Lock();
  844. if (NULL == pVal)
  845. {
  846. hr = E_POINTER;
  847. DebugTrace("Error: invalid parameter, pVal is NULL.\n");
  848. goto ErrorExit;
  849. }
  850. //
  851. // Make sure message has been signed?
  852. //
  853. if (!m_bSigned)
  854. {
  855. hr = CAPICOM_E_SIGN_NOT_SIGNED;
  856. DebugTrace("Error: cannot cosign an unsigned message.\n");
  857. goto ErrorExit;
  858. }
  859. //
  860. // Make sure content is already initialized.
  861. //
  862. if (0 == m_ContentBlob.cbData)
  863. {
  864. hr = CAPICOM_E_SIGN_NOT_INITIALIZED;
  865. DebugTrace("Error: SignedData object has not been initialized.\n");
  866. goto ErrorExit;
  867. }
  868. //
  869. // Sanity check.
  870. //
  871. ATLASSERT(m_ContentBlob.pbData);
  872. ATLASSERT(m_MessageBlob.cbData);
  873. ATLASSERT(m_MessageBlob.pbData);
  874. //
  875. // QI for ISigner2 if user passed in an ISigner.
  876. //
  877. if (pISigner)
  878. {
  879. if (FAILED(hr = pISigner->QueryInterface(__uuidof(ISigner2), (void **) &pISigner2)))
  880. {
  881. DebugTrace("Internal error [%#x]: pISigner->QueryInterface() failed.\n", hr);
  882. goto ErrorExit;
  883. }
  884. }
  885. //
  886. // Get the signer's cert (may prompt user to select signer's cert).
  887. //
  888. if (FAILED(hr = ::GetSignerCert(pISigner2,
  889. CERT_CHAIN_POLICY_BASE,
  890. StoreInfo,
  891. FindDataSigningCertCallback,
  892. &pISelectedSigner2,
  893. &pISelectedCertificate,
  894. &pSelectedCertContext)))
  895. {
  896. DebugTrace("Error [%#x]: GetSignerCert() failed.\n", hr);
  897. goto ErrorExit;
  898. }
  899. //
  900. // If we are called from a web page, we need to pop up UI
  901. // to get user permission to perform signing operation.
  902. //
  903. if (m_dwCurrentSafety &&
  904. FAILED(hr = OperationApproved(IDD_SIGN_SECURITY_ALERT_DLG)))
  905. {
  906. DebugTrace("Error [%#x]: OperationApproved() failed.\n", hr);
  907. goto ErrorExit;
  908. }
  909. //
  910. // Acquire CSP context and access to private key.
  911. //
  912. if (FAILED(hr = ::AcquireContext(pSelectedCertContext,
  913. &hCryptProv,
  914. &dwKeySpec,
  915. &bReleaseContext)))
  916. {
  917. DebugTrace("Error [%#x]: AcquireContext() failed.\n", hr);
  918. goto ErrorExit;
  919. }
  920. //
  921. // Get additional store handle.
  922. //
  923. if (FAILED(hr = ::GetSignerAdditionalStore(pISelectedSigner2, &hAdditionalStore)))
  924. {
  925. DebugTrace("Error [%#x]: GetSignerAdditionalStore() failed.\n", hr);
  926. goto ErrorExit;
  927. }
  928. //
  929. // Build the bag of certs to be included into the message.
  930. //
  931. if (FAILED(hr = InitCertificateChain(pISelectedCertificate,
  932. hAdditionalStore,
  933. &ChainBlob)))
  934. {
  935. DebugTrace("Error [%#x]: InitCertificateChain() failed.\n", hr);
  936. goto ErrorExit;
  937. }
  938. //
  939. // Allocate and initialize a CMSG_SIGNER_ENCODE_INFO structure.
  940. //
  941. if (FAILED(hr = ::InitSignerEncodeInfo(pISelectedSigner2,
  942. pSelectedCertContext,
  943. hCryptProv,
  944. dwKeySpec,
  945. &SignerEncodeInfo)))
  946. {
  947. DebugTrace("Error [%#x]: InitSignerEncodeInfo() failed.\n", hr);
  948. goto ErrorExit;
  949. }
  950. //
  951. // CoSign the content.
  952. //
  953. if (FAILED(hr = CoSignContent(pISelectedSigner2,
  954. &SignerEncodeInfo,
  955. &ChainBlob,
  956. EncodingType,
  957. pVal)))
  958. {
  959. DebugTrace("Error [%#x]: CSignedData::CoSignContent() failed.\n", hr);
  960. goto ErrorExit;
  961. }
  962. }
  963. catch(...)
  964. {
  965. hr = E_INVALIDARG;
  966. DebugTrace("Exception: invalid parameter.\n");
  967. goto ErrorExit;
  968. }
  969. UnlockExit:
  970. //
  971. // Free resources.
  972. //
  973. ::FreeSignerEncodeInfo(&SignerEncodeInfo);
  974. if (ChainBlob.pbData)
  975. {
  976. ::FreeCertificateChain(&ChainBlob);
  977. }
  978. if (hCryptProv && bReleaseContext)
  979. {
  980. ::CryptReleaseContext(hCryptProv, 0);
  981. }
  982. if (pSelectedCertContext)
  983. {
  984. ::CertFreeCertificateContext(pSelectedCertContext);
  985. }
  986. if (hAdditionalStore)
  987. {
  988. ::CertCloseStore(hAdditionalStore, 0);
  989. }
  990. //
  991. // Unlock access to this object.
  992. //
  993. m_Lock.Unlock();
  994. DebugTrace("Leaving CSignedData::CoSign().\n");
  995. return hr;
  996. ErrorExit:
  997. //
  998. // Sanity check.
  999. //
  1000. ATLASSERT(FAILED(hr));
  1001. ReportError(hr);
  1002. goto UnlockExit;
  1003. }
  1004. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1005. Function : CSignedData::Verify
  1006. Synopsis : Verify a signed message.
  1007. Parameter: BSTR SignedMessage - BSTR containing the signed message to be
  1008. verified.
  1009. VARIANT_BOOL bDetached - TRUE if content was detached, else
  1010. FALSE.
  1011. CAPICOM_SIGNED_DATA_VERIFY_FLAG VerifyFlag - Verify flag.
  1012. Remark : Note that for non-detached message, this method will always try
  1013. to set the Content property using the signed message, even if the
  1014. signed message does not verify.
  1015. ------------------------------------------------------------------------------*/
  1016. STDMETHODIMP CSignedData::Verify (BSTR SignedMessage,
  1017. VARIANT_BOOL bDetached,
  1018. CAPICOM_SIGNED_DATA_VERIFY_FLAG VerifyFlag)
  1019. {
  1020. HRESULT hr = S_OK;
  1021. HCRYPTMSG hMsg = NULL;
  1022. HCERTSTORE hPKCS7Store = NULL;
  1023. DWORD dwNumSigners = 0;
  1024. DWORD cbSigners = sizeof(dwNumSigners);
  1025. DWORD dwSigner = 0;
  1026. DebugTrace("Entering CSignedData::Verify().\n");
  1027. try
  1028. {
  1029. //
  1030. // Lock access to this object.
  1031. //
  1032. m_Lock.Lock();
  1033. //
  1034. // Initialize member variables.
  1035. //
  1036. if (!bDetached)
  1037. {
  1038. if (m_ContentBlob.pbData)
  1039. {
  1040. ::CoTaskMemFree(m_ContentBlob.pbData);
  1041. }
  1042. m_ContentBlob.cbData = 0;
  1043. m_ContentBlob.pbData = NULL;
  1044. }
  1045. if (m_MessageBlob.pbData)
  1046. {
  1047. ::CoTaskMemFree(m_MessageBlob.pbData);
  1048. }
  1049. m_bSigned = FALSE;
  1050. m_bDetached = bDetached;
  1051. m_MessageBlob.cbData = 0;
  1052. m_MessageBlob.pbData = NULL;
  1053. //
  1054. // Make sure parameters are valid.
  1055. //
  1056. if (0 == ::SysStringByteLen(SignedMessage))
  1057. {
  1058. hr = E_INVALIDARG;
  1059. DebugTrace("Error [%#x]: Parameter SignedMessage is NULL or empty.\n", hr);
  1060. goto ErrorExit;
  1061. }
  1062. //
  1063. // If detached, make sure content is already initialized.
  1064. //
  1065. if (m_bDetached)
  1066. {
  1067. if (0 == m_ContentBlob.cbData)
  1068. {
  1069. hr = CAPICOM_E_SIGN_NOT_INITIALIZED;
  1070. DebugTrace("Error: content was not initialized for detached decoding.\n");
  1071. goto ErrorExit;
  1072. }
  1073. //
  1074. // Sanity check.
  1075. //
  1076. ATLASSERT(m_ContentBlob.pbData);
  1077. }
  1078. //
  1079. // Import the message.
  1080. //
  1081. if (FAILED(hr = ::ImportData(SignedMessage, CAPICOM_ENCODE_ANY, &m_MessageBlob)))
  1082. {
  1083. DebugTrace("Error [%#x]: ImportData() failed.\n", hr);
  1084. goto ErrorExit;
  1085. }
  1086. //
  1087. // Write encoded blob to file, so we can use offline tool such as
  1088. // ASN parser to analyze message.
  1089. //
  1090. // The following line will resolve to void for non debug build, and
  1091. // thus can be safely removed if desired.
  1092. //
  1093. DumpToFile("ImportedSigned.asn", m_MessageBlob.pbData, m_MessageBlob.cbData);
  1094. //
  1095. // Open the message to decode.
  1096. //
  1097. if (FAILED(hr = OpenToDecode(NULL, &hMsg)))
  1098. {
  1099. DebugTrace("Error [%#x]: OpenToDecode() failed.\n", hr);
  1100. goto ErrorExit;
  1101. }
  1102. //
  1103. // Verify cert as well?
  1104. //
  1105. if (CAPICOM_VERIFY_SIGNATURE_AND_CERTIFICATE == VerifyFlag)
  1106. {
  1107. //
  1108. // Yes, so open the PKCS7 store.
  1109. //
  1110. if (!(hPKCS7Store = ::CertOpenStore(CERT_STORE_PROV_PKCS7,
  1111. CAPICOM_ASN_ENCODING,
  1112. NULL,
  1113. CERT_STORE_OPEN_EXISTING_FLAG,
  1114. &m_MessageBlob)))
  1115. {
  1116. DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
  1117. goto ErrorExit;
  1118. }
  1119. }
  1120. //
  1121. // Get number of content signers (first level signers).
  1122. //
  1123. if (!::CryptMsgGetParam(hMsg,
  1124. CMSG_SIGNER_COUNT_PARAM,
  1125. 0,
  1126. (void **) &dwNumSigners,
  1127. &cbSigners))
  1128. {
  1129. hr = HRESULT_FROM_WIN32(::GetLastError());
  1130. DebugTrace("Error [%#x]: CryptMsgGetParam() failed to get CMSG_SIGNER_COUNT_PARAM.\n", hr);
  1131. goto ErrorExit;
  1132. }
  1133. //
  1134. // Verify all signatures.
  1135. //
  1136. for (dwSigner = 0; dwSigner < dwNumSigners; dwSigner++)
  1137. {
  1138. PCERT_CONTEXT pCertContext = NULL;
  1139. CMSG_SIGNER_INFO * pSignerInfo = NULL;
  1140. CRYPT_DATA_BLOB SignerInfoBlob = {0, NULL};
  1141. //
  1142. // Get signer info.
  1143. //
  1144. if (FAILED(hr = ::GetMsgParam(hMsg,
  1145. CMSG_SIGNER_INFO_PARAM,
  1146. dwSigner,
  1147. (void**) &SignerInfoBlob.pbData,
  1148. &SignerInfoBlob.cbData)))
  1149. {
  1150. DebugTrace("Error [%#x]: GetMsgParam() failed to get CMSG_SIGNER_INFO_PARAM for signer #%d.\n", hr, dwSigner);
  1151. goto ErrorExit;
  1152. }
  1153. pSignerInfo = (CMSG_SIGNER_INFO *) SignerInfoBlob.pbData;
  1154. //
  1155. // Find the cert in the message.
  1156. //
  1157. hr = ::FindSignerCertInMessage(hMsg,
  1158. &pSignerInfo->Issuer,
  1159. &pSignerInfo->SerialNumber,
  1160. &pCertContext);
  1161. //
  1162. // First free memory.
  1163. //
  1164. ::CoTaskMemFree(SignerInfoBlob.pbData);
  1165. //
  1166. // Check result.
  1167. //
  1168. if (FAILED(hr))
  1169. {
  1170. DebugTrace("Error [%#x]: FindSignerCertInMessage() failed.\n", hr);
  1171. goto ErrorExit;
  1172. }
  1173. //
  1174. // Verify the cert regardless if the user had requested. This
  1175. // is done so that the chain will always be built first before
  1176. // we later verify the signature, which is required by DSS.
  1177. //
  1178. if (FAILED(hr = ::VerifyCertificate(pCertContext, hPKCS7Store, CERT_CHAIN_POLICY_BASE)))
  1179. {
  1180. //
  1181. // Verify cert as well?
  1182. //
  1183. if (CAPICOM_VERIFY_SIGNATURE_AND_CERTIFICATE == VerifyFlag)
  1184. {
  1185. //
  1186. // Free CERT_CONTEXT.
  1187. //
  1188. ::CertFreeCertificateContext(pCertContext);
  1189. DebugTrace("Error [%#x]: VerifyCertificate() failed.\n", hr);
  1190. goto ErrorExit;
  1191. }
  1192. //
  1193. // Reset hr.
  1194. //
  1195. hr = S_OK;
  1196. }
  1197. //
  1198. // Verify signature.
  1199. //
  1200. if (!::CryptMsgControl(hMsg,
  1201. 0,
  1202. CMSG_CTRL_VERIFY_SIGNATURE,
  1203. pCertContext->pCertInfo))
  1204. {
  1205. //
  1206. // Invalid signature.
  1207. //
  1208. hr = HRESULT_FROM_WIN32(::GetLastError());
  1209. //
  1210. // Free CERT_CONTEXT.
  1211. //
  1212. ::CertFreeCertificateContext(pCertContext);
  1213. DebugTrace("Error [%#x]: CryptMsgControl(CMSG_CTRL_VERIFY_SIGNATURE) failed.\n", hr);
  1214. goto ErrorExit;
  1215. }
  1216. //
  1217. // Free CERT_CONTEXT.
  1218. //
  1219. ::CertFreeCertificateContext(pCertContext);
  1220. }
  1221. //
  1222. // Update member variables.
  1223. //
  1224. m_bSigned = TRUE;
  1225. }
  1226. catch(...)
  1227. {
  1228. hr = E_INVALIDARG;
  1229. DebugTrace("Exception: invalid parameter.\n");
  1230. goto ErrorExit;
  1231. }
  1232. UnlockExit:
  1233. //
  1234. // Free resouce.
  1235. //
  1236. if(hMsg)
  1237. {
  1238. ::CryptMsgClose(hMsg);
  1239. }
  1240. if (hPKCS7Store)
  1241. {
  1242. ::CertCloseStore(hPKCS7Store, 0);
  1243. }
  1244. //
  1245. // Unlock access to this object.
  1246. //
  1247. m_Lock.Unlock();
  1248. DebugTrace("Leaving CSignedData::Verify().\n");
  1249. return hr;
  1250. ErrorExit:
  1251. //
  1252. // Sanity check.
  1253. //
  1254. ATLASSERT(FAILED(hr));
  1255. //
  1256. // Reset member variables.
  1257. //
  1258. m_bSigned = FALSE;
  1259. m_bDetached = VARIANT_FALSE;
  1260. #if (0)
  1261. if (m_ContentBlob.pbData)
  1262. {
  1263. ::CoTaskMemFree(m_ContentBlob.pbData);
  1264. }
  1265. m_ContentBlob.cbData = 0;
  1266. m_ContentBlob.pbData = NULL;
  1267. #endif
  1268. if (m_MessageBlob.pbData)
  1269. {
  1270. ::CoTaskMemFree(m_MessageBlob.pbData);
  1271. }
  1272. m_MessageBlob.cbData = 0;
  1273. m_MessageBlob.pbData = NULL;
  1274. ReportError(hr);
  1275. goto UnlockExit;
  1276. }
  1277. ////////////////////////////////////////////////////////////////////////////////
  1278. //
  1279. // Private member functions.
  1280. //
  1281. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1282. Function : CSignData::OpenToEncode
  1283. Synopsis : Open a message for encoding.
  1284. Parameter: CMSG_SIGNER_ENCODE_INFO * pSignerEncodeInfo - Pointer to signer's
  1285. CMSG_SIGNER_ENCODE_INFO
  1286. structure.
  1287. DATA_BLOB * pChainBlob - Pointer chain blob
  1288. of PCCERT_CONTEXT.
  1289. CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption - Include option.
  1290. HCRYPTMSG * phMsg - Pointer to HCRYPTMSG
  1291. to receive handle.
  1292. Remark :
  1293. ------------------------------------------------------------------------------*/
  1294. STDMETHODIMP CSignedData::OpenToEncode(CMSG_SIGNER_ENCODE_INFO * pSignerEncodeInfo,
  1295. DATA_BLOB * pChainBlob,
  1296. CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption,
  1297. HCRYPTMSG * phMsg)
  1298. {
  1299. HRESULT hr = S_OK;
  1300. HCRYPTMSG hMsg = NULL;
  1301. DWORD dwFlags = 0;
  1302. CERT_BLOB * rgEncodedCertBlob = NULL;
  1303. DWORD i;
  1304. CMSG_SIGNED_ENCODE_INFO SignedEncodeInfo;
  1305. DebugTrace("Entering CSignedData::OpenToEncode().\n");
  1306. //
  1307. // Sanity check.
  1308. //
  1309. ATLASSERT(pSignerEncodeInfo);
  1310. ATLASSERT(pChainBlob);
  1311. ATLASSERT(phMsg);
  1312. //
  1313. // Initialize.
  1314. //
  1315. ::ZeroMemory(&SignedEncodeInfo, sizeof(SignedEncodeInfo));
  1316. DWORD cCertContext = pChainBlob->cbData;
  1317. PCERT_CONTEXT * rgCertContext = (PCERT_CONTEXT *) pChainBlob->pbData;
  1318. //
  1319. // Determine number of cert(s) to include in the bag.
  1320. //
  1321. switch (IncludeOption)
  1322. {
  1323. case CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY:
  1324. {
  1325. cCertContext = 1;
  1326. break;
  1327. }
  1328. case CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN:
  1329. {
  1330. break;
  1331. }
  1332. case CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT:
  1333. {
  1334. //
  1335. // <<< Falling thru to default >>>
  1336. //
  1337. }
  1338. default:
  1339. {
  1340. if (1 < cCertContext)
  1341. {
  1342. cCertContext--;
  1343. }
  1344. break;
  1345. }
  1346. }
  1347. //
  1348. // Allocate memory for the array.
  1349. //
  1350. if (!(rgEncodedCertBlob = (CERT_BLOB *) ::CoTaskMemAlloc(cCertContext * sizeof(CERT_BLOB))))
  1351. {
  1352. hr = E_OUTOFMEMORY;
  1353. DebugTrace("Error: out of memory.\n");
  1354. goto ErrorExit;
  1355. }
  1356. ::ZeroMemory(rgEncodedCertBlob, cCertContext * sizeof(CERT_BLOB));
  1357. //
  1358. // Build encoded certs array.
  1359. //
  1360. for (i = 0; i < cCertContext; i++)
  1361. {
  1362. rgEncodedCertBlob[i].cbData = rgCertContext[i]->cbCertEncoded;
  1363. rgEncodedCertBlob[i].pbData = rgCertContext[i]->pbCertEncoded;
  1364. }
  1365. //
  1366. // Setup up CMSG_SIGNED_ENCODE_INFO structure.
  1367. //
  1368. SignedEncodeInfo.cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO);
  1369. SignedEncodeInfo.cSigners = 1;
  1370. SignedEncodeInfo.rgSigners = pSignerEncodeInfo;
  1371. SignedEncodeInfo.cCertEncoded = cCertContext;
  1372. SignedEncodeInfo.rgCertEncoded = rgEncodedCertBlob;
  1373. //
  1374. // Detached flag.
  1375. //
  1376. if (m_bDetached)
  1377. {
  1378. dwFlags = CMSG_DETACHED_FLAG;
  1379. }
  1380. //
  1381. // Open a message to encode.
  1382. //
  1383. if (!(hMsg = ::CryptMsgOpenToEncode(CAPICOM_ASN_ENCODING,
  1384. dwFlags,
  1385. CMSG_SIGNED,
  1386. &SignedEncodeInfo,
  1387. NULL,
  1388. NULL)))
  1389. {
  1390. hr = HRESULT_FROM_WIN32(::GetLastError());
  1391. DebugTrace("Error [%#x]: CryptMsgOpenToEncode() failed.\n", hr);
  1392. goto ErrorExit;
  1393. }
  1394. //
  1395. // Returned message handle to caller.
  1396. //
  1397. *phMsg = hMsg;
  1398. CommonExit:
  1399. //
  1400. // Free resources.
  1401. //
  1402. if (rgEncodedCertBlob)
  1403. {
  1404. ::CoTaskMemFree(rgEncodedCertBlob);
  1405. }
  1406. DebugTrace("Leaving CSignedData::OpenToEncode().\n");
  1407. return hr;
  1408. ErrorExit:
  1409. //
  1410. // Sanity check.
  1411. //
  1412. ATLASSERT(FAILED(hr));
  1413. //
  1414. // Free resource.
  1415. //
  1416. if (hMsg)
  1417. {
  1418. ::CryptMsgClose(hMsg);
  1419. }
  1420. goto CommonExit;
  1421. }
  1422. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1423. Function : CSignedData::OpenToDecode
  1424. Synopsis : Open a signed message for decoding.
  1425. Parameter: HCRYPTPROV hCryptProv - CSP handle or NULL for default CSP.
  1426. HCRYPTMSG * phMsg - Pointer to HCRYPTMSG to receive handle.
  1427. Remark :
  1428. ------------------------------------------------------------------------------*/
  1429. STDMETHODIMP CSignedData::OpenToDecode (HCRYPTPROV hCryptProv,
  1430. HCRYPTMSG * phMsg)
  1431. {
  1432. HRESULT hr = S_OK;
  1433. HCRYPTMSG hMsg = NULL;
  1434. DWORD dwFlags = 0;
  1435. DWORD dwMsgType = 0;
  1436. DWORD cbMsgType = sizeof(dwMsgType);
  1437. DebugTrace("Entering CSignedData::OpenToDecode().\n");
  1438. //
  1439. // Sanity check.
  1440. //
  1441. ATLASSERT(phMsg);
  1442. //
  1443. // Detached flag.
  1444. //
  1445. if (m_bDetached)
  1446. {
  1447. dwFlags = CMSG_DETACHED_FLAG;
  1448. }
  1449. //
  1450. // Open a message for decode.
  1451. //
  1452. if (!(hMsg = ::CryptMsgOpenToDecode(CAPICOM_ASN_ENCODING, // ANS encoding type
  1453. dwFlags, // Flags
  1454. 0, // Message type (get from message)
  1455. hCryptProv, // Cryptographic provider
  1456. NULL, // Inner content OID
  1457. NULL))) // Stream information (not used)
  1458. {
  1459. hr = HRESULT_FROM_WIN32(::GetLastError());
  1460. DebugTrace("Error [%#x]: CryptMsgOpenToDecode() failed.\n");
  1461. goto ErrorExit;
  1462. }
  1463. //
  1464. // Update message with signed content.
  1465. //
  1466. if (!::CryptMsgUpdate(hMsg,
  1467. m_MessageBlob.pbData,
  1468. m_MessageBlob.cbData,
  1469. TRUE))
  1470. {
  1471. hr = HRESULT_FROM_WIN32(::GetLastError());
  1472. DebugTrace("Error [%#x]: CryptMsgUpdate() failed.\n",hr);
  1473. goto ErrorExit;
  1474. }
  1475. //
  1476. // Check message type.
  1477. //
  1478. if (!::CryptMsgGetParam(hMsg,
  1479. CMSG_TYPE_PARAM,
  1480. 0,
  1481. (void *) &dwMsgType,
  1482. &cbMsgType))
  1483. {
  1484. hr = HRESULT_FROM_WIN32(::GetLastError());
  1485. DebugTrace("Error [%#x]: CryptMsgGetParam() failed for CMSG_TYPE_PARAM.\n", hr);
  1486. goto ErrorExit;
  1487. }
  1488. if (CMSG_SIGNED != dwMsgType)
  1489. {
  1490. hr = CAPICOM_E_SIGN_INVALID_TYPE;
  1491. DebugTrace("Error: not an singed message.\n");
  1492. goto ErrorExit;
  1493. }
  1494. //
  1495. // If detached message, update content.
  1496. //
  1497. if (m_bDetached)
  1498. {
  1499. if (!::CryptMsgUpdate(hMsg,
  1500. m_ContentBlob.pbData,
  1501. m_ContentBlob.cbData,
  1502. TRUE))
  1503. {
  1504. hr = HRESULT_FROM_WIN32(::GetLastError());
  1505. DebugTrace("Error [%#x]: CryptMsgUpdate() failed.\n",hr);
  1506. goto ErrorExit;
  1507. }
  1508. }
  1509. else
  1510. {
  1511. //
  1512. // Retrieve content.
  1513. //
  1514. if (FAILED(hr = ::GetMsgParam(hMsg,
  1515. CMSG_CONTENT_PARAM,
  1516. 0,
  1517. (void **) &m_ContentBlob.pbData,
  1518. &m_ContentBlob.cbData)))
  1519. {
  1520. DebugTrace("Error [%#x]: GetMsgParam() failed to get CMSG_CONTENT_PARAM.\n", hr);
  1521. goto ErrorExit;
  1522. }
  1523. }
  1524. //
  1525. // Returned message handle to caller.
  1526. //
  1527. *phMsg = hMsg;
  1528. CommonExit:
  1529. DebugTrace("Leaving SignedData::OpenToDecode().\n");
  1530. return hr;
  1531. ErrorExit:
  1532. //
  1533. // Sanity check.
  1534. //
  1535. ATLASSERT(FAILED(hr));
  1536. //
  1537. // Free resource.
  1538. //
  1539. if (hMsg)
  1540. {
  1541. ::CryptMsgClose(hMsg);
  1542. }
  1543. goto CommonExit;
  1544. }
  1545. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1546. Function : CSignedData::SignContent
  1547. Synopsis : Sign the content by adding the very first signature to the message.
  1548. Parameter: ISigner2 * pISigner2 - Poitner to ISigner2 object of signer.
  1549. CMSG_SIGNER_ENCODE_INFO * pSignerEncodeInfo - Pointer to signer's
  1550. CMSG_SIGNER_ENCODE_INFO
  1551. structure.
  1552. DATA_BLOB * pChainBlob - Pointer chain blob of PCCERT_CONTEXT.
  1553. VARIANT_BOOL bDetached - Detached flag.
  1554. CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
  1555. BSTR * pVal - Pointer to BSTR to receive the signed message.
  1556. Remark :
  1557. ------------------------------------------------------------------------------*/
  1558. STDMETHODIMP CSignedData::SignContent (ISigner2 * pISigner2,
  1559. CMSG_SIGNER_ENCODE_INFO * pSignerEncodeInfo,
  1560. DATA_BLOB * pChainBlob,
  1561. VARIANT_BOOL bDetached,
  1562. CAPICOM_ENCODING_TYPE EncodingType,
  1563. BSTR * pVal)
  1564. {
  1565. HRESULT hr = S_OK;
  1566. HCRYPTMSG hMsg = NULL;
  1567. DATA_BLOB MessageBlob = {0, NULL};
  1568. CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption = CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT;
  1569. DebugTrace("Entering CSignedData::SignContent().\n");
  1570. //
  1571. // Sanity check.
  1572. //
  1573. ATLASSERT(pISigner2);
  1574. ATLASSERT(pSignerEncodeInfo);
  1575. ATLASSERT(pChainBlob);
  1576. ATLASSERT(pChainBlob->cbData);
  1577. ATLASSERT(pChainBlob->pbData);
  1578. ATLASSERT(pVal);
  1579. ATLASSERT(m_ContentBlob.cbData);
  1580. ATLASSERT(m_ContentBlob.pbData);
  1581. try
  1582. {
  1583. //
  1584. // Initialize member variables.
  1585. //
  1586. if (m_MessageBlob.pbData)
  1587. {
  1588. ::CoTaskMemFree(m_MessageBlob.pbData);
  1589. }
  1590. m_bSigned = FALSE;
  1591. m_bDetached = bDetached;
  1592. m_MessageBlob.cbData = 0;
  1593. m_MessageBlob.pbData = NULL;
  1594. //
  1595. // Get signer option flag.
  1596. //
  1597. if (FAILED(hr = pISigner2->get_Options(&IncludeOption)))
  1598. {
  1599. DebugTrace("Error [%#x]: pISigner2->get_Options() failed.\n", hr);
  1600. goto ErrorExit;
  1601. }
  1602. //
  1603. // Open message to encode.
  1604. //
  1605. if (FAILED(hr = OpenToEncode(pSignerEncodeInfo,
  1606. pChainBlob,
  1607. IncludeOption,
  1608. &hMsg)))
  1609. {
  1610. DebugTrace("Error [%#x]: OpenToEncode() failed.\n", hr);
  1611. goto ErrorExit;
  1612. }
  1613. //
  1614. // Update the message with data.
  1615. //
  1616. if (!::CryptMsgUpdate(hMsg, // Handle to the message
  1617. m_ContentBlob.pbData, // Pointer to the content
  1618. m_ContentBlob.cbData, // Size of the content
  1619. TRUE)) // Last call
  1620. {
  1621. hr = HRESULT_FROM_WIN32(::GetLastError());
  1622. DebugTrace("Error [%#x]: CryptMsgUpdate() failed.\n",hr);
  1623. goto ErrorExit;
  1624. }
  1625. //
  1626. // Retrieve the resulting message.
  1627. //
  1628. if (FAILED(hr = ::GetMsgParam(hMsg,
  1629. CMSG_CONTENT_PARAM,
  1630. 0,
  1631. (void **) &MessageBlob.pbData,
  1632. &MessageBlob.cbData)))
  1633. {
  1634. DebugTrace("Error [%#x]: GetMsgParam() failed to get CMSG_CONTENT_PARAM.\n", hr);
  1635. goto ErrorExit;
  1636. }
  1637. //
  1638. // Now export the signed message.
  1639. //
  1640. if (FAILED(hr = ::ExportData(MessageBlob, EncodingType, pVal)))
  1641. {
  1642. DebugTrace("Error [%#x]: ExportData() failed.\n", hr);
  1643. goto ErrorExit;
  1644. }
  1645. //
  1646. // Write encoded blob to file, so we can use offline tool such as
  1647. // ASN parser to analyze message.
  1648. //
  1649. // The following line will resolve to void for non debug build, and
  1650. // thus can be safely removed if desired.
  1651. //
  1652. DumpToFile("ExportedSigned.asn", MessageBlob.pbData, MessageBlob.cbData);
  1653. //
  1654. // Update member variables.
  1655. //
  1656. //
  1657. if (m_MessageBlob.pbData)
  1658. {
  1659. ::CoTaskMemFree(m_MessageBlob.pbData);
  1660. }
  1661. m_bSigned = TRUE;
  1662. m_bDetached = bDetached;
  1663. m_MessageBlob = MessageBlob;
  1664. }
  1665. catch(...)
  1666. {
  1667. hr = E_INVALIDARG;
  1668. DebugTrace("Exception: invalid parameter.\n");
  1669. goto ErrorExit;
  1670. }
  1671. CommonExit:
  1672. //
  1673. // Free resource.
  1674. //
  1675. if (hMsg)
  1676. {
  1677. ::CryptMsgClose(hMsg);
  1678. }
  1679. DebugTrace("Leaving CSignedData::SignContent().\n");
  1680. return hr;
  1681. ErrorExit:
  1682. //
  1683. // Sanity check.
  1684. //
  1685. ATLASSERT(FAILED(hr));
  1686. //
  1687. // Free resource.
  1688. //
  1689. if (MessageBlob.pbData)
  1690. {
  1691. ::CoTaskMemFree(MessageBlob.pbData);
  1692. }
  1693. goto CommonExit;
  1694. }
  1695. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1696. Function : CSign::CoSignContent
  1697. Synopsis : CoSign the content by adding another signature to the message.
  1698. Parameter: ISigner2 * pISigner2 - Poitner to ISigner2 object of signer.
  1699. CMSG_SIGNER_ENCODE_INFO * pSignerEncodeInfo - Pointer to signer's
  1700. CMSG_SIGNER_ENCODE_INFO
  1701. structure.
  1702. DATA_BLOB * pChainBlob - Pointer chain blob of PCCERT_CONTEXT.
  1703. CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
  1704. BSTR * pVal - Pointer to BSTR to receive the co-signed message.
  1705. Remark :
  1706. ------------------------------------------------------------------------------*/
  1707. STDMETHODIMP CSignedData::CoSignContent (ISigner2 * pISigner2,
  1708. CMSG_SIGNER_ENCODE_INFO * pSignerEncodeInfo,
  1709. DATA_BLOB * pChainBlob,
  1710. CAPICOM_ENCODING_TYPE EncodingType,
  1711. BSTR * pVal)
  1712. {
  1713. HRESULT hr = S_OK;
  1714. HCRYPTMSG hMsg = NULL;
  1715. DATA_BLOB MessageBlob = {0, NULL};
  1716. CAPICOM_CERTIFICATE_INCLUDE_OPTION IncludeOption = CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT;
  1717. DebugTrace("Entering CSignedData::CoSignContent().\n");
  1718. //
  1719. // Sanity check.
  1720. //
  1721. ATLASSERT(pISigner2);
  1722. ATLASSERT(pSignerEncodeInfo);
  1723. ATLASSERT(pChainBlob);
  1724. ATLASSERT(pChainBlob->cbData);
  1725. ATLASSERT(pChainBlob->pbData);
  1726. ATLASSERT(pVal);
  1727. ATLASSERT(m_bSigned);
  1728. ATLASSERT(m_ContentBlob.cbData);
  1729. ATLASSERT(m_ContentBlob.pbData);
  1730. ATLASSERT(m_MessageBlob.cbData);
  1731. ATLASSERT(m_MessageBlob.pbData);
  1732. try
  1733. {
  1734. //
  1735. // Get signer option flag.
  1736. //
  1737. if (FAILED(hr = pISigner2->get_Options(&IncludeOption)))
  1738. {
  1739. DebugTrace("Error [%#x]: pISigner2->get_Options() failed.\n", hr);
  1740. goto ErrorExit;
  1741. }
  1742. //
  1743. // Open the encoded message for decode.
  1744. //
  1745. if (FAILED(hr = OpenToDecode(pSignerEncodeInfo->hCryptProv, &hMsg)))
  1746. {
  1747. DebugTrace("Error [%#x]: OpenToDecode() failed.\n", hr);
  1748. goto ErrorExit;
  1749. }
  1750. //
  1751. // Add the co-signature to the message.
  1752. //
  1753. if (!::CryptMsgControl(hMsg,
  1754. 0,
  1755. CMSG_CTRL_ADD_SIGNER,
  1756. (const void *) pSignerEncodeInfo))
  1757. {
  1758. hr = HRESULT_FROM_WIN32(::GetLastError());
  1759. DebugTrace("Error [%#x]: CryptMsgControl() failed for CMSG_CTRL_ADD_SIGNER.\n",hr);
  1760. goto ErrorExit;
  1761. }
  1762. //
  1763. // Add chain to message.
  1764. //
  1765. if (FAILED(hr = ::AddCertificateChain(hMsg, pChainBlob, IncludeOption)))
  1766. {
  1767. DebugTrace("Error [%#x]: AddCertificateChain() failed.\n", hr);
  1768. goto ErrorExit;
  1769. }
  1770. //
  1771. // Retrieve the resulting message.
  1772. //
  1773. if (FAILED(hr = ::GetMsgParam(hMsg,
  1774. CMSG_ENCODED_MESSAGE,
  1775. 0,
  1776. (void **) &MessageBlob.pbData,
  1777. &MessageBlob.cbData)))
  1778. {
  1779. DebugTrace("Error [%#x]: GetMsgParam() failed to get CMSG_ENCODED_MESSAGE.\n",hr);
  1780. goto ErrorExit;
  1781. }
  1782. //
  1783. // Now export the signed message.
  1784. //
  1785. if (FAILED(hr = ::ExportData(MessageBlob, EncodingType, pVal)))
  1786. {
  1787. DebugTrace("Error [%#x]: ExportData() failed.\n", hr);
  1788. goto ErrorExit;
  1789. }
  1790. //
  1791. // Write encoded blob to file, so we can use offline tool such as
  1792. // ASN parser to analyze message.
  1793. //
  1794. // The following line will resolve to void for non debug build, and
  1795. // thus can be safely removed if desired.
  1796. //
  1797. DumpToFile("ExportedCoSigned.asn", MessageBlob.pbData, MessageBlob.cbData);
  1798. //
  1799. // Update member variables.
  1800. //
  1801. //
  1802. if (m_MessageBlob.pbData)
  1803. {
  1804. ::CoTaskMemFree(m_MessageBlob.pbData);
  1805. }
  1806. m_bSigned = TRUE;
  1807. m_MessageBlob = MessageBlob;
  1808. }
  1809. catch(...)
  1810. {
  1811. hr = E_INVALIDARG;
  1812. DebugTrace("Exception: invalid parameter.\n");
  1813. goto ErrorExit;
  1814. }
  1815. CommonExit:
  1816. //
  1817. // Free resource.
  1818. //
  1819. if (hMsg)
  1820. {
  1821. ::CryptMsgClose(hMsg);
  1822. }
  1823. return hr;
  1824. ErrorExit:
  1825. //
  1826. // Sanity check.
  1827. //
  1828. ATLASSERT(FAILED(hr));
  1829. //
  1830. // Free resource.
  1831. //
  1832. if (MessageBlob.pbData)
  1833. {
  1834. ::CoTaskMemFree(MessageBlob.pbData);
  1835. }
  1836. goto CommonExit;
  1837. }