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
699 lines
21 KiB
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1996
|
|
//
|
|
// File: tchain.cpp
|
|
//
|
|
// Contents: Chain threading tests
|
|
//
|
|
// See Usage() for a list of test options.
|
|
//
|
|
//
|
|
// Functions: main
|
|
//
|
|
// History: 28-Mar-00 philh created
|
|
//--------------------------------------------------------------------------
|
|
|
|
#define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS 1
|
|
|
|
#include <windows.h>
|
|
#include <assert.h>
|
|
#include "wincrypt.h"
|
|
#include "certtest.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
#include <time.h>
|
|
|
|
|
|
#define CTRL_THR_CNT 3
|
|
#define RESYNC_THR_IDX 0
|
|
#define DELETE_THR_IDX 1
|
|
#define REPLACE_THR_IDX 2
|
|
|
|
HANDLE rghCtrlThread[CTRL_THR_CNT];
|
|
DWORD rgdwCtrlIterations[CTRL_THR_CNT];
|
|
DWORD rgdwCtrlSleepMilliSeconds[CTRL_THR_CNT];
|
|
|
|
#define MAX_CHAIN_THR_CNT 16
|
|
HANDLE rghChainThread[MAX_CHAIN_THR_CNT];
|
|
DWORD rgdwChainIterations[MAX_CHAIN_THR_CNT];
|
|
|
|
LONG lIterations = -1;
|
|
BOOL fCreateEndCert = FALSE;
|
|
|
|
HCERTSTORE hStore = NULL;
|
|
HCERTSTORE hCaStore = NULL;
|
|
HCERTSTORE hAdditionalChainStore = NULL;
|
|
PCCERT_CONTEXT pReplaceCertContext = NULL;
|
|
PCCERT_CONTEXT pDeleteCertContext = NULL;
|
|
HCERTCHAINENGINE hChainEngine = NULL;
|
|
|
|
#define MAX_USAGE_CNT 16
|
|
LPSTR rgpszUsageOID[MAX_USAGE_CNT];
|
|
DWORD cUsageOID = 0;
|
|
CERT_CHAIN_PARA ChainPara;
|
|
|
|
DWORD dwChainFlags = 0;
|
|
BOOL fDone = FALSE;
|
|
|
|
|
|
static void Usage(void)
|
|
{
|
|
printf("Usage: tchain [options] <StoreName>\n");
|
|
printf("\n");
|
|
printf(" -CreateEndCert - Create new end cert for each chain\n");
|
|
printf(" -LocalMachine - Defaults to CurrentUser\n");
|
|
printf(" -Pause\n");
|
|
printf("\n");
|
|
printf("Options are:\n");
|
|
printf(" -u<OID String> - Usage OID string -u1.3.6.1.5.5.7.3.3\n");
|
|
printf(" -t<number> - Threads (defaults to 4)\n");
|
|
printf(" -i<number> - Iterations (defaults to -1, infinite)\n");
|
|
printf(" -l<number> - Lru cache count, enable end cert caching\n");
|
|
printf(" -f<Number> - Chain Flags\n");
|
|
printf(" -T<number> - Url Timeout (milliseconds)\n");
|
|
printf(" -F<number> - Revocation Freshness (seconds)\n");
|
|
printf(" -r[<number>] - Resync engine, defaults to 2K millisecs\n");
|
|
printf(" -d[<num>] <cert> - Delete cert from CA store\n");
|
|
printf(" -R[<num>] <cert> - Replace cert in CA store\n");
|
|
printf(" -s - Open the \"StoreName\" System store\n");
|
|
printf(" -a<filename> - Additional chain store filename\n");
|
|
printf(" -A<filename> - Additional engine store filename\n");
|
|
printf(" -h - This message\n");
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
DWORD WINAPI ChainThreadProc(
|
|
LPVOID lpThreadParameter
|
|
)
|
|
{
|
|
DWORD dwThrIdx = (DWORD) ((DWORD_PTR) lpThreadParameter);
|
|
|
|
if (dwThrIdx >= MAX_CHAIN_THR_CNT) {
|
|
printf("Invalid dwThrIdx\n");
|
|
return 0;
|
|
}
|
|
|
|
while (TRUE) {
|
|
PCCERT_CONTEXT pCert = NULL;
|
|
while (pCert = CertEnumCertificatesInStore(hStore, pCert)) {
|
|
PCCERT_CONTEXT pCreateCert = NULL;
|
|
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
|
|
|
|
if (fCreateEndCert) {
|
|
pCreateCert = CertCreateCertificateContext(
|
|
pCert->dwCertEncodingType,
|
|
pCert->pbCertEncoded,
|
|
pCert->cbCertEncoded
|
|
);
|
|
if (NULL == pCreateCert) {
|
|
PrintLastError("CertCreateCertificateContext");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
if (!CertGetCertificateChain(
|
|
hChainEngine,
|
|
fCreateEndCert ? pCreateCert : pCert,
|
|
NULL, // pTime
|
|
hAdditionalChainStore,
|
|
&ChainPara,
|
|
dwChainFlags,
|
|
NULL, // pvReserved
|
|
&pChainContext
|
|
)) {
|
|
PrintLastError("CertGetCertificateChain");
|
|
return 0;
|
|
}
|
|
|
|
CertFreeCertificateChain(pChainContext);
|
|
if (pCreateCert)
|
|
CertFreeCertificateContext(pCreateCert);
|
|
}
|
|
|
|
rgdwChainIterations[dwThrIdx]++;
|
|
if (lIterations > 0 &&
|
|
rgdwChainIterations[dwThrIdx] >= (DWORD) lIterations)
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
DWORD WINAPI ResyncThreadProc(
|
|
LPVOID lpThreadParameter
|
|
)
|
|
{
|
|
while (TRUE) {
|
|
if (fDone)
|
|
break;
|
|
|
|
if (!CertResyncCertificateChainEngine(hChainEngine)) {
|
|
PrintLastError("CertResyncCertificateChainEngine");
|
|
return 0;
|
|
}
|
|
|
|
rgdwCtrlIterations[RESYNC_THR_IDX]++;
|
|
Sleep(rgdwCtrlSleepMilliSeconds[RESYNC_THR_IDX]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
DWORD WINAPI DeleteThreadProc(
|
|
LPVOID lpThreadParameter
|
|
)
|
|
{
|
|
BYTE rgbHash[MAX_HASH_LEN];
|
|
CRYPT_HASH_BLOB HashBlob;
|
|
|
|
HashBlob.cbData = MAX_HASH_LEN;
|
|
HashBlob.pbData = rgbHash;
|
|
|
|
if (!CertGetCertificateContextProperty(
|
|
pDeleteCertContext,
|
|
CERT_MD5_HASH_PROP_ID,
|
|
rgbHash,
|
|
&HashBlob.cbData
|
|
)) {
|
|
PrintLastError("CertGetCertificateContextProperty");
|
|
return 0;
|
|
}
|
|
|
|
while (TRUE) {
|
|
PCCERT_CONTEXT pFound = NULL;
|
|
|
|
if (fDone)
|
|
break;
|
|
|
|
pFound = CertFindCertificateInStore(
|
|
hCaStore,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_MD5_HASH,
|
|
&HashBlob,
|
|
NULL
|
|
);
|
|
|
|
if (pFound) {
|
|
CertDeleteCertificateFromStore(pFound);
|
|
rgdwCtrlIterations[DELETE_THR_IDX]++;
|
|
}
|
|
|
|
Sleep(rgdwCtrlSleepMilliSeconds[DELETE_THR_IDX]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
DWORD WINAPI ReplaceThreadProc(
|
|
LPVOID lpThreadParameter
|
|
)
|
|
{
|
|
while (TRUE) {
|
|
if (fDone)
|
|
break;
|
|
|
|
if (!CertAddCertificateContextToStore(
|
|
hCaStore,
|
|
pReplaceCertContext,
|
|
CERT_STORE_ADD_REPLACE_EXISTING,
|
|
NULL // ppStoreContext
|
|
)) {
|
|
PrintLastError("CertAddCertificateContextToStore");
|
|
return 0;
|
|
}
|
|
|
|
rgdwCtrlIterations[REPLACE_THR_IDX]++;
|
|
Sleep(rgdwCtrlSleepMilliSeconds[REPLACE_THR_IDX]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
PCCERT_CONTEXT ReadCert(
|
|
IN LPSTR pszCert
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbEncoded;
|
|
DWORD cbEncoded;
|
|
PCCERT_CONTEXT pCert;
|
|
|
|
if (!ReadDERFromFile(pszCert, &pbEncoded, &cbEncoded)) {
|
|
PrintLastError("ReadCert");
|
|
return NULL;
|
|
}
|
|
|
|
pCert = CertCreateCertificateContext(
|
|
dwCertEncodingType,
|
|
pbEncoded,
|
|
cbEncoded
|
|
);
|
|
if (pCert == NULL)
|
|
PrintLastError("CertCreateCertificateContext");
|
|
|
|
TestFree(pbEncoded);
|
|
return pCert;
|
|
}
|
|
|
|
int _cdecl main(int argc, char * argv[])
|
|
{
|
|
int status;
|
|
|
|
LPSTR pszAdditionalChainStore = NULL;
|
|
LPSTR pszAdditionalEngineStore = NULL;
|
|
BOOL fResync = FALSE;
|
|
DWORD dwLruCnt = 0;
|
|
LPSTR pszDeleteCert = NULL;
|
|
LPSTR pszReplaceCert = NULL;
|
|
BOOL fSystemStore = FALSE;
|
|
LPSTR pszStoreFilename = NULL;
|
|
BOOL fPause = FALSE;
|
|
DWORD dwThrCnt = 4;
|
|
|
|
HCERTSTORE hAdditionalEngineStore = NULL;
|
|
|
|
DWORD dwThreadId;
|
|
DWORD dwIterations;
|
|
DWORD i;
|
|
|
|
for (i = 0; i < CTRL_THR_CNT; i ++)
|
|
rgdwCtrlSleepMilliSeconds[i] = 2000; // 2 second
|
|
|
|
// Initialize the chain parameters
|
|
memset(&ChainPara, 0, sizeof(ChainPara));
|
|
ChainPara.cbSize = sizeof(ChainPara);
|
|
|
|
while (--argc>0) {
|
|
if (**++argv == '-')
|
|
{
|
|
if (0 == _stricmp(argv[0]+1, "CreateEndCert")) {
|
|
fCreateEndCert = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "LocalMachine")) {
|
|
hChainEngine = HCCE_LOCAL_MACHINE;
|
|
} else if (0 == _stricmp(argv[0]+1, "Pause")) {
|
|
fPause = TRUE;
|
|
|
|
} else {
|
|
switch(argv[0][1])
|
|
{
|
|
case 'u':
|
|
if (MAX_USAGE_CNT <= cUsageOID) {
|
|
printf("Too many usages\n");
|
|
goto BadUsage;
|
|
}
|
|
|
|
rgpszUsageOID[cUsageOID++] = argv[0]+2;
|
|
break;
|
|
case 'i':
|
|
lIterations = strtol(argv[0]+2, NULL, 0);
|
|
break;
|
|
case 't':
|
|
dwThrCnt = (DWORD) strtoul(argv[0]+2, NULL, 0);
|
|
if (dwThrCnt > MAX_CHAIN_THR_CNT) {
|
|
printf("exceeded max thread count of %d\n",
|
|
MAX_CHAIN_THR_CNT);
|
|
goto BadUsage;
|
|
}
|
|
break;
|
|
case 'l':
|
|
dwLruCnt = (DWORD) strtoul(argv[0]+2, NULL, 0);
|
|
break;
|
|
case 'r':
|
|
fResync = TRUE;
|
|
if (argv[0][2]) {
|
|
rgdwCtrlSleepMilliSeconds[RESYNC_THR_IDX] =
|
|
(DWORD) strtoul(argv[0]+2, NULL, 0);
|
|
}
|
|
break;
|
|
case 'd':
|
|
if (argv[0][2]) {
|
|
rgdwCtrlSleepMilliSeconds[DELETE_THR_IDX] =
|
|
(DWORD) strtoul(argv[0]+2, NULL, 0);
|
|
}
|
|
|
|
++argv;
|
|
if (--argc <= 0 || argv[0][0] == '-') {
|
|
printf("Missing Delete cert\n");
|
|
goto BadUsage;
|
|
}
|
|
pszDeleteCert = argv[0];
|
|
break;
|
|
case 'R':
|
|
if (argv[0][2]) {
|
|
rgdwCtrlSleepMilliSeconds[REPLACE_THR_IDX] =
|
|
(DWORD) strtoul(argv[0]+2, NULL, 0);
|
|
}
|
|
|
|
++argv;
|
|
if (--argc <= 0 || argv[0][0] == '-') {
|
|
printf("Missing Replace cert\n");
|
|
goto BadUsage;
|
|
}
|
|
pszReplaceCert = argv[0];
|
|
break;
|
|
case 'f':
|
|
dwChainFlags = (DWORD) strtoul(argv[0]+2, NULL, 0);
|
|
break;
|
|
case 's':
|
|
fSystemStore = TRUE;
|
|
break;
|
|
case 'a':
|
|
pszAdditionalChainStore = argv[0]+2;
|
|
if (*pszAdditionalChainStore == '\0') {
|
|
printf("Need to specify filename\n");
|
|
goto BadUsage;
|
|
}
|
|
break;
|
|
case 'A':
|
|
pszAdditionalEngineStore = argv[0]+2;
|
|
if (*pszAdditionalEngineStore == '\0') {
|
|
printf("Need to specify filename\n");
|
|
goto BadUsage;
|
|
}
|
|
break;
|
|
case 'T':
|
|
ChainPara.dwUrlRetrievalTimeout =
|
|
(DWORD) strtoul(argv[0]+2, NULL, 0);
|
|
break;
|
|
case 'F':
|
|
ChainPara.fCheckRevocationFreshnessTime = TRUE;
|
|
ChainPara.dwRevocationFreshnessTime =
|
|
(DWORD) strtoul(argv[0]+2, NULL, 0);
|
|
break;
|
|
case 'h':
|
|
default:
|
|
goto BadUsage;
|
|
}
|
|
}
|
|
} else {
|
|
if (pszStoreFilename) {
|
|
printf("Multiple StoreNames\n");
|
|
goto BadUsage;
|
|
}
|
|
pszStoreFilename = argv[0];
|
|
}
|
|
}
|
|
|
|
|
|
printf("command line: %s\n", GetCommandLine());
|
|
|
|
if (pszStoreFilename == NULL) {
|
|
printf("missing store filename\n");
|
|
goto BadUsage;
|
|
}
|
|
|
|
// Attempt to open the store
|
|
printf("Store :: %s\n", pszStoreFilename);
|
|
hStore = OpenSystemStoreOrFile(fSystemStore, pszStoreFilename, 0);
|
|
if (hStore == NULL) {
|
|
printf("failed to open the store\n");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
// Attempt to open the 'CA' store
|
|
hCaStore = OpenSystemStoreOrFile(TRUE, "Ca", 0);
|
|
if (hCaStore == NULL) {
|
|
printf("failed to open the CA store\n");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (!CertControlStore(
|
|
hCaStore,
|
|
0, // dwFlags
|
|
CERT_STORE_CTRL_AUTO_RESYNC,
|
|
NULL // pvCtrlPara
|
|
)) {
|
|
PrintLastError("CertControlStore(AUTO_RESYNC)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (pszAdditionalChainStore) {
|
|
printf("AdditionalChainStore :: %s\n", pszAdditionalChainStore);
|
|
hAdditionalChainStore =
|
|
OpenSystemStoreOrFile(FALSE, pszAdditionalChainStore, 0);
|
|
if (hAdditionalChainStore == NULL) {
|
|
printf("failed to open the AdditionalChainStore\n");
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
|
|
if (pszAdditionalEngineStore) {
|
|
printf("AdditionalEngineStore :: %s\n", pszAdditionalEngineStore);
|
|
hAdditionalEngineStore =
|
|
OpenSystemStoreOrFile(FALSE, pszAdditionalEngineStore, 0);
|
|
if (hAdditionalEngineStore == NULL) {
|
|
printf("failed to open the AdditionalEngineStore\n");
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
|
|
if (fResync) {
|
|
printf("Resync :: Sleep: %d (milliseconds)\n",
|
|
rgdwCtrlSleepMilliSeconds[RESYNC_THR_IDX]);
|
|
}
|
|
|
|
if (pszDeleteCert) {
|
|
printf("Delete :: Sleep: %d (milliseconds) Cert: %s\n",
|
|
rgdwCtrlSleepMilliSeconds[DELETE_THR_IDX],
|
|
pszDeleteCert);
|
|
pDeleteCertContext = ReadCert(pszDeleteCert);
|
|
if (NULL == pDeleteCertContext) {
|
|
printf("failed to read the DeleteCert\n");
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
|
|
if (pszReplaceCert) {
|
|
printf("Replace :: Sleep: %d (milliseconds) Cert: %s\n",
|
|
rgdwCtrlSleepMilliSeconds[REPLACE_THR_IDX],
|
|
pszReplaceCert);
|
|
pReplaceCertContext = ReadCert(pszReplaceCert);
|
|
if (NULL == pReplaceCertContext) {
|
|
printf("failed to read the ReplaceCert\n");
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
|
|
// Determine if we need to create our own engine
|
|
|
|
if (dwLruCnt != 0 || hAdditionalEngineStore != NULL) {
|
|
CERT_CHAIN_ENGINE_CONFIG ChainEngineConfig;
|
|
|
|
printf("Create chain engine ::");
|
|
if (hAdditionalEngineStore)
|
|
printf(" AdditionalStore : %s", pszAdditionalEngineStore);
|
|
if (dwLruCnt != 0)
|
|
printf(" Lru Count : %d", dwLruCnt);
|
|
printf("\n");
|
|
|
|
memset(&ChainEngineConfig, 0, sizeof(ChainEngineConfig));
|
|
ChainEngineConfig.cbSize = sizeof(ChainEngineConfig);
|
|
if (hAdditionalEngineStore) {
|
|
ChainEngineConfig.cAdditionalStore = 1;
|
|
ChainEngineConfig.rghAdditionalStore = &hAdditionalEngineStore;
|
|
}
|
|
|
|
ChainEngineConfig.dwFlags =
|
|
CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE |
|
|
CERT_CHAIN_ENABLE_SHARE_STORE;
|
|
|
|
if (dwLruCnt != 0) {
|
|
ChainEngineConfig.MaximumCachedCertificates = dwLruCnt;
|
|
ChainEngineConfig.dwFlags |= CERT_CHAIN_CACHE_END_CERT;
|
|
}
|
|
|
|
if (!CertCreateCertificateChainEngine(
|
|
&ChainEngineConfig, &hChainEngine)) {
|
|
PrintLastError("CertCreateCertificateChainEngine");
|
|
goto ErrorReturn;
|
|
}
|
|
} else if (HCCE_LOCAL_MACHINE == hChainEngine) {
|
|
printf("Using LocalMachine chain engine\n");
|
|
}
|
|
|
|
|
|
// Update the chain usage parameters
|
|
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
|
|
ChainPara.RequestedUsage.Usage.cUsageIdentifier = cUsageOID;
|
|
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier =
|
|
rgpszUsageOID;
|
|
|
|
for (i = 0; i < cUsageOID; i++) {
|
|
printf("Usage[%d] : %s\n", i, rgpszUsageOID[i]);
|
|
}
|
|
|
|
if (0 >= lIterations) {
|
|
lIterations = -1;
|
|
printf("Infinite iterations\n");
|
|
} else
|
|
printf("%d iterations\n", lIterations);
|
|
|
|
if (fPause) {
|
|
int c;
|
|
fputs("Waiting to start ->", stdout);
|
|
fflush(stdin);
|
|
fflush(stdout);
|
|
c = getchar();
|
|
}
|
|
|
|
|
|
// Create the control threads
|
|
if (fResync) {
|
|
if (NULL == (rghCtrlThread[RESYNC_THR_IDX] = CreateThread(
|
|
NULL, // lpThreadAttributes
|
|
0, // dwStackSize
|
|
ResyncThreadProc,
|
|
NULL, // lpParameters
|
|
0, // dwCreationFlags
|
|
&dwThreadId
|
|
))) {
|
|
PrintLastError("CreateThread(Resync)");
|
|
}
|
|
}
|
|
|
|
if (pDeleteCertContext) {
|
|
if (NULL == (rghCtrlThread[DELETE_THR_IDX] = CreateThread(
|
|
NULL, // lpThreadAttributes
|
|
0, // dwStackSize
|
|
DeleteThreadProc,
|
|
NULL, // lpParameters
|
|
0, // dwCreationFlags
|
|
&dwThreadId
|
|
))) {
|
|
PrintLastError("CreateThread(Delete)");
|
|
}
|
|
}
|
|
|
|
if (pReplaceCertContext) {
|
|
if (NULL == (rghCtrlThread[REPLACE_THR_IDX] = CreateThread(
|
|
NULL, // lpThreadAttributes
|
|
0, // dwStackSize
|
|
ReplaceThreadProc,
|
|
NULL, // lpParameters
|
|
0, // dwCreationFlags
|
|
&dwThreadId
|
|
))) {
|
|
PrintLastError("CreateThread(Replace)");
|
|
}
|
|
}
|
|
|
|
// Create the chain threads
|
|
for (i = 0; i < dwThrCnt; i++) {
|
|
if (NULL == (rghChainThread[i] = CreateThread(
|
|
NULL, // lpThreadAttributes
|
|
0, // dwStackSize
|
|
ChainThreadProc,
|
|
(LPVOID) ((DWORD_PTR) i), // lpParameters
|
|
0, // dwCreationFlags
|
|
&dwThreadId
|
|
))) {
|
|
PrintLastError("CreateThread(Chain)");
|
|
dwThrCnt = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwIterations = 0;
|
|
while(TRUE) {
|
|
dwIterations++;
|
|
|
|
printf("%d - ", dwIterations);
|
|
|
|
for (i = 0; i < dwThrCnt; i++)
|
|
printf("%d ", rgdwChainIterations[i]);
|
|
|
|
if (rghCtrlThread[RESYNC_THR_IDX])
|
|
printf("r:%d ", rgdwCtrlIterations[RESYNC_THR_IDX]);
|
|
if (rghCtrlThread[DELETE_THR_IDX])
|
|
printf("d:%d ", rgdwCtrlIterations[DELETE_THR_IDX]);
|
|
if (rghCtrlThread[REPLACE_THR_IDX])
|
|
printf("R:%d ", rgdwCtrlIterations[REPLACE_THR_IDX]);
|
|
|
|
printf("\n");
|
|
|
|
if (0 == dwThrCnt)
|
|
break;
|
|
|
|
// Check if all the chain threads have completed
|
|
if (WAIT_OBJECT_0 == WaitForMultipleObjects(
|
|
dwThrCnt,
|
|
rghChainThread,
|
|
TRUE, // bWaitAll
|
|
0 // dwMilliseconds
|
|
))
|
|
break;
|
|
|
|
if (dwThrCnt <= 5)
|
|
Sleep(1000);
|
|
else
|
|
Sleep(5000);
|
|
}
|
|
|
|
// Signal the control threads to exit
|
|
fDone = TRUE;
|
|
|
|
// Close all the chain thread handles
|
|
for (i = 0; i < dwThrCnt; i++)
|
|
CloseHandle(rghChainThread[i]);
|
|
|
|
// Wait for the control threads to exit
|
|
for (i = 0; i < CTRL_THR_CNT; i++) {
|
|
if (rghCtrlThread[i]) {
|
|
WaitForSingleObject(rghCtrlThread[i], INFINITE);
|
|
CloseHandle(rghCtrlThread[i]);
|
|
}
|
|
}
|
|
|
|
|
|
status = 0;
|
|
CommonReturn:
|
|
// This does a flush for CurrentUser or LocalMachine
|
|
CertFreeCertificateChainEngine(hChainEngine);
|
|
|
|
if (pReplaceCertContext)
|
|
CertFreeCertificateContext(pReplaceCertContext);
|
|
if (pDeleteCertContext)
|
|
CertFreeCertificateContext(pDeleteCertContext);
|
|
if (hAdditionalChainStore)
|
|
CertCloseStore(hAdditionalChainStore, 0);
|
|
if (hAdditionalEngineStore)
|
|
CertCloseStore(hAdditionalEngineStore, 0);
|
|
|
|
if (hCaStore)
|
|
CertCloseStore(hCaStore, 0);
|
|
if (hStore)
|
|
CertCloseStore(hStore, 0);
|
|
|
|
if (fPause) {
|
|
int c;
|
|
fputs("Waiting to exit ->", stdout);
|
|
fflush(stdin);
|
|
fflush(stdout);
|
|
c = getchar();
|
|
}
|
|
|
|
return status;
|
|
|
|
ErrorReturn:
|
|
status = -1;
|
|
goto CommonReturn;
|
|
|
|
BadUsage:
|
|
Usage();
|
|
status = -1;
|
|
goto CommonReturn;
|
|
|
|
}
|
|
|