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.
605 lines
19 KiB
605 lines
19 KiB
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1996
|
|
//
|
|
// File: tfindclt.cpp
|
|
//
|
|
// Contents: FindCertsByIssuer, CertFindChainInStore APIs test
|
|
//
|
|
// See Usage() for list of test options.
|
|
//
|
|
//
|
|
// Functions: main
|
|
//
|
|
// History: 21-May-96 philh created
|
|
// 07-Jun-96 HelleS Added printing the command line
|
|
// and Failed or Passed at the end.
|
|
// 01-Mar-98 philh Added to call CertFindChainInStore
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#define CERT_CHAIN_FIND_BY_ISSUER_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>
|
|
|
|
static struct
|
|
{
|
|
LPCSTR pszName;
|
|
DWORD dwKeySpec;
|
|
} KeyTypes[] = {
|
|
"Sign", AT_SIGNATURE,
|
|
"Xchg", AT_KEYEXCHANGE
|
|
};
|
|
#define NKEYTYPES (sizeof(KeyTypes)/sizeof(KeyTypes[0]))
|
|
|
|
static DWORD dwDisplayFlags = 0;
|
|
|
|
|
|
static void Usage(void)
|
|
{
|
|
printf("Usage: tfindclt [options] [<Issuer CertFilename> [<KeyType>]]\n");
|
|
printf("Options are:\n");
|
|
printf(" -CompareKey\n");
|
|
printf(" -ComplexChain\n");
|
|
printf(" -CacheOnly\n");
|
|
printf(" -NoKey\n");
|
|
printf("\n");
|
|
printf(" -c<SystemStore> - Chain System Store\n");
|
|
printf(" -C<FileSystemStore> - Chain File System Store\n");
|
|
printf(" -u<OID String> - Usage OID string -u1.3.6.1.5.5.7.3.3\n");
|
|
printf(" -S[<FileName>] - Use issuer cert's subject name (default)\n");
|
|
printf(" -I[<FileName>] - Use issuer cert's issuer name\n");
|
|
printf(" -b - Brief\n");
|
|
printf(" -v - Verbose\n");
|
|
printf(" -h - This message\n");
|
|
printf("\n");
|
|
printf("KeyType (case insensitive):\n");
|
|
|
|
int i;
|
|
for (i = 0; i < NKEYTYPES; i++)
|
|
printf(" %s\n", KeyTypes[i].pszName);
|
|
printf("\n");
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Synopsis: Chain Display Functions
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
LPSTR rgszErrorStatus[] = {
|
|
|
|
"CERT_TRUST_IS_NOT_TIME_VALID",
|
|
"CERT_TRUST_IS_NOT_TIME_NESTED",
|
|
"CERT_TRUST_IS_REVOKED",
|
|
"CERT_TRUST_IS_NOT_SIGNATURE_VALID",
|
|
"CERT_TRUST_IS_NOT_VALID_FOR_USAGE",
|
|
"CERT_TRUST_IS_UNTRUSTED_ROOT",
|
|
"CERT_TRUST_REVOCATION_STATUS_UNKNOWN",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"CERT_TRUST_IS_PARTIAL_CHAIN",
|
|
"CERT_TRUST_CTL_IS_NOT_TIME_VALID",
|
|
"CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID",
|
|
"CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status",
|
|
"Unknown Error Status"
|
|
};
|
|
|
|
LPSTR rgszInfoStatus[] = {
|
|
|
|
"CERT_TRUST_HAS_EXACT_MATCH_ISSUER",// 0x00000001
|
|
"CERT_TRUST_HAS_KEY_MATCH_ISSUER", // 0x00000002
|
|
"CERT_TRUST_HAS_NAME_MATCH_ISSUER", // 0x00000004
|
|
"Unknown Info Status", // 0x00000008
|
|
"Unknown Info Status", // 0x00000010
|
|
"Unknown Info Status", // 0x00000020
|
|
"Unknown Info Status", // 0x00000040
|
|
"Unknown Info Status", // 0x00000080
|
|
"Unknown Info Status", // 0x00000100
|
|
"Unknown Info Status", // 0x00000200
|
|
"Unknown Info Status", // 0x00000400
|
|
"Unknown Info Status", // 0x00000800
|
|
"Unknown Info Status", // 0x00001000
|
|
"Unknown Info Status", // 0x00002000
|
|
"Unknown Info Status", // 0x00004000
|
|
"Unknown Info Status", // 0x00008000
|
|
"CERT_TRUST_IS_SELF_SIGNED", // 0x00010000
|
|
"Unknown Info Status", // 0x00020000
|
|
"Unknown Info Status", // 0x00040000
|
|
"Unknown Info Status", // 0x00080000
|
|
"Unknown Info Status", // 0x00100000
|
|
"Unknown Info Status", // 0x00200000
|
|
"Unknown Info Status", // 0x00400000
|
|
"Unknown Info Status", // 0x00800000
|
|
"Unknown Info Status", // 0x01000000
|
|
"Unknown Info Status", // 0x02000000
|
|
"Unknown Info Status", // 0x04000000
|
|
"Unknown Info Status", // 0x08000000
|
|
"CERT_TRUST_IS_COMPLEX_CHAIN", // 0x10000000
|
|
"Unknown Info Status", // 0x20000000
|
|
"Unknown Info Status", // 0x40000000
|
|
"Unknown Info Status" // 0x80000000
|
|
};
|
|
|
|
void DisplayTrustStatus(
|
|
IN const CERT_TRUST_STATUS *pStatus
|
|
)
|
|
{
|
|
DWORD dwMask;
|
|
DWORD cCount;
|
|
|
|
printf(
|
|
"Trust Status (E=0x%lx,I=0x%lx)\n\n",
|
|
pStatus->dwErrorStatus,
|
|
pStatus->dwInfoStatus
|
|
);
|
|
|
|
dwMask = 1;
|
|
for ( cCount = 0; cCount < 32; cCount++ )
|
|
{
|
|
if ( pStatus->dwErrorStatus & dwMask )
|
|
{
|
|
if ( strcmp( rgszErrorStatus[ cCount ], "Unknown Error Status" ) != 0 )
|
|
{
|
|
printf("%s\n", rgszErrorStatus[ cCount ]);
|
|
}
|
|
}
|
|
|
|
dwMask = dwMask << 1;
|
|
}
|
|
|
|
dwMask = 1;
|
|
for ( cCount = 0; cCount < 32; cCount++ )
|
|
{
|
|
if ( pStatus->dwInfoStatus & dwMask )
|
|
{
|
|
if ( strcmp( rgszInfoStatus[ cCount ], "Unknown Info Status" ) != 0 )
|
|
{
|
|
printf("%s\n", rgszInfoStatus[ cCount ]);
|
|
}
|
|
}
|
|
|
|
dwMask = dwMask << 1;
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
void DisplayChainElement(
|
|
IN PCERT_CHAIN_ELEMENT pElement
|
|
)
|
|
{
|
|
DisplayCert( pElement->pCertContext, dwDisplayFlags );
|
|
printf("\n");
|
|
DisplayTrustStatus( &pElement->TrustStatus );
|
|
}
|
|
|
|
void DisplaySimpleChain(
|
|
IN PCERT_SIMPLE_CHAIN pChain
|
|
)
|
|
{
|
|
DWORD cElement;
|
|
|
|
DisplayTrustStatus( &pChain->TrustStatus );
|
|
printf("Chain Element Count = %d\n", pChain->cElement);
|
|
for ( cElement = 0; cElement < pChain->cElement; cElement++ )
|
|
{
|
|
printf("Chain Element [%d]\n", cElement);
|
|
DisplayChainElement( pChain->rgpElement[ cElement ]);
|
|
}
|
|
}
|
|
|
|
void DisplayComplexChain(
|
|
IN PCCERT_CHAIN_CONTEXT pChainContext
|
|
)
|
|
{
|
|
DWORD cChain;
|
|
|
|
if (NULL == pChainContext)
|
|
return;
|
|
|
|
DisplayTrustStatus(&pChainContext->TrustStatus );
|
|
printf("\n");
|
|
printf("Simple Chain Count = %d\n\n", pChainContext->cChain );
|
|
|
|
for ( cChain = 0; cChain < pChainContext->cChain; cChain++ )
|
|
{
|
|
printf("Simple Chain [%d]\n", cChain);
|
|
DisplaySimpleChain( pChainContext->rgpChain[ cChain ]);
|
|
}
|
|
}
|
|
|
|
#define FIND_BY_ISSUER_ARG 0x1539beef
|
|
BOOL WINAPI FindByIssuerCallback(
|
|
IN PCCERT_CONTEXT pCert,
|
|
IN void *pvFindArg
|
|
)
|
|
{
|
|
if (dwDisplayFlags & DISPLAY_VERBOSE_FLAG)
|
|
printf(">>>>> FindByIssuerCallback <<<<<\n");
|
|
if (pvFindArg != (void *) FIND_BY_ISSUER_ARG)
|
|
printf("failed => wrong pvFindArg\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL CreateChainByIssuer(
|
|
IN HCERTSTORE hChainStore,
|
|
IN DWORD dwFindFlags,
|
|
IN LPCSTR pszUsageIdentifier,
|
|
IN DWORD dwKeySpec,
|
|
IN DWORD cIssuer,
|
|
IN PCERT_NAME_BLOB rgIssuer
|
|
)
|
|
{
|
|
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
|
|
DWORD dwChainIndex = 0;
|
|
DWORD dwIssuerChainIndex = 0;
|
|
DWORD dwIssuerElementIndex = 0;
|
|
|
|
CERT_CHAIN_FIND_BY_ISSUER_PARA FindPara;
|
|
memset(&FindPara, 0, sizeof(FindPara));
|
|
FindPara.cbSize = sizeof(FindPara);
|
|
FindPara.pszUsageIdentifier = pszUsageIdentifier;
|
|
FindPara.dwKeySpec = dwKeySpec;
|
|
FindPara.cIssuer = cIssuer;
|
|
FindPara.rgIssuer = rgIssuer;
|
|
FindPara.pfnFindCallback = FindByIssuerCallback;
|
|
FindPara.pvFindArg = (void *) FIND_BY_ISSUER_ARG;
|
|
FindPara.pdwIssuerChainIndex = &dwIssuerChainIndex;
|
|
FindPara.pdwIssuerElementIndex = &dwIssuerElementIndex;
|
|
|
|
while (pChainContext = CertFindChainInStore(
|
|
hChainStore,
|
|
dwCertEncodingType,
|
|
dwFindFlags,
|
|
CERT_CHAIN_FIND_BY_ISSUER,
|
|
&FindPara,
|
|
pChainContext
|
|
)) {
|
|
printf("\n");
|
|
printf("======================= CHAIN[%d,%d] %d =======================\n",
|
|
dwIssuerChainIndex, dwIssuerElementIndex, dwChainIndex);
|
|
dwChainIndex++;
|
|
|
|
DisplayComplexChain(pChainContext);
|
|
dwIssuerChainIndex = 0;
|
|
dwIssuerElementIndex = 0;
|
|
}
|
|
|
|
if (0 == dwChainIndex)
|
|
printf(">>>> No Chains <<<<\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static BOOL AllocAndGetEncodedIssuer(
|
|
LPSTR pszCertFilename,
|
|
BOOL fUseIssuerName,
|
|
PCERT_NAME_BLOB pIssuer
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbEncodedCert = NULL;
|
|
DWORD cbEncodedCert;
|
|
PCCERT_CONTEXT pCert = NULL;
|
|
BYTE *pbEncodedIssuer;
|
|
DWORD cbEncodedIssuer;
|
|
|
|
|
|
if (!ReadDERFromFile(pszCertFilename, &pbEncodedCert, &cbEncodedCert)) {
|
|
PrintLastError("AllocAndGetEncodedIssuer::ReadDERFromFile");
|
|
goto ErrorReturn;
|
|
}
|
|
if (NULL == (pCert = CertCreateCertificateContext(
|
|
dwCertEncodingType,
|
|
pbEncodedCert,
|
|
cbEncodedCert
|
|
))) {
|
|
PrintLastError("AllocAndGetEncodedIssuer::CertCreateCertificateContext");
|
|
goto ErrorReturn;
|
|
}
|
|
if (fUseIssuerName) {
|
|
cbEncodedIssuer = pCert->pCertInfo->Issuer.cbData;
|
|
pbEncodedIssuer = pCert->pCertInfo->Issuer.pbData;
|
|
} else {
|
|
cbEncodedIssuer = pCert->pCertInfo->Subject.cbData;
|
|
pbEncodedIssuer = pCert->pCertInfo->Subject.pbData;
|
|
}
|
|
pIssuer->pbData = (BYTE *) TestAlloc(cbEncodedIssuer);
|
|
if (pIssuer->pbData == NULL) goto ErrorReturn;
|
|
memcpy(pIssuer->pbData, pbEncodedIssuer, cbEncodedIssuer);
|
|
pIssuer->cbData = cbEncodedIssuer;
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (pbEncodedCert)
|
|
TestFree(pbEncodedCert);
|
|
if (pCert)
|
|
CertFreeCertificateContext(pCert);
|
|
return fResult;
|
|
}
|
|
|
|
int _cdecl main(int argc, char * argv[])
|
|
{
|
|
HRESULT hr;
|
|
int ReturnStatus;
|
|
BOOL fUseIssuerName = FALSE;
|
|
LPSTR pszCertFilename = NULL;
|
|
LPSTR pszKeyType = NULL;
|
|
DWORD dwKeySpec;
|
|
|
|
#define MAX_ISSUER_CNT 32
|
|
DWORD cIssuer = 0;
|
|
CERT_NAME_BLOB rgIssuer[MAX_ISSUER_CNT];
|
|
|
|
PCERT_CHAIN pCertChains = NULL;
|
|
DWORD cbCertChains;
|
|
DWORD cCertChains;
|
|
DWORD i,j;
|
|
|
|
HCERTSTORE hChainStore = NULL;
|
|
LPSTR pszUsageIdentifier = NULL;
|
|
DWORD dwFindFlags = 0;
|
|
|
|
while (--argc>0)
|
|
{
|
|
if (**++argv == '-')
|
|
{
|
|
if (0 == _stricmp(argv[0]+1, "CompareKey")) {
|
|
dwFindFlags |= CERT_CHAIN_FIND_BY_ISSUER_COMPARE_KEY_FLAG;
|
|
} else if (0 == _stricmp(argv[0]+1, "ComplexChain")) {
|
|
dwFindFlags |= CERT_CHAIN_FIND_BY_ISSUER_COMPLEX_CHAIN_FLAG;
|
|
} else if (0 == _stricmp(argv[0]+1, "CacheOnly")) {
|
|
dwFindFlags |= CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG;
|
|
} else if (0 == _stricmp(argv[0]+1, "NoKey")) {
|
|
dwFindFlags |= CERT_CHAIN_FIND_BY_ISSUER_NO_KEY_FLAG;
|
|
} else {
|
|
switch(argv[0][1])
|
|
{
|
|
case 'c':
|
|
case 'C':
|
|
if (hChainStore) {
|
|
printf("Only one chain store allowed\n");
|
|
goto BadUsage;
|
|
}
|
|
if (NULL == (hChainStore =
|
|
OpenSystemStoreOrFile(
|
|
argv[0][1] == 'c', // fSystemStore
|
|
argv[0]+2,
|
|
0 // dwFlags
|
|
)))
|
|
goto BadUsage;
|
|
break;
|
|
case 'S':
|
|
case 'I':
|
|
if ('S' == argv[0][1])
|
|
fUseIssuerName = FALSE;
|
|
else
|
|
fUseIssuerName = TRUE;
|
|
if (argv[0][2]) {
|
|
if (MAX_ISSUER_CNT <= cIssuer) {
|
|
printf("Exceeded Maximum Issuer Count %d\n",
|
|
MAX_ISSUER_CNT);
|
|
goto BadUsage;
|
|
} else {
|
|
if (!AllocAndGetEncodedIssuer(argv[0]+2,
|
|
fUseIssuerName, &rgIssuer[cIssuer]))
|
|
goto ErrorReturn;
|
|
cIssuer++;
|
|
}
|
|
}
|
|
break;
|
|
case 'u':
|
|
pszUsageIdentifier = argv[0]+2;
|
|
break;
|
|
case 'b':
|
|
dwDisplayFlags |= DISPLAY_BRIEF_FLAG;
|
|
break;
|
|
case 'v':
|
|
dwDisplayFlags |= DISPLAY_VERBOSE_FLAG;
|
|
break;
|
|
case 'h':
|
|
default:
|
|
goto BadUsage;
|
|
}
|
|
}
|
|
} else {
|
|
if (pszCertFilename == NULL)
|
|
pszCertFilename = argv[0];
|
|
else if(pszKeyType == NULL)
|
|
pszKeyType = argv[0];
|
|
else {
|
|
printf("Too many arguments\n");
|
|
goto BadUsage;
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("command line: %s\n", GetCommandLine());
|
|
|
|
|
|
if (dwDisplayFlags & DISPLAY_VERBOSE_FLAG)
|
|
dwDisplayFlags &= ~DISPLAY_BRIEF_FLAG;
|
|
|
|
|
|
if (pszCertFilename == NULL || *pszCertFilename == '\0') {
|
|
if (0 == cIssuer) {
|
|
rgIssuer[0].cbData = 0;
|
|
rgIssuer[0].pbData = NULL;
|
|
printf("Match any Issuer\n");
|
|
}
|
|
} else if (MAX_ISSUER_CNT <= cIssuer) {
|
|
printf("Exceeded Maximum Issuer Count %d\n", MAX_ISSUER_CNT);
|
|
goto BadUsage;
|
|
} else {
|
|
if (!AllocAndGetEncodedIssuer(pszCertFilename, fUseIssuerName,
|
|
&rgIssuer[cIssuer]))
|
|
goto ErrorReturn;
|
|
cIssuer++;
|
|
}
|
|
|
|
if (NULL == hChainStore && 1 < cIssuer) {
|
|
printf("Only one issuer for FindCertsByIssuer\n");
|
|
goto BadUsage;
|
|
}
|
|
|
|
dwKeySpec = 0;
|
|
if (pszKeyType) {
|
|
DWORD KeyIdx;
|
|
for (KeyIdx = 0; KeyIdx < NKEYTYPES; KeyIdx++) {
|
|
if (_stricmp(pszKeyType, KeyTypes[KeyIdx].pszName) == 0) {
|
|
dwKeySpec = KeyTypes[KeyIdx].dwKeySpec;
|
|
break;
|
|
}
|
|
}
|
|
if (dwKeySpec == 0) {
|
|
printf("Bad KeyType: %s\n", pszKeyType);
|
|
goto BadUsage;
|
|
}
|
|
} else
|
|
printf("Match any key type\n");
|
|
|
|
if (hChainStore) {
|
|
if (CreateChainByIssuer(
|
|
hChainStore,
|
|
dwFindFlags,
|
|
pszUsageIdentifier,
|
|
dwKeySpec,
|
|
cIssuer,
|
|
rgIssuer
|
|
))
|
|
goto SuccessReturn;
|
|
else
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
|
|
cbCertChains = 0;
|
|
hr = FindCertsByIssuer(
|
|
NULL, // pCertChains
|
|
&cbCertChains,
|
|
&cCertChains,
|
|
rgIssuer[0].pbData,
|
|
rgIssuer[0].cbData,
|
|
NULL, // pwszPurpose "ClientAuth" or "CodeSigning"
|
|
dwKeySpec
|
|
);
|
|
if (cbCertChains == 0) {
|
|
if (hr == CRYPT_E_NOT_FOUND)
|
|
printf("NO Certificate Chains\n");
|
|
else {
|
|
SetLastError((DWORD) hr);
|
|
PrintLastError("FindCertsByIssuer");
|
|
}
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (NULL == (pCertChains = (PCERT_CHAIN) TestAlloc(cbCertChains)))
|
|
goto ErrorReturn;
|
|
if (FAILED(hr = FindCertsByIssuer(
|
|
pCertChains,
|
|
&cbCertChains,
|
|
&cCertChains,
|
|
rgIssuer[0].pbData,
|
|
rgIssuer[0].cbData,
|
|
NULL, // pwszPurpose "ClientAuth" or "CodeSigning"
|
|
dwKeySpec
|
|
))) {
|
|
SetLastError((DWORD) hr);
|
|
PrintLastError("FindCertsByIssuer");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
for (i = 0; i < cCertChains; i++) {
|
|
PCRYPT_KEY_PROV_INFO pKeyInfo = &pCertChains[i].keyLocatorInfo;
|
|
printf("\n");
|
|
printf("##### Chain %d #####\n", i);
|
|
printf("Key Provider:: %d", pKeyInfo->dwProvType);
|
|
if (pKeyInfo->pwszProvName)
|
|
printf(" %S", pKeyInfo->pwszProvName);
|
|
if (pKeyInfo->dwFlags)
|
|
printf(" Flags: 0x%x", pKeyInfo->dwFlags);
|
|
if (pKeyInfo->pwszContainerName)
|
|
printf(" Container: %S", pKeyInfo->pwszContainerName);
|
|
if (pKeyInfo->cProvParam)
|
|
printf(" Params: %d", pKeyInfo->cProvParam);
|
|
if (pKeyInfo->dwKeySpec)
|
|
printf(" KeySpec: %d", pKeyInfo->dwKeySpec);
|
|
printf("\n");
|
|
for (j = 0; j < pCertChains[i].cCerts; j++) {
|
|
PCCERT_CONTEXT pCert;
|
|
if (pCert = CertCreateCertificateContext(
|
|
dwCertEncodingType,
|
|
pCertChains[i].certs[j].pbData,
|
|
pCertChains[i].certs[j].cbData
|
|
)) {
|
|
printf("===== %d =====\n", j);
|
|
DisplayCert(pCert, dwDisplayFlags);
|
|
CertFreeCertificateContext(pCert);
|
|
} else {
|
|
printf("Unable to decode cert %d\n", j);
|
|
PrintLastError("CertCreateCertificateContext");
|
|
}
|
|
}
|
|
}
|
|
|
|
SuccessReturn:
|
|
ReturnStatus = 0;
|
|
goto CommonReturn;
|
|
|
|
BadUsage:
|
|
Usage();
|
|
ErrorReturn:
|
|
ReturnStatus = -1;
|
|
CommonReturn:
|
|
while (cIssuer--)
|
|
TestFree(rgIssuer[cIssuer].pbData);
|
|
if (pCertChains)
|
|
TestFree(pCertChains);
|
|
if (hChainStore) {
|
|
if (!CertCloseStore(hChainStore, 0))
|
|
PrintLastError("CertCloseStore(ChainStore)");
|
|
}
|
|
if (!ReturnStatus)
|
|
printf("Passed\n");
|
|
else
|
|
printf("Failed\n");
|
|
return ReturnStatus;
|
|
}
|