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.

699 lines
21 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1996
  6. //
  7. // File: tchain.cpp
  8. //
  9. // Contents: Chain threading tests
  10. //
  11. // See Usage() for a list of test options.
  12. //
  13. //
  14. // Functions: main
  15. //
  16. // History: 28-Mar-00 philh created
  17. //--------------------------------------------------------------------------
  18. #define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS 1
  19. #include <windows.h>
  20. #include <assert.h>
  21. #include "wincrypt.h"
  22. #include "certtest.h"
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <memory.h>
  27. #include <time.h>
  28. #define CTRL_THR_CNT 3
  29. #define RESYNC_THR_IDX 0
  30. #define DELETE_THR_IDX 1
  31. #define REPLACE_THR_IDX 2
  32. HANDLE rghCtrlThread[CTRL_THR_CNT];
  33. DWORD rgdwCtrlIterations[CTRL_THR_CNT];
  34. DWORD rgdwCtrlSleepMilliSeconds[CTRL_THR_CNT];
  35. #define MAX_CHAIN_THR_CNT 16
  36. HANDLE rghChainThread[MAX_CHAIN_THR_CNT];
  37. DWORD rgdwChainIterations[MAX_CHAIN_THR_CNT];
  38. LONG lIterations = -1;
  39. BOOL fCreateEndCert = FALSE;
  40. HCERTSTORE hStore = NULL;
  41. HCERTSTORE hCaStore = NULL;
  42. HCERTSTORE hAdditionalChainStore = NULL;
  43. PCCERT_CONTEXT pReplaceCertContext = NULL;
  44. PCCERT_CONTEXT pDeleteCertContext = NULL;
  45. HCERTCHAINENGINE hChainEngine = NULL;
  46. #define MAX_USAGE_CNT 16
  47. LPSTR rgpszUsageOID[MAX_USAGE_CNT];
  48. DWORD cUsageOID = 0;
  49. CERT_CHAIN_PARA ChainPara;
  50. DWORD dwChainFlags = 0;
  51. BOOL fDone = FALSE;
  52. static void Usage(void)
  53. {
  54. printf("Usage: tchain [options] <StoreName>\n");
  55. printf("\n");
  56. printf(" -CreateEndCert - Create new end cert for each chain\n");
  57. printf(" -LocalMachine - Defaults to CurrentUser\n");
  58. printf(" -Pause\n");
  59. printf("\n");
  60. printf("Options are:\n");
  61. printf(" -u<OID String> - Usage OID string -u1.3.6.1.5.5.7.3.3\n");
  62. printf(" -t<number> - Threads (defaults to 4)\n");
  63. printf(" -i<number> - Iterations (defaults to -1, infinite)\n");
  64. printf(" -l<number> - Lru cache count, enable end cert caching\n");
  65. printf(" -f<Number> - Chain Flags\n");
  66. printf(" -T<number> - Url Timeout (milliseconds)\n");
  67. printf(" -F<number> - Revocation Freshness (seconds)\n");
  68. printf(" -r[<number>] - Resync engine, defaults to 2K millisecs\n");
  69. printf(" -d[<num>] <cert> - Delete cert from CA store\n");
  70. printf(" -R[<num>] <cert> - Replace cert in CA store\n");
  71. printf(" -s - Open the \"StoreName\" System store\n");
  72. printf(" -a<filename> - Additional chain store filename\n");
  73. printf(" -A<filename> - Additional engine store filename\n");
  74. printf(" -h - This message\n");
  75. printf("\n");
  76. }
  77. DWORD WINAPI ChainThreadProc(
  78. LPVOID lpThreadParameter
  79. )
  80. {
  81. DWORD dwThrIdx = (DWORD) ((DWORD_PTR) lpThreadParameter);
  82. if (dwThrIdx >= MAX_CHAIN_THR_CNT) {
  83. printf("Invalid dwThrIdx\n");
  84. return 0;
  85. }
  86. while (TRUE) {
  87. PCCERT_CONTEXT pCert = NULL;
  88. while (pCert = CertEnumCertificatesInStore(hStore, pCert)) {
  89. PCCERT_CONTEXT pCreateCert = NULL;
  90. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  91. if (fCreateEndCert) {
  92. pCreateCert = CertCreateCertificateContext(
  93. pCert->dwCertEncodingType,
  94. pCert->pbCertEncoded,
  95. pCert->cbCertEncoded
  96. );
  97. if (NULL == pCreateCert) {
  98. PrintLastError("CertCreateCertificateContext");
  99. return 0;
  100. }
  101. }
  102. if (!CertGetCertificateChain(
  103. hChainEngine,
  104. fCreateEndCert ? pCreateCert : pCert,
  105. NULL, // pTime
  106. hAdditionalChainStore,
  107. &ChainPara,
  108. dwChainFlags,
  109. NULL, // pvReserved
  110. &pChainContext
  111. )) {
  112. PrintLastError("CertGetCertificateChain");
  113. return 0;
  114. }
  115. CertFreeCertificateChain(pChainContext);
  116. if (pCreateCert)
  117. CertFreeCertificateContext(pCreateCert);
  118. }
  119. rgdwChainIterations[dwThrIdx]++;
  120. if (lIterations > 0 &&
  121. rgdwChainIterations[dwThrIdx] >= (DWORD) lIterations)
  122. break;
  123. }
  124. return 0;
  125. }
  126. DWORD WINAPI ResyncThreadProc(
  127. LPVOID lpThreadParameter
  128. )
  129. {
  130. while (TRUE) {
  131. if (fDone)
  132. break;
  133. if (!CertResyncCertificateChainEngine(hChainEngine)) {
  134. PrintLastError("CertResyncCertificateChainEngine");
  135. return 0;
  136. }
  137. rgdwCtrlIterations[RESYNC_THR_IDX]++;
  138. Sleep(rgdwCtrlSleepMilliSeconds[RESYNC_THR_IDX]);
  139. }
  140. return 0;
  141. }
  142. DWORD WINAPI DeleteThreadProc(
  143. LPVOID lpThreadParameter
  144. )
  145. {
  146. BYTE rgbHash[MAX_HASH_LEN];
  147. CRYPT_HASH_BLOB HashBlob;
  148. HashBlob.cbData = MAX_HASH_LEN;
  149. HashBlob.pbData = rgbHash;
  150. if (!CertGetCertificateContextProperty(
  151. pDeleteCertContext,
  152. CERT_MD5_HASH_PROP_ID,
  153. rgbHash,
  154. &HashBlob.cbData
  155. )) {
  156. PrintLastError("CertGetCertificateContextProperty");
  157. return 0;
  158. }
  159. while (TRUE) {
  160. PCCERT_CONTEXT pFound = NULL;
  161. if (fDone)
  162. break;
  163. pFound = CertFindCertificateInStore(
  164. hCaStore,
  165. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  166. 0,
  167. CERT_FIND_MD5_HASH,
  168. &HashBlob,
  169. NULL
  170. );
  171. if (pFound) {
  172. CertDeleteCertificateFromStore(pFound);
  173. rgdwCtrlIterations[DELETE_THR_IDX]++;
  174. }
  175. Sleep(rgdwCtrlSleepMilliSeconds[DELETE_THR_IDX]);
  176. }
  177. return 0;
  178. }
  179. DWORD WINAPI ReplaceThreadProc(
  180. LPVOID lpThreadParameter
  181. )
  182. {
  183. while (TRUE) {
  184. if (fDone)
  185. break;
  186. if (!CertAddCertificateContextToStore(
  187. hCaStore,
  188. pReplaceCertContext,
  189. CERT_STORE_ADD_REPLACE_EXISTING,
  190. NULL // ppStoreContext
  191. )) {
  192. PrintLastError("CertAddCertificateContextToStore");
  193. return 0;
  194. }
  195. rgdwCtrlIterations[REPLACE_THR_IDX]++;
  196. Sleep(rgdwCtrlSleepMilliSeconds[REPLACE_THR_IDX]);
  197. }
  198. return 0;
  199. }
  200. PCCERT_CONTEXT ReadCert(
  201. IN LPSTR pszCert
  202. )
  203. {
  204. BOOL fResult;
  205. BYTE *pbEncoded;
  206. DWORD cbEncoded;
  207. PCCERT_CONTEXT pCert;
  208. if (!ReadDERFromFile(pszCert, &pbEncoded, &cbEncoded)) {
  209. PrintLastError("ReadCert");
  210. return NULL;
  211. }
  212. pCert = CertCreateCertificateContext(
  213. dwCertEncodingType,
  214. pbEncoded,
  215. cbEncoded
  216. );
  217. if (pCert == NULL)
  218. PrintLastError("CertCreateCertificateContext");
  219. TestFree(pbEncoded);
  220. return pCert;
  221. }
  222. int _cdecl main(int argc, char * argv[])
  223. {
  224. int status;
  225. LPSTR pszAdditionalChainStore = NULL;
  226. LPSTR pszAdditionalEngineStore = NULL;
  227. BOOL fResync = FALSE;
  228. DWORD dwLruCnt = 0;
  229. LPSTR pszDeleteCert = NULL;
  230. LPSTR pszReplaceCert = NULL;
  231. BOOL fSystemStore = FALSE;
  232. LPSTR pszStoreFilename = NULL;
  233. BOOL fPause = FALSE;
  234. DWORD dwThrCnt = 4;
  235. HCERTSTORE hAdditionalEngineStore = NULL;
  236. DWORD dwThreadId;
  237. DWORD dwIterations;
  238. DWORD i;
  239. for (i = 0; i < CTRL_THR_CNT; i ++)
  240. rgdwCtrlSleepMilliSeconds[i] = 2000; // 2 second
  241. // Initialize the chain parameters
  242. memset(&ChainPara, 0, sizeof(ChainPara));
  243. ChainPara.cbSize = sizeof(ChainPara);
  244. while (--argc>0) {
  245. if (**++argv == '-')
  246. {
  247. if (0 == _stricmp(argv[0]+1, "CreateEndCert")) {
  248. fCreateEndCert = TRUE;
  249. } else if (0 == _stricmp(argv[0]+1, "LocalMachine")) {
  250. hChainEngine = HCCE_LOCAL_MACHINE;
  251. } else if (0 == _stricmp(argv[0]+1, "Pause")) {
  252. fPause = TRUE;
  253. } else {
  254. switch(argv[0][1])
  255. {
  256. case 'u':
  257. if (MAX_USAGE_CNT <= cUsageOID) {
  258. printf("Too many usages\n");
  259. goto BadUsage;
  260. }
  261. rgpszUsageOID[cUsageOID++] = argv[0]+2;
  262. break;
  263. case 'i':
  264. lIterations = strtol(argv[0]+2, NULL, 0);
  265. break;
  266. case 't':
  267. dwThrCnt = (DWORD) strtoul(argv[0]+2, NULL, 0);
  268. if (dwThrCnt > MAX_CHAIN_THR_CNT) {
  269. printf("exceeded max thread count of %d\n",
  270. MAX_CHAIN_THR_CNT);
  271. goto BadUsage;
  272. }
  273. break;
  274. case 'l':
  275. dwLruCnt = (DWORD) strtoul(argv[0]+2, NULL, 0);
  276. break;
  277. case 'r':
  278. fResync = TRUE;
  279. if (argv[0][2]) {
  280. rgdwCtrlSleepMilliSeconds[RESYNC_THR_IDX] =
  281. (DWORD) strtoul(argv[0]+2, NULL, 0);
  282. }
  283. break;
  284. case 'd':
  285. if (argv[0][2]) {
  286. rgdwCtrlSleepMilliSeconds[DELETE_THR_IDX] =
  287. (DWORD) strtoul(argv[0]+2, NULL, 0);
  288. }
  289. ++argv;
  290. if (--argc <= 0 || argv[0][0] == '-') {
  291. printf("Missing Delete cert\n");
  292. goto BadUsage;
  293. }
  294. pszDeleteCert = argv[0];
  295. break;
  296. case 'R':
  297. if (argv[0][2]) {
  298. rgdwCtrlSleepMilliSeconds[REPLACE_THR_IDX] =
  299. (DWORD) strtoul(argv[0]+2, NULL, 0);
  300. }
  301. ++argv;
  302. if (--argc <= 0 || argv[0][0] == '-') {
  303. printf("Missing Replace cert\n");
  304. goto BadUsage;
  305. }
  306. pszReplaceCert = argv[0];
  307. break;
  308. case 'f':
  309. dwChainFlags = (DWORD) strtoul(argv[0]+2, NULL, 0);
  310. break;
  311. case 's':
  312. fSystemStore = TRUE;
  313. break;
  314. case 'a':
  315. pszAdditionalChainStore = argv[0]+2;
  316. if (*pszAdditionalChainStore == '\0') {
  317. printf("Need to specify filename\n");
  318. goto BadUsage;
  319. }
  320. break;
  321. case 'A':
  322. pszAdditionalEngineStore = argv[0]+2;
  323. if (*pszAdditionalEngineStore == '\0') {
  324. printf("Need to specify filename\n");
  325. goto BadUsage;
  326. }
  327. break;
  328. case 'T':
  329. ChainPara.dwUrlRetrievalTimeout =
  330. (DWORD) strtoul(argv[0]+2, NULL, 0);
  331. break;
  332. case 'F':
  333. ChainPara.fCheckRevocationFreshnessTime = TRUE;
  334. ChainPara.dwRevocationFreshnessTime =
  335. (DWORD) strtoul(argv[0]+2, NULL, 0);
  336. break;
  337. case 'h':
  338. default:
  339. goto BadUsage;
  340. }
  341. }
  342. } else {
  343. if (pszStoreFilename) {
  344. printf("Multiple StoreNames\n");
  345. goto BadUsage;
  346. }
  347. pszStoreFilename = argv[0];
  348. }
  349. }
  350. printf("command line: %s\n", GetCommandLine());
  351. if (pszStoreFilename == NULL) {
  352. printf("missing store filename\n");
  353. goto BadUsage;
  354. }
  355. // Attempt to open the store
  356. printf("Store :: %s\n", pszStoreFilename);
  357. hStore = OpenSystemStoreOrFile(fSystemStore, pszStoreFilename, 0);
  358. if (hStore == NULL) {
  359. printf("failed to open the store\n");
  360. goto ErrorReturn;
  361. }
  362. // Attempt to open the 'CA' store
  363. hCaStore = OpenSystemStoreOrFile(TRUE, "Ca", 0);
  364. if (hCaStore == NULL) {
  365. printf("failed to open the CA store\n");
  366. goto ErrorReturn;
  367. }
  368. if (!CertControlStore(
  369. hCaStore,
  370. 0, // dwFlags
  371. CERT_STORE_CTRL_AUTO_RESYNC,
  372. NULL // pvCtrlPara
  373. )) {
  374. PrintLastError("CertControlStore(AUTO_RESYNC)");
  375. goto ErrorReturn;
  376. }
  377. if (pszAdditionalChainStore) {
  378. printf("AdditionalChainStore :: %s\n", pszAdditionalChainStore);
  379. hAdditionalChainStore =
  380. OpenSystemStoreOrFile(FALSE, pszAdditionalChainStore, 0);
  381. if (hAdditionalChainStore == NULL) {
  382. printf("failed to open the AdditionalChainStore\n");
  383. goto ErrorReturn;
  384. }
  385. }
  386. if (pszAdditionalEngineStore) {
  387. printf("AdditionalEngineStore :: %s\n", pszAdditionalEngineStore);
  388. hAdditionalEngineStore =
  389. OpenSystemStoreOrFile(FALSE, pszAdditionalEngineStore, 0);
  390. if (hAdditionalEngineStore == NULL) {
  391. printf("failed to open the AdditionalEngineStore\n");
  392. goto ErrorReturn;
  393. }
  394. }
  395. if (fResync) {
  396. printf("Resync :: Sleep: %d (milliseconds)\n",
  397. rgdwCtrlSleepMilliSeconds[RESYNC_THR_IDX]);
  398. }
  399. if (pszDeleteCert) {
  400. printf("Delete :: Sleep: %d (milliseconds) Cert: %s\n",
  401. rgdwCtrlSleepMilliSeconds[DELETE_THR_IDX],
  402. pszDeleteCert);
  403. pDeleteCertContext = ReadCert(pszDeleteCert);
  404. if (NULL == pDeleteCertContext) {
  405. printf("failed to read the DeleteCert\n");
  406. goto ErrorReturn;
  407. }
  408. }
  409. if (pszReplaceCert) {
  410. printf("Replace :: Sleep: %d (milliseconds) Cert: %s\n",
  411. rgdwCtrlSleepMilliSeconds[REPLACE_THR_IDX],
  412. pszReplaceCert);
  413. pReplaceCertContext = ReadCert(pszReplaceCert);
  414. if (NULL == pReplaceCertContext) {
  415. printf("failed to read the ReplaceCert\n");
  416. goto ErrorReturn;
  417. }
  418. }
  419. // Determine if we need to create our own engine
  420. if (dwLruCnt != 0 || hAdditionalEngineStore != NULL) {
  421. CERT_CHAIN_ENGINE_CONFIG ChainEngineConfig;
  422. printf("Create chain engine ::");
  423. if (hAdditionalEngineStore)
  424. printf(" AdditionalStore : %s", pszAdditionalEngineStore);
  425. if (dwLruCnt != 0)
  426. printf(" Lru Count : %d", dwLruCnt);
  427. printf("\n");
  428. memset(&ChainEngineConfig, 0, sizeof(ChainEngineConfig));
  429. ChainEngineConfig.cbSize = sizeof(ChainEngineConfig);
  430. if (hAdditionalEngineStore) {
  431. ChainEngineConfig.cAdditionalStore = 1;
  432. ChainEngineConfig.rghAdditionalStore = &hAdditionalEngineStore;
  433. }
  434. ChainEngineConfig.dwFlags =
  435. CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE |
  436. CERT_CHAIN_ENABLE_SHARE_STORE;
  437. if (dwLruCnt != 0) {
  438. ChainEngineConfig.MaximumCachedCertificates = dwLruCnt;
  439. ChainEngineConfig.dwFlags |= CERT_CHAIN_CACHE_END_CERT;
  440. }
  441. if (!CertCreateCertificateChainEngine(
  442. &ChainEngineConfig, &hChainEngine)) {
  443. PrintLastError("CertCreateCertificateChainEngine");
  444. goto ErrorReturn;
  445. }
  446. } else if (HCCE_LOCAL_MACHINE == hChainEngine) {
  447. printf("Using LocalMachine chain engine\n");
  448. }
  449. // Update the chain usage parameters
  450. ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  451. ChainPara.RequestedUsage.Usage.cUsageIdentifier = cUsageOID;
  452. ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier =
  453. rgpszUsageOID;
  454. for (i = 0; i < cUsageOID; i++) {
  455. printf("Usage[%d] : %s\n", i, rgpszUsageOID[i]);
  456. }
  457. if (0 >= lIterations) {
  458. lIterations = -1;
  459. printf("Infinite iterations\n");
  460. } else
  461. printf("%d iterations\n", lIterations);
  462. if (fPause) {
  463. int c;
  464. fputs("Waiting to start ->", stdout);
  465. fflush(stdin);
  466. fflush(stdout);
  467. c = getchar();
  468. }
  469. // Create the control threads
  470. if (fResync) {
  471. if (NULL == (rghCtrlThread[RESYNC_THR_IDX] = CreateThread(
  472. NULL, // lpThreadAttributes
  473. 0, // dwStackSize
  474. ResyncThreadProc,
  475. NULL, // lpParameters
  476. 0, // dwCreationFlags
  477. &dwThreadId
  478. ))) {
  479. PrintLastError("CreateThread(Resync)");
  480. }
  481. }
  482. if (pDeleteCertContext) {
  483. if (NULL == (rghCtrlThread[DELETE_THR_IDX] = CreateThread(
  484. NULL, // lpThreadAttributes
  485. 0, // dwStackSize
  486. DeleteThreadProc,
  487. NULL, // lpParameters
  488. 0, // dwCreationFlags
  489. &dwThreadId
  490. ))) {
  491. PrintLastError("CreateThread(Delete)");
  492. }
  493. }
  494. if (pReplaceCertContext) {
  495. if (NULL == (rghCtrlThread[REPLACE_THR_IDX] = CreateThread(
  496. NULL, // lpThreadAttributes
  497. 0, // dwStackSize
  498. ReplaceThreadProc,
  499. NULL, // lpParameters
  500. 0, // dwCreationFlags
  501. &dwThreadId
  502. ))) {
  503. PrintLastError("CreateThread(Replace)");
  504. }
  505. }
  506. // Create the chain threads
  507. for (i = 0; i < dwThrCnt; i++) {
  508. if (NULL == (rghChainThread[i] = CreateThread(
  509. NULL, // lpThreadAttributes
  510. 0, // dwStackSize
  511. ChainThreadProc,
  512. (LPVOID) ((DWORD_PTR) i), // lpParameters
  513. 0, // dwCreationFlags
  514. &dwThreadId
  515. ))) {
  516. PrintLastError("CreateThread(Chain)");
  517. dwThrCnt = i;
  518. break;
  519. }
  520. }
  521. dwIterations = 0;
  522. while(TRUE) {
  523. dwIterations++;
  524. printf("%d - ", dwIterations);
  525. for (i = 0; i < dwThrCnt; i++)
  526. printf("%d ", rgdwChainIterations[i]);
  527. if (rghCtrlThread[RESYNC_THR_IDX])
  528. printf("r:%d ", rgdwCtrlIterations[RESYNC_THR_IDX]);
  529. if (rghCtrlThread[DELETE_THR_IDX])
  530. printf("d:%d ", rgdwCtrlIterations[DELETE_THR_IDX]);
  531. if (rghCtrlThread[REPLACE_THR_IDX])
  532. printf("R:%d ", rgdwCtrlIterations[REPLACE_THR_IDX]);
  533. printf("\n");
  534. if (0 == dwThrCnt)
  535. break;
  536. // Check if all the chain threads have completed
  537. if (WAIT_OBJECT_0 == WaitForMultipleObjects(
  538. dwThrCnt,
  539. rghChainThread,
  540. TRUE, // bWaitAll
  541. 0 // dwMilliseconds
  542. ))
  543. break;
  544. if (dwThrCnt <= 5)
  545. Sleep(1000);
  546. else
  547. Sleep(5000);
  548. }
  549. // Signal the control threads to exit
  550. fDone = TRUE;
  551. // Close all the chain thread handles
  552. for (i = 0; i < dwThrCnt; i++)
  553. CloseHandle(rghChainThread[i]);
  554. // Wait for the control threads to exit
  555. for (i = 0; i < CTRL_THR_CNT; i++) {
  556. if (rghCtrlThread[i]) {
  557. WaitForSingleObject(rghCtrlThread[i], INFINITE);
  558. CloseHandle(rghCtrlThread[i]);
  559. }
  560. }
  561. status = 0;
  562. CommonReturn:
  563. // This does a flush for CurrentUser or LocalMachine
  564. CertFreeCertificateChainEngine(hChainEngine);
  565. if (pReplaceCertContext)
  566. CertFreeCertificateContext(pReplaceCertContext);
  567. if (pDeleteCertContext)
  568. CertFreeCertificateContext(pDeleteCertContext);
  569. if (hAdditionalChainStore)
  570. CertCloseStore(hAdditionalChainStore, 0);
  571. if (hAdditionalEngineStore)
  572. CertCloseStore(hAdditionalEngineStore, 0);
  573. if (hCaStore)
  574. CertCloseStore(hCaStore, 0);
  575. if (hStore)
  576. CertCloseStore(hStore, 0);
  577. if (fPause) {
  578. int c;
  579. fputs("Waiting to exit ->", stdout);
  580. fflush(stdin);
  581. fflush(stdout);
  582. c = getchar();
  583. }
  584. return status;
  585. ErrorReturn:
  586. status = -1;
  587. goto CommonReturn;
  588. BadUsage:
  589. Usage();
  590. status = -1;
  591. goto CommonReturn;
  592. }