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.

1048 lines
30 KiB

  1. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Microsoft Windows, Copyright (C) Microsoft Corporation, 2000 - 2001.
  3. File: CertHlpr.cpp
  4. Content: Helper functions for cert.
  5. History: 09-10-2001 dsie created
  6. ------------------------------------------------------------------------------*/
  7. #include "StdAfx.h"
  8. #include "CAPICOM.h"
  9. #include "CertHlpr.h"
  10. #include "Settings.h"
  11. #include "Certificate.h"
  12. #include "Common.h"
  13. typedef PCCERT_CONTEXT (WINAPI * PCRYPTUIDLGSELECTCERTIFICATEW)
  14. (IN PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc);
  15. ////////////////////////////////////////////////////////////////////////////////
  16. //
  17. // Exported functions.
  18. //
  19. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  20. Function : GetEnhancedKeyUsage
  21. Synopsis : Retrieve the EKU from the cert.
  22. Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT.
  23. DWORD dwFlags - 0, or
  24. CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, or
  25. CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG.
  26. PCERT_ENHKEY_USAGE * ppUsage - Pointer to PCERT_ENHKEY_USAGE
  27. to receive the usages.
  28. Remark : If EKU extension is found with no EKU, then return HRESULT
  29. is CERT_E_WRONG_USAGE.
  30. ------------------------------------------------------------------------------*/
  31. HRESULT GetEnhancedKeyUsage (PCCERT_CONTEXT pCertContext,
  32. DWORD dwFlags,
  33. PCERT_ENHKEY_USAGE * ppUsage)
  34. {
  35. HRESULT hr = S_OK;
  36. DWORD dwWinError = 0;
  37. DWORD cbUsage = 0;
  38. PCERT_ENHKEY_USAGE pUsage = NULL;
  39. //
  40. // Sanity check.
  41. //
  42. ATLASSERT(pCertContext);
  43. ATLASSERT(ppUsage);
  44. //
  45. // Initialize.
  46. //
  47. *ppUsage = NULL;
  48. //
  49. // Determine extended key usage data length.
  50. //
  51. if (!::CertGetEnhancedKeyUsage(pCertContext,
  52. dwFlags,
  53. NULL,
  54. &cbUsage))
  55. {
  56. //
  57. // Older version of Crypt32.dll would return FALSE for
  58. // empty EKU. In this case, we want to treat it as success,
  59. //
  60. if (CRYPT_E_NOT_FOUND == (dwWinError = ::GetLastError()))
  61. {
  62. //
  63. // and also set the cbUsage.
  64. //
  65. cbUsage = sizeof(CERT_ENHKEY_USAGE);
  66. DebugTrace("Info: CertGetEnhancedKeyUsage() found no EKU, so valid for all uses.\n");
  67. }
  68. else
  69. {
  70. hr = HRESULT_FROM_WIN32(dwWinError);
  71. DebugTrace("Error [%#x]: CertGetEnhancedKeyUsage() failed to get size.\n", hr);
  72. goto ErrorExit;
  73. }
  74. }
  75. //
  76. // Allocate memory.
  77. //
  78. if (!(pUsage = (PCERT_ENHKEY_USAGE) ::CoTaskMemAlloc((ULONG) cbUsage)))
  79. {
  80. hr = E_OUTOFMEMORY;
  81. DebugTrace("Error: out of memory.\n");
  82. goto ErrorExit;
  83. }
  84. //
  85. // Get extended key usage data.
  86. //
  87. if (!::CertGetEnhancedKeyUsage(pCertContext,
  88. dwFlags,
  89. pUsage,
  90. &cbUsage))
  91. {
  92. //
  93. // Older version of Crypt32.dll would return FALSE for
  94. // empty EKU. In this case, we want to treat it as success.
  95. //
  96. if (CRYPT_E_NOT_FOUND == (dwWinError = ::GetLastError()))
  97. {
  98. //
  99. // Structure pointed to by pUsage is not initialized by older
  100. // version of Cryp32 for empty EKU.
  101. //
  102. ::ZeroMemory(pUsage, sizeof(CERT_ENHKEY_USAGE));
  103. }
  104. else
  105. {
  106. hr = HRESULT_FROM_WIN32(dwWinError);
  107. DebugTrace("Error [%#x]: CertGetEnhancedKeyUsage() failed to get data.\n", hr);
  108. goto ErrorExit;
  109. }
  110. }
  111. //
  112. // See if we have any EKU?
  113. //
  114. if (0 == pUsage->cUsageIdentifier && CRYPT_E_NOT_FOUND != ::GetLastError())
  115. {
  116. //
  117. // This is not valid for any usage.
  118. //
  119. hr = CERT_E_WRONG_USAGE;
  120. goto ErrorExit;
  121. }
  122. //
  123. // Return usages to caller.
  124. //
  125. *ppUsage = pUsage;
  126. CommonExit:
  127. DebugTrace("Leaving GetEnhancedKeyUsage().\n");
  128. return hr;
  129. ErrorExit:
  130. //
  131. // Sanity check.
  132. //
  133. ATLASSERT(FAILED(hr));
  134. //
  135. // Free resource.
  136. //
  137. if (pUsage)
  138. {
  139. ::CoTaskMemFree(pUsage);
  140. }
  141. goto CommonExit;
  142. }
  143. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  144. Function : BuildChain
  145. Synopsis : Build a chain using the specified policy.
  146. Parameter: PCCERT_CONTEXT pCertContext - CERT_CONTEXT of cert to verify.
  147. HCERTSTORE hCertStore - Additional store (can be NULL).
  148. LPCSTR pszPolicy - Policy used to verify the cert (i.e.
  149. CERT_CHAIN_POLICY_BASE).
  150. PCCERT_CHAIN_CONTEXT * ppChainContext - Pointer to
  151. PCCERT_CHAIN_CONTEXT.
  152. Remark :
  153. ------------------------------------------------------------------------------*/
  154. HRESULT BuildChain (PCCERT_CONTEXT pCertContext,
  155. HCERTSTORE hCertStore,
  156. LPCSTR pszPolicy,
  157. PCCERT_CHAIN_CONTEXT * ppChainContext)
  158. {
  159. HRESULT hr = S_OK;
  160. CERT_CHAIN_PARA ChainPara = {0};;
  161. LPSTR rgpszUsageIdentifier[1] = {NULL};
  162. DebugTrace("Entering BuildChain().\n");
  163. //
  164. // Sanity check.
  165. //
  166. ATLASSERT(pCertContext);
  167. ATLASSERT(pszPolicy);
  168. ATLASSERT(ppChainContext);
  169. //
  170. // Initialize.
  171. //
  172. ChainPara.cbSize = sizeof(ChainPara);
  173. //
  174. // Check policy.
  175. //
  176. if (CERT_CHAIN_POLICY_BASE == pszPolicy)
  177. {
  178. //
  179. // No EKU for base policy.
  180. //
  181. }
  182. else if (CERT_CHAIN_POLICY_AUTHENTICODE == pszPolicy)
  183. {
  184. //
  185. // Setup EKU for Authenticode policy.
  186. //
  187. rgpszUsageIdentifier[0] = szOID_PKIX_KP_CODE_SIGNING;
  188. ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  189. ChainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
  190. ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgpszUsageIdentifier;
  191. }
  192. else
  193. {
  194. //
  195. // We don't support any other policy, yet.
  196. //
  197. hr = CERT_E_INVALID_POLICY;
  198. DebugTrace("Internal error [%#x]: unexpected policy (%#x).\n", hr, pszPolicy);
  199. goto ErrorExit;
  200. }
  201. //
  202. // Build the chain.
  203. //
  204. if (!::CertGetCertificateChain(NULL, // in optional
  205. pCertContext, // in
  206. NULL, // in optional
  207. hCertStore, // in optional
  208. &ChainPara, // in
  209. 0, // in
  210. NULL, // in
  211. ppChainContext)) // out
  212. {
  213. hr = HRESULT_FROM_WIN32(::GetLastError());
  214. DebugTrace("Error [%#x]: CertGetCertificateChain() failed.\n", hr);
  215. goto ErrorExit;
  216. }
  217. CommonExit:
  218. DebugTrace("Leaving BuildChain().\n");
  219. return hr;
  220. ErrorExit:
  221. //
  222. // Sanity check.
  223. //
  224. ATLASSERT(FAILED(hr));
  225. goto CommonExit;
  226. }
  227. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  228. Function : VerifyCertificate
  229. Synopsis : Verify if the certificate is valid.
  230. Parameter: PCCERT_CONTEXT pCertContext - CERT_CONTEXT of cert to verify.
  231. HCERTSTORE hCertStore - Additional store (can be NULL).
  232. LPCSTR pszPolicy - Policy used to verify the cert (i.e.
  233. CERT_CHAIN_POLICY_BASE).
  234. Remark :
  235. ------------------------------------------------------------------------------*/
  236. HRESULT VerifyCertificate (PCCERT_CONTEXT pCertContext,
  237. HCERTSTORE hCertStore,
  238. LPCSTR pszPolicy)
  239. {
  240. HRESULT hr = S_OK;
  241. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  242. CERT_CHAIN_POLICY_PARA PolicyPara = {0};
  243. CERT_CHAIN_POLICY_STATUS PolicyStatus = {0};
  244. DebugTrace("Entering VerifyCertificate().\n");
  245. //
  246. // Sanity check.
  247. //
  248. ATLASSERT(pCertContext);
  249. ATLASSERT(pszPolicy);
  250. //
  251. // Initialize.
  252. //
  253. PolicyPara.cbSize = sizeof(PolicyPara);
  254. PolicyStatus.cbSize = sizeof(PolicyStatus);
  255. //
  256. // Build the chain.
  257. //
  258. if (FAILED(hr = ::BuildChain(pCertContext,
  259. hCertStore,
  260. pszPolicy,
  261. &pChainContext)))
  262. {
  263. DebugTrace("Error [%#x]: BuildChain() failed.\n", hr);
  264. goto ErrorExit;
  265. }
  266. //
  267. // Verify the chain using the specified policy.
  268. //
  269. if (::CertVerifyCertificateChainPolicy(pszPolicy,
  270. pChainContext,
  271. &PolicyPara,
  272. &PolicyStatus))
  273. {
  274. if (PolicyStatus.dwError)
  275. {
  276. hr = HRESULT_FROM_WIN32(PolicyStatus.dwError);
  277. DebugTrace("Error [%#x]: invalid policy.\n", hr);
  278. goto ErrorExit;
  279. }
  280. }
  281. else
  282. {
  283. hr = HRESULT_FROM_WIN32(CERT_E_INVALID_POLICY);
  284. DebugTrace("Error [%#x]: CertVerifyCertificateChainPolicy() failed.\n", hr);
  285. goto ErrorExit;
  286. }
  287. CommonExit:
  288. //
  289. // Free resource.
  290. //
  291. if (pChainContext)
  292. {
  293. ::CertFreeCertificateChain(pChainContext);
  294. }
  295. DebugTrace("Leaving VerifyCertificate().\n");
  296. return hr;
  297. ErrorExit:
  298. //
  299. // Sanity check.
  300. //
  301. ATLASSERT(FAILED(hr));
  302. goto CommonExit;
  303. }
  304. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  305. Function : SelectCertificateContext
  306. Synopsis : Pop UI to prompt user to select a certificate from an opened store.
  307. Parameter: HCERTSTORE hCertStore - Source cert store.
  308. LPWCSTR pwszTitle - Dialog title string.
  309. LPWCSTR - pwszDisplayString - Dialog display string.
  310. BOOL bMultiSelect - TRUE to enable multi-select.
  311. PFNCFILTERPROC pfnFilterCallback - Pointer to filter callback
  312. function.
  313. HCERTSTORE hSelectedCertStore - HCERTSTORE to receive the
  314. selected certs for multi-select
  315. mode.
  316. PCCERT_CONTEXT * ppCertContext - Pointer to PCCERT_CONTEXT
  317. receive the certificate context
  318. for single selection mode.
  319. Remark : typedef struct tagCRYPTUI_SELECTCERTIFICATE_STRUCTW {
  320. DWORD dwSize;
  321. HWND hwndParent; // OPTIONAL
  322. DWORD dwFlags; // OPTIONAL
  323. LPCWSTR szTitle; // OPTIONAL
  324. DWORD dwDontUseColumn; // OPTIONAL
  325. LPCWSTR szDisplayString; // OPTIONAL
  326. PFNCFILTERPROC pFilterCallback; // OPTIONAL
  327. PFNCCERTDISPLAYPROC pDisplayCallback; // OPTIONAL
  328. void * pvCallbackData; // OPTIONAL
  329. DWORD cDisplayStores;
  330. HCERTSTORE * rghDisplayStores;
  331. DWORD cStores; // OPTIONAL
  332. HCERTSTORE * rghStores; // OPTIONAL
  333. DWORD cPropSheetPages; // OPTIONAL
  334. LPCPROPSHEETPAGEW rgPropSheetPages; // OPTIONAL
  335. HCERTSTORE hSelectedCertStore; // OPTIONAL
  336. } CRYPTUI_SELECTCERTIFICATE_STRUCTW
  337. ------------------------------------------------------------------------------*/
  338. HRESULT SelectCertificateContext (HCERTSTORE hCertStore,
  339. LPCWSTR pwszTitle,
  340. LPCWSTR pwszDisplayString,
  341. BOOL bMultiSelect,
  342. PFNCFILTERPROC pfnFilterCallback,
  343. HCERTSTORE hSelectedCertStore,
  344. PCCERT_CONTEXT * ppCertContext)
  345. {
  346. HRESULT hr = S_OK;
  347. HINSTANCE hDLL = NULL;
  348. PCCERT_CONTEXT pCertContext = NULL;
  349. PCRYPTUIDLGSELECTCERTIFICATEW pCryptUIDlgSelectCertificateW = NULL;
  350. CRYPTUI_SELECTCERTIFICATE_STRUCTW csc;
  351. DebugTrace("Entering SelectCertificateContext().\n");
  352. //
  353. // Sanity check.
  354. //
  355. ATLASSERT(hCertStore);
  356. //
  357. // Initialize.
  358. //
  359. if (ppCertContext)
  360. {
  361. *ppCertContext = NULL;
  362. }
  363. //
  364. // Make sure we are allowed to pop UI.
  365. //
  366. if (!PromptForCertificateEnabled())
  367. {
  368. hr = CAPICOM_E_UI_DISABLED;
  369. DebugTrace("Error [%#x]: Certificate selection UI is disabled.\n", hr);
  370. goto ErrorExit;
  371. }
  372. //
  373. // Get pointer to CryptUIDlgSelectCertificateW().
  374. //
  375. if (hDLL = ::LoadLibrary("CryptUI.dll"))
  376. {
  377. pCryptUIDlgSelectCertificateW = (PCRYPTUIDLGSELECTCERTIFICATEW)
  378. ::GetProcAddress(hDLL, "CryptUIDlgSelectCertificateW");
  379. }
  380. //
  381. // Is CryptUIDlgSelectCertificateW() available?
  382. //
  383. if (!pCryptUIDlgSelectCertificateW)
  384. {
  385. hr = CAPICOM_E_NOT_SUPPORTED;
  386. DebugTrace("Error [%#x]: CryptUIDlgSelectCertificateW() API not available.\n", hr);
  387. goto ErrorExit;
  388. }
  389. //
  390. // Pop UI to prompt user to select cert.
  391. //
  392. ::ZeroMemory(&csc, sizeof(csc));
  393. #if (0) //DSIE: Bug in older version of CRYPTUI does not check size correctly,
  394. // so always force it to the oldest version of structure.
  395. csc.dwSize = sizeof(csc);
  396. #else
  397. csc.dwSize = offsetof(CRYPTUI_SELECTCERTIFICATE_STRUCTW, hSelectedCertStore);
  398. #endif
  399. csc.dwFlags = bMultiSelect ? CRYPTUI_SELECTCERT_MULTISELECT : 0;
  400. csc.szTitle = pwszTitle;
  401. csc.szDisplayString = pwszDisplayString;
  402. csc.cDisplayStores = 1;
  403. csc.rghDisplayStores = &hCertStore;
  404. csc.pFilterCallback = pfnFilterCallback;
  405. csc.hSelectedCertStore = bMultiSelect ? hSelectedCertStore : NULL;
  406. //
  407. // Display the selection dialog.
  408. //
  409. if (pCertContext = (PCERT_CONTEXT) pCryptUIDlgSelectCertificateW(&csc))
  410. {
  411. //
  412. // Return CERT_CONTEXT to caller.
  413. //
  414. if (!(*ppCertContext = ::CertDuplicateCertificateContext(pCertContext)))
  415. {
  416. hr = HRESULT_FROM_WIN32(::GetLastError());
  417. DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n", hr);
  418. goto ErrorExit;
  419. }
  420. }
  421. else
  422. {
  423. //
  424. // Is this multi-select?
  425. //
  426. if (bMultiSelect)
  427. {
  428. //
  429. // See if we have any cert in the store?
  430. //
  431. if (!(pCertContext = ::CertEnumCertificatesInStore(hSelectedCertStore, pCertContext)))
  432. {
  433. hr = CAPICOM_E_CANCELLED;
  434. DebugTrace("Error [%#x]: user cancelled cert selection dialog box.\n", hr);
  435. goto ErrorExit;
  436. }
  437. }
  438. else
  439. {
  440. hr = CAPICOM_E_CANCELLED;
  441. DebugTrace("Error [%#x]: user cancelled cert selection dialog box.\n", hr);
  442. goto ErrorExit;
  443. }
  444. }
  445. CommonExit:
  446. //
  447. // Release resources.
  448. //
  449. if (pCertContext)
  450. {
  451. ::CertFreeCertificateContext(pCertContext);
  452. }
  453. if (hDLL)
  454. {
  455. ::FreeLibrary(hDLL);
  456. }
  457. DebugTrace("Leaving SelectCertificateContext().\n");
  458. return hr;
  459. ErrorExit:
  460. //
  461. // Sanity check.
  462. //
  463. ATLASSERT(FAILED(hr));
  464. goto CommonExit;
  465. }
  466. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  467. Function : SelectCertificate
  468. Synopsis : Select a certificate from the sepcified store. If only 1 cert is
  469. found after the filter, then that cert is returned. If more than
  470. 1 cert is found, then UI is popped to prompt user to select a
  471. certificate from the specified store.
  472. Parameter: CAPICOM_STORE_INFO StoreInfo - Store to select from.
  473. PFNCFILTERPROC pfnFilterCallback - Pointer to filter callback
  474. function.
  475. ICertificate2 ** ppICertificate - Pointer to pointer to
  476. ICertificate2 to receive
  477. interface pointer.
  478. Remark :
  479. ------------------------------------------------------------------------------*/
  480. HRESULT SelectCertificate (CAPICOM_STORE_INFO StoreInfo,
  481. PFNCFILTERPROC pfnFilterCallback,
  482. ICertificate2 ** ppICertificate)
  483. {
  484. HRESULT hr = S_OK;
  485. HCERTSTORE hCertStore = NULL;
  486. PCCERT_CONTEXT pCertContext = NULL;
  487. PCCERT_CONTEXT pEnumContext = NULL;
  488. DWORD dwValidCerts = 0;
  489. DebugTrace("Entering SelectCertificate().\n");
  490. //
  491. // Sanity check.
  492. //
  493. ATLASSERT(ppICertificate);
  494. //
  495. // Open the store for cert selection if necessary.
  496. //
  497. switch (StoreInfo.dwChoice)
  498. {
  499. case CAPICOM_STORE_INFO_STORENAME:
  500. {
  501. if (!(hCertStore = ::CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM,
  502. CAPICOM_ASN_ENCODING,
  503. NULL,
  504. CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER,
  505. (void *) StoreInfo.pwszStoreName)))
  506. {
  507. hr = HRESULT_FROM_WIN32(::GetLastError());
  508. DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
  509. goto ErrorExit;
  510. }
  511. break;
  512. }
  513. case CAPICOM_STORE_INFO_HCERTSTORE:
  514. {
  515. if (!(hCertStore = ::CertDuplicateStore(StoreInfo.hCertStore)))
  516. {
  517. hr = HRESULT_FROM_WIN32(::GetLastError());
  518. DebugTrace("Error [%#x]: CertDuplicateStore() failed.\n", hr);
  519. goto ErrorExit;
  520. }
  521. break;
  522. }
  523. default:
  524. {
  525. hr = CAPICOM_E_INTERNAL;
  526. DebugTrace("Internal error [%#x]: unknow store info deChoice (%d).\n", hr, StoreInfo.dwChoice);
  527. goto ErrorExit;
  528. }
  529. }
  530. //
  531. // Count number of certs in store.
  532. //
  533. while (pEnumContext = ::CertEnumCertificatesInStore(hCertStore, pEnumContext))
  534. {
  535. //
  536. // Count only if it will not be filtered out.
  537. //
  538. if (pfnFilterCallback && !pfnFilterCallback(pEnumContext, NULL, NULL))
  539. {
  540. continue;
  541. }
  542. if (pCertContext)
  543. {
  544. ::CertFreeCertificateContext(pCertContext);
  545. }
  546. if (!(pCertContext = ::CertDuplicateCertificateContext(pEnumContext)))
  547. {
  548. hr = HRESULT_FROM_WIN32(::GetLastError());
  549. DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n", hr);
  550. goto ErrorExit;
  551. }
  552. dwValidCerts++;
  553. }
  554. //
  555. // Above loop can exit either because there is no more certificate in
  556. // the store or an error. Need to check last error to be certain.
  557. //
  558. if (CRYPT_E_NOT_FOUND != ::GetLastError())
  559. {
  560. hr = HRESULT_FROM_WIN32(::GetLastError());
  561. DebugTrace("Error [%#x]: CertEnumCertificatesInStore() failed.\n", hr);
  562. goto ErrorExit;
  563. }
  564. //
  565. // If only 1 cert available, don't pop UI (just use it).
  566. //
  567. if (0 == dwValidCerts)
  568. {
  569. hr = CAPICOM_E_STORE_EMPTY;
  570. DebugTrace("Error [%#x]: no certificate found.\n", hr);
  571. goto ErrorExit;
  572. }
  573. else if (1 < dwValidCerts)
  574. {
  575. //
  576. // First free the CERT_CONTEXT we duplicated above.
  577. //
  578. ::CertFreeCertificateContext(pCertContext), pCertContext = NULL;
  579. //
  580. // Pop UI to prompt user to select the signer cert.
  581. //
  582. if (FAILED(hr = ::SelectCertificateContext(hCertStore,
  583. NULL,
  584. NULL,
  585. FALSE,
  586. pfnFilterCallback,
  587. NULL,
  588. &pCertContext)))
  589. {
  590. DebugTrace("Error [%#x]: SelectCertificateContext() failed.\n", hr);
  591. goto ErrorExit;
  592. }
  593. }
  594. //
  595. // Create an ICertificate object from the CERT_CONTEXT.
  596. //
  597. if (FAILED(hr = ::CreateCertificateObject(pCertContext, 0, ppICertificate)))
  598. {
  599. DebugTrace("Error [%#x]: CreateCertificateObject() failed.\n", hr);
  600. goto ErrorExit;
  601. }
  602. CommonExit:
  603. //
  604. // Release resources.
  605. //
  606. if (pEnumContext)
  607. {
  608. ::CertFreeCertificateContext(pEnumContext);
  609. }
  610. if (pCertContext)
  611. {
  612. ::CertFreeCertificateContext(pCertContext);
  613. }
  614. if (hCertStore)
  615. {
  616. ::CertCloseStore(hCertStore, 0);
  617. }
  618. DebugTrace("Leaving SelectCertificate().\n");
  619. return hr;
  620. ErrorExit:
  621. //
  622. // Sanity check.
  623. //
  624. ATLASSERT(FAILED(hr));
  625. goto CommonExit;
  626. }
  627. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  628. Function : ExportCertificatesToStore
  629. Synopsis : Copy all certs from the collections to the specified store.
  630. Parameter: ICertificates2 * pICertificate - Pointer to collection.
  631. HCERTSTORE hCertStore - Store to copy to.
  632. Remark :
  633. ------------------------------------------------------------------------------*/
  634. HRESULT ExportCertificatesToStore(ICertificates2 * pICertificates,
  635. HCERTSTORE hCertStore)
  636. {
  637. HRESULT hr = S_OK;
  638. CComPtr<ICCertificates> pICCertificates = NULL;
  639. DebugTrace("Entering ExportCertificatesToStore().\n");
  640. //
  641. // Sanity check.
  642. //
  643. ATLASSERT(hCertStore);
  644. //
  645. // Make sure we have something to load.
  646. //
  647. if (pICertificates)
  648. {
  649. //
  650. // Get ICCertificate interface pointer.
  651. //
  652. if (FAILED(hr = pICertificates->QueryInterface(IID_ICCertificates, (void **) &pICCertificates)))
  653. {
  654. DebugTrace("Error [%#x]: pICertificates->QueryInterface() failed.\n", hr);
  655. goto ErrorExit;
  656. }
  657. //
  658. // Get the CERT_CONTEXT.
  659. //
  660. if (FAILED(hr = pICCertificates->_ExportToStore(hCertStore)))
  661. {
  662. DebugTrace("Error [%#x]: pICCertificates->_ExportToStore() failed.\n", hr);
  663. goto ErrorExit;
  664. }
  665. }
  666. CommonExit:
  667. DebugTrace("Leaving ExportCertificatesToStore().\n");
  668. return hr;
  669. ErrorExit:
  670. //
  671. // Sanity check.
  672. //
  673. ATLASSERT(FAILED(hr));
  674. goto CommonExit;
  675. }
  676. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  677. Function : CreateMemoryStoreFromCertificates
  678. Synopsis : Create a memory cert store and copy all certs from the collections
  679. to the store.
  680. Parameter: ICertificates2 * pICertificates - Pointer to collection.
  681. HCERTSTORE * phCertStore - Pointer to receive store handle.
  682. Remark : If pICertificate is NULL, then the returned store is still valid
  683. nut empty. Also, caller must close the returned store.
  684. ------------------------------------------------------------------------------*/
  685. HRESULT CreateMemoryStoreFromCertificates(ICertificates2 * pICertificates,
  686. HCERTSTORE * phCertStore)
  687. {
  688. HRESULT hr = S_OK;
  689. HCERTSTORE hCertStore = NULL;
  690. DebugTrace("Entering CreateMemoryStoreFromCertificates().\n");
  691. //
  692. // Sanity check.
  693. //
  694. ATLASSERT(phCertStore);
  695. //
  696. // Initialize.
  697. //
  698. *phCertStore = hCertStore;
  699. //
  700. // Create the memory store.
  701. //
  702. if (!(hCertStore = ::CertOpenStore(CERT_STORE_PROV_MEMORY,
  703. CAPICOM_ASN_ENCODING,
  704. NULL,
  705. CERT_STORE_CREATE_NEW_FLAG,
  706. NULL)))
  707. {
  708. DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
  709. goto ErrorExit;
  710. }
  711. //
  712. // Now load the collection into the store.
  713. //
  714. if (FAILED(hr = ::ExportCertificatesToStore(pICertificates, hCertStore)))
  715. {
  716. DebugTrace("Error [%#x]: ExportCertificatesToStore() failed.\n", hr);
  717. goto ErrorExit;
  718. }
  719. //
  720. // Return store handle to caller.
  721. //
  722. *phCertStore = hCertStore;
  723. CommonExit:
  724. DebugTrace("Leaving CreateMemoryStoreFromCertificates().\n");
  725. return hr;
  726. ErrorExit:
  727. //
  728. // Sanity check.
  729. //
  730. ATLASSERT(FAILED(hr));
  731. //
  732. // Free resource.
  733. //
  734. if (hCertStore)
  735. {
  736. ::CertCloseStore(hCertStore, 0);
  737. }
  738. goto CommonExit;
  739. }
  740. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  741. Function : CompareCertAndContainerPublicKey
  742. Synopsis : Compare public key in cert matches the container's key.
  743. Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT to be used
  744. to initialize the IPrivateKey object.
  745. BSTR ContainerName - Container name.
  746. BSTR ProviderName - Provider name.
  747. DWORD dwProvType - Provider type.
  748. DWORD dwKeySpec - Key spec.
  749. DWORD dwFlags - Provider flags.
  750. Remark :
  751. ------------------------------------------------------------------------------*/
  752. HRESULT CompareCertAndContainerPublicKey (PCCERT_CONTEXT pCertContext,
  753. LPWSTR pwszContainerName,
  754. LPWSTR pwszProvName,
  755. DWORD dwProvType,
  756. DWORD dwKeySpec,
  757. DWORD dwFlags)
  758. {
  759. HRESULT hr = S_OK;
  760. HCRYPTPROV hCryptProv = NULL;
  761. DWORD cbProvPubKeyInfo = 0;
  762. PCERT_PUBLIC_KEY_INFO pProvPubKeyInfo = NULL;
  763. DebugTrace("Entering CompareCertAndContainerPublicKey().\n");
  764. //
  765. // Sanity check.
  766. //
  767. ATLASSERT(pCertContext);
  768. ATLASSERT(pwszContainerName);
  769. ATLASSERT(pwszProvName);
  770. //
  771. // Acquire provider with key access.
  772. //
  773. if (FAILED(hr = ::AcquireContext(pwszProvName,
  774. pwszContainerName,
  775. dwProvType,
  776. dwFlags,
  777. TRUE,
  778. &hCryptProv)))
  779. {
  780. DebugTrace("Error [%#x]: AcquireContext() failed.\n", hr);
  781. goto ErrorExit;
  782. }
  783. //
  784. // Get provider's public key.
  785. //
  786. if (!::CryptExportPublicKeyInfo(hCryptProv,
  787. dwKeySpec,
  788. pCertContext->dwCertEncodingType,
  789. NULL,
  790. &cbProvPubKeyInfo))
  791. {
  792. hr = HRESULT_FROM_WIN32(::GetLastError());
  793. DebugTrace("Error [%#x]: CryptExportPublicKeyInfo() failed.\n", hr);
  794. goto ErrorExit;
  795. }
  796. if (!(pProvPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) ::CoTaskMemAlloc(cbProvPubKeyInfo)))
  797. {
  798. hr = E_OUTOFMEMORY;
  799. DebugTrace("Error: out of memory.\n");
  800. goto ErrorExit;
  801. }
  802. if (!::CryptExportPublicKeyInfo(hCryptProv,
  803. dwKeySpec,
  804. pCertContext->dwCertEncodingType,
  805. pProvPubKeyInfo,
  806. &cbProvPubKeyInfo))
  807. {
  808. hr = HRESULT_FROM_WIN32(::GetLastError());
  809. DebugTrace("Error [%#x]: CryptExportPublicKeyInfo() failed.\n", hr);
  810. goto ErrorExit;
  811. }
  812. //
  813. // Compare the keys.
  814. //
  815. if (!::CertComparePublicKeyInfo(pCertContext->dwCertEncodingType,
  816. &pCertContext->pCertInfo->SubjectPublicKeyInfo,
  817. pProvPubKeyInfo))
  818. {
  819. hr = HRESULT_FROM_WIN32(NTE_BAD_PUBLIC_KEY);
  820. DebugTrace("Error [%#x]: CertComparePublicKeyInfo() failed.\n", hr);
  821. goto ErrorExit;
  822. }
  823. CommonExit:
  824. //
  825. // Free resources.
  826. //
  827. if (pProvPubKeyInfo)
  828. {
  829. ::CoTaskMemFree(pProvPubKeyInfo);
  830. }
  831. if (hCryptProv)
  832. {
  833. ::CryptReleaseContext(hCryptProv, 0);
  834. }
  835. DebugTrace("Leaving CompareCertAndContainerPublicKey().\n");
  836. return hr;
  837. ErrorExit:
  838. //
  839. // Sanity check.
  840. //
  841. ATLASSERT(FAILED(hr));
  842. goto CommonExit;
  843. }