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.

678 lines
25 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1996
  6. //
  7. // File: tstore5.cpp
  8. //
  9. // Contents: Test certificate store collection and context link functions
  10. //
  11. // See Usage() for a list of test options.
  12. //
  13. //
  14. // Functions: main
  15. //
  16. // History: 06-Sep-97 philh created
  17. //--------------------------------------------------------------------------
  18. #include <windows.h>
  19. #include <assert.h>
  20. #include "wincrypt.h"
  21. #include "certtest.h"
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <memory.h>
  26. #include <time.h>
  27. static void Usage(void)
  28. {
  29. printf("Usage: tstore5 [options] <StoreName1> <StoreName2>\n");
  30. printf("Options are:\n");
  31. printf(" -h - This message\n");
  32. printf(" -C - Collection tests (default)\n");
  33. printf(" -L - Context Link tests\n");
  34. printf(" -C -L - Context Links enumerated in Collection\n");
  35. printf(" -R - Replace contexts that exist\n");
  36. printf(" -A - Always add a new context\n");
  37. printf(" -P - Set property\n");
  38. printf(" -v - Verbose\n");
  39. printf(" -b - Brief\n");
  40. printf(" -f<number> - Open System Store Flags\n");
  41. printf("\n");
  42. printf("If <StoreName> has embedded \".\", File. Otherwise System Store\n");
  43. }
  44. int _cdecl main(int argc, char * argv[])
  45. {
  46. int status;
  47. DWORD i;
  48. DWORD dwDisplayFlags = 0;
  49. DWORD dwOpenFlags = 0;
  50. DWORD dwAddDisposition = CERT_STORE_ADD_USE_EXISTING;
  51. BOOL fVerbose = FALSE;
  52. BOOL fProperty = FALSE;
  53. #define COLLECTION_TEST_FLAG 0x1
  54. #define LINK_TEST_FLAG 0x2
  55. DWORD dwTestFlags = 0;
  56. #define MAX_STORE_CNT 32
  57. DWORD dwStoreCnt = 0;
  58. LPCSTR rgpszStore[MAX_STORE_CNT];
  59. HCERTSTORE rghStore[MAX_STORE_CNT];
  60. memset(rghStore, 0, sizeof(rghStore));
  61. HCERTSTORE hCollectionStore = NULL;
  62. HCERTSTORE hLinkStore = NULL;
  63. PCCERT_CONTEXT pSiblingCert = NULL;
  64. PCCRL_CONTEXT pSiblingCrl = NULL;
  65. PCCTL_CONTEXT pSiblingCtl = NULL;
  66. PCCERT_CONTEXT pLinkCert = NULL;
  67. PCCRL_CONTEXT pLinkCrl = NULL;
  68. PCCTL_CONTEXT pLinkCtl = NULL;
  69. DWORD dwCertAddCnt = 0;
  70. DWORD dwCrlAddCnt = 0;
  71. DWORD dwCtlAddCnt = 0;
  72. while (--argc>0) {
  73. if (**++argv == '-')
  74. {
  75. switch(argv[0][1])
  76. {
  77. case 'C':
  78. dwTestFlags |= COLLECTION_TEST_FLAG;
  79. break;
  80. case 'L':
  81. dwTestFlags |= LINK_TEST_FLAG;
  82. break;
  83. case 'v':
  84. fVerbose = TRUE;
  85. dwDisplayFlags = DISPLAY_VERBOSE_FLAG;
  86. break;
  87. case 'b':
  88. dwDisplayFlags = DISPLAY_BRIEF_FLAG;
  89. break;
  90. case 'f':
  91. dwOpenFlags = strtoul(argv[0]+2, NULL, 0);
  92. break;
  93. case 'R':
  94. dwAddDisposition = CERT_STORE_ADD_REPLACE_EXISTING;
  95. break;
  96. case 'A':
  97. dwAddDisposition = CERT_STORE_ADD_ALWAYS;
  98. break;
  99. case 'P':
  100. fProperty = TRUE;
  101. break;
  102. case 'h':
  103. default:
  104. goto BadUsage;
  105. }
  106. } else {
  107. if (MAX_STORE_CNT <= dwStoreCnt) {
  108. printf("Too many store names starting with:: %s\n", argv[0]);
  109. goto BadUsage;
  110. }
  111. rgpszStore[dwStoreCnt++] = argv[0];
  112. }
  113. }
  114. printf("command line: %s\n", GetCommandLine());
  115. if (0 == dwStoreCnt) {
  116. printf("Missing store names\n");
  117. goto BadUsage;
  118. }
  119. // Attempt to open the store names
  120. for (i = 0; i < dwStoreCnt; i++) {
  121. DWORD dwFlags;
  122. BOOL fSystemStore;
  123. LPCSTR psz;
  124. char ch;
  125. // Check if store name has an embedded ".".
  126. fSystemStore = TRUE;
  127. psz = rgpszStore[i];
  128. while (ch = *psz++) {
  129. if ('.' == ch) {
  130. fSystemStore = FALSE;
  131. break;
  132. }
  133. }
  134. if (fSystemStore &&
  135. 0 == (dwOpenFlags & CERT_SYSTEM_STORE_LOCATION_MASK))
  136. dwFlags = dwOpenFlags | CERT_SYSTEM_STORE_CURRENT_USER;
  137. else
  138. dwFlags = dwOpenFlags;
  139. rghStore[i] = OpenSystemStoreOrFile(fSystemStore, rgpszStore[i],
  140. dwOpenFlags);
  141. }
  142. if (0 == dwTestFlags)
  143. dwTestFlags = COLLECTION_TEST_FLAG;
  144. if (dwTestFlags & COLLECTION_TEST_FLAG) {
  145. // Open collection store
  146. hCollectionStore = CertOpenStore(
  147. CERT_STORE_PROV_COLLECTION,
  148. 0, // dwEncodingType
  149. 0, // hCryptProv
  150. 0, // dwFlags
  151. NULL // pvPara
  152. );
  153. if (NULL == hCollectionStore) {
  154. PrintLastError("CertOpenStore(COLLECTION)");
  155. goto ErrorReturn;
  156. }
  157. }
  158. if (dwTestFlags & LINK_TEST_FLAG) {
  159. HCERTSTORE hParentStore;
  160. // Open memory store to hold the context links
  161. hLinkStore = CertOpenStore(
  162. CERT_STORE_PROV_MEMORY,
  163. 0, // dwEncodingType
  164. 0, // hCryptProv
  165. 0, // dwFlags
  166. NULL // pvPara
  167. );
  168. if (NULL == hLinkStore) {
  169. PrintLastError("CertOpenStore(MEMORY)");
  170. goto ErrorReturn;
  171. }
  172. if (dwTestFlags & COLLECTION_TEST_FLAG) {
  173. if (!CertAddStoreToCollection(
  174. hCollectionStore,
  175. hLinkStore,
  176. CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
  177. 0 // dwPriority
  178. )) {
  179. PrintLastError("CertAddStoreToCollection");
  180. goto ErrorReturn;
  181. }
  182. hParentStore = hCollectionStore;
  183. } else
  184. hParentStore = hLinkStore;
  185. // Loop through stores and add the certificate, CRL and CTL contexts
  186. // as links
  187. for (i = 0; i < dwStoreCnt; i++) {
  188. HCERTSTORE hStore;
  189. PCCERT_CONTEXT pCert;
  190. PCCRL_CONTEXT pCrl;
  191. PCCTL_CONTEXT pCtl;
  192. DWORD dwCrlFlags;
  193. if (NULL == (hStore = rghStore[i]))
  194. continue;
  195. pCert = NULL;
  196. while (pCert = CertEnumCertificatesInStore(hStore, pCert)) {
  197. if (!CertAddCertificateLinkToStore(
  198. hLinkStore,
  199. pCert,
  200. dwAddDisposition,
  201. (0 == dwCertAddCnt) ? &pLinkCert : NULL
  202. )) {
  203. PrintLastError("CertAddCertificateLinkToStore");
  204. goto ErrorReturn;
  205. }
  206. if (0 == dwCertAddCnt) {
  207. if (NULL == pLinkCert) {
  208. printf("failed => didn't return cert link\n");
  209. goto ErrorReturn;
  210. }
  211. pSiblingCert = CertDuplicateCertificateContext(pCert);
  212. }
  213. dwCertAddCnt++;
  214. if (CertAddCertificateLinkToStore(
  215. hLinkStore,
  216. pCert,
  217. CERT_STORE_ADD_NEW,
  218. NULL // ppStoreCert
  219. ))
  220. printf("failed => expected CertAddCertificateLinkToStore(ADD_NEW) to fail\n");
  221. else if (CRYPT_E_EXISTS != GetLastError()) {
  222. PrintLastError("CertAddCertificateLinkToStore(ADD_NEW)");
  223. printf("failed => expected CRYPT_E_EXISTS\n");
  224. }
  225. }
  226. dwCrlFlags = 0;
  227. pCrl = NULL;
  228. while (pCrl = CertGetCRLFromStore(hStore, NULL, pCrl,
  229. &dwCrlFlags)) {
  230. if (!CertAddCRLLinkToStore(
  231. hLinkStore,
  232. pCrl,
  233. dwAddDisposition,
  234. (0 == dwCrlAddCnt) ? &pLinkCrl : NULL
  235. )) {
  236. PrintLastError("CertAddCRLLinkToStore");
  237. goto ErrorReturn;
  238. }
  239. if (0 == dwCrlAddCnt) {
  240. if (NULL == pLinkCrl) {
  241. printf("failed => didn't return crl link\n");
  242. goto ErrorReturn;
  243. }
  244. pSiblingCrl = CertDuplicateCRLContext(pCrl);
  245. }
  246. dwCrlAddCnt++;
  247. if (CertAddCRLLinkToStore(
  248. hLinkStore,
  249. pCrl,
  250. CERT_STORE_ADD_NEW,
  251. NULL // ppStoreCrl
  252. ))
  253. printf("failed => expected CertAddCRLLinkToStore(ADD_NEW) to fail\n");
  254. else if (CRYPT_E_EXISTS != GetLastError()) {
  255. PrintLastError("CertAddCRLLinkToStore(ADD_NEW)");
  256. printf("failed => expected CRYPT_E_EXISTS\n");
  257. }
  258. }
  259. pCtl = NULL;
  260. while (pCtl = CertEnumCTLsInStore(hStore, pCtl)) {
  261. if (!CertAddCTLLinkToStore(
  262. hLinkStore,
  263. pCtl,
  264. dwAddDisposition,
  265. (0 == dwCtlAddCnt) ? &pLinkCtl : NULL
  266. )) {
  267. PrintLastError("CertAddCTLLinkToStore");
  268. goto ErrorReturn;
  269. }
  270. if (0 == dwCtlAddCnt) {
  271. if (NULL == pLinkCtl) {
  272. printf("failed => didn't return crl link\n");
  273. goto ErrorReturn;
  274. }
  275. pSiblingCtl = CertDuplicateCTLContext(pCtl);
  276. }
  277. dwCtlAddCnt++;
  278. if (CertAddCTLLinkToStore(
  279. hLinkStore,
  280. pCtl,
  281. CERT_STORE_ADD_NEW,
  282. NULL // ppStoreCtl
  283. ))
  284. printf("failed => expected CertAddCTLLinkToStore(ADD_NEW) to fail\n");
  285. else if (CRYPT_E_EXISTS != GetLastError()) {
  286. PrintLastError("CertAddCTLLinkToStore(ADD_NEW)");
  287. printf("failed => expected CRYPT_E_EXISTS\n");
  288. }
  289. }
  290. }
  291. printf("Added %d Certificates\n", dwCertAddCnt);
  292. printf("Added %d CRLs\n", dwCrlAddCnt);
  293. printf("Added %d CTLs\n", dwCtlAddCnt);
  294. printf("\n");
  295. printf("$$$$$ Certificate Context Links $$$$$\n");
  296. DisplayStore(hParentStore, dwDisplayFlags);
  297. if (fProperty) {
  298. CRYPT_DATA_BLOB LinkSetData;
  299. BYTE rgbLinkSet[4] = {0xDE, 0xAD, 0xBE, 0xEF};
  300. LinkSetData.pbData = rgbLinkSet;
  301. LinkSetData.cbData = sizeof(rgbLinkSet);
  302. CRYPT_DATA_BLOB SiblingSetData;
  303. BYTE rgbSiblingSet[4] = {0xDE, 0xAF, 0xCA, 0xFE};
  304. SiblingSetData.pbData = rgbSiblingSet;
  305. SiblingSetData.cbData = sizeof(rgbSiblingSet);
  306. BYTE rgbGet[4];
  307. DWORD cbData;
  308. if (pLinkCert) {
  309. printf("Setting Certificate Context Link Property\n");
  310. // First make sure the property is deleted
  311. CertSetCertificateContextProperty(
  312. pLinkCert,
  313. CERT_FIRST_USER_PROP_ID,
  314. 0, // dwFlags
  315. NULL
  316. );
  317. cbData = sizeof(rgbGet);
  318. if (CertGetCertificateContextProperty(
  319. pLinkCert,
  320. CERT_FIRST_USER_PROP_ID,
  321. rgbGet,
  322. &cbData) || CRYPT_E_NOT_FOUND != GetLastError()) {
  323. printf("failed => expected link property to be deleted\n");
  324. PrintLastError("CertGetCertificateContextProperty(LINK)");
  325. }
  326. cbData = sizeof(rgbGet);
  327. if (CertGetCertificateContextProperty(
  328. pSiblingCert,
  329. CERT_FIRST_USER_PROP_ID,
  330. rgbGet,
  331. &cbData) || CRYPT_E_NOT_FOUND != GetLastError()) {
  332. printf("failed => expected sibling property to be deleted\n");
  333. PrintLastError("CertGetCertificateContextProperty(SIBLING)");
  334. }
  335. // Set property in link. It should also be visible in sibling
  336. cbData = sizeof(rgbGet);
  337. memset(rgbGet, 0, sizeof(rgbGet));
  338. if (!CertSetCertificateContextProperty(
  339. pLinkCert,
  340. CERT_FIRST_USER_PROP_ID,
  341. 0, // dwFlags
  342. &LinkSetData
  343. ))
  344. PrintLastError("CertSetCertificateContextProperty(LINK)");
  345. else if (!CertGetCertificateContextProperty(
  346. pSiblingCert,
  347. CERT_FIRST_USER_PROP_ID,
  348. rgbGet,
  349. &cbData))
  350. PrintLastError("CertGetCertificateContextProperty(SIBLING)");
  351. else if (cbData != sizeof(rgbLinkSet) ||
  352. 0 != memcmp(rgbGet, rgbLinkSet, cbData))
  353. printf("failed => cert sibling not updated with link property\n");
  354. // Set property in sibling. It should also be visible in link
  355. cbData = sizeof(rgbGet);
  356. memset(rgbGet, 0, sizeof(rgbGet));
  357. if (!CertSetCertificateContextProperty(
  358. pSiblingCert,
  359. CERT_FIRST_USER_PROP_ID,
  360. 0, // dwFlags
  361. &SiblingSetData
  362. ))
  363. PrintLastError("CertSetCertificateContextProperty(SIBLING)");
  364. else if (!CertGetCertificateContextProperty(
  365. pLinkCert,
  366. CERT_FIRST_USER_PROP_ID,
  367. rgbGet,
  368. &cbData))
  369. PrintLastError("CertGetCertificateContextProperty(LINK)");
  370. else if (cbData != sizeof(rgbSiblingSet) ||
  371. 0 != memcmp(rgbGet, rgbSiblingSet, cbData))
  372. printf("failed => cert link not updated with sibling property\n");
  373. }
  374. if (pLinkCrl) {
  375. printf("Setting CRL Context Link Property\n");
  376. // First make sure the property is deleted
  377. CertSetCRLContextProperty(
  378. pLinkCrl,
  379. CERT_FIRST_USER_PROP_ID,
  380. 0, // dwFlags
  381. NULL
  382. );
  383. cbData = sizeof(rgbGet);
  384. if (CertGetCRLContextProperty(
  385. pLinkCrl,
  386. CERT_FIRST_USER_PROP_ID,
  387. rgbGet,
  388. &cbData) || CRYPT_E_NOT_FOUND != GetLastError()) {
  389. printf("failed => expected link property to be deleted\n");
  390. PrintLastError("CertGetCRLContextProperty(LINK)");
  391. }
  392. cbData = sizeof(rgbGet);
  393. if (CertGetCRLContextProperty(
  394. pSiblingCrl,
  395. CERT_FIRST_USER_PROP_ID,
  396. rgbGet,
  397. &cbData) || CRYPT_E_NOT_FOUND != GetLastError()) {
  398. printf("failed => expected sibling property to be deleted\n");
  399. PrintLastError("CertGetCRLContextProperty(SIBLING)");
  400. }
  401. // Set property in link. It should also be visible in sibling
  402. cbData = sizeof(rgbGet);
  403. memset(rgbGet, 0, sizeof(rgbGet));
  404. if (!CertSetCRLContextProperty(
  405. pLinkCrl,
  406. CERT_FIRST_USER_PROP_ID,
  407. 0, // dwFlags
  408. &LinkSetData
  409. ))
  410. PrintLastError("CertSetCRLContextProperty(LINK)");
  411. else if (!CertGetCRLContextProperty(
  412. pSiblingCrl,
  413. CERT_FIRST_USER_PROP_ID,
  414. rgbGet,
  415. &cbData))
  416. PrintLastError("CertGetCRLContextProperty(SIBLING)");
  417. else if (cbData != sizeof(rgbLinkSet) ||
  418. 0 != memcmp(rgbGet, rgbLinkSet, cbData))
  419. printf("failed => CRL sibling not updated with link property\n");
  420. // Set property in sibling. It should also be visible in link
  421. cbData = sizeof(rgbGet);
  422. memset(rgbGet, 0, sizeof(rgbGet));
  423. if (!CertSetCRLContextProperty(
  424. pSiblingCrl,
  425. CERT_FIRST_USER_PROP_ID,
  426. 0, // dwFlags
  427. &SiblingSetData
  428. ))
  429. PrintLastError("CertSetCRLContextProperty(SIBLING)");
  430. else if (!CertGetCRLContextProperty(
  431. pLinkCrl,
  432. CERT_FIRST_USER_PROP_ID,
  433. rgbGet,
  434. &cbData))
  435. PrintLastError("CertGetCRLContextProperty(LINK)");
  436. else if (cbData != sizeof(rgbSiblingSet) ||
  437. 0 != memcmp(rgbGet, rgbSiblingSet, cbData))
  438. printf("failed => CRL link not updated with sibling property\n");
  439. }
  440. if (pLinkCtl) {
  441. printf("Setting CTL Context Link Property\n");
  442. // First make sure the property is deleted
  443. CertSetCTLContextProperty(
  444. pLinkCtl,
  445. CERT_FIRST_USER_PROP_ID,
  446. 0, // dwFlags
  447. NULL
  448. );
  449. cbData = sizeof(rgbGet);
  450. if (CertGetCTLContextProperty(
  451. pLinkCtl,
  452. CERT_FIRST_USER_PROP_ID,
  453. rgbGet,
  454. &cbData) || CRYPT_E_NOT_FOUND != GetLastError()) {
  455. printf("failed => expected link property to be deleted\n");
  456. PrintLastError("CertGetCTLContextProperty(LINK)");
  457. }
  458. cbData = sizeof(rgbGet);
  459. if (CertGetCTLContextProperty(
  460. pSiblingCtl,
  461. CERT_FIRST_USER_PROP_ID,
  462. rgbGet,
  463. &cbData) || CRYPT_E_NOT_FOUND != GetLastError()) {
  464. printf("failed => expected sibling property to be deleted\n");
  465. PrintLastError("CertGetCTLContextProperty(SIBLING)");
  466. }
  467. // Set property in link. It should also be visible in sibling
  468. cbData = sizeof(rgbGet);
  469. memset(rgbGet, 0, sizeof(rgbGet));
  470. if (!CertSetCTLContextProperty(
  471. pLinkCtl,
  472. CERT_FIRST_USER_PROP_ID,
  473. 0, // dwFlags
  474. &LinkSetData
  475. ))
  476. PrintLastError("CertSetCTLContextProperty(LINK)");
  477. else if (!CertGetCTLContextProperty(
  478. pSiblingCtl,
  479. CERT_FIRST_USER_PROP_ID,
  480. rgbGet,
  481. &cbData))
  482. PrintLastError("CertGetCTLContextProperty(SIBLING)");
  483. else if (cbData != sizeof(rgbLinkSet) ||
  484. 0 != memcmp(rgbGet, rgbLinkSet, cbData))
  485. printf("failed => CTL sibling not updated with link property\n");
  486. // Set property in sibling. It should also be visible in link
  487. cbData = sizeof(rgbGet);
  488. memset(rgbGet, 0, sizeof(rgbGet));
  489. if (!CertSetCTLContextProperty(
  490. pSiblingCtl,
  491. CERT_FIRST_USER_PROP_ID,
  492. 0, // dwFlags
  493. &SiblingSetData
  494. ))
  495. PrintLastError("CertSetCTLContextProperty(SIBLING)");
  496. else if (!CertGetCTLContextProperty(
  497. pLinkCtl,
  498. CERT_FIRST_USER_PROP_ID,
  499. rgbGet,
  500. &cbData))
  501. PrintLastError("CertGetCTLContextProperty(LINK)");
  502. else if (cbData != sizeof(rgbSiblingSet) ||
  503. 0 != memcmp(rgbGet, rgbSiblingSet, cbData))
  504. printf("failed => CTL link not updated with sibling property\n");
  505. }
  506. }
  507. if (pLinkCert) {
  508. CertDeleteCertificateFromStore(pLinkCert);
  509. pLinkCert = NULL;
  510. }
  511. if (pLinkCrl) {
  512. CertDeleteCRLFromStore(pLinkCrl);
  513. pLinkCrl = NULL;
  514. }
  515. if (pLinkCtl) {
  516. CertDeleteCTLFromStore(pLinkCtl);
  517. pLinkCtl = NULL;
  518. }
  519. } else {
  520. PCCERT_CONTEXT pCert;
  521. for (i = 0; i < dwStoreCnt; i++) {
  522. if (NULL == rghStore[i])
  523. continue;
  524. if (!CertAddStoreToCollection(
  525. hCollectionStore,
  526. rghStore[i],
  527. 0, // dwUpdateFlags
  528. i // dwPriority
  529. )) {
  530. PrintLastError("CertAddStoreToCollection");
  531. goto ErrorReturn;
  532. }
  533. }
  534. printf("\n");
  535. printf("$$$$$ Collection Stores $$$$$\n");
  536. DisplayStore(hCollectionStore, dwDisplayFlags);
  537. // Get first cert and duplicate. It should be in last store.
  538. // Remove the last store and the second to last store. Continue
  539. // the enumeration.
  540. if (pCert = CertEnumCertificatesInStore(hCollectionStore, NULL)) {
  541. pLinkCert = CertDuplicateCertificateContext(pCert);
  542. if (0 < dwStoreCnt && rghStore[dwStoreCnt - 1]) {
  543. CertRemoveStoreFromCollection(
  544. hCollectionStore,
  545. rghStore[dwStoreCnt - 1]
  546. );
  547. // Also close the last store
  548. CertCloseStore(rghStore[dwStoreCnt - 1], 0);
  549. rghStore[dwStoreCnt - 1] = NULL;
  550. }
  551. if (1 < dwStoreCnt && rghStore[dwStoreCnt - 2])
  552. CertRemoveStoreFromCollection(
  553. hCollectionStore,
  554. rghStore[dwStoreCnt - 2]
  555. );
  556. printf("$$$$$ Collection Certificates after removing last 2 stores $$$$$\n");
  557. i = 0;
  558. while (pCert = CertEnumCertificatesInStore(hCollectionStore,
  559. pCert)) {
  560. printf("===== %d =====\n", i);
  561. DisplayCert(pCert, DISPLAY_BRIEF_FLAG);
  562. i++;
  563. }
  564. }
  565. }
  566. status = 0;
  567. CommonReturn:
  568. if (pSiblingCert)
  569. CertFreeCertificateContext(pSiblingCert);
  570. if (pLinkCert)
  571. CertFreeCertificateContext(pLinkCert);
  572. if (pLinkCrl)
  573. CertFreeCRLContext(pLinkCrl);
  574. if (pSiblingCrl)
  575. CertFreeCRLContext(pSiblingCrl);
  576. if (pLinkCtl)
  577. CertFreeCTLContext(pLinkCtl);
  578. if (pSiblingCtl)
  579. CertFreeCTLContext(pSiblingCtl);
  580. for (i = 1; i < dwStoreCnt; i++) {
  581. if (rghStore[i])
  582. CertCloseStore(rghStore[i], 0);
  583. }
  584. if (hCollectionStore) {
  585. if (!CertCloseStore(hCollectionStore, CERT_CLOSE_STORE_CHECK_FLAG))
  586. PrintLastError("CertCloseStore(COLLECTION)");
  587. }
  588. if (hLinkStore) {
  589. if (!CertCloseStore(hLinkStore, CERT_CLOSE_STORE_CHECK_FLAG))
  590. PrintLastError("CertCloseStore(LINK)");
  591. }
  592. if (0 < dwStoreCnt) {
  593. if (rghStore[0]) {
  594. if (!CertCloseStore(rghStore[0], CERT_CLOSE_STORE_CHECK_FLAG))
  595. PrintLastError("CertCloseStore(SIBLING[0])");
  596. }
  597. }
  598. return status;
  599. BadUsage:
  600. Usage();
  601. status = -1;
  602. goto CommonReturn;
  603. ErrorReturn:
  604. status = -1;
  605. goto CommonReturn;
  606. }