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.

2216 lines
62 KiB

  1. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
  3. File: Store.cpp
  4. Content: Implementation of CStore.
  5. History: 11-15-99 dsie created
  6. ------------------------------------------------------------------------------*/
  7. #include "StdAfx.h"
  8. #include "CAPICOM.h"
  9. #include "Store.h"
  10. #include "ADHelpers.h"
  11. #include "Certificate.h"
  12. #include "Certificates.h"
  13. #include "Common.h"
  14. #include "Convert.h"
  15. #include "PFXHlpr.h"
  16. #include "Settings.h"
  17. #include "SmartCard.h"
  18. ////////////////////////////////////////////////////////////////////////////////
  19. //
  20. // Internal functions.
  21. //
  22. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  23. Function : IsProtectedStore
  24. Synopsis : Determine if the requested store is proctected from update from
  25. WEB within script.
  26. Parameter: CAPICOM_STORE_LOCATION StoreLocation - Store location.
  27. LPWSTR pwszStoreName - Store name.
  28. Remark : 1) All LM stores are considered protected.
  29. 2) CU\Root, CU\AuthRoot, CU\TrustedPeople, CU\TrustedPublisher,
  30. and CU\Disallowed are considered protected.
  31. 3) All error conditions would be considered as protected.
  32. 4) Otherwise, it is not considered protected.
  33. ------------------------------------------------------------------------------*/
  34. static BOOL IsProtectedStore (CAPICOM_STORE_LOCATION StoreLocation,
  35. LPWSTR pwszStoreName)
  36. {
  37. BOOL bIsProtected = TRUE;
  38. switch (StoreLocation)
  39. {
  40. case CAPICOM_LOCAL_MACHINE_STORE:
  41. {
  42. //
  43. // 1) All LM stores are considered protected.
  44. //
  45. break;
  46. }
  47. case CAPICOM_CURRENT_USER_STORE:
  48. {
  49. //
  50. // Sanity check.
  51. //
  52. ATLASSERT(pwszStoreName);
  53. //
  54. // 2) CU\Root, CU\AuthRoot, CU\TrustedPeople, CU\TrustedPublisher,
  55. // and CU\Disallowed are considered protected.
  56. //
  57. if (0 != _wcsicmp(L"root", pwszStoreName) &&
  58. 0 != _wcsicmp(L"authroot", pwszStoreName) &&
  59. 0 != _wcsicmp(L"trustedpeople", pwszStoreName) &&
  60. 0 != _wcsicmp(L"trustedpublisher", pwszStoreName) &&
  61. 0 != _wcsicmp(L"disallowed", pwszStoreName))
  62. {
  63. bIsProtected = FALSE;
  64. }
  65. break;
  66. }
  67. case CAPICOM_MEMORY_STORE:
  68. case CAPICOM_ACTIVE_DIRECTORY_USER_STORE:
  69. case CAPICOM_SMART_CARD_USER_STORE:
  70. {
  71. //
  72. // Memory backed store is not protected.
  73. //
  74. bIsProtected = FALSE;
  75. break;
  76. }
  77. default:
  78. {
  79. //
  80. // 3) All error conditions would be considered as protected.
  81. //
  82. break;
  83. }
  84. }
  85. return bIsProtected;
  86. }
  87. ////////////////////////////////////////////////////////////////////////////////
  88. //
  89. // CStore
  90. //
  91. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  92. Function : CStore::get_Certificates
  93. Synopsis : Get the ICertificates collection object.
  94. Parameter: ICertificates ** ppCertificates - Pointer to pointer to
  95. ICertificates to receive the
  96. interface pointer.
  97. Remark : This is the default property which returns an ICertificates
  98. collection object, which can then be accessed using standard COM
  99. collection interface.
  100. The collection is not ordered, and can be accessed using a 1-based
  101. numeric index.
  102. Note that the collection is a snapshot of all current certificates
  103. in the store. In other words, the collection will not be affected
  104. by Add/Remove operations after the collection is obtained.
  105. ------------------------------------------------------------------------------*/
  106. STDMETHODIMP CStore::get_Certificates (ICertificates ** pVal)
  107. {
  108. HRESULT hr = S_OK;
  109. CComPtr<ICertificates2> pICertificates2 = NULL;
  110. CAPICOM_CERTIFICATES_SOURCE ccs = {CAPICOM_CERTIFICATES_LOAD_FROM_STORE, 0};
  111. DebugTrace("Entering CStore::get_Certificates().\n");
  112. try
  113. {
  114. //
  115. // Lock access to this object.
  116. //
  117. m_Lock.Lock();
  118. //
  119. // Check parameters.
  120. //
  121. if (NULL == pVal)
  122. {
  123. hr = E_INVALIDARG;
  124. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  125. goto ErrorExit;
  126. }
  127. //
  128. // Is the store object opened?
  129. //
  130. if (!m_hCertStore)
  131. {
  132. hr = CAPICOM_E_STORE_NOT_OPENED;
  133. DebugTrace("Error [%#x]: store has not been opened.\n", hr);
  134. goto ErrorExit;
  135. }
  136. //
  137. // Create the ICertificates2 collection object.
  138. //
  139. ccs.hCertStore = m_hCertStore;
  140. if (FAILED(hr = ::CreateCertificatesObject(ccs, m_dwCurrentSafety, TRUE, &pICertificates2)))
  141. {
  142. DebugTrace("Error [%#x]: CreateCertificatesObject() failed.\n", hr);
  143. goto ErrorExit;
  144. }
  145. //
  146. // Return ICertificates to calller.
  147. //
  148. if (FAILED(hr = pICertificates2->QueryInterface(__uuidof(ICertificates), (void **) pVal)))
  149. {
  150. DebugTrace("Error [%#x]: pICertificates2->QueryInterface() failed.\n", hr);
  151. goto ErrorExit;
  152. }
  153. }
  154. catch(...)
  155. {
  156. hr = E_INVALIDARG;
  157. DebugTrace("Exception: invalid parameter.\n");
  158. goto ErrorExit;
  159. }
  160. UnlockExit:
  161. //
  162. // Unlock access to this object.
  163. //
  164. m_Lock.Unlock();
  165. DebugTrace("Leaving CStore::get_Certificates().\n");
  166. return hr;
  167. ErrorExit:
  168. //
  169. // Sanity check.
  170. //
  171. ATLASSERT(FAILED(hr));
  172. ReportError(hr);
  173. goto UnlockExit;
  174. }
  175. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  176. Function : CStore::Open
  177. Synopsis : Open a certificate store for read/write. Note that for MEMORY_STORE
  178. and ACTIVE_DIRECTORY_USER_STORE, the write operation does not
  179. persist the certificate.
  180. Parameter: CAPICOM_STORE_LOCATION StoreLocation - Store location.
  181. BSTR StoreName - Store name or NULL.
  182. For:
  183. MEMORY_STORE - This argument is ignored.
  184. LOCAL_MACHINE_STORE - System store name or NULL.
  185. If NULL, then "MY" is used.
  186. CURRENT_USER_STORE - See explaination for
  187. LOCAL_MACHINE_STORE.
  188. ACTIVE_DIRECTORY_USER_STORE - LDAP filter for user container
  189. or NULL,.
  190. If NULL, then all users in the
  191. default domain will be
  192. included, so this can be very
  193. slow.
  194. If not NULL, then it should
  195. resolve to group of 0 or more
  196. users.
  197. For example,
  198. "cn=Daniel Sie"
  199. "cn=Daniel *"
  200. "sn=Sie"
  201. "mailNickname=dsie"
  202. "[email protected]"
  203. "distinguishedName=CN=Daniel Sie,OU=Users,OU=ITG,DC=ntdev,DC=microsoft,DC=com"
  204. "|((cn=Daniel Sie)(sn=Hallin))"
  205. SMART_CARD_STORE - This is ignored.
  206. CAPICOM_STORE_OPEN_MODE OpenMode - Always force to read only for
  207. MEMORY_STORE,
  208. ACTIVE_DIRECTORY_USER_STORE,
  209. and SMART_CARD_STORE.
  210. Remark :
  211. ------------------------------------------------------------------------------*/
  212. STDMETHODIMP CStore::Open (CAPICOM_STORE_LOCATION StoreLocation,
  213. BSTR StoreName,
  214. CAPICOM_STORE_OPEN_MODE OpenMode)
  215. {
  216. HRESULT hr = S_OK;
  217. LPWSTR wszName = NULL;
  218. LPCSTR szProvider = (LPCSTR) CERT_STORE_PROV_SYSTEM;
  219. DWORD dwModeFlag = 0;
  220. DWORD dwArchivedFlag = 0;
  221. DWORD dwOpenExistingFlag = 0;
  222. DWORD dwLocationFlag = 0;
  223. HCERTSTORE hCertStore = NULL;
  224. HMODULE hDSClientDLL = NULL;
  225. HMODULE hWinSCardDLL = NULL;
  226. DebugTrace("Entering CStore::Open().\n");
  227. try
  228. {
  229. //
  230. // Lock access to this object.
  231. //
  232. m_Lock.Lock();
  233. //
  234. // Can't open remote store if called from WEB script.
  235. //
  236. if (m_dwCurrentSafety && wcschr(StoreName, L'\\'))
  237. {
  238. hr = CAPICOM_E_NOT_ALLOWED;
  239. DebugTrace("Error [%#x]: Openning remote store from WEB script is not allowed.\n", hr);
  240. goto ErrorExit;
  241. }
  242. //
  243. // Make sure parameters are valid.
  244. //
  245. switch (OpenMode & 0x3) // Only the last two bits.
  246. {
  247. case CAPICOM_STORE_OPEN_READ_ONLY:
  248. {
  249. dwModeFlag = CERT_STORE_READONLY_FLAG;
  250. break;
  251. }
  252. case CAPICOM_STORE_OPEN_READ_WRITE:
  253. {
  254. break;
  255. }
  256. case CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED:
  257. {
  258. dwModeFlag = CERT_STORE_MAXIMUM_ALLOWED_FLAG;
  259. break;
  260. }
  261. default:
  262. {
  263. hr = E_INVALIDARG;
  264. DebugTrace("Error [%#x]: Unknown store open mode (%#x).\n", hr, OpenMode);
  265. goto ErrorExit;
  266. }
  267. }
  268. //
  269. // Set open existing flag if WEB client or specifically requested.
  270. //
  271. if (m_dwCurrentSafety || (OpenMode & CAPICOM_STORE_OPEN_EXISTING_ONLY))
  272. {
  273. dwOpenExistingFlag = CERT_STORE_OPEN_EXISTING_FLAG;
  274. }
  275. //
  276. // Set archive flag if requested.
  277. //
  278. if (OpenMode & CAPICOM_STORE_OPEN_INCLUDE_ARCHIVED)
  279. {
  280. dwArchivedFlag = CERT_STORE_ENUM_ARCHIVED_FLAG;
  281. }
  282. switch (StoreLocation)
  283. {
  284. case CAPICOM_MEMORY_STORE:
  285. {
  286. wszName = NULL;
  287. szProvider = (LPSTR) CERT_STORE_PROV_MEMORY;
  288. dwModeFlag = CERT_STORE_READONLY_FLAG;
  289. break;
  290. }
  291. case CAPICOM_LOCAL_MACHINE_STORE:
  292. {
  293. wszName = StoreName;
  294. dwLocationFlag = CERT_SYSTEM_STORE_LOCAL_MACHINE;
  295. break;
  296. }
  297. case CAPICOM_CURRENT_USER_STORE:
  298. {
  299. wszName = StoreName;
  300. dwLocationFlag = CERT_SYSTEM_STORE_CURRENT_USER;
  301. break;
  302. }
  303. case CAPICOM_ACTIVE_DIRECTORY_USER_STORE:
  304. {
  305. //
  306. // Make sure DSClient is installed.
  307. //
  308. if (!(hDSClientDLL = ::LoadLibrary("ActiveDS.dll")))
  309. {
  310. hr = CAPICOM_E_NOT_SUPPORTED;
  311. DebugTrace("Error [%#x]: DSClient not installed.\n", hr);
  312. goto ErrorExit;
  313. }
  314. wszName = NULL;
  315. szProvider = (LPSTR) CERT_STORE_PROV_MEMORY;
  316. dwModeFlag = CERT_STORE_READONLY_FLAG;
  317. break;
  318. }
  319. case CAPICOM_SMART_CARD_USER_STORE:
  320. {
  321. //
  322. // Make sure WIn2K and above.
  323. //
  324. if (!IsWin2KAndAbove())
  325. {
  326. hr = CAPICOM_E_NOT_SUPPORTED;
  327. DebugTrace("Error [%#x]: Smart Card store not supported for pre-W2K platforms.\n", hr);
  328. goto ErrorExit;
  329. }
  330. wszName = NULL;
  331. szProvider = (LPSTR) CERT_STORE_PROV_MEMORY;
  332. dwModeFlag = CERT_STORE_READONLY_FLAG;
  333. break;
  334. }
  335. default:
  336. {
  337. hr = E_INVALIDARG;
  338. DebugTrace("Error [%#x]: Unknown store location (%#x).\n", hr, StoreLocation);
  339. goto ErrorExit;
  340. }
  341. }
  342. //
  343. // Prompt user for approval to open store, if called from WEB script.
  344. //
  345. if ((m_dwCurrentSafety) &&
  346. (StoreLocation != CAPICOM_MEMORY_STORE) &&
  347. (FAILED(hr = OperationApproved(IDD_STORE_OPEN_SECURITY_ALERT_DLG))))
  348. {
  349. DebugTrace("Error [%#x]: OperationApproved() failed.\n", hr);
  350. goto ErrorExit;
  351. }
  352. //
  353. // First close the store.
  354. //
  355. if (FAILED(hr = Close()))
  356. {
  357. DebugTrace("Error [%#x]: CStore::Close().\n", hr);
  358. goto ErrorExit;
  359. }
  360. //
  361. // Call CAPI to open the store.
  362. //
  363. if (!(hCertStore = ::CertOpenStore(szProvider,
  364. CAPICOM_ASN_ENCODING,
  365. NULL,
  366. dwModeFlag |
  367. dwLocationFlag |
  368. dwArchivedFlag |
  369. dwOpenExistingFlag |
  370. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  371. (void *) (LPCWSTR) wszName)))
  372. {
  373. hr = HRESULT_FROM_WIN32(::GetLastError());
  374. DebugTrace("Error [%#x]: CertOpenStore() failed.\n", hr);
  375. goto ErrorExit;
  376. }
  377. //
  378. // Load certificates from virtual stores, if necessary.
  379. //
  380. switch (StoreLocation)
  381. {
  382. case CAPICOM_ACTIVE_DIRECTORY_USER_STORE:
  383. {
  384. //
  385. // Load userCertificate from the active directory.
  386. //
  387. if (FAILED(hr = ::LoadFromDirectory(hCertStore, StoreName)))
  388. {
  389. DebugTrace("Error [%#x]: LoadFromDirectory() failed.\n", hr);
  390. goto ErrorExit;
  391. }
  392. break;
  393. }
  394. case CAPICOM_SMART_CARD_USER_STORE:
  395. {
  396. //
  397. // Load certificate(s) from all smart card readers.
  398. //
  399. if (FAILED(hr = ::LoadFromSmartCard(hCertStore)))
  400. {
  401. DebugTrace("Error [%#x]: LoadFromSmartCard() failed.\n", hr);
  402. goto ErrorExit;
  403. }
  404. break;
  405. }
  406. default:
  407. {
  408. //
  409. // Not virtual store, so nothing to load.
  410. //
  411. break;
  412. }
  413. }
  414. //
  415. // Update member variables.
  416. //
  417. m_hCertStore = hCertStore;
  418. m_StoreLocation = StoreLocation;
  419. m_bIsProtected = ::IsProtectedStore(StoreLocation, StoreName);
  420. DebugTrace("Info: CStore::Open() for %s store.\n", m_bIsProtected ? "protected" : "non-protected");
  421. }
  422. catch(...)
  423. {
  424. hr = E_INVALIDARG;
  425. DebugTrace("Exception: invalid parameter.\n");
  426. goto ErrorExit;
  427. }
  428. UnlockExit:
  429. //
  430. // Free resource.
  431. //
  432. if (hDSClientDLL)
  433. {
  434. ::FreeLibrary(hDSClientDLL);
  435. }
  436. if (hWinSCardDLL)
  437. {
  438. ::FreeLibrary(hWinSCardDLL);
  439. }
  440. //
  441. // Unlock access to this object.
  442. //
  443. m_Lock.Unlock();
  444. DebugTrace("Leaving CStore::Open().\n");
  445. return hr;
  446. ErrorExit:
  447. //
  448. // Sanity check.
  449. //
  450. ATLASSERT(FAILED(hr));
  451. //
  452. // Free resource.
  453. //
  454. if (hCertStore)
  455. {
  456. ::CertCloseStore(hCertStore, 0);
  457. }
  458. ReportError(hr);
  459. goto UnlockExit;
  460. }
  461. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  462. Function : CStore::Add
  463. Synopsis : Add a certificate to the store.
  464. Parameter: ICertificate * pVal - Pointer to ICertificate to add.
  465. Remark : If called from web, UI will be displayed, if has not been
  466. previuosly disabled, to solicit user's permission to add
  467. certificate to the system store.
  468. Added certificates are not persisted for non-system stores.
  469. ------------------------------------------------------------------------------*/
  470. STDMETHODIMP CStore::Add (ICertificate * pVal)
  471. {
  472. HRESULT hr = S_OK;
  473. PCCERT_CONTEXT pCertContext = NULL;
  474. CComPtr<ICertificate> pICertificate = NULL;
  475. DebugTrace("Entering CStore::Add().\n");
  476. try
  477. {
  478. //
  479. // Lock access to this object.
  480. //
  481. m_Lock.Lock();
  482. //
  483. // QI for ICertificate pointer (Just to make sure it is indeed
  484. // an ICertificate object).
  485. //
  486. if (!(pICertificate = pVal))
  487. {
  488. hr = E_INVALIDARG;
  489. DebugTrace("Error [%#x]: Parameter pVal is not an ICertificate interface pointer.\n", hr);
  490. goto ErrorExit;
  491. }
  492. //
  493. // Is the store object opened?
  494. //
  495. if (!m_hCertStore)
  496. {
  497. hr = CAPICOM_E_STORE_NOT_OPENED;
  498. DebugTrace("Error [%#x]: Store has not been opened.\n", hr);
  499. goto ErrorExit;
  500. }
  501. //
  502. // Add is not allowed for protected store when called from WEB script.
  503. //
  504. if (m_dwCurrentSafety)
  505. {
  506. DebugTrace("Info: CStore::Add called from WEB script.\n");
  507. if (m_bIsProtected)
  508. {
  509. hr = CAPICOM_E_NOT_ALLOWED;
  510. DebugTrace("Error [%#x]: Adding to this store is not allowed from WEB script.\n", hr);
  511. goto ErrorExit;
  512. }
  513. if (CAPICOM_CURRENT_USER_STORE != m_StoreLocation &&
  514. CAPICOM_LOCAL_MACHINE_STORE != m_StoreLocation &&
  515. FAILED(hr = OperationApproved(IDD_STORE_ADD_SECURITY_ALERT_DLG)))
  516. {
  517. DebugTrace("Error [%#x]: OperationApproved() failed.\n", hr);
  518. goto ErrorExit;
  519. }
  520. }
  521. //
  522. // Get cert context from certificate object.
  523. //
  524. if (FAILED(hr = ::GetCertContext(pICertificate, &pCertContext)))
  525. {
  526. DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
  527. goto ErrorExit;
  528. }
  529. //
  530. // Sanity check.
  531. //
  532. ATLASSERT(pCertContext);
  533. //
  534. // Add to the store.
  535. //
  536. if (!::CertAddCertificateContextToStore(m_hCertStore,
  537. pCertContext,
  538. CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES,
  539. NULL))
  540. {
  541. hr = HRESULT_FROM_WIN32(::GetLastError());
  542. DebugTrace("Error [%#x]: CertAddCertificateContextToStore() failed.\n", hr);
  543. goto ErrorExit;
  544. }
  545. }
  546. catch(...)
  547. {
  548. hr = E_INVALIDARG;
  549. DebugTrace("Exception: invalid parameter.\n");
  550. goto ErrorExit;
  551. }
  552. UnlockExit:
  553. //
  554. // Free resource.
  555. //
  556. if (pCertContext)
  557. {
  558. ::CertFreeCertificateContext(pCertContext);
  559. }
  560. //
  561. // Unlock access to this object.
  562. //
  563. m_Lock.Unlock();
  564. DebugTrace("Leaving CStore::Add().\n");
  565. return hr;
  566. ErrorExit:
  567. //
  568. // Sanity check.
  569. //
  570. ATLASSERT(FAILED(hr));
  571. ReportError(hr);
  572. goto UnlockExit;
  573. }
  574. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  575. Function : CStore::Remove
  576. Synopsis : Remove a certificate from the store.
  577. Parameter: ICertificate * - Pointer to certificate object to remove.
  578. Remark : If called from web, UI will be displayed, if has not been
  579. previuosly disabled, to solicit user's permission to remove
  580. certificate to the system store.
  581. Removed certificates are not persisted for non-system stores.
  582. ------------------------------------------------------------------------------*/
  583. STDMETHODIMP CStore::Remove (ICertificate * pVal)
  584. {
  585. HRESULT hr = S_OK;
  586. PCCERT_CONTEXT pCertContext = NULL;
  587. PCCERT_CONTEXT pCertContext2 = NULL;
  588. CComPtr<ICertificate> pICertificate = NULL;
  589. BOOL bResult = FALSE;
  590. DebugTrace("Entering CStore::Remove().\n");
  591. try
  592. {
  593. //
  594. // Lock access to this object.
  595. //
  596. m_Lock.Lock();
  597. //
  598. // QI for ICertificate pointer (Just to make sure it is indeed
  599. // an ICertificate object).
  600. //
  601. if (!(pICertificate = pVal))
  602. {
  603. hr = E_INVALIDARG;
  604. DebugTrace("Error [%#x]: Parameter pVal is not an ICertificate interface pointer.\n", hr);
  605. goto ErrorExit;
  606. }
  607. //
  608. // Is the store object opened?
  609. //
  610. if (!m_hCertStore)
  611. {
  612. hr = CAPICOM_E_STORE_NOT_OPENED;
  613. DebugTrace("Error [%#x]: Store has not been opened.\n", hr);
  614. goto ErrorExit;
  615. }
  616. //
  617. // Remove is not allowed for protected store when called from WEB script.
  618. //
  619. if (m_dwCurrentSafety)
  620. {
  621. DebugTrace("Info: CStore::Remove called from WEB script.\n");
  622. if (m_bIsProtected)
  623. {
  624. hr = CAPICOM_E_NOT_ALLOWED;
  625. DebugTrace("Error [%#x]: Removing from this store is not allowed from WEB script.\n", hr);
  626. goto ErrorExit;
  627. }
  628. if (CAPICOM_CURRENT_USER_STORE != m_StoreLocation &&
  629. CAPICOM_LOCAL_MACHINE_STORE != m_StoreLocation &&
  630. FAILED(hr = OperationApproved(IDD_STORE_REMOVE_SECURITY_ALERT_DLG)))
  631. {
  632. DebugTrace("Error [%#x]: OperationApproved() failed.\n", hr);
  633. goto ErrorExit;
  634. }
  635. }
  636. //
  637. // Get cert context from certificate object.
  638. //
  639. if (FAILED(hr = ::GetCertContext(pICertificate, &pCertContext)))
  640. {
  641. DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
  642. goto ErrorExit;
  643. }
  644. //
  645. // Sanity check.
  646. //
  647. ATLASSERT(pCertContext);
  648. //
  649. // Find the cert in store.
  650. //
  651. if (!(pCertContext2 = ::CertFindCertificateInStore(m_hCertStore,
  652. CAPICOM_ASN_ENCODING,
  653. 0,
  654. CERT_FIND_EXISTING,
  655. (const void *) pCertContext,
  656. NULL)))
  657. {
  658. DebugTrace("Error [%#x]: CertFindCertificateInStore() failed.\n", hr);
  659. goto ErrorExit;
  660. }
  661. //
  662. // Sanity check.
  663. //
  664. ATLASSERT(pCertContext2);
  665. //
  666. // Remove from the store.
  667. //
  668. bResult =::CertDeleteCertificateFromStore(pCertContext2);
  669. //
  670. // Since CertDeleteCertificateFromStore always release the
  671. // context regardless of success or failure, we must first
  672. // NULL the CERT_CONTEXT before checking for result.
  673. //
  674. pCertContext2 = NULL;
  675. if (!bResult)
  676. {
  677. hr = HRESULT_FROM_WIN32(::GetLastError());
  678. DebugTrace("Error [%#x]: CertDeleteCertificateFromStore() failed.\n", hr);
  679. goto ErrorExit;
  680. }
  681. }
  682. catch(...)
  683. {
  684. hr = E_INVALIDARG;
  685. DebugTrace("Exception: invalid parameter.\n");
  686. goto ErrorExit;
  687. }
  688. UnlockExit:
  689. //
  690. // Free resource.
  691. //
  692. if (pCertContext2)
  693. {
  694. ::CertFreeCertificateContext(pCertContext2);
  695. }
  696. if (pCertContext)
  697. {
  698. ::CertFreeCertificateContext(pCertContext);
  699. }
  700. //
  701. // Unlock access to this object.
  702. //
  703. m_Lock.Unlock();
  704. DebugTrace("Leaving CStore::Remove().\n");
  705. return hr;
  706. ErrorExit:
  707. //
  708. // Sanity check.
  709. //
  710. ATLASSERT(FAILED(hr));
  711. ReportError(hr);
  712. goto UnlockExit;
  713. }
  714. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  715. Function : CStore:Export
  716. Synopsis : Export all certificates in the store.
  717. Parameter: CAPICOM_STORE_SAVE_AS_TYPE SaveAs - Save as type.
  718. CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
  719. BSTR * pVal - Pointer to BSTR to receive the store blob.
  720. Remark : If called from web, UI will be displayed, if has not been
  721. previuosly disabled, to solicit user's permission to export
  722. certificate from the system store.
  723. ------------------------------------------------------------------------------*/
  724. STDMETHODIMP CStore::Export (CAPICOM_STORE_SAVE_AS_TYPE SaveAs,
  725. CAPICOM_ENCODING_TYPE EncodingType,
  726. BSTR * pVal)
  727. {
  728. HRESULT hr = S_OK;
  729. DWORD dwSaveAs = 0;
  730. DATA_BLOB DataBlob = {0, NULL};
  731. DebugTrace("Entering CStore::Export().\n");
  732. try
  733. {
  734. //
  735. // Lock access to this object.
  736. //
  737. m_Lock.Lock();
  738. //
  739. // Check parameters.
  740. //
  741. if (NULL == pVal)
  742. {
  743. hr = E_INVALIDARG;
  744. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  745. goto ErrorExit;
  746. }
  747. //
  748. // Determine SaveAs type.
  749. //
  750. switch (SaveAs)
  751. {
  752. case CAPICOM_STORE_SAVE_AS_SERIALIZED:
  753. {
  754. dwSaveAs = CERT_STORE_SAVE_AS_STORE;
  755. break;
  756. }
  757. case CAPICOM_STORE_SAVE_AS_PKCS7:
  758. {
  759. dwSaveAs = CERT_STORE_SAVE_AS_PKCS7;
  760. break;
  761. }
  762. default:
  763. {
  764. hr = E_INVALIDARG;
  765. DebugTrace("Error: invalid parameter, unknown save as type.\n");
  766. goto ErrorExit;
  767. }
  768. }
  769. //
  770. // Is the store object opened?
  771. //
  772. if (!m_hCertStore)
  773. {
  774. hr = CAPICOM_E_STORE_NOT_OPENED;
  775. DebugTrace("Error [%#x]: store has not been opened.\n", hr);
  776. goto ErrorExit;
  777. }
  778. //
  779. // Determine required length.
  780. //
  781. if (!::CertSaveStore(m_hCertStore, // in
  782. CAPICOM_ASN_ENCODING, // in
  783. dwSaveAs, // in
  784. CERT_STORE_SAVE_TO_MEMORY, // in
  785. (void *) &DataBlob, // in/out
  786. 0)) // in
  787. {
  788. hr = HRESULT_FROM_WIN32(GetLastError());
  789. DebugTrace("Error [%#x]: CertSaveStore() failed.\n", hr);
  790. goto ErrorExit;
  791. }
  792. //
  793. // Allocate memory.
  794. //
  795. if (!(DataBlob.pbData = (BYTE *) ::CoTaskMemAlloc(DataBlob.cbData)))
  796. {
  797. hr = E_OUTOFMEMORY;
  798. DebugTrace("Error [%#x]: DataBlob.pbData = (BYTE *) ::CoTaskMemAlloc(DataBlob.cbData).\n", hr);
  799. goto ErrorExit;
  800. }
  801. //
  802. // Now save the store to memory blob.
  803. //
  804. if (!::CertSaveStore(m_hCertStore, // in
  805. CAPICOM_ASN_ENCODING, // in
  806. dwSaveAs, // in
  807. CERT_STORE_SAVE_TO_MEMORY, // in
  808. (void *) &DataBlob, // in/out
  809. 0)) // in
  810. {
  811. hr = HRESULT_FROM_WIN32(::GetLastError());
  812. DebugTrace("Error [%#x]: CertSaveStore() failed.\n", hr);
  813. goto ErrorExit;
  814. }
  815. //
  816. // Export store.
  817. //
  818. if (FAILED(hr = ::ExportData(DataBlob, EncodingType, pVal)))
  819. {
  820. DebugTrace("Error [%#x]: ExportData() failed.\n", hr);
  821. goto ErrorExit;
  822. }
  823. }
  824. catch(...)
  825. {
  826. hr = E_INVALIDARG;
  827. DebugTrace("Exception: invalid parameter.\n");
  828. goto ErrorExit;
  829. }
  830. UnlockExit:
  831. //
  832. // Free resource.
  833. //
  834. if (DataBlob.pbData)
  835. {
  836. ::CoTaskMemFree((LPVOID) DataBlob.pbData);
  837. }
  838. //
  839. // Unlock access to this object.
  840. //
  841. m_Lock.Unlock();
  842. DebugTrace("Leaving CStore::Export().\n");
  843. return hr;
  844. ErrorExit:
  845. //
  846. // Sanity check.
  847. //
  848. ATLASSERT(FAILED(hr));
  849. ReportError(hr);
  850. goto UnlockExit;
  851. }
  852. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  853. Function : CStore::Import
  854. Synopsis : Import either a serialized or PKCS #7 certificate store.
  855. Parameter: BSTR EncodedStore - Pointer to BSTR containing the encoded
  856. store blob.
  857. Remark : Note that the SaveAs and EncodingType will be determined
  858. automatically.
  859. If called from web, UI will be displayed, if has not been
  860. previuosly disabled, to solicit user's permission to import
  861. certificate to the system store.
  862. ------------------------------------------------------------------------------*/
  863. STDMETHODIMP CStore::Import (BSTR EncodedStore)
  864. {
  865. HRESULT hr = S_OK;
  866. DATA_BLOB StoreBlob = {0, NULL};
  867. DebugTrace("Entering CStore::Import().\n");
  868. try
  869. {
  870. //
  871. // Lock access to this object.
  872. //
  873. m_Lock.Lock();
  874. //
  875. // Make sure parameters are valid.
  876. //
  877. if ((NULL == (StoreBlob.pbData = (LPBYTE) EncodedStore)) ||
  878. (0 == (StoreBlob.cbData = ::SysStringByteLen(EncodedStore))))
  879. {
  880. hr = E_INVALIDARG;
  881. DebugTrace("Error [%#x]: Parameter EncodedStore is NULL or empty.\n", hr);
  882. goto ErrorExit;
  883. }
  884. //
  885. // Is the store object opened?
  886. //
  887. if (!m_hCertStore)
  888. {
  889. hr = CAPICOM_E_STORE_NOT_OPENED;
  890. DebugTrace("Error [%#x]: store has not been opened.\n", hr);
  891. goto ErrorExit;
  892. }
  893. //
  894. // Import is not allowed if the store is protected when called from
  895. // WEB script.
  896. //
  897. if (m_dwCurrentSafety)
  898. {
  899. DebugTrace("Info: CStore::Import called from WEB script.\n");
  900. if (m_bIsProtected)
  901. {
  902. hr = CAPICOM_E_NOT_ALLOWED;
  903. DebugTrace("Error [%#x]: Importing to this store is not allowed from WEB script.\n", hr);
  904. goto ErrorExit;
  905. }
  906. if (CAPICOM_CURRENT_USER_STORE != m_StoreLocation &&
  907. CAPICOM_LOCAL_MACHINE_STORE != m_StoreLocation &&
  908. FAILED(hr = OperationApproved(IDD_STORE_ADD_SECURITY_ALERT_DLG)))
  909. {
  910. DebugTrace("Error [%#x]: OperationApproved() failed.\n", hr);
  911. goto ErrorExit;
  912. }
  913. }
  914. //
  915. // Now import the blob.
  916. //
  917. if (FAILED(hr = ImportCertObject(CERT_QUERY_OBJECT_BLOB,
  918. (LPVOID) &StoreBlob,
  919. FALSE,
  920. NULL,
  921. (CAPICOM_KEY_STORAGE_FLAG) 0)))
  922. {
  923. DebugTrace("Error [%#x]: CStore::ImportCertObject() failed.\n", hr);
  924. goto ErrorExit;
  925. }
  926. }
  927. catch(...)
  928. {
  929. hr = E_INVALIDARG;
  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 CStore::Import().\n");
  939. return hr;
  940. ErrorExit:
  941. //
  942. // Sanity check.
  943. //
  944. ATLASSERT(FAILED(hr));
  945. ReportError(hr);
  946. goto UnlockExit;
  947. }
  948. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  949. Function : CStore::Load
  950. Synopsis : Method to load certificate(s) from a file.
  951. Parameter: BSTR FileName - File name.
  952. BSTR Password - Password (required for PFX file.)
  953. CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag - Key storage flag.
  954. Remark :
  955. ------------------------------------------------------------------------------*/
  956. STDMETHODIMP CStore::Load (BSTR FileName,
  957. BSTR Password,
  958. CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag)
  959. {
  960. HRESULT hr = S_OK;
  961. DebugTrace("Entering CStore::Load().\n");
  962. try
  963. {
  964. //
  965. // Lock access to this object.
  966. //
  967. m_Lock.Lock();
  968. //
  969. // Make sure parameters are valid.
  970. //
  971. if (0 == ::SysStringLen(FileName))
  972. {
  973. hr = E_INVALIDARG;
  974. DebugTrace("Error [%#x]: Paremeter FileName is NULL or empty.\n", hr);
  975. goto ErrorExit;
  976. }
  977. //
  978. // Work around MIDL problem.
  979. //
  980. if (0 == ::SysStringLen(Password))
  981. {
  982. Password = NULL;
  983. }
  984. //
  985. // Is the store object opened?
  986. //
  987. if (!m_hCertStore)
  988. {
  989. hr = CAPICOM_E_STORE_NOT_OPENED;
  990. DebugTrace("Error [%#x]: store has not been opened.\n", hr);
  991. goto ErrorExit;
  992. }
  993. //
  994. // Not allowed if called from WEB script.
  995. //
  996. if (m_dwCurrentSafety)
  997. {
  998. hr = CAPICOM_E_NOT_ALLOWED;
  999. DebugTrace("Error [%#x]: Loading cert file from WEB script is not allowed.\n", hr);
  1000. goto ErrorExit;
  1001. }
  1002. //
  1003. // Make sure it is a disk file.
  1004. //
  1005. if (FAILED(hr = ::IsDiskFile(FileName)))
  1006. {
  1007. DebugTrace("Error [%#x]: CStore::IsDiskFile() failed.\n", hr);
  1008. goto ErrorExit;
  1009. }
  1010. //
  1011. // Now import the blob.
  1012. //
  1013. if (FAILED(hr = ImportCertObject(CERT_QUERY_OBJECT_FILE,
  1014. (LPVOID) FileName,
  1015. TRUE,
  1016. Password,
  1017. KeyStorageFlag)))
  1018. {
  1019. DebugTrace("Error [%#x]: CStore::ImportCertObject() failed.\n", hr);
  1020. goto ErrorExit;
  1021. }
  1022. }
  1023. catch(...)
  1024. {
  1025. hr = E_POINTER;
  1026. DebugTrace("Exception: invalid parameter.\n");
  1027. goto ErrorExit;
  1028. }
  1029. UnlockExit:
  1030. //
  1031. // Unlock access to this object.
  1032. //
  1033. m_Lock.Unlock();
  1034. DebugTrace("Leaving CStore::Load().\n");
  1035. return hr;
  1036. ErrorExit:
  1037. //
  1038. // Sanity check.
  1039. //
  1040. ATLASSERT(FAILED(hr));
  1041. ReportError(hr);
  1042. goto UnlockExit;
  1043. }
  1044. ////////////////////////////////////////////////////////////////////////////////
  1045. //
  1046. // Custom interfaces.
  1047. //
  1048. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1049. Function : CStore::get_StoreHandle
  1050. Synopsis : Return the store's HCERTSTORE.
  1051. Parameter: long * pphCertStore - Pointer to HCERTSTORE disguished in a long.
  1052. Remark : We need to use long instead of HCERTSTORE because VB can't handle
  1053. double indirection (i.e. vb would bark on this HCERTSTORE *
  1054. phCertStore, as HCERTSTORE is defined as void *).
  1055. ------------------------------------------------------------------------------*/
  1056. STDMETHODIMP CStore::get_StoreHandle (long * phCertStore)
  1057. {
  1058. HRESULT hr = S_OK;
  1059. HCERTSTORE hCertStore = NULL;
  1060. DebugTrace("Entering CStore::get_StoreHandle().\n");
  1061. try
  1062. {
  1063. //
  1064. // Lock access to this object.
  1065. //
  1066. m_Lock.Lock();
  1067. //
  1068. // Check parameters.
  1069. //
  1070. if (NULL == phCertStore)
  1071. {
  1072. hr = E_INVALIDARG;
  1073. DebugTrace("Error [%#x]: Parameter phCertStore is NULL.\n", hr);
  1074. goto ErrorExit;
  1075. }
  1076. //
  1077. // Is the store object opened?
  1078. //
  1079. if (!m_hCertStore)
  1080. {
  1081. hr = CAPICOM_E_STORE_NOT_OPENED;
  1082. DebugTrace("Error [%#x]: store has not been opened.\n", hr);
  1083. goto ErrorExit;
  1084. }
  1085. //
  1086. // Duplicate the HCERTSTORE.
  1087. //
  1088. if (!(hCertStore = ::CertDuplicateStore(m_hCertStore)))
  1089. {
  1090. DebugTrace("Error [%#x]: CertDuplicateStore() failed.\n", hr);
  1091. goto ErrorExit;
  1092. }
  1093. //
  1094. // Returen handle to caller.
  1095. //
  1096. *phCertStore = (long) hCertStore;
  1097. }
  1098. catch(...)
  1099. {
  1100. hr = E_POINTER;
  1101. DebugTrace("Exception: invalid parameter.\n");
  1102. goto ErrorExit;
  1103. }
  1104. UnlockExit:
  1105. //
  1106. // Unlock access to this object.
  1107. //
  1108. m_Lock.Unlock();
  1109. DebugTrace("Leaving CStore::get_StoreHandle().\n");
  1110. return hr;
  1111. ErrorExit:
  1112. //
  1113. // Sanity check.
  1114. //
  1115. ATLASSERT(FAILED(hr));
  1116. ReportError(hr);
  1117. goto UnlockExit;
  1118. }
  1119. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1120. Function : CStore::put_StoreHandle
  1121. Synopsis : Initialize the object with a HCERTSTORE.
  1122. Parameter: long hCertStore - HCERTSTORE, disguised in a long, used to
  1123. initialize this object.
  1124. Remark : Note that this is NOT 64-bit compatiable. Plese see remark of
  1125. get_hCertStore for more detail.
  1126. ------------------------------------------------------------------------------*/
  1127. STDMETHODIMP CStore::put_StoreHandle (long hCertStore)
  1128. {
  1129. HRESULT hr = S_OK;
  1130. HCERTSTORE hCertStore2 = NULL;
  1131. DebugTrace("Entering CStore::put_StoreHandle().\n");
  1132. try
  1133. {
  1134. //
  1135. // Lock access to this object.
  1136. //
  1137. m_Lock.Lock();
  1138. //
  1139. // Check parameter.
  1140. //
  1141. if (0 == hCertStore)
  1142. {
  1143. hr = E_INVALIDARG;
  1144. DebugTrace("Error [%#x]: Parameter hCertStore is NULL.\n", hr);
  1145. goto ErrorExit;
  1146. }
  1147. //
  1148. // Duplicate the HCERTSTORE.
  1149. //
  1150. if (!(hCertStore2 = ::CertDuplicateStore((HCERTSTORE) hCertStore)))
  1151. {
  1152. DebugTrace("Error [%#x]: CertDuplicateStore() failed.\n", hr);
  1153. goto ErrorExit;
  1154. }
  1155. //
  1156. // Close the store.
  1157. //
  1158. if (FAILED(hr = Close()))
  1159. {
  1160. DebugTrace("Error [%#x]: CStore::Close() failed.\n", hr);
  1161. goto ErrorExit;
  1162. }
  1163. //
  1164. // Reset the object with this handle.
  1165. //
  1166. m_hCertStore = hCertStore2;
  1167. }
  1168. catch(...)
  1169. {
  1170. hr = E_POINTER;
  1171. DebugTrace("Exception: invalid parameter.\n");
  1172. goto ErrorExit;
  1173. }
  1174. UnlockExit:
  1175. //
  1176. // Unlock access to this object.
  1177. //
  1178. m_Lock.Unlock();
  1179. DebugTrace("Leaving CStore::put_StoreHandle().\n");
  1180. return hr;
  1181. ErrorExit:
  1182. //
  1183. // Sanity check.
  1184. //
  1185. ATLASSERT(FAILED(hr));
  1186. //
  1187. // Free resources.
  1188. //
  1189. if (hCertStore2)
  1190. {
  1191. ::CertCloseStore(hCertStore2, 0);
  1192. }
  1193. ReportError(hr);
  1194. goto UnlockExit;
  1195. }
  1196. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1197. Function : CStore::get_StoreLocation
  1198. Synopsis : Get the store location property.
  1199. Parameter: CAPICOM_STORE_LOCATION * pStoreLocation - Pointer to
  1200. CAPICOM_STORE_LOCATION
  1201. to recieve the value.
  1202. Remark : For custom interface, we only support CU, LM, and Memory store.
  1203. ------------------------------------------------------------------------------*/
  1204. STDMETHODIMP CStore::get_StoreLocation (CAPICOM_STORE_LOCATION * pStoreLocation)
  1205. {
  1206. HRESULT hr = S_OK;
  1207. DebugTrace("Entering CStore::get_StoreLocation().\n");
  1208. try
  1209. {
  1210. //
  1211. // Lock access to this object.
  1212. //
  1213. m_Lock.Lock();
  1214. //
  1215. // Check parameter.
  1216. //
  1217. if (NULL == pStoreLocation)
  1218. {
  1219. hr = E_INVALIDARG;
  1220. DebugTrace("Error [%#x]: Parameter pStoreLocation is NULL.\n", hr);
  1221. goto ErrorExit;
  1222. }
  1223. //
  1224. // Return value to caller.
  1225. //
  1226. *pStoreLocation = m_StoreLocation;
  1227. }
  1228. catch(...)
  1229. {
  1230. hr = E_POINTER;
  1231. DebugTrace("Exception: invalid parameter.\n");
  1232. goto ErrorExit;
  1233. }
  1234. UnlockExit:
  1235. //
  1236. // Unlock access to this object.
  1237. //
  1238. m_Lock.Unlock();
  1239. DebugTrace("Leaving CStore::get_StoreLocation().\n");
  1240. return hr;
  1241. ErrorExit:
  1242. //
  1243. // Sanity check.
  1244. //
  1245. ATLASSERT(FAILED(hr));
  1246. ReportError(hr);
  1247. goto UnlockExit;
  1248. }
  1249. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1250. Function : CStore::put_StoreLocation
  1251. Synopsis : Set the store location property.
  1252. Parameter: CAPICOM_STORE_LOCATION StoreLocation - Store location.
  1253. Remark : For custom interface, we only support CU, LM, and Memory store.
  1254. ------------------------------------------------------------------------------*/
  1255. STDMETHODIMP CStore::put_StoreLocation (CAPICOM_STORE_LOCATION StoreLocation)
  1256. {
  1257. HRESULT hr = S_OK;
  1258. DebugTrace("Entering CStore::put_StoreLocation().\n");
  1259. try
  1260. {
  1261. //
  1262. // Lock access to this object.
  1263. //
  1264. m_Lock.Lock();
  1265. //
  1266. // Make sure it is a CAPI store (CU, LM, or Memory).
  1267. //
  1268. switch (StoreLocation)
  1269. {
  1270. case CAPICOM_MEMORY_STORE:
  1271. case CAPICOM_LOCAL_MACHINE_STORE:
  1272. case CAPICOM_CURRENT_USER_STORE:
  1273. {
  1274. //
  1275. // Set it.
  1276. //
  1277. m_StoreLocation = StoreLocation;
  1278. break;
  1279. }
  1280. default:
  1281. {
  1282. hr = E_INVALIDARG;
  1283. DebugTrace("Error [%#x]: invalid store location (%#x).\n", hr, StoreLocation);
  1284. goto ErrorExit;
  1285. }
  1286. }
  1287. }
  1288. catch(...)
  1289. {
  1290. hr = E_POINTER;
  1291. DebugTrace("Exception: invalid parameter.\n");
  1292. goto ErrorExit;
  1293. }
  1294. UnlockExit:
  1295. //
  1296. // Unlock access to this object.
  1297. //
  1298. m_Lock.Unlock();
  1299. DebugTrace("Leaving CStore::put_StoreLocation().\n");
  1300. return hr;
  1301. ErrorExit:
  1302. //
  1303. // Sanity check.
  1304. //
  1305. ATLASSERT(FAILED(hr));
  1306. ReportError(hr);
  1307. goto UnlockExit;
  1308. }
  1309. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1310. Function : CStore::CloseHandle
  1311. Synopsis : Close a HCERTSTORE.
  1312. Parameter: long hCertStoret - HCERTSTORE, disguised in a long, to be closed.
  1313. Remark : Note that this is NOT 64-bit compatiable. Plese see remark of
  1314. get_hCertStore for more detail.
  1315. ------------------------------------------------------------------------------*/
  1316. STDMETHODIMP CStore::CloseHandle (long hCertStore)
  1317. {
  1318. HRESULT hr = S_OK;
  1319. DebugTrace("Entering CStore::CloseHandle().\n");
  1320. try
  1321. {
  1322. //
  1323. // Lock access to this object.
  1324. //
  1325. m_Lock.Lock();
  1326. //
  1327. // Check parameter.
  1328. //
  1329. if (0 == hCertStore)
  1330. {
  1331. hr = E_INVALIDARG;
  1332. DebugTrace("Error [%#x]: Parameter hCertStore is NULL.\n", hr);
  1333. goto ErrorExit;
  1334. }
  1335. //
  1336. // Duplicate the HCERTSTORE.
  1337. //
  1338. if (!::CertCloseStore((HCERTSTORE) hCertStore, 0))
  1339. {
  1340. hr = HRESULT_FROM_WIN32(::GetLastError());
  1341. DebugTrace("Error [%#x]: CertCloseStore() failed.\n", hr);
  1342. goto ErrorExit;
  1343. }
  1344. }
  1345. catch(...)
  1346. {
  1347. hr = E_POINTER;
  1348. DebugTrace("Exception: invalid parameter.\n");
  1349. goto ErrorExit;
  1350. }
  1351. UnlockExit:
  1352. //
  1353. // Unlock access to this object.
  1354. //
  1355. m_Lock.Unlock();
  1356. DebugTrace("Leaving CStore::CloseHandle().\n");
  1357. return hr;
  1358. ErrorExit:
  1359. //
  1360. // Sanity check.
  1361. //
  1362. ATLASSERT(FAILED(hr));
  1363. ReportError(hr);
  1364. goto UnlockExit;
  1365. }
  1366. ////////////////////////////////////////////////////////////////////////////////
  1367. //
  1368. // Private methods.
  1369. //
  1370. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1371. Function : CStore::ImportCertObject
  1372. Synopsis : Private function to import from a file.
  1373. Parameter: DWORD dwObjectType - CERT_QUERY_OBJECT_FILE or
  1374. CERT_QUERY_OBJECT_BLOB.
  1375. LPVOID pvObject - LPWSTR to file name for file object, and
  1376. DATA_BLOB * for blob object.
  1377. BOOL bAllowPfx
  1378. LPWSTR pwszPassword (Optional)
  1379. CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag (Optional)
  1380. Remark :
  1381. ------------------------------------------------------------------------------*/
  1382. STDMETHODIMP CStore::ImportCertObject (DWORD dwObjectType,
  1383. LPVOID pvObject,
  1384. BOOL bAllowPfx,
  1385. LPWSTR pwszPassword,
  1386. CAPICOM_KEY_STORAGE_FLAG KeyStorageFlag)
  1387. {
  1388. HRESULT hr = S_OK;
  1389. HCERTSTORE hCertStore = NULL;
  1390. PCCERT_CONTEXT pEnumContext = NULL;
  1391. PCCERT_CONTEXT pCertContext = NULL;
  1392. DATA_BLOB StoreBlob = {0, NULL};
  1393. DWORD dwContentType = 0;
  1394. DWORD dwExpectedType = CERT_QUERY_CONTENT_FLAG_CERT |
  1395. CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
  1396. CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT |
  1397. CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED |
  1398. CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
  1399. CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED;
  1400. DebugTrace("Entering CStore::ImportCertObject().\n");
  1401. //
  1402. // Sanity check.
  1403. //
  1404. ATLASSERT(pvObject);
  1405. ATLASSERT(m_hCertStore);
  1406. //
  1407. // Set PFX flag, if allowed.
  1408. //
  1409. if (bAllowPfx)
  1410. {
  1411. dwExpectedType |= CERT_QUERY_CONTENT_FLAG_PFX;
  1412. }
  1413. //
  1414. // Crack the blob.
  1415. //
  1416. if (!::CryptQueryObject(dwObjectType,
  1417. (LPCVOID) pvObject,
  1418. dwExpectedType,
  1419. CERT_QUERY_FORMAT_FLAG_ALL,
  1420. 0,
  1421. NULL,
  1422. &dwContentType,
  1423. NULL,
  1424. &hCertStore,
  1425. NULL,
  1426. NULL))
  1427. {
  1428. hr = HRESULT_FROM_WIN32(::GetLastError());
  1429. DebugTrace("Error [%#x]: CryptQueryObject() failed.\n", hr);
  1430. goto ErrorExit;
  1431. }
  1432. DebugTrace("Info: CryptQueryObject() returns dwContentType = %#x.\n", dwContentType);
  1433. //
  1434. // Need to import it ourselves for PFX.
  1435. //
  1436. if (CERT_QUERY_CONTENT_PFX == dwContentType)
  1437. {
  1438. DWORD dwFlags = 0;
  1439. //
  1440. // Make sure PFX is allowed.
  1441. //
  1442. if (!bAllowPfx)
  1443. {
  1444. hr = CAPICOM_E_NOT_SUPPORTED;
  1445. DebugTrace("Error [%#x]: Importing PFX where not supported.\n", hr);
  1446. goto ErrorExit;
  1447. }
  1448. //
  1449. // Read the file if CERT_QUERY_OBJECT_FILE.
  1450. //
  1451. if (CERT_QUERY_OBJECT_FILE == dwObjectType)
  1452. {
  1453. if (FAILED(hr = ::ReadFileContent((LPWSTR) pvObject, &StoreBlob)))
  1454. {
  1455. DebugTrace("Error [%#x]: ReadFileContent() failed.\n", hr);
  1456. goto ErrorExit;
  1457. }
  1458. }
  1459. else
  1460. {
  1461. StoreBlob = * (DATA_BLOB *) pvObject;
  1462. }
  1463. //
  1464. // Setup import flags.
  1465. //
  1466. if (CAPICOM_LOCAL_MACHINE_STORE == m_StoreLocation)
  1467. {
  1468. dwFlags |= CRYPT_MACHINE_KEYSET;
  1469. }
  1470. else if (IsWin2KAndAbove())
  1471. {
  1472. dwFlags |= CRYPT_USER_KEYSET;
  1473. }
  1474. if (KeyStorageFlag & CAPICOM_KEY_STORAGE_EXPORTABLE)
  1475. {
  1476. dwFlags |= CRYPT_EXPORTABLE;
  1477. }
  1478. if (KeyStorageFlag & CAPICOM_KEY_STORAGE_USER_PROTECTED)
  1479. {
  1480. dwFlags |= CRYPT_USER_PROTECTED;
  1481. }
  1482. //
  1483. // Now import the blob to store.
  1484. //
  1485. if (!(hCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB *) &StoreBlob,
  1486. pwszPassword,
  1487. dwFlags)))
  1488. {
  1489. hr = HRESULT_FROM_WIN32(::GetLastError());
  1490. DebugTrace("Error [%#x]: PFXImportCertStore() failed, dwFlags = %#x.\n", hr, dwFlags);
  1491. goto ErrorExit;
  1492. }
  1493. }
  1494. //
  1495. // Sanity check.
  1496. //
  1497. ATLASSERT(hCertStore);
  1498. //
  1499. // Add all certificates to the current store.
  1500. //
  1501. while (pEnumContext = ::CertEnumCertificatesInStore(hCertStore, pEnumContext))
  1502. {
  1503. //
  1504. // To avoid orphaning key container when importing PFX into system store,
  1505. // we need to find the cert in the target store. If we find the cert in the
  1506. // target store and the eixsitng cert also contain a key, then we will
  1507. // delete the new key container and key prov info before adding, if any.
  1508. //
  1509. if ((CERT_QUERY_CONTENT_PFX == dwContentType) && (CAPICOM_MEMORY_STORE != m_StoreLocation))
  1510. {
  1511. DWORD cbData = 0;
  1512. DWORD cbData2 = 0;
  1513. PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
  1514. PCCERT_CONTEXT pExistingCertContext = NULL;
  1515. //
  1516. // Delete the new container, iif:
  1517. // 1. The new cert exists in the target store, and
  1518. // 2. The new cert has a key container, and
  1519. // 3. The existing cert also has a key container.
  1520. //
  1521. if ((pExistingCertContext = ::CertFindCertificateInStore(m_hCertStore,
  1522. CAPICOM_ASN_ENCODING,
  1523. 0,
  1524. CERT_FIND_EXISTING,
  1525. (PVOID) pEnumContext,
  1526. NULL)) &&
  1527. (::CertGetCertificateContextProperty(pEnumContext,
  1528. CERT_KEY_PROV_INFO_PROP_ID,
  1529. NULL,
  1530. &cbData)) &&
  1531. (::CertGetCertificateContextProperty(pExistingCertContext,
  1532. CERT_KEY_PROV_INFO_PROP_ID,
  1533. NULL,
  1534. &cbData2)))
  1535. {
  1536. HCRYPTPROV hCryptProv;
  1537. //
  1538. // Yes, so retrieve the new key prov info.
  1539. //
  1540. if (!(pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) ::CoTaskMemAlloc(cbData)))
  1541. {
  1542. hr = E_OUTOFMEMORY;
  1543. ::CertFreeCertificateContext(pExistingCertContext);
  1544. DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
  1545. goto ErrorExit;
  1546. }
  1547. if (!::CertGetCertificateContextProperty(pEnumContext,
  1548. CERT_KEY_PROV_INFO_PROP_ID,
  1549. pKeyProvInfo,
  1550. &cbData))
  1551. {
  1552. hr = HRESULT_FROM_WIN32(::GetLastError());
  1553. ::CoTaskMemFree(pKeyProvInfo);
  1554. ::CertFreeCertificateContext(pExistingCertContext);
  1555. DebugTrace("Info [%#x]: CertGetCertificateContextProperty() failed.\n", hr);
  1556. goto ErrorExit;
  1557. }
  1558. //
  1559. // Delete the new key container and its key prov info.
  1560. //
  1561. if (!::CertSetCertificateContextProperty(pEnumContext,
  1562. CERT_KEY_PROV_INFO_PROP_ID,
  1563. 0,
  1564. NULL))
  1565. {
  1566. hr = HRESULT_FROM_WIN32(::GetLastError());
  1567. ::CoTaskMemFree(pKeyProvInfo);
  1568. ::CertFreeCertificateContext(pExistingCertContext);
  1569. DebugTrace("Error [%#x]: CertSetCertificateContextProperty() failed.\n", hr);
  1570. goto ErrorExit;
  1571. }
  1572. if (FAILED(hr = ::AcquireContext(pKeyProvInfo->pwszProvName,
  1573. pKeyProvInfo->pwszContainerName,
  1574. pKeyProvInfo->dwProvType,
  1575. CRYPT_DELETEKEYSET | (pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET),
  1576. FALSE,
  1577. &hCryptProv)))
  1578. {
  1579. ::CoTaskMemFree(pKeyProvInfo);
  1580. ::CertFreeCertificateContext(pExistingCertContext);
  1581. DebugTrace("Error [%#x]: AcquireContext(CRYPT_DELETEKEYSET) failed.\n", hr);
  1582. goto ErrorExit;
  1583. }
  1584. ::CoTaskMemFree(pKeyProvInfo);
  1585. ::CertFreeCertificateContext(pExistingCertContext);
  1586. }
  1587. }
  1588. //
  1589. // Add to store.
  1590. //
  1591. if (!::CertAddCertificateContextToStore(m_hCertStore,
  1592. pEnumContext,
  1593. CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES,
  1594. &pCertContext))
  1595. {
  1596. hr = HRESULT_FROM_WIN32(::GetLastError());
  1597. DebugTrace("Error [%#x]: CertAddCertificateContextToStore() failed.\n", hr);
  1598. goto ErrorExit;
  1599. }
  1600. //
  1601. // Sanity check.
  1602. //
  1603. ATLASSERT(pCertContext);
  1604. //
  1605. // If loading a PFX, need to collect the key provider info for memory store
  1606. // so that we know how to delete the key containers when the store is closed.
  1607. //
  1608. if (CERT_QUERY_CONTENT_PFX == dwContentType &&
  1609. CAPICOM_MEMORY_STORE == m_StoreLocation)
  1610. {
  1611. DWORD cbData = 0;
  1612. PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
  1613. PCRYPT_KEY_PROV_INFO * rgpKeyProvInfo = NULL;
  1614. //
  1615. // Keep info of those with private key.
  1616. //
  1617. if (::CertGetCertificateContextProperty(pCertContext,
  1618. CERT_KEY_PROV_INFO_PROP_ID,
  1619. NULL,
  1620. &cbData))
  1621. {
  1622. if (!(pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) ::CoTaskMemAlloc(cbData)))
  1623. {
  1624. hr = E_OUTOFMEMORY;
  1625. DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
  1626. goto ErrorExit;
  1627. }
  1628. if (!::CertGetCertificateContextProperty(pCertContext,
  1629. CERT_KEY_PROV_INFO_PROP_ID,
  1630. pKeyProvInfo,
  1631. &cbData))
  1632. {
  1633. hr = HRESULT_FROM_WIN32(::GetLastError());
  1634. ::CoTaskMemFree(pKeyProvInfo);
  1635. DebugTrace("Info [%#x]: CertGetCertificateContextProperty() failed.\n", hr);
  1636. goto ErrorExit;
  1637. }
  1638. //
  1639. // Realloc the array.
  1640. //
  1641. if (!(rgpKeyProvInfo = (PCRYPT_KEY_PROV_INFO *)
  1642. ::CoTaskMemRealloc(m_rgpKeyProvInfo,
  1643. (m_cKeyProvInfo + 1) * sizeof(PCRYPT_KEY_PROV_INFO))))
  1644. {
  1645. hr = E_OUTOFMEMORY;
  1646. ::CoTaskMemFree(pKeyProvInfo);
  1647. DebugTrace("Error [%#x]: CoTaskMemRealloc() failed.\n", hr);
  1648. goto ErrorExit;
  1649. }
  1650. //
  1651. // Store key info in array.
  1652. //
  1653. m_rgpKeyProvInfo = rgpKeyProvInfo;
  1654. m_rgpKeyProvInfo[m_cKeyProvInfo++] = pKeyProvInfo;
  1655. }
  1656. }
  1657. //
  1658. // Free context.
  1659. //
  1660. ::CertFreeCertificateContext(pCertContext), pCertContext = NULL;
  1661. }
  1662. //
  1663. // Above loop can exit either because there is no more certificate in
  1664. // the store or an error. Need to check last error to be certain.
  1665. //
  1666. if (CRYPT_E_NOT_FOUND != ::GetLastError())
  1667. {
  1668. hr = HRESULT_FROM_WIN32(::GetLastError());
  1669. DebugTrace("Error [%#x]: CertEnumCertificatesInStore() failed.\n", hr);
  1670. goto ErrorExit;
  1671. }
  1672. CommonExit:
  1673. //
  1674. // Free resources.
  1675. //
  1676. if (StoreBlob.pbData)
  1677. {
  1678. ::UnmapViewOfFile(StoreBlob.pbData);
  1679. }
  1680. if (pCertContext)
  1681. {
  1682. ::CertFreeCertificateContext(pCertContext);
  1683. }
  1684. if (pEnumContext)
  1685. {
  1686. ::CertFreeCertificateContext(pEnumContext);
  1687. }
  1688. if (hCertStore)
  1689. {
  1690. ::CertCloseStore(hCertStore, 0);
  1691. }
  1692. DebugTrace("Leaving CStore::ImportCertObject().\n");
  1693. return hr;
  1694. ErrorExit:
  1695. //
  1696. // Sanity check.
  1697. //
  1698. ATLASSERT(FAILED(hr));
  1699. goto CommonExit;
  1700. }
  1701. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1702. Function : CStore::Close
  1703. Synopsis : Private function to close the store.
  1704. Parameter:
  1705. Remark : Store is always closed even if error.
  1706. ------------------------------------------------------------------------------*/
  1707. STDMETHODIMP CStore::Close (void)
  1708. {
  1709. HRESULT hr = S_OK;
  1710. DebugTrace("Entering CStore::Close().\n");
  1711. //
  1712. // Close it if opened.
  1713. //
  1714. if (m_hCertStore)
  1715. {
  1716. //
  1717. // Delete key containers if necessary.
  1718. //
  1719. while (m_cKeyProvInfo--)
  1720. {
  1721. HCRYPTPROV hCryptProv = NULL;
  1722. if (FAILED(hr = ::AcquireContext(m_rgpKeyProvInfo[m_cKeyProvInfo]->pwszProvName,
  1723. m_rgpKeyProvInfo[m_cKeyProvInfo]->pwszContainerName,
  1724. m_rgpKeyProvInfo[m_cKeyProvInfo]->dwProvType,
  1725. CRYPT_DELETEKEYSET |
  1726. (m_rgpKeyProvInfo[m_cKeyProvInfo]->dwFlags & CRYPT_MACHINE_KEYSET),
  1727. FALSE,
  1728. &hCryptProv)))
  1729. {
  1730. DebugTrace("Info [%#x]: AcquireContext(CRYPT_DELETEKEYSET) failed.\n", hr);
  1731. }
  1732. ::CoTaskMemFree((LPVOID) m_rgpKeyProvInfo[m_cKeyProvInfo]);
  1733. }
  1734. //
  1735. // Now free the arrays itself.
  1736. //
  1737. if (m_rgpKeyProvInfo)
  1738. {
  1739. ::CoTaskMemFree((LPVOID) m_rgpKeyProvInfo);
  1740. }
  1741. //
  1742. // Close it.
  1743. //
  1744. ::CertCloseStore(m_hCertStore, 0);
  1745. }
  1746. //
  1747. // Reset.
  1748. //
  1749. m_hCertStore = NULL;
  1750. m_StoreLocation = CAPICOM_CURRENT_USER_STORE;
  1751. m_bIsProtected = TRUE;
  1752. m_cKeyProvInfo = 0;
  1753. m_rgpKeyProvInfo = NULL;
  1754. DebugTrace("Leaving CStore::Close().\n");
  1755. return hr;
  1756. }