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.

2300 lines
62 KiB

  1. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
  3. File: Chain.cpp
  4. Content: Implementation of CChain.
  5. History: 11-15-99 dsie created
  6. ------------------------------------------------------------------------------*/
  7. #include "StdAfx.h"
  8. #include "CAPICOM.h"
  9. #include "Chain.h"
  10. #include "Convert.h"
  11. #include "Common.h"
  12. #include "OIDs.h"
  13. #include "Certificates.h"
  14. #include "CertificateStatus.h"
  15. ////////////////////////////////////////////////////////////////////////////////
  16. //
  17. // Exported functions.
  18. //
  19. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  20. Function : CreateChainObject
  21. Synopsis : Create and initialize an IChain object by building the chain
  22. of a specified certificate and policy.
  23. Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT.
  24. ICertificateStatus * pIStatus - Pointer to ICertificateStatus
  25. object.
  26. HCERTSTORE hAdditionalStore - Additional store handle.
  27. VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive chain
  28. overall validity result.
  29. IChain ** ppIChain - Pointer to pointer to IChain object.
  30. Remark :
  31. ------------------------------------------------------------------------------*/
  32. HRESULT CreateChainObject (PCCERT_CONTEXT pCertContext,
  33. ICertificateStatus * pIStatus,
  34. HCERTSTORE hAdditionalStore,
  35. VARIANT_BOOL * pbResult,
  36. IChain ** ppIChain)
  37. {
  38. HRESULT hr = S_OK;
  39. CComObject<CChain> * pCChain = NULL;
  40. DebugTrace("Entering CreateChainObject().\n");
  41. //
  42. // Sanity check.
  43. //
  44. ATLASSERT(pCertContext);
  45. ATLASSERT(pIStatus);
  46. ATLASSERT(pbResult);
  47. ATLASSERT(ppIChain);
  48. try
  49. {
  50. //
  51. // Create the object. Note that the ref count will still be 0
  52. // after the object is created.
  53. //
  54. if (FAILED(hr = CComObject<CChain>::CreateInstance(&pCChain)))
  55. {
  56. DebugTrace("Error [%#x]: CComObject<CChain>::CreateInstance() failed.\n", hr);
  57. goto ErrorExit;
  58. }
  59. //
  60. // Initialize object.
  61. //
  62. if (FAILED(hr = pCChain->Init(pCertContext,
  63. pIStatus,
  64. hAdditionalStore,
  65. pbResult)))
  66. {
  67. DebugTrace("Error [%#x]: pCChain->Init() failed.\n", hr);
  68. goto ErrorExit;
  69. }
  70. //
  71. // Return IChain pointer to caller.
  72. //
  73. if (FAILED(hr = pCChain->QueryInterface(ppIChain)))
  74. {
  75. DebugTrace("Error [%#x]: pCChain->QueryInterface() failed.\n", hr);
  76. goto ErrorExit;
  77. }
  78. }
  79. catch(...)
  80. {
  81. hr = E_POINTER;
  82. DebugTrace("Exception: invalid parameter.\n");
  83. goto ErrorExit;
  84. }
  85. CommonExit:
  86. DebugTrace("Leaving CreateChainObject().\n");
  87. return hr;
  88. ErrorExit:
  89. //
  90. // Sanity check.
  91. //
  92. ATLASSERT(FAILED(hr));
  93. //
  94. // Free resource.
  95. //
  96. if (pCChain)
  97. {
  98. delete pCChain;
  99. }
  100. goto CommonExit;
  101. }
  102. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  103. Function : CreateChainObject
  104. Synopsis : Create and initialize an IChain object by building the chain
  105. of a specified certificate and policy.
  106. Parameter: ICertificate * pICertificate - Poitner to ICertificate.
  107. HCERTSTORE hAdditionalStore - Additional store handle.
  108. VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive chain
  109. overall validity result.
  110. IChain ** ppIChain - Pointer to pointer to IChain object.
  111. Remark :
  112. ------------------------------------------------------------------------------*/
  113. HRESULT CreateChainObject (ICertificate * pICertificate,
  114. HCERTSTORE hAdditionalStore,
  115. VARIANT_BOOL * pbResult,
  116. IChain ** ppIChain)
  117. {
  118. HRESULT hr = S_OK;
  119. PCCERT_CONTEXT pCertContext = NULL;
  120. CComPtr<ICertificateStatus> pIStatus = NULL;
  121. DebugTrace("Entering CreateChainObject().\n");
  122. //
  123. // Sanity check.
  124. //
  125. ATLASSERT(pICertificate);
  126. ATLASSERT(pbResult);
  127. ATLASSERT(ppIChain);
  128. try
  129. {
  130. //
  131. // Get CERT_CONTEXT.
  132. //
  133. if (FAILED(hr = ::GetCertContext(pICertificate, &pCertContext)))
  134. {
  135. DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
  136. goto ErrorExit;
  137. }
  138. //
  139. // Get status check object.
  140. //
  141. if (FAILED(hr = pICertificate->IsValid(&pIStatus)))
  142. {
  143. DebugTrace("Error [%#x]: pICertificate->IsValid() failed.\n", hr);
  144. goto ErrorExit;
  145. }
  146. //
  147. // Create the object.
  148. //
  149. if (FAILED(hr = ::CreateChainObject(pCertContext,
  150. pIStatus,
  151. hAdditionalStore,
  152. pbResult,
  153. ppIChain)))
  154. {
  155. DebugTrace("Error [%#x]: CreateChainObject() failed.\n", hr);
  156. goto ErrorExit;
  157. }
  158. }
  159. catch(...)
  160. {
  161. hr = E_POINTER;
  162. DebugTrace("Exception: invalid parameter.\n");
  163. goto ErrorExit;
  164. }
  165. CommonExit:
  166. //
  167. // Free resource.
  168. //
  169. if (pCertContext)
  170. {
  171. ::CertFreeCertificateContext(pCertContext);
  172. }
  173. DebugTrace("Leaving CreateChainObject().\n");
  174. return hr;
  175. ErrorExit:
  176. //
  177. // Sanity check.
  178. //
  179. ATLASSERT(FAILED(hr));
  180. goto CommonExit;
  181. }
  182. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  183. Function : CreateChainObject
  184. Synopsis : Create and initialize an IChain object from a built chain.
  185. Parameter: PCCERT_CHAIN_CONTEXT pChainContext - Chain context.
  186. IChain ** ppIChain - Pointer to pointer to IChain object.
  187. Remark :
  188. ------------------------------------------------------------------------------*/
  189. HRESULT CreateChainObject (PCCERT_CHAIN_CONTEXT pChainContext,
  190. IChain ** ppIChain)
  191. {
  192. HRESULT hr = S_OK;
  193. CComObject<CChain> * pCChain = NULL;
  194. DebugTrace("Entering CreateChainObject().\n");
  195. //
  196. // Sanity check.
  197. //
  198. ATLASSERT(pChainContext);
  199. ATLASSERT(ppIChain);
  200. try
  201. {
  202. //
  203. // Create the object. Note that the ref count will still be 0
  204. // after the object is created.
  205. //
  206. if (FAILED(hr = CComObject<CChain>::CreateInstance(&pCChain)))
  207. {
  208. DebugTrace("Error [%#x]: CComObject<CChain>::CreateInstance() failed.\n", hr);
  209. goto ErrorExit;
  210. }
  211. //
  212. // Initialize object.
  213. //
  214. if (FAILED(hr = pCChain->PutContext(pChainContext)))
  215. {
  216. DebugTrace("Error [%#x]: pCChain->Init() failed.\n", hr);
  217. goto ErrorExit;
  218. }
  219. //
  220. // Return IChain pointer to caller.
  221. //
  222. if (FAILED(hr = pCChain->QueryInterface(ppIChain)))
  223. {
  224. DebugTrace("Error [%#x]: pCChain->QueryInterface() failed.\n", hr);
  225. goto ErrorExit;
  226. }
  227. }
  228. catch(...)
  229. {
  230. hr = E_POINTER;
  231. DebugTrace("Exception: invalid parameter.\n");
  232. goto ErrorExit;
  233. }
  234. CommonExit:
  235. DebugTrace("Leaving CreateChainObject().\n");
  236. return hr;
  237. ErrorExit:
  238. //
  239. // Sanity check.
  240. //
  241. ATLASSERT(FAILED(hr));
  242. //
  243. // Free resource.
  244. //
  245. if (pCChain)
  246. {
  247. delete pCChain;
  248. }
  249. goto CommonExit;
  250. }
  251. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  252. Function : GetChainContext
  253. Synopsis : Return an array of PCCERT_CONTEXT from the chain.
  254. Parameter: IChain * pIChain - Pointer to IChain.
  255. CRYPT_DATA_BLOB * pChainBlob - Pointer to blob to recevie the
  256. size and array of PCERT_CONTEXT
  257. for the chain.
  258. Remark :
  259. ------------------------------------------------------------------------------*/
  260. STDMETHODIMP GetChainContext (IChain * pIChain,
  261. CRYPT_DATA_BLOB * pChainBlob)
  262. {
  263. HRESULT hr = S_OK;
  264. DWORD dwCerts = 0;
  265. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  266. PCERT_SIMPLE_CHAIN pSimpleChain = NULL;
  267. PCCERT_CONTEXT * rgCertContext = NULL;
  268. CComPtr<IChainContext> pIChainContext = NULL;
  269. DebugTrace("Entering GetChainContext().\n");
  270. //
  271. // Sanity check.
  272. //
  273. ATLASSERT(pIChain);
  274. ATLASSERT(pChainBlob);
  275. //
  276. // Get ICCertificate interface pointer.
  277. //
  278. if (FAILED(hr = pIChain->QueryInterface(IID_IChainContext, (void **) &pIChainContext)))
  279. {
  280. DebugTrace("Error [%#x]: pIChainContext->QueryInterface() failed.\n", hr);
  281. goto ErrorExit;
  282. }
  283. //
  284. // Get the CHAIN_CONTEXT.
  285. //
  286. if (FAILED(hr = pIChainContext->get_ChainContext((long *) &pChainContext)))
  287. {
  288. DebugTrace("Error [%#x]: pIChainContext->get_ChainContext() failed.\n", hr);
  289. goto ErrorExit;
  290. }
  291. //
  292. // Process only the simple chain.
  293. //
  294. pSimpleChain = *pChainContext->rgpChain;
  295. //
  296. // Should have at least one cert in the chain.
  297. //
  298. ATLASSERT(pSimpleChain->cElement);
  299. //
  300. // Allocate memory for array of PCERT_CONTEXT to return.
  301. //
  302. if (!(rgCertContext = (PCCERT_CONTEXT *) ::CoTaskMemAlloc(pSimpleChain->cElement * sizeof(PCCERT_CONTEXT))))
  303. {
  304. hr = E_OUTOFMEMORY;
  305. DebugTrace("Error: out of memory.\n");
  306. goto ErrorExit;
  307. }
  308. //
  309. // Now loop through all certs in the chain.
  310. //
  311. for (dwCerts = 0; dwCerts < pSimpleChain->cElement; dwCerts++)
  312. {
  313. //
  314. // Add the cert.
  315. //
  316. if (!(rgCertContext[dwCerts] = ::CertDuplicateCertificateContext(pSimpleChain->rgpElement[dwCerts]->pCertContext)))
  317. {
  318. hr = HRESULT_FROM_WIN32(::GetLastError());
  319. DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n", hr);
  320. goto ErrorExit;
  321. }
  322. }
  323. //
  324. // Return PCCERT_CONTEXT array.
  325. //
  326. pChainBlob->cbData = dwCerts;
  327. pChainBlob->pbData = (BYTE *) rgCertContext;
  328. CommonExit:
  329. //
  330. // Free resource.
  331. //
  332. if (pChainContext)
  333. {
  334. ::CertFreeCertificateChain(pChainContext);
  335. }
  336. DebugTrace("Leaving GetChainContext().\n");
  337. return hr;
  338. ErrorExit:
  339. //
  340. // Sanity check.
  341. //
  342. ATLASSERT(FAILED(hr));
  343. //
  344. // Free resource.
  345. //
  346. if (rgCertContext)
  347. {
  348. while (dwCerts--)
  349. {
  350. if (rgCertContext[dwCerts])
  351. {
  352. ::CertFreeCertificateContext(rgCertContext[dwCerts]);
  353. }
  354. }
  355. ::CoTaskMemFree((LPVOID) rgCertContext);
  356. }
  357. goto CommonExit;
  358. }
  359. ///////////////////////////////////////////////////////////////////////////////
  360. //
  361. // CChain
  362. //
  363. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  364. Function : CChain::get_Certificates
  365. Synopsis : Return the certificate chain in the form of ICertificates
  366. collection object.
  367. Parameter: ICertificates ** pVal - Pointer to pointer to ICertificates
  368. collection object.
  369. Remark : This collection is ordered with index 1 being the end certificate
  370. and Certificates.Count() being the root certificate.
  371. ------------------------------------------------------------------------------*/
  372. STDMETHODIMP CChain::get_Certificates (ICertificates ** pVal)
  373. {
  374. HRESULT hr = S_OK;
  375. CComPtr<ICertificates2> pICertificates2 = NULL;
  376. CAPICOM_CERTIFICATES_SOURCE ccs = {CAPICOM_CERTIFICATES_LOAD_FROM_CHAIN, 0};
  377. DebugTrace("Entering CChain::get_Certificates().\n");
  378. try
  379. {
  380. //
  381. // Lock access to this object.
  382. //
  383. m_Lock.Lock();
  384. //
  385. // Check parameters.
  386. //
  387. if (NULL == pVal)
  388. {
  389. hr = E_INVALIDARG;
  390. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  391. goto ErrorExit;
  392. }
  393. //
  394. // Make sure chain has been built.
  395. //
  396. if (NULL == m_pChainContext)
  397. {
  398. hr = CAPICOM_E_CHAIN_NOT_BUILT;
  399. DebugTrace("Error [%#x]: chain object was not initialized.\n", hr);
  400. goto ErrorExit;
  401. }
  402. ccs.pChainContext = m_pChainContext;
  403. //
  404. // Create a ICertificates2 object.
  405. //
  406. if (FAILED(hr = ::CreateCertificatesObject(ccs, m_dwCurrentSafety, FALSE, &pICertificates2)))
  407. {
  408. DebugTrace("Error [%#x]: CreateCertificatesObject() failed.\n", hr);
  409. goto ErrorExit;
  410. }
  411. //
  412. // Return ICertificates to calller.
  413. //
  414. if (FAILED(hr = pICertificates2->QueryInterface(__uuidof(ICertificates), (void **) pVal)))
  415. {
  416. DebugTrace("Error [%#x]: pICertificates2->QueryInterface() failed.\n", hr);
  417. goto ErrorExit;
  418. }
  419. }
  420. catch(...)
  421. {
  422. hr = E_POINTER;
  423. DebugTrace("Exception: invalid parameter.\n");
  424. goto ErrorExit;
  425. }
  426. UnlockExit:
  427. //
  428. // Unlock access to this object.
  429. //
  430. m_Lock.Unlock();
  431. DebugTrace("Leaving CChain::get_Certificates().\n");
  432. return hr;
  433. ErrorExit:
  434. //
  435. // Sanity check.
  436. //
  437. ATLASSERT(FAILED(hr));
  438. ReportError(hr);
  439. goto UnlockExit;
  440. }
  441. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  442. Function : CChain::get_Status
  443. Synopsis : Return validity status for the chain or a specific certificate in
  444. the chain.
  445. Parameter: long Index - 0 to specify chain status, 1 for the end cert
  446. status, or Certificates.Count() for the root cert
  447. status.
  448. long * pVal - Pointer to a long integer to receive the status,
  449. which can be ORed with the following flags:
  450. //
  451. // These can be applied to certificates and chains.
  452. //
  453. CAPICOM_TRUST_IS_NOT_TIME_VALID = 0x00000001
  454. CAPICOM_TRUST_IS_NOT_TIME_NESTED = 0x00000002
  455. CAPICOM_TRUST_IS_REVOKED = 0x00000004
  456. CAPICOM_TRUST_IS_NOT_SIGNATURE_VALID = 0x00000008
  457. CAPICOM_TRUST_IS_NOT_VALID_FOR_USAGE = 0x00000010
  458. CAPICOM_TRUST_IS_UNTRUSTED_ROOT = 0x00000020
  459. CAPICOM_TRUST_REVOCATION_STATUS_UNKNOWN = 0x00000040
  460. CAPICOM_TRUST_IS_CYCLIC = 0x00000080
  461. CAPICOM_TRUST_INVALID_EXTENSION = 0x00000100
  462. CAPICOM_TRUST_INVALID_POLICY_CONSTRAINTS = 0x00000200
  463. CAPICOM_TRUST_INVALID_BASIC_CONSTRAINTS = 0x00000400
  464. CAPICOM_TRUST_INVALID_NAME_CONSTRAINTS = 0x00000800
  465. CAPICOM_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x00001000
  466. CAPICOM_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000
  467. CAPICOM_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000
  468. CAPICOM_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000
  469. CAPICOM_TRUST_IS_OFFLINE_REVOCATION = 0x01000000
  470. CAPICOM_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000
  471. //
  472. // These can be applied to chains only.
  473. //
  474. CAPICOM_TRUST_IS_PARTIAL_CHAIN = 0x00010000
  475. CAPICOM_TRUST_CTL_IS_NOT_TIME_VALID = 0x00020000
  476. CAPICOM_TRUST_CTL_IS_NOT_SIGNATURE_VALID = 0x00040000
  477. CAPICOM_TRUST_CTL_IS_NOT_VALID_FOR_USAGE = 0x00080000
  478. Remark :
  479. ------------------------------------------------------------------------------*/
  480. STDMETHODIMP CChain::get_Status (long Index,
  481. long * pVal)
  482. {
  483. HRESULT hr = S_OK;
  484. DWORD dwIndex = (DWORD) Index;
  485. DebugTrace("Entering CChain::get_Status().\n");
  486. try
  487. {
  488. //
  489. // Lock access to this object.
  490. //
  491. m_Lock.Lock();
  492. //
  493. // Check parameters.
  494. //
  495. if (NULL == pVal)
  496. {
  497. hr = E_INVALIDARG;
  498. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  499. goto ErrorExit;
  500. }
  501. //
  502. // Make sure chain has been built.
  503. //
  504. if (NULL == m_pChainContext)
  505. {
  506. hr = CAPICOM_E_CHAIN_NOT_BUILT;
  507. DebugTrace("Error [%#x]: chain object was not initialized.\n", hr);
  508. goto ErrorExit;
  509. }
  510. //
  511. // Return requested status.
  512. //
  513. if (0 == dwIndex)
  514. {
  515. *pVal = (long) m_dwStatus;
  516. }
  517. else
  518. {
  519. //
  520. // We only look at the first simple chain.
  521. //
  522. PCERT_SIMPLE_CHAIN pChain = m_pChainContext->rgpChain[0];
  523. //
  524. // Make sure index is not out of range.
  525. //
  526. if (dwIndex > pChain->cElement)
  527. {
  528. hr = E_INVALIDARG;
  529. DebugTrace("Error [%#x]: certificate index (%#x) out of range.\n", hr, dwIndex);
  530. goto ErrorExit;
  531. }
  532. *pVal = (long) pChain->rgpElement[dwIndex - 1]->TrustStatus.dwErrorStatus;
  533. }
  534. }
  535. catch(...)
  536. {
  537. hr = E_POINTER;
  538. DebugTrace("Exception: invalid parameter.\n");
  539. goto ErrorExit;
  540. }
  541. UnlockExit:
  542. //
  543. // Unlock access to this object.
  544. //
  545. m_Lock.Unlock();
  546. DebugTrace("Leaving CChain::get_Status().\n");
  547. return hr;
  548. ErrorExit:
  549. //
  550. // Sanity check.
  551. //
  552. ATLASSERT(FAILED(hr));
  553. ReportError(hr);
  554. goto UnlockExit;
  555. }
  556. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  557. Function : CChain::Build
  558. Synopsis : Build the chain.
  559. Parameter: ICertificate * pICertificate - Pointer to certificate for which
  560. the chain is to build.
  561. VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive chain
  562. overall validity result.
  563. Remark :
  564. ------------------------------------------------------------------------------*/
  565. STDMETHODIMP CChain::Build (ICertificate * pICertificate,
  566. VARIANT_BOOL * pVal)
  567. {
  568. HRESULT hr = S_OK;
  569. PCCERT_CONTEXT pCertContext = NULL;
  570. CComPtr<ICertificateStatus> pIStatus = NULL;
  571. DebugTrace("Entering CChain::Build().\n");
  572. try
  573. {
  574. //
  575. // Lock access to this object.
  576. //
  577. m_Lock.Lock();
  578. //
  579. // Check parameters.
  580. //
  581. if (NULL == pICertificate)
  582. {
  583. hr = E_INVALIDARG;
  584. DebugTrace("Error [%#x]: Parameter pICertificate is NULL.\n", hr);
  585. goto ErrorExit;
  586. }
  587. if (NULL == pVal)
  588. {
  589. hr = E_INVALIDARG;
  590. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  591. goto ErrorExit;
  592. }
  593. //
  594. // Get CERT_CONTEXT.
  595. //
  596. if (FAILED(hr = ::GetCertContext(pICertificate, &pCertContext)))
  597. {
  598. DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
  599. goto ErrorExit;
  600. }
  601. //
  602. // Get status check object.
  603. //
  604. if (FAILED(hr = pICertificate->IsValid(&pIStatus)))
  605. {
  606. DebugTrace("Error [%#x]: pICertificate->IsValid() failed.\n", hr);
  607. goto ErrorExit;
  608. }
  609. //
  610. // Build the chain.
  611. //
  612. if (FAILED(hr = Init(pCertContext, pIStatus, NULL, pVal)))
  613. {
  614. DebugTrace("Error [%#x]: CChain::Init() failed.\n", hr);
  615. goto ErrorExit;
  616. }
  617. }
  618. catch(...)
  619. {
  620. hr = E_POINTER;
  621. DebugTrace("Exception: invalid parameter.\n");
  622. goto ErrorExit;
  623. }
  624. UnlockExit:
  625. //
  626. // Free resource.
  627. //
  628. if (pCertContext)
  629. {
  630. ::CertFreeCertificateContext(pCertContext);
  631. }
  632. //
  633. // Unlock access to this object.
  634. //
  635. m_Lock.Unlock();
  636. DebugTrace("Leaving CChain::Build().\n");
  637. return hr;
  638. ErrorExit:
  639. //
  640. // Sanity check.
  641. //
  642. ATLASSERT(FAILED(hr));
  643. ReportError(hr);
  644. goto UnlockExit;
  645. }
  646. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  647. Function : CChain::CertificatePolicies
  648. Synopsis : Return the certificate policies OIDs collection for which this
  649. chain is valid.
  650. Parameter: IOID ** pVal - Pointer to pointer to IOIDs to receive the
  651. interface pointer.
  652. Remark :
  653. ------------------------------------------------------------------------------*/
  654. STDMETHODIMP CChain::CertificatePolicies (IOIDs ** pVal)
  655. {
  656. HRESULT hr = S_OK;
  657. DebugTrace("Entering CChain::CertificatePolicies().\n");
  658. try
  659. {
  660. //
  661. // Lock access to this object.
  662. //
  663. m_Lock.Lock();
  664. //
  665. // Check parameters.
  666. //
  667. if (NULL == pVal)
  668. {
  669. hr = E_INVALIDARG;
  670. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  671. goto ErrorExit;
  672. }
  673. //
  674. // Make sure chain has been built.
  675. //
  676. if (NULL == m_pChainContext)
  677. {
  678. hr = CAPICOM_E_CHAIN_NOT_BUILT;
  679. DebugTrace("Error [%#x]: chain object was not initialized.\n", hr);
  680. goto ErrorExit;
  681. }
  682. //
  683. // Make sure OS is XP and above.
  684. //
  685. if (IsWinXPAndAbove())
  686. {
  687. //
  688. // Make sure rgbElement is present.
  689. //
  690. if (1 > m_pChainContext->cChain)
  691. {
  692. hr = CAPICOM_E_UNKNOWN;
  693. DebugTrace("Error [%#x]: m_pChainContext->cChain = %d.\n",
  694. hr, m_pChainContext->cChain);
  695. goto ErrorExit;
  696. }
  697. if (1 > m_pChainContext->rgpChain[0]->cElement)
  698. {
  699. hr = CAPICOM_E_UNKNOWN;
  700. DebugTrace("Error [%#x]: m_pChainContext->rgpChain[0]->cElement = %d.\n",
  701. hr, m_pChainContext->rgpChain[0]->cElement);
  702. goto ErrorExit;
  703. }
  704. //
  705. // Create the OIDs collection for the simple chain.
  706. //
  707. if (FAILED(hr = ::CreateOIDsObject(m_pChainContext->rgpChain[0]->rgpElement[0]->pIssuanceUsage,
  708. TRUE, pVal)))
  709. {
  710. DebugTrace("Error [%#x]: CreateOIDsObject() failed.\n", hr);
  711. goto ErrorExit;
  712. }
  713. }
  714. else
  715. {
  716. CERT_ENHKEY_USAGE PolicyUsages = {0, NULL};
  717. //
  718. // Create the OIDs collection for the simple chain.
  719. //
  720. if (FAILED(hr = ::CreateOIDsObject(&PolicyUsages, TRUE, pVal)))
  721. {
  722. DebugTrace("Error [%#x]: CreateOIDsObject() failed.\n", hr);
  723. goto ErrorExit;
  724. }
  725. }
  726. }
  727. catch(...)
  728. {
  729. hr = E_POINTER;
  730. DebugTrace("Exception: invalid parameter.\n");
  731. goto ErrorExit;
  732. }
  733. UnlockExit:
  734. //
  735. // Unlock access to this object.
  736. //
  737. m_Lock.Unlock();
  738. DebugTrace("Leaving CChain::CertificatePolicies().\n");
  739. return hr;
  740. ErrorExit:
  741. //
  742. // Sanity check.
  743. //
  744. ATLASSERT(FAILED(hr));
  745. ReportError(hr);
  746. goto UnlockExit;
  747. }
  748. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  749. Function : CChain::ApplicationPolicies
  750. Synopsis : Return the application policies OIDs collection for which this
  751. chain is valid.
  752. Parameter: IOID ** pVal - Pointer to pointer to IOIDs to receive the
  753. interface pointer.
  754. Remark :
  755. ------------------------------------------------------------------------------*/
  756. STDMETHODIMP CChain::ApplicationPolicies (IOIDs ** pVal)
  757. {
  758. HRESULT hr = S_OK;
  759. DebugTrace("Entering CChain::ApplicationPolicies().\n");
  760. try
  761. {
  762. //
  763. // Lock access to this object.
  764. //
  765. m_Lock.Lock();
  766. //
  767. // Check parameters.
  768. //
  769. if (NULL == pVal)
  770. {
  771. hr = E_INVALIDARG;
  772. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  773. goto ErrorExit;
  774. }
  775. //
  776. // Make sure chain has been built.
  777. //
  778. if (NULL == m_pChainContext)
  779. {
  780. hr = CAPICOM_E_CHAIN_NOT_BUILT;
  781. DebugTrace("Error [%#x]: chain object was not initialized.\n", hr);
  782. goto ErrorExit;
  783. }
  784. //
  785. // Make sure OS is XP and above.
  786. //
  787. if (IsWinXPAndAbove())
  788. {
  789. //
  790. // Make sure rgbElement is present.
  791. //
  792. if (1 > m_pChainContext->cChain)
  793. {
  794. hr = CAPICOM_E_UNKNOWN;
  795. DebugTrace("Error [%#x]: m_pChainContext->cChain = %d.\n",
  796. hr, m_pChainContext->cChain);
  797. goto ErrorExit;
  798. }
  799. if (1 > m_pChainContext->rgpChain[0]->cElement)
  800. {
  801. hr = CAPICOM_E_UNKNOWN;
  802. DebugTrace("Error [%#x]: m_pChainContext->rgpChain[0]->cElement = %d.\n",
  803. hr, m_pChainContext->rgpChain[0]->cElement);
  804. goto ErrorExit;
  805. }
  806. //
  807. // Create the OIDs collection for the simple chain.
  808. //
  809. if (FAILED(hr = ::CreateOIDsObject(m_pChainContext->rgpChain[0]->rgpElement[0]->pApplicationUsage,
  810. FALSE, pVal)))
  811. {
  812. DebugTrace("Error [%#x]: CreateOIDsObject() failed.\n", hr);
  813. goto ErrorExit;
  814. }
  815. }
  816. else
  817. {
  818. //
  819. // $BUGBUG: Not supported (should we return CAPICOM_E_NOT_SUPPORTED?)
  820. //
  821. *pVal = NULL;
  822. }
  823. }
  824. catch(...)
  825. {
  826. hr = E_POINTER;
  827. DebugTrace("Exception: invalid parameter.\n");
  828. goto ErrorExit;
  829. }
  830. UnlockExit:
  831. //
  832. // Unlock access to this object.
  833. //
  834. m_Lock.Unlock();
  835. DebugTrace("Leaving CChain::ApplicationPolicies().\n");
  836. return hr;
  837. ErrorExit:
  838. //
  839. // Sanity check.
  840. //
  841. ATLASSERT(FAILED(hr));
  842. ReportError(hr);
  843. goto UnlockExit;
  844. }
  845. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  846. Function : CChain::ExtendedErrorInfo
  847. Synopsis : Return the extended error information description string.
  848. Parameter: long Index - Index of the chain (one based).
  849. BSTR * pVal - Pointer to BSTR to receive the string.
  850. Remark :
  851. ------------------------------------------------------------------------------*/
  852. STDMETHODIMP CChain::ExtendedErrorInfo (long Index, BSTR * pVal)
  853. {
  854. HRESULT hr = S_OK;
  855. DebugTrace("Entering CChain::ExtendedErrorInfo().\n");
  856. try
  857. {
  858. //
  859. // Lock access to this object.
  860. //
  861. m_Lock.Lock();
  862. //
  863. // Check parameters.
  864. //
  865. if (NULL == pVal)
  866. {
  867. hr = E_INVALIDARG;
  868. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  869. goto ErrorExit;
  870. }
  871. //
  872. // Make sure chain has been built.
  873. //
  874. if (NULL == m_pChainContext)
  875. {
  876. hr = CAPICOM_E_CHAIN_NOT_BUILT;
  877. DebugTrace("Error [%#x]: chain object was not initialized.\n", hr);
  878. goto ErrorExit;
  879. }
  880. DebugTrace("m_pChainContext = %#x.\n", m_pChainContext);
  881. //
  882. // Make sure OS is XP and above.
  883. //
  884. if (IsWinXPAndAbove())
  885. {
  886. CComBSTR bstrErrorInfo;
  887. //
  888. // Make sure rgbElement is present.
  889. //
  890. if (1 > m_pChainContext->cChain)
  891. {
  892. hr = CAPICOM_E_UNKNOWN;
  893. DebugTrace("Error [%#x]: m_pChainContext->cChain = %d.\n",
  894. hr, m_pChainContext->cChain);
  895. goto ErrorExit;
  896. }
  897. if (Index < 1 || (DWORD) Index > m_pChainContext->rgpChain[0]->cElement)
  898. {
  899. hr = E_INVALIDARG;
  900. DebugTrace("Error [%#x]: Index out of range, Index = %d, m_pChainContext->rgpChain[0]->cElement = %u.\n",
  901. hr, Index, m_pChainContext->rgpChain[0]->cElement);
  902. goto ErrorExit;
  903. }
  904. //
  905. // Convert string to BSTR.
  906. //
  907. if (m_pChainContext->rgpChain[0]->rgpElement[Index - 1]->pwszExtendedErrorInfo &&
  908. !(bstrErrorInfo = m_pChainContext->rgpChain[0]->rgpElement[Index - 1]->pwszExtendedErrorInfo))
  909. {
  910. hr = E_OUTOFMEMORY;
  911. DebugTrace("Error [%#x]: bstrErrorInfo = pwszExtendedErrorInfo failed.\n", hr);
  912. goto ErrorExit;
  913. }
  914. //
  915. // Return string to caller.
  916. //
  917. *pVal = bstrErrorInfo.Detach();
  918. }
  919. else
  920. {
  921. //
  922. // $BUGBUG: Not supported (should we return CAPICOM_E_NOT_SUPPORTED?)
  923. //
  924. *pVal = NULL;
  925. }
  926. }
  927. catch(...)
  928. {
  929. hr = E_POINTER;
  930. DebugTrace("Exception: invalid parameter.\n");
  931. goto ErrorExit;
  932. }
  933. UnlockExit:
  934. //
  935. // Unlock access to this object.
  936. //
  937. m_Lock.Unlock();
  938. DebugTrace("Leaving CChain::ExtendedErrorInfo().\n");
  939. return hr;
  940. ErrorExit:
  941. //
  942. // Sanity check.
  943. //
  944. ATLASSERT(FAILED(hr));
  945. ReportError(hr);
  946. goto UnlockExit;
  947. }
  948. ////////////////////////////////////////////////////////////////////////////////
  949. //
  950. // Custom interfaces.
  951. //
  952. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  953. Function : CChain::get_ChainContext
  954. Synopsis : Return the chains's PCCERT_CHAIN_CONTEXT.
  955. Parameter: long * ppChainContext - Pointer to PCCERT_CHAIN_CONTEXT disguished
  956. in a long.
  957. Remark : We need to use long instead of PCCERT_CHAIN_CONTEXT because VB
  958. can't handle double indirection (i.e. vb would bark on this
  959. PCCERT_CHAIN_CONTEXT * ppChainContext).
  960. ------------------------------------------------------------------------------*/
  961. STDMETHODIMP CChain::get_ChainContext (long * ppChainContext)
  962. {
  963. HRESULT hr = S_OK;
  964. DebugTrace("Entering CChain::get_ChainContext().\n");
  965. try
  966. {
  967. //
  968. // Lock access to this object.
  969. //
  970. m_Lock.Lock();
  971. //
  972. // Check parameters.
  973. //
  974. if (NULL == ppChainContext)
  975. {
  976. hr = E_INVALIDARG;
  977. DebugTrace("Error [%#x]: Parameter ppChainContext is NULL.\n", hr);
  978. goto ErrorExit;
  979. }
  980. //
  981. // Return chain context to caller.
  982. //
  983. if (FAILED(hr = GetContext((PCCERT_CHAIN_CONTEXT *) ppChainContext)))
  984. {
  985. DebugTrace("Error [%#x]: CChain::GetContext() failed.\n", hr);
  986. goto ErrorExit;
  987. }
  988. }
  989. catch(...)
  990. {
  991. hr = E_POINTER;
  992. DebugTrace("Exception: invalid parameter.\n");
  993. goto ErrorExit;
  994. }
  995. UnlockExit:
  996. //
  997. // Unlock access to this object.
  998. //
  999. m_Lock.Unlock();
  1000. DebugTrace("Leaving CChain::get_ChainContext().\n");
  1001. return hr;
  1002. ErrorExit:
  1003. //
  1004. // Sanity check.
  1005. //
  1006. ATLASSERT(FAILED(hr));
  1007. ReportError(hr);
  1008. goto UnlockExit;
  1009. }
  1010. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1011. Function : CChain::put_ChainContext
  1012. Synopsis : Initialize the object with a CERT_CHAIN_CONTEXT.
  1013. Parameter: long pChainContext - Poiner to CERT_CHAIN_CONTEXT, disguised in a
  1014. long, used to initialize this object.
  1015. Remark : Note that this is NOT 64-bit compatiable. Plese see remark of
  1016. get_ChainContext for more detail.
  1017. ------------------------------------------------------------------------------*/
  1018. STDMETHODIMP CChain::put_ChainContext (long pChainContext)
  1019. {
  1020. HRESULT hr = S_OK;
  1021. DebugTrace("Entering CChain::put_ChainContext().\n");
  1022. try
  1023. {
  1024. //
  1025. // Lock access to this object.
  1026. //
  1027. m_Lock.Lock();
  1028. //
  1029. // Check parameters.
  1030. //
  1031. if (NULL == pChainContext)
  1032. {
  1033. hr = E_INVALIDARG;
  1034. DebugTrace("Error [%#x]: Parameter pChainContext is NULL.\n", hr);
  1035. goto ErrorExit;
  1036. }
  1037. //
  1038. // Reset the object with this context.
  1039. //
  1040. if (FAILED(hr = PutContext((PCCERT_CHAIN_CONTEXT) pChainContext)))
  1041. {
  1042. DebugTrace("Error [%#x]: CChain::PutContext() failed.\n", hr);
  1043. goto ErrorExit;
  1044. }
  1045. }
  1046. catch(...)
  1047. {
  1048. hr = E_POINTER;
  1049. DebugTrace("Exception: invalid parameter.\n");
  1050. goto ErrorExit;
  1051. }
  1052. UnlockExit:
  1053. //
  1054. // Unlock access to this object.
  1055. //
  1056. m_Lock.Unlock();
  1057. DebugTrace("Leaving CChain::put_CertContext().\n");
  1058. return hr;
  1059. ErrorExit:
  1060. //
  1061. // Sanity check.
  1062. //
  1063. ATLASSERT(FAILED(hr));
  1064. ReportError(hr);
  1065. goto UnlockExit;
  1066. }
  1067. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1068. Function : CChain::FreeContext
  1069. Synopsis : Free a CERT_CHAIN_CONTEXT.
  1070. Parameter: long pChainContext - Poiner to CERT_CHAIN_CONTEXT, disguised in a
  1071. long, to be freed.
  1072. Remark : Note that this is NOT 64-bit compatiable. Plese see remark of
  1073. get_ChainContext for more detail.
  1074. ------------------------------------------------------------------------------*/
  1075. STDMETHODIMP CChain::FreeContext (long pChainContext)
  1076. {
  1077. HRESULT hr = S_OK;
  1078. DebugTrace("Entering CChain::FreeContext().\n");
  1079. try
  1080. {
  1081. //
  1082. // Lock access to this object.
  1083. //
  1084. m_Lock.Lock();
  1085. //
  1086. // Check parameters.
  1087. //
  1088. if (NULL == pChainContext)
  1089. {
  1090. hr = E_INVALIDARG;
  1091. DebugTrace("Error [%#x]: Parameter pChainContext is NULL.\n", hr);
  1092. goto ErrorExit;
  1093. }
  1094. //
  1095. // Free the context.
  1096. //
  1097. ::CertFreeCertificateChain((PCCERT_CHAIN_CONTEXT) pChainContext);
  1098. }
  1099. catch(...)
  1100. {
  1101. hr = E_POINTER;
  1102. DebugTrace("Exception: invalid parameter.\n");
  1103. goto ErrorExit;
  1104. }
  1105. UnlockExit:
  1106. //
  1107. // Unlock access to this object.
  1108. //
  1109. m_Lock.Unlock();
  1110. DebugTrace("Leaving CChain::FreeContext().\n");
  1111. return hr;
  1112. ErrorExit:
  1113. //
  1114. // Sanity check.
  1115. //
  1116. ATLASSERT(FAILED(hr));
  1117. ReportError(hr);
  1118. goto UnlockExit;
  1119. }
  1120. ////////////////////////////////////////////////////////////////////////////////
  1121. //
  1122. // Private methods.
  1123. //
  1124. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1125. Function : CChain::Init
  1126. Synopsis : Initialize the object.
  1127. Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT.
  1128. ICertificateStatus * pIStatus - Pointer to ICertificateStus object
  1129. used to build the chain.
  1130. HCERTSTORE hAdditionalStore - Additional store handle.
  1131. VARIANT_BOOL * pVal - Pointer to VARIANT_BOOL to receive chain
  1132. overall validity result.
  1133. Remark : This method is not part of the COM interface (it is a normal C++
  1134. member function). We need it to initialize the object created
  1135. internally by us with CERT_CONTEXT.
  1136. Since it is only a normal C++ member function, this function can
  1137. only be called from a C++ class pointer, not an interface pointer.
  1138. ------------------------------------------------------------------------------*/
  1139. STDMETHODIMP CChain::Init (PCCERT_CONTEXT pCertContext,
  1140. ICertificateStatus * pIStatus,
  1141. HCERTSTORE hAdditionalStore,
  1142. VARIANT_BOOL * pbResult)
  1143. {
  1144. HRESULT hr = S_OK;
  1145. VARIANT_BOOL bResult = VARIANT_FALSE;
  1146. long lIndex = 0;
  1147. long cEkuOid = 0;
  1148. long cIssuanceOid = 0;
  1149. DWORD dwCheckFlags = 0;
  1150. CAPICOM_CHECK_FLAG UserFlags = CAPICOM_CHECK_NONE;
  1151. CComPtr<IEKU> pIEku = NULL;
  1152. LPSTR * rgpEkuOid = NULL;
  1153. LPSTR * rgpIssuanceOid = NULL;
  1154. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  1155. CComPtr<ICertificateStatus2> pICertificateStatus2 = NULL;
  1156. CComPtr<IOIDs> pIApplicationPolicies = NULL;
  1157. CComPtr<IOIDs> pICertificatePolicies = NULL;
  1158. DATE dtVerificationTime = {0};
  1159. SYSTEMTIME stVerificationTime = {0};
  1160. FILETIME ftVerificationTime = {0};
  1161. FILETIME ftUTCVerificationTime = {0};
  1162. LPFILETIME pftVerificationTime = NULL;
  1163. DWORD dwUrlRetrievalTimeout = 0;
  1164. CAPICOM_CHAIN_STATUS PolicyStatus = CAPICOM_CHAIN_STATUS_OK;
  1165. CERT_CHAIN_PARA ChainPara = {0};
  1166. CComBSTR bstrEkuOid;
  1167. DebugTrace("Entering CChain::Init().\n");
  1168. //
  1169. // Sanity check.
  1170. //
  1171. ATLASSERT(pCertContext);
  1172. ATLASSERT(pIStatus);
  1173. ATLASSERT(pbResult);
  1174. //
  1175. // Is this v2?
  1176. //
  1177. if (FAILED(hr = pIStatus->QueryInterface(IID_ICertificateStatus2,
  1178. (void **) &pICertificateStatus2)))
  1179. {
  1180. DebugTrace("Info [%#x]: pIStatus->QueryInterface(IID_ICertificateStatus2) failed.\n", hr);
  1181. hr = S_OK;
  1182. }
  1183. //
  1184. // Get the user's requested check flag.
  1185. //
  1186. if (FAILED(hr = pIStatus->get_CheckFlag(&UserFlags)))
  1187. {
  1188. DebugTrace("Error [%#x]: pIStatus->CheckFlag() failed.\n", hr);
  1189. goto ErrorExit;
  1190. }
  1191. //
  1192. // Set revocation flags.
  1193. //
  1194. if ((CAPICOM_CHECK_ONLINE_REVOCATION_STATUS & UserFlags) ||
  1195. (CAPICOM_CHECK_OFFLINE_REVOCATION_STATUS & UserFlags))
  1196. {
  1197. if (UserFlags & CAPICOM_CHECK_REVOCATION_END_CERT_ONLY)
  1198. {
  1199. dwCheckFlags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT;
  1200. }
  1201. else if (UserFlags & CAPICOM_CHECK_REVOCATION_ENTIRE_CHAIN)
  1202. {
  1203. dwCheckFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN;
  1204. }
  1205. else // default is chain minus root.
  1206. {
  1207. dwCheckFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
  1208. }
  1209. if (CAPICOM_CHECK_OFFLINE_REVOCATION_STATUS & UserFlags)
  1210. {
  1211. dwCheckFlags |= CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY;
  1212. }
  1213. }
  1214. //
  1215. // Is this v2?
  1216. //
  1217. if (pICertificateStatus2)
  1218. {
  1219. //
  1220. // Get verification time.
  1221. //
  1222. if (FAILED(hr = pICertificateStatus2->get_VerificationTime(&dtVerificationTime)))
  1223. {
  1224. DebugTrace("Error [%#x]: pICertificateStatus2->get_VerificationTime() failed.\n", hr);
  1225. goto ErrorExit;
  1226. }
  1227. //
  1228. // Get URL retrieval timeout.
  1229. //
  1230. if (FAILED(hr = pICertificateStatus2->get_UrlRetrievalTimeout((long *) &dwUrlRetrievalTimeout)))
  1231. {
  1232. DebugTrace("Error [%#x]: pICertificateStatus2->get_UrlRetrievalTimeout() failed.\n", hr);
  1233. goto ErrorExit;
  1234. }
  1235. //
  1236. // Try application policies.
  1237. //
  1238. if (FAILED(hr = pICertificateStatus2->ApplicationPolicies(&pIApplicationPolicies)))
  1239. {
  1240. DebugTrace("Error [%#x]: pICertificateStatus2->ApplicationPolicies() failed.\n", hr);
  1241. goto ErrorExit;
  1242. }
  1243. //
  1244. // Get count of OIDs.
  1245. //
  1246. if (FAILED(hr = pIApplicationPolicies->get_Count(&cEkuOid)))
  1247. {
  1248. DebugTrace("Error [%#x]: pIApplicationPolicies->get_Count() failed.\n", hr);
  1249. goto ErrorExit;
  1250. }
  1251. //
  1252. // Do we have any application usage?
  1253. //
  1254. if (0 < cEkuOid)
  1255. {
  1256. //
  1257. // Allocate memory for usage array.
  1258. //
  1259. if (!(rgpEkuOid = (LPTSTR *) ::CoTaskMemAlloc(sizeof(LPSTR) * cEkuOid)))
  1260. {
  1261. hr = E_OUTOFMEMORY;
  1262. DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
  1263. goto ErrorExit;
  1264. }
  1265. ::ZeroMemory(rgpEkuOid, sizeof(LPSTR) * cEkuOid);
  1266. //
  1267. // Setup usage array.
  1268. //
  1269. for (lIndex = 0; lIndex < cEkuOid; lIndex++)
  1270. {
  1271. CComBSTR bstrOid;
  1272. CComPtr<IOID> pIOID = NULL;
  1273. CComVariant varOid = NULL;
  1274. CComVariant varIndex = lIndex + 1;
  1275. if (FAILED(hr = pIApplicationPolicies->get_Item(varIndex, &varOid)))
  1276. {
  1277. DebugTrace("Error [%#x]: pIApplicationPolicies->get_Item() failed.\n", hr);
  1278. goto ErrorExit;
  1279. }
  1280. if (FAILED(hr = varOid.pdispVal->QueryInterface(IID_IOID, (void **) &pIOID)))
  1281. {
  1282. DebugTrace("Error [%#x]: varOid.pdispVal->QueryInterface() failed.\n", hr);
  1283. goto ErrorExit;
  1284. }
  1285. if (FAILED(hr = pIOID->get_Value(&bstrOid)))
  1286. {
  1287. DebugTrace("Error [%#x]: pIOID->get_Value() failed.\n", hr);
  1288. goto ErrorExit;
  1289. }
  1290. if (FAILED(hr = ::UnicodeToAnsi((LPWSTR) bstrOid,
  1291. -1,
  1292. &rgpEkuOid[lIndex],
  1293. NULL)))
  1294. {
  1295. DebugTrace("Error [%#x]:UnicodeToAnsi() failed.\n", hr);
  1296. goto ErrorExit;
  1297. }
  1298. }
  1299. }
  1300. //
  1301. // OK, try issuance policies.
  1302. //
  1303. if (FAILED(hr = pICertificateStatus2->CertificatePolicies(&pICertificatePolicies)))
  1304. {
  1305. DebugTrace("Error [%#x]: pICertificateStatus2->CertificatePolicies() failed.\n", hr);
  1306. goto ErrorExit;
  1307. }
  1308. //
  1309. // Get count of OIDs.
  1310. //
  1311. if (FAILED(hr = pICertificatePolicies->get_Count(&cIssuanceOid)))
  1312. {
  1313. DebugTrace("Error [%#x]: pICertificatePolicies->get_Count() failed.\n", hr);
  1314. goto ErrorExit;
  1315. }
  1316. //
  1317. // Do we have any usage?
  1318. //
  1319. if (0 < cIssuanceOid)
  1320. {
  1321. //
  1322. // Make sure we have WinXP and above.
  1323. //
  1324. if (!IsWinXPAndAbove())
  1325. {
  1326. hr = CAPICOM_E_NOT_SUPPORTED;
  1327. DebugTrace("Error [%#x]: building chain with issuance policy is not support.\n", hr);
  1328. goto ErrorExit;
  1329. }
  1330. //
  1331. // Allocate memory for usage array.
  1332. //
  1333. if (!(rgpIssuanceOid = (LPTSTR *) ::CoTaskMemAlloc(sizeof(LPSTR) * cIssuanceOid)))
  1334. {
  1335. hr = E_OUTOFMEMORY;
  1336. DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
  1337. goto ErrorExit;
  1338. }
  1339. //
  1340. // Setup usage array.
  1341. //
  1342. for (lIndex = 0; lIndex < cIssuanceOid; lIndex++)
  1343. {
  1344. CComBSTR bstrOid;
  1345. CComPtr<IOID> pIOID = NULL;
  1346. CComVariant varOid = NULL;
  1347. CComVariant varIndex = lIndex + 1;
  1348. if (FAILED(hr = pICertificatePolicies->get_Item(varIndex, &varOid)))
  1349. {
  1350. DebugTrace("Error [%#x]: pICertificatePolicies->get_Item() failed.\n", hr);
  1351. goto ErrorExit;
  1352. }
  1353. if (FAILED(hr = varOid.pdispVal->QueryInterface(IID_IOID, (void **) &pIOID)))
  1354. {
  1355. DebugTrace("Error [%#x]: varOid.pdispVal->QueryInterface() failed.\n", hr);
  1356. goto ErrorExit;
  1357. }
  1358. if (FAILED(hr = pIOID->get_Value(&bstrOid)))
  1359. {
  1360. DebugTrace("Error [%#x]: pIOID->get_Value() failed.\n", hr);
  1361. goto ErrorExit;
  1362. }
  1363. if (FAILED(hr = ::UnicodeToAnsi((LPWSTR) bstrOid,
  1364. -1,
  1365. &rgpIssuanceOid[lIndex],
  1366. NULL)))
  1367. {
  1368. DebugTrace("Error [%#x]:UnicodeToAnsi() failed.\n", hr);
  1369. goto ErrorExit;
  1370. }
  1371. }
  1372. }
  1373. }
  1374. //
  1375. // If we didn't find any application usage, then try the old EKU object.
  1376. //
  1377. if (0 == cEkuOid)
  1378. {
  1379. //
  1380. // Get EKU object.
  1381. //
  1382. if (FAILED(hr = pIStatus->EKU(&pIEku)))
  1383. {
  1384. DebugTrace("Error [%#x]: pIStatus->EKU() failed.\n", hr);
  1385. goto ErrorExit;
  1386. }
  1387. //
  1388. // Get EKU OID value.
  1389. //
  1390. if (FAILED(hr = pIEku->get_OID(&bstrEkuOid)))
  1391. {
  1392. DebugTrace("Error [%#x]: pIEku->get_OID() failed.\n", hr);
  1393. goto ErrorExit;
  1394. }
  1395. //
  1396. // If not empty EKU, then set it.
  1397. //
  1398. if (bstrEkuOid.Length() > 0)
  1399. {
  1400. //
  1401. // Allocate memory for EKU usage array.
  1402. //
  1403. cEkuOid = 1;
  1404. if (!(rgpEkuOid = (LPTSTR *) ::CoTaskMemAlloc(sizeof(LPSTR))))
  1405. {
  1406. hr = E_OUTOFMEMORY;
  1407. DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
  1408. goto ErrorExit;
  1409. }
  1410. ::ZeroMemory(rgpEkuOid, sizeof(LPSTR) * cEkuOid);
  1411. if (FAILED(hr = ::UnicodeToAnsi((LPWSTR) bstrEkuOid,
  1412. -1,
  1413. &rgpEkuOid[0],
  1414. NULL)))
  1415. {
  1416. DebugTrace("Error [%#x]:UnicodeToAnsi() failed.\n", hr);
  1417. goto ErrorExit;
  1418. }
  1419. }
  1420. }
  1421. //
  1422. // If we found any usage, then force the appropriate policy check flags.
  1423. //
  1424. if (0 < cEkuOid)
  1425. {
  1426. UserFlags = (CAPICOM_CHECK_FLAG) ((DWORD) UserFlags | CAPICOM_CHECK_APPLICATION_USAGE);
  1427. }
  1428. if (0 < cIssuanceOid)
  1429. {
  1430. UserFlags = (CAPICOM_CHECK_FLAG) ((DWORD) UserFlags | CAPICOM_CHECK_CERTIFICATE_POLICY);
  1431. }
  1432. //
  1433. // Initialize.
  1434. //
  1435. ChainPara.cbSize = sizeof(ChainPara);
  1436. ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  1437. ChainPara.RequestedUsage.Usage.cUsageIdentifier = cEkuOid;
  1438. ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgpEkuOid;
  1439. ChainPara.RequestedIssuancePolicy.dwType = USAGE_MATCH_TYPE_AND;
  1440. ChainPara.RequestedIssuancePolicy.Usage.cUsageIdentifier = cIssuanceOid;
  1441. ChainPara.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = rgpIssuanceOid;
  1442. //
  1443. // Set verification time, if specified.
  1444. //
  1445. if ((DATE) 0 != dtVerificationTime)
  1446. {
  1447. //
  1448. // Convert to SYSTEMTIME format.
  1449. //
  1450. if (!::VariantTimeToSystemTime(dtVerificationTime, &stVerificationTime))
  1451. {
  1452. hr = E_INVALIDARG;
  1453. DebugTrace("Error [%#x]: VariantTimeToSystemTime() failed.\n", hr);
  1454. goto ErrorExit;
  1455. }
  1456. //
  1457. // Convert to FILETIME format.
  1458. //
  1459. if (!::SystemTimeToFileTime(&stVerificationTime, &ftVerificationTime))
  1460. {
  1461. hr = HRESULT_FROM_WIN32(::GetLastError());
  1462. DebugTrace("Error [%#x]: SystemTimeToFileTime() failed.\n", hr);
  1463. goto ErrorExit;
  1464. }
  1465. //
  1466. // Convert to UTC FILETIME.
  1467. //
  1468. if (!::LocalFileTimeToFileTime(&ftVerificationTime, &ftUTCVerificationTime))
  1469. {
  1470. hr = HRESULT_FROM_WIN32(::GetLastError());
  1471. DebugTrace("Error [%#x]: LocalFileTimeToFileTime() failed.\n", hr);
  1472. goto ErrorExit;
  1473. }
  1474. pftVerificationTime = &ftUTCVerificationTime;
  1475. }
  1476. //
  1477. // Set URL retrieval timeout, if avaliable.
  1478. //
  1479. // Note: Ignored by CAPI by pre Win2K platforms.
  1480. //
  1481. if (0 != dwUrlRetrievalTimeout)
  1482. {
  1483. ChainPara.dwUrlRetrievalTimeout = dwUrlRetrievalTimeout * 1000;
  1484. }
  1485. //
  1486. // Build the chain.
  1487. //
  1488. if (!::CertGetCertificateChain(NULL, // in optional
  1489. pCertContext, // in
  1490. pftVerificationTime, // in optional
  1491. hAdditionalStore, // in optional
  1492. &ChainPara, // in
  1493. dwCheckFlags, // in
  1494. NULL, // in
  1495. &pChainContext)) // out
  1496. {
  1497. hr = HRESULT_FROM_WIN32(::GetLastError());
  1498. DebugTrace("Error [%#x]: CertGetCertificateChain() failed.\n", hr);
  1499. goto ErrorExit;
  1500. }
  1501. //
  1502. // Chain was successfully built, so update states.
  1503. //
  1504. if (m_pChainContext)
  1505. {
  1506. ::CertFreeCertificateChain(m_pChainContext);
  1507. }
  1508. m_pChainContext = pChainContext;
  1509. m_dwStatus = pChainContext->TrustStatus.dwErrorStatus;
  1510. //
  1511. // Verify the chain using base policy.
  1512. //
  1513. if (FAILED(hr = Verify(UserFlags, &PolicyStatus)))
  1514. {
  1515. DebugTrace("Error [%#x]: Chain::Verify() failed.\n", hr);
  1516. goto ErrorExit;
  1517. }
  1518. //
  1519. // Ignore errors that user specifically requested not to check.
  1520. //
  1521. if (CAPICOM_CHAIN_STATUS_REVOCATION_OFFLINE == PolicyStatus)
  1522. {
  1523. if (CAPICOM_CHECK_OFFLINE_REVOCATION_STATUS & UserFlags)
  1524. {
  1525. bResult = VARIANT_TRUE;
  1526. DebugTrace("Info: offline revocation when performing offline revocation checking.\n");
  1527. goto CommonExit;
  1528. }
  1529. else if (CAPICOM_CHECK_ONLINE_REVOCATION_STATUS & UserFlags)
  1530. {
  1531. DebugTrace("Info: offline revocation when performing online revocation checking.\n");
  1532. goto CommonExit;
  1533. }
  1534. }
  1535. if ((CAPICOM_CHECK_TRUSTED_ROOT & UserFlags) &&
  1536. (CAPICOM_CHAIN_STATUS_UNTRUSTEDROOT == PolicyStatus))
  1537. {
  1538. DebugTrace("Info: chain does not verify because of untrusted root.\n");
  1539. goto CommonExit;
  1540. }
  1541. if ((CAPICOM_CHECK_TIME_VALIDITY & UserFlags) &&
  1542. (CAPICOM_CHAIN_STATUS_EXPIRED == PolicyStatus))
  1543. {
  1544. DebugTrace("Info: chain does not verify because of certificate expiration.\n");
  1545. goto CommonExit;
  1546. }
  1547. if ((CAPICOM_CHECK_SIGNATURE_VALIDITY & UserFlags) &&
  1548. (CAPICOM_CHAIN_STATUS_INVALID_SIGNATURE == PolicyStatus))
  1549. {
  1550. DebugTrace("Info: chain does not verify because of invalid certificate signature.\n");
  1551. goto CommonExit;
  1552. }
  1553. if (((CAPICOM_CHECK_ONLINE_REVOCATION_STATUS | CAPICOM_CHECK_OFFLINE_REVOCATION_STATUS) & UserFlags) &&
  1554. (CAPICOM_CHAIN_STATUS_REVOKED == PolicyStatus || CAPICOM_CHAIN_STATUS_REVOCATION_NO_CHECK == PolicyStatus))
  1555. {
  1556. DebugTrace("Info: chain does not verify because a certificate in the chain was revoked or could not be checked most likely due to no CDP in certificate.\n");
  1557. goto CommonExit;
  1558. }
  1559. if ((CAPICOM_CHECK_COMPLETE_CHAIN & UserFlags) &&
  1560. (CAPICOM_CHAIN_STATUS_PARTIAL_CHAINING == PolicyStatus))
  1561. {
  1562. DebugTrace("Info: chain does not verify because of partial chain.\n");
  1563. goto CommonExit;
  1564. }
  1565. if (((CAPICOM_CHECK_APPLICATION_USAGE & UserFlags) ||
  1566. (CAPICOM_CHECK_CERTIFICATE_POLICY & UserFlags)) &&
  1567. (CAPICOM_CHAIN_STATUS_INVALID_USAGE == PolicyStatus))
  1568. {
  1569. DebugTrace("Info: chain does not verify because of invalid usage.\n");
  1570. goto CommonExit;
  1571. }
  1572. if ((CAPICOM_CHECK_NAME_CONSTRAINTS & UserFlags) &&
  1573. (CAPICOM_CHAIN_STATUS_INVALID_NAME == PolicyStatus))
  1574. {
  1575. DebugTrace("Info: chain does not verify because of invalid name constraints.\n");
  1576. goto CommonExit;
  1577. }
  1578. if ((CAPICOM_CHECK_BASIC_CONSTRAINTS & UserFlags) &&
  1579. (CAPICOM_CHAIN_STATUS_INVALID_BASIC_CONSTRAINTS == PolicyStatus))
  1580. {
  1581. DebugTrace("Info: chain does not verify because of invalid basic constraints.\n");
  1582. goto CommonExit;
  1583. }
  1584. if ((CAPICOM_CHECK_NESTED_VALIDITY_PERIOD & UserFlags) &&
  1585. (CAPICOM_CHAIN_STATUS_NESTED_VALIDITY_PERIOD == PolicyStatus))
  1586. {
  1587. DebugTrace("Info: chain does not verify because of invalid nested validity period.\n");
  1588. goto CommonExit;
  1589. }
  1590. //
  1591. // Everything is check out OK.
  1592. //
  1593. bResult = VARIANT_TRUE;
  1594. CommonExit:
  1595. //
  1596. // Free resources.
  1597. //
  1598. if (rgpEkuOid)
  1599. {
  1600. for (lIndex = 0; lIndex < cEkuOid; lIndex++)
  1601. {
  1602. if (rgpEkuOid[lIndex])
  1603. {
  1604. ::CoTaskMemFree(rgpEkuOid[lIndex]);
  1605. }
  1606. }
  1607. ::CoTaskMemFree((LPVOID) rgpEkuOid);
  1608. }
  1609. if (rgpIssuanceOid)
  1610. {
  1611. for (lIndex = 0; lIndex < cIssuanceOid; lIndex++)
  1612. {
  1613. if (rgpIssuanceOid[lIndex])
  1614. {
  1615. ::CoTaskMemFree(rgpIssuanceOid[lIndex]);
  1616. }
  1617. }
  1618. ::CoTaskMemFree((LPVOID) rgpIssuanceOid);
  1619. }
  1620. //
  1621. // Return result.
  1622. //
  1623. *pbResult = bResult;
  1624. DebugTrace("Leaving CChain::Init().\n");
  1625. return hr;
  1626. ErrorExit:
  1627. //
  1628. // Sanity check.
  1629. //
  1630. ATLASSERT(FAILED(hr));
  1631. //
  1632. // Free resouce.
  1633. //
  1634. if (pChainContext)
  1635. {
  1636. ::CertFreeCertificateChain(pChainContext);
  1637. }
  1638. goto CommonExit;
  1639. }
  1640. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1641. Function : CChain::Verify
  1642. Synopsis : Verify the chain using base policy.
  1643. Parameter: CAPICOM_CHECK_FLAG CheckFlag - Check flag.
  1644. CAPICOM_CHAIN_STATUS * pVal - Pointer to CAPICOM_CHAIN_STATUS to
  1645. receive the chain validity status.
  1646. Remark :
  1647. ------------------------------------------------------------------------------*/
  1648. STDMETHODIMP CChain::Verify (CAPICOM_CHECK_FLAG CheckFlag,
  1649. CAPICOM_CHAIN_STATUS * pVal)
  1650. {
  1651. HRESULT hr = S_OK;
  1652. LPCSTR pszPolicy = CERT_CHAIN_POLICY_BASE;
  1653. CERT_CHAIN_POLICY_PARA PolicyPara = {0};
  1654. CERT_CHAIN_POLICY_STATUS PolicyStatus = {0};
  1655. DebugTrace("Entering CChain::Verify().\n");
  1656. //
  1657. // Check parameters.
  1658. //
  1659. if (NULL == pVal)
  1660. {
  1661. hr = E_INVALIDARG;
  1662. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  1663. goto ErrorExit;
  1664. }
  1665. //
  1666. // Make sure chain has been built.
  1667. //
  1668. if (NULL == m_pChainContext)
  1669. {
  1670. hr = CAPICOM_E_CHAIN_NOT_BUILT;
  1671. DebugTrace("Error [%#x]: chain object was not initialized.\n", hr);
  1672. goto ErrorExit;
  1673. }
  1674. //
  1675. // Initialize.
  1676. //
  1677. PolicyStatus.cbSize = sizeof(PolicyStatus);
  1678. PolicyPara.cbSize = sizeof(PolicyPara);
  1679. //
  1680. // Setup policy structures.
  1681. //
  1682. if (0 == (CheckFlag & CAPICOM_CHECK_TIME_VALIDITY))
  1683. {
  1684. PolicyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS;
  1685. }
  1686. if (0 == (CheckFlag & CAPICOM_CHECK_APPLICATION_USAGE) &&
  1687. 0 == (CheckFlag & CAPICOM_CHECK_CERTIFICATE_POLICY))
  1688. {
  1689. PolicyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG;
  1690. }
  1691. if (0 == (CheckFlag & CAPICOM_CHECK_NAME_CONSTRAINTS))
  1692. {
  1693. PolicyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG;
  1694. }
  1695. if (0 == (CheckFlag & CAPICOM_CHECK_BASIC_CONSTRAINTS))
  1696. {
  1697. PolicyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG;
  1698. }
  1699. if (0 == (CheckFlag & CAPICOM_CHECK_NESTED_VALIDITY_PERIOD))
  1700. {
  1701. PolicyPara.dwFlags |= CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
  1702. }
  1703. //
  1704. // Verify the chain policy.
  1705. //
  1706. if (!::CertVerifyCertificateChainPolicy(pszPolicy,
  1707. m_pChainContext,
  1708. &PolicyPara,
  1709. &PolicyStatus))
  1710. {
  1711. hr = HRESULT_FROM_WIN32(::GetLastError());
  1712. DebugTrace("Error [%#x]: CertVerifyCertificateChainPolicy() failed.\n", hr);
  1713. goto ErrorExit;
  1714. }
  1715. //
  1716. // Return policy status to caller.
  1717. //
  1718. *pVal = (CAPICOM_CHAIN_STATUS) PolicyStatus.dwError;
  1719. CommonExit:
  1720. DebugTrace("Leaving CChain::Verify().\n");
  1721. return hr;
  1722. ErrorExit:
  1723. //
  1724. // Sanity check.
  1725. //
  1726. ATLASSERT(FAILED(hr));
  1727. ReportError(hr);
  1728. goto CommonExit;
  1729. }
  1730. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1731. Function : CChain::GetContext
  1732. Synopsis : Return the PCCERT_CHAIN_CONTEXT.
  1733. Parameter: PCCERT_CHAIN_CONTEXT * ppChainContext - Pointer to
  1734. PCCERT_CHAIN_CONTEXT.
  1735. Remark : This method is not part of the COM interface (it is a normal C++
  1736. member function). We need it to initialize the object created
  1737. internally by us with CERT_CONTEXT.
  1738. Since it is only a normal C++ member function, this function can
  1739. only be called from a C++ class pointer, not an interface pointer.
  1740. ------------------------------------------------------------------------------*/
  1741. STDMETHODIMP CChain::GetContext (PCCERT_CHAIN_CONTEXT * ppChainContext)
  1742. {
  1743. HRESULT hr = S_OK;
  1744. DebugTrace("Entering CChain::GetContext().\n");
  1745. //
  1746. // Sanity check.
  1747. //
  1748. ATLASSERT(ppChainContext);
  1749. //
  1750. // Make sure chain has been built.
  1751. //
  1752. if (!m_pChainContext)
  1753. {
  1754. hr = CAPICOM_E_CHAIN_NOT_BUILT;
  1755. DebugTrace("Error: chain object was not initialized.\n");
  1756. goto ErrorExit;
  1757. }
  1758. //
  1759. // Duplicate the chain context.
  1760. //
  1761. if (!(*ppChainContext = ::CertDuplicateCertificateChain(m_pChainContext)))
  1762. {
  1763. hr = HRESULT_FROM_WIN32(::GetLastError());
  1764. DebugTrace("Error [%#x]: CertDuplicateCertificateChain() failed.\n");
  1765. goto ErrorExit;
  1766. }
  1767. CommonExit:
  1768. DebugTrace("Leaving CChain::GetContext().\n");
  1769. return hr;
  1770. ErrorExit:
  1771. //
  1772. // Sanity check.
  1773. //
  1774. ATLASSERT(FAILED(hr));
  1775. goto CommonExit;
  1776. }
  1777. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1778. Function : CChain::PutContext
  1779. Synopsis : Initialize the object.
  1780. Parameter: PCCERT_CHAIN_CONTEXT pChainContext - Chain context.
  1781. Remark : This method is not part of the COM interface (it is a normal C++
  1782. member function). We need it to initialize the object created
  1783. internally by us with CERT_CONTEXT.
  1784. Since it is only a normal C++ member function, this function can
  1785. only be called from a C++ class pointer, not an interface pointer.
  1786. ------------------------------------------------------------------------------*/
  1787. STDMETHODIMP CChain::PutContext (PCCERT_CHAIN_CONTEXT pChainContext)
  1788. {
  1789. HRESULT hr = S_OK;
  1790. PCCERT_CHAIN_CONTEXT pChainContext2 = NULL;
  1791. DebugTrace("Entering CChain::PutContext().\n");
  1792. //
  1793. // Sanity check.
  1794. //
  1795. ATLASSERT(pChainContext);
  1796. //
  1797. // Dupliacte the context.
  1798. //
  1799. if (!(pChainContext2 = ::CertDuplicateCertificateChain(pChainContext)))
  1800. {
  1801. hr = HRESULT_FROM_WIN32(::GetLastError());
  1802. DebugTrace("Error [%#x]: CertDuplicateCertificateChain() failed.\n", hr);
  1803. goto ErrorExit;
  1804. }
  1805. //
  1806. // Free ay previous chain context.
  1807. //
  1808. if (m_pChainContext)
  1809. {
  1810. ::CertFreeCertificateChain(m_pChainContext);
  1811. }
  1812. //
  1813. // Update state.
  1814. //
  1815. m_pChainContext = pChainContext2;
  1816. m_dwStatus = pChainContext->TrustStatus.dwErrorStatus;
  1817. CommonExit:
  1818. DebugTrace("Leaving CChain::PutContext().\n");
  1819. return hr;
  1820. ErrorExit:
  1821. //
  1822. // Sanity check.
  1823. //
  1824. ATLASSERT(FAILED(hr));
  1825. goto CommonExit;
  1826. }