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.
1169 lines
26 KiB
1169 lines
26 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
|
|
Module Name:
|
|
|
|
CheckSC
|
|
|
|
Abstract:
|
|
|
|
This application is used to provide a snapshot of the Calais (Smart Card
|
|
Resource Manager) service's status, and to display certificates on smart
|
|
cards via the common WinNT UI.
|
|
|
|
CheckSC -- describes the RM status and displays each available sc cert(s)
|
|
|
|
-r Readername -- for just one reader
|
|
-sig -- display signature key certs only
|
|
-ex -- display exchange key certs only
|
|
-nocert -- don't look for certs to display
|
|
-key -- verify keyset public key matches cert public key
|
|
|
|
Author:
|
|
|
|
Amanda Matlosz (AMatlosz) 07/14/1998
|
|
|
|
Environment:
|
|
|
|
Win32 Console App
|
|
|
|
Notes:
|
|
|
|
For use in NT5 public key rollout testing
|
|
|
|
--*/
|
|
|
|
/*++
|
|
need to include the following libs:
|
|
|
|
calaislb.lib (unicode build: calaislbw.lib)
|
|
winscard.lib
|
|
--*/
|
|
#include <iostream.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
// #include <string.h>
|
|
// #include <stdarg.h>
|
|
#include <winscard.h>
|
|
#include <SCardLib.h>
|
|
#include <winsvc.h>
|
|
#include <scEvents.h>
|
|
#include <cryptui.h>
|
|
|
|
|
|
|
|
#ifndef SCARD_PROVIDER_CSP
|
|
#define SCARD_PROVIDER_CSP 2
|
|
#endif
|
|
|
|
#define KERB_PKINIT_CLIENT_CERT_TYPE szOID_PKIX_KP_CLIENT_AUTH
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
int g_nKeys;
|
|
DWORD g_rgKeySet[2]; // { AT_KEYEXCHANGE , AT_SIGNATURE };
|
|
SCARDCONTEXT g_hSCardCtx;
|
|
LPTSTR g_szReaderName;
|
|
DWORD g_dwNumReaders;
|
|
BOOL g_fReaderNameAllocd;
|
|
BOOL g_fChain = FALSE;
|
|
BOOL g_fPublicKeyCheck = FALSE;
|
|
SCARD_READERSTATE* g_pReaderStatusArray;
|
|
const char* g_szEx = TEXT("exchange");
|
|
const char* g_szSig = TEXT("signature");
|
|
|
|
|
|
//
|
|
// Functions
|
|
//
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// DisplayUsage does easy UI
|
|
void DisplayUsage()
|
|
{
|
|
cout << "\n"
|
|
<< "CheckSC [-sig|-ex|-nocert|-chain|-key] [-r \"Readername\"]\n"
|
|
<< " -sig Displays only signature key certificates.\n"
|
|
<< " -ex Displays only signature key certificates.\n"
|
|
<< " -nocert Does not display smart card certificates.\n"
|
|
<< " -chain Check trust status.\n"
|
|
<< " -key Verify keyset public key matches certificate public key.\n"
|
|
<< endl;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// ProcessCommandLine does the dirty work, sets behavior globals
|
|
bool ProcessCommandLine(DWORD cArgs, LPCTSTR rgszArgs[])
|
|
{
|
|
|
|
// set everything to default
|
|
|
|
g_szReaderName = NULL; // no reader
|
|
g_rgKeySet[0] = AT_KEYEXCHANGE; // certs for both kinds of keys
|
|
g_rgKeySet[1] = AT_SIGNATURE;
|
|
g_nKeys = 2;
|
|
|
|
if (cArgs == 1)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// For each arg, verify that it's a real arg and deal with it
|
|
|
|
bool fLookForReader = false;
|
|
bool fCertOptionSpecified = false;
|
|
bool fBogus = FALSE;
|
|
|
|
for (DWORD n=1; n<cArgs; n++)
|
|
{
|
|
if ('/' == *rgszArgs[n] || '-' == *rgszArgs[n])
|
|
{
|
|
if (0 == _stricmp("r", rgszArgs[n]+1*sizeof(TCHAR))) // reader
|
|
{
|
|
fLookForReader = true;
|
|
}
|
|
else if (0 == _stricmp("sig",rgszArgs[n]+1*sizeof(TCHAR))) // signature cert only
|
|
{
|
|
if (true == fCertOptionSpecified)
|
|
{
|
|
// bogus!
|
|
fBogus = true;
|
|
break;
|
|
}
|
|
g_rgKeySet[0] = AT_SIGNATURE;
|
|
g_nKeys = 1;
|
|
}
|
|
else if (0 == _stricmp("ex",rgszArgs[n]+1*sizeof(TCHAR))) // exchange cert only
|
|
{
|
|
if (true == fCertOptionSpecified)
|
|
{
|
|
// bogus!
|
|
fBogus = true;
|
|
break;
|
|
}
|
|
g_rgKeySet[0] = AT_KEYEXCHANGE;
|
|
g_nKeys = 1;
|
|
}
|
|
else if (0 == _stricmp("nocert",rgszArgs[n]+1*sizeof(TCHAR))) // no certs
|
|
{
|
|
if (true == fCertOptionSpecified)
|
|
{
|
|
// bogus!
|
|
fBogus = true;
|
|
break;
|
|
}
|
|
g_nKeys = 0;
|
|
}
|
|
else if (0 == _stricmp("chain",rgszArgs[n]+1*sizeof(TCHAR))) // verify chain
|
|
{
|
|
g_fChain = TRUE;
|
|
|
|
}
|
|
else if (0 == _stricmp("key",rgszArgs[n]+1*sizeof(TCHAR))) // verify cert & keyset
|
|
{
|
|
g_fPublicKeyCheck = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// bogus!!
|
|
fBogus = true;
|
|
break;
|
|
}
|
|
}
|
|
else if (fLookForReader)
|
|
{
|
|
fLookForReader = false;
|
|
g_szReaderName = (LPTSTR)rgszArgs[n];
|
|
}
|
|
else
|
|
{
|
|
// Bogus!
|
|
fBogus = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fLookForReader && !fBogus)
|
|
{
|
|
// All's well, we're set to go
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// educate user when args incorrect
|
|
//
|
|
|
|
DisplayUsage();
|
|
return false;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool IsCalaisRunning()
|
|
{
|
|
bool fCalaisUp = false;
|
|
HANDLE hCalaisStarted = NULL;
|
|
|
|
HMODULE hDll = GetModuleHandle( TEXT("WINSCARD.DLL") );
|
|
|
|
typedef HANDLE (WINAPI *PFN_SCARDACCESSSTARTEDEVENT)(VOID);
|
|
PFN_SCARDACCESSSTARTEDEVENT pSCardAccessStartedEvent;
|
|
|
|
pSCardAccessStartedEvent = (PFN_SCARDACCESSSTARTEDEVENT) GetProcAddress(hDll, "SCardAccessStartedEvent");
|
|
|
|
if (pSCardAccessStartedEvent)
|
|
{
|
|
hCalaisStarted = pSCardAccessStartedEvent();
|
|
}
|
|
|
|
if (hCalaisStarted)
|
|
{
|
|
if (WAIT_OBJECT_0 == WaitForSingleObject(hCalaisStarted, 1000))
|
|
{
|
|
fCalaisUp = true;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Display status
|
|
//
|
|
|
|
if (fCalaisUp)
|
|
{
|
|
cout << "\n"
|
|
<< "The Microsoft Smart Card Resource Manager is running.\n"
|
|
<< endl;
|
|
}
|
|
else
|
|
{
|
|
cout << "\n"
|
|
<< "The Microsoft Smart Card Resource Manager is not running.\n"
|
|
<< endl;
|
|
}
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
|
|
return fCalaisUp;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// DisplayReaderList tries to set g_hSCardCtx, get a list of currently available
|
|
// smart card readers, and display their status
|
|
void DisplayReaderList()
|
|
{
|
|
long lReturn = SCARD_S_SUCCESS;
|
|
|
|
cout << "Current reader/card status:\n" << endl;
|
|
|
|
// Acquire global SCARDCONTEXT from resource manager if possible
|
|
|
|
lReturn = SCardEstablishContext(SCARD_SCOPE_USER,
|
|
NULL,
|
|
NULL,
|
|
&g_hSCardCtx);
|
|
|
|
if (SCARD_S_SUCCESS != lReturn)
|
|
{
|
|
cout << "SCardEstablishContext failed for user scope.\n"
|
|
<< "A list of smart card readers cannot be determined.\n"
|
|
<< endl;
|
|
|
|
return;
|
|
}
|
|
|
|
// Build a readerstatus array from either a list of readers; or use the one the user specified
|
|
|
|
g_dwNumReaders = 0;
|
|
if (NULL == g_szReaderName)
|
|
{
|
|
DWORD dwAutoAllocate = SCARD_AUTOALLOCATE;
|
|
g_fReaderNameAllocd = true;
|
|
lReturn = SCardListReaders(g_hSCardCtx,
|
|
SCARD_DEFAULT_READERS,
|
|
(LPTSTR)&g_szReaderName,
|
|
&dwAutoAllocate);
|
|
|
|
if (SCARD_S_SUCCESS != lReturn)
|
|
{
|
|
TCHAR szMsg[128]; // %Xx
|
|
sprintf(szMsg,
|
|
"SCardListReaders failed for SCARD_ALL_READERS with: 0x%X.\n",
|
|
lReturn);
|
|
|
|
cout << szMsg;
|
|
if (SCARD_E_NO_READERS_AVAILABLE == lReturn)
|
|
{
|
|
cout << "No smart card readers are currently available.\n";
|
|
}
|
|
else
|
|
{
|
|
cout << "A list of smart card readers could not be determined.\n";
|
|
}
|
|
cout << endl;
|
|
|
|
return;
|
|
}
|
|
|
|
// Build a readerstatus array...
|
|
|
|
LPCTSTR szReaderName = g_szReaderName;
|
|
g_dwNumReaders = MStringCount(szReaderName);
|
|
|
|
g_pReaderStatusArray = new SCARD_READERSTATE[g_dwNumReaders];
|
|
::ZeroMemory((LPVOID)g_pReaderStatusArray, sizeof(g_pReaderStatusArray));
|
|
|
|
szReaderName = FirstString(szReaderName);
|
|
|
|
for (DWORD dwRdr = 0; NULL != szReaderName && dwRdr < g_dwNumReaders; szReaderName = NextString(szReaderName), dwRdr++)
|
|
{
|
|
g_pReaderStatusArray[dwRdr].szReader = (LPCTSTR)szReaderName;
|
|
g_pReaderStatusArray[dwRdr].dwCurrentState = SCARD_STATE_UNAWARE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_dwNumReaders = 1;
|
|
g_pReaderStatusArray = new SCARD_READERSTATE;
|
|
g_pReaderStatusArray->szReader = (LPCTSTR)g_szReaderName;
|
|
g_pReaderStatusArray->dwCurrentState = SCARD_STATE_UNAWARE;
|
|
}
|
|
|
|
// ...And get the reader status from the resource manager
|
|
|
|
lReturn = SCardGetStatusChange(g_hSCardCtx,
|
|
INFINITE, // hardly
|
|
g_pReaderStatusArray,
|
|
g_dwNumReaders);
|
|
|
|
if (SCARD_S_SUCCESS != lReturn)
|
|
{
|
|
TCHAR szMsg[128]; // %Xx
|
|
sprintf(szMsg,
|
|
"SCardGetStatusChange failed with: 0x%X.\n",
|
|
lReturn);
|
|
|
|
cout << szMsg << endl;
|
|
|
|
sprintf(szMsg,
|
|
"MStringCount returned %d readers.\n",
|
|
g_dwNumReaders);
|
|
cout << szMsg << endl;
|
|
|
|
return;
|
|
}
|
|
|
|
// Finally, display all reader information
|
|
|
|
DWORD dwState = 0;
|
|
for (DWORD dwRdrSt = 0; dwRdrSt < g_dwNumReaders; dwRdrSt++)
|
|
{
|
|
|
|
//--- reader: readerName\n
|
|
cout << TEXT("--- reader: ")
|
|
<< g_pReaderStatusArray[dwRdrSt].szReader
|
|
<< TEXT("\n");
|
|
|
|
//--- status: /bits/\n
|
|
bool fOr = false;
|
|
cout << TEXT("--- status: ");
|
|
dwState = g_pReaderStatusArray[dwRdrSt].dwEventState;
|
|
|
|
if (0 != (dwState & SCARD_STATE_UNKNOWN))
|
|
{
|
|
cout << TEXT("SCARD_STATE_UNKNOWN ");
|
|
fOr = true;
|
|
}
|
|
if (0 != (dwState & SCARD_STATE_UNAVAILABLE))
|
|
{
|
|
if (fOr)
|
|
{
|
|
cout << TEXT("| ");
|
|
}
|
|
cout << TEXT("SCARD_STATE_UNAVAILABLE ");
|
|
fOr = true;
|
|
}
|
|
if (0 != (dwState & SCARD_STATE_EMPTY))
|
|
{
|
|
if (fOr)
|
|
{
|
|
cout << TEXT("| ");
|
|
}
|
|
cout << TEXT("SCARD_STATE_EMPTY ");
|
|
fOr = true;
|
|
}
|
|
if (0 != (dwState & SCARD_STATE_PRESENT))
|
|
{
|
|
if (fOr)
|
|
{
|
|
cout << TEXT("| ");
|
|
}
|
|
cout << TEXT("SCARD_STATE_PRESENT ";)
|
|
fOr = true;
|
|
}
|
|
if (0 != (dwState & SCARD_STATE_EXCLUSIVE))
|
|
{
|
|
if (fOr)
|
|
{
|
|
cout << TEXT("| ";)
|
|
}
|
|
cout << TEXT("SCARD_STATE_EXCLUSIVE ");
|
|
fOr = true;
|
|
}
|
|
if (0 != (dwState & SCARD_STATE_INUSE))
|
|
{
|
|
if (fOr)
|
|
{
|
|
cout << TEXT("| ");
|
|
}
|
|
cout << TEXT("SCARD_STATE_INUSE ");
|
|
fOr = true;
|
|
}
|
|
if (0 != (dwState & SCARD_STATE_MUTE))
|
|
{
|
|
if (fOr)
|
|
{
|
|
cout << TEXT("| ");
|
|
}
|
|
cout << TEXT("SCARD_STATE_MUTE ");
|
|
fOr = true;
|
|
}
|
|
if (0 != (dwState & SCARD_STATE_UNPOWERED))
|
|
{
|
|
if (fOr)
|
|
{
|
|
cout << TEXT("| ");
|
|
}
|
|
cout << TEXT("SCARD_STATE_UNPOWERED");
|
|
fOr = true;
|
|
}
|
|
cout << TEXT("\n");
|
|
|
|
//--- status: what scstatus would say\n
|
|
cout << TEXT("--- status: ");
|
|
|
|
// NO CARD
|
|
if(dwState & SCARD_STATE_EMPTY)
|
|
{
|
|
cout << TEXT("No card.");// SC_STATUS_NO_CARD;
|
|
}
|
|
// CARD in reader: SHARED, EXCLUSIVE, FREE, UNKNOWN ?
|
|
else if(dwState & SCARD_STATE_PRESENT)
|
|
{
|
|
if (dwState & SCARD_STATE_MUTE)
|
|
{
|
|
cout << TEXT("The card is unrecognized or not responding.");// SC_STATUS_UNKNOWN;
|
|
}
|
|
else if (dwState & SCARD_STATE_INUSE)
|
|
{
|
|
if(dwState & SCARD_STATE_EXCLUSIVE)
|
|
{
|
|
cout << TEXT("Card is in use exclusively by another process.");// SC_STATUS_EXCLUSIVE;
|
|
}
|
|
else
|
|
{
|
|
cout << TEXT("The card is being shared by a process.");// SC_STATUS_SHARED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cout << TEXT("The card is available for use.");// SC_SATATUS_AVAILABLE;
|
|
}
|
|
}
|
|
// READER ERROR: at this point, something's gone wrong
|
|
else // dwState & SCARD_STATE_UNAVAILABLE
|
|
{
|
|
cout << TEXT("Card/Reader not responding.");// SC_STATUS_ERROR;
|
|
}
|
|
|
|
cout << TEXT("\n");
|
|
|
|
//- card name(s):\n\n
|
|
cout << TEXT("--- card: ");
|
|
if (0 < g_pReaderStatusArray[dwRdrSt].cbAtr)
|
|
{
|
|
//
|
|
// Get the name of the card
|
|
//
|
|
LPTSTR szCardName = NULL;
|
|
DWORD dwAutoAllocate = SCARD_AUTOALLOCATE;
|
|
lReturn = SCardListCards(g_hSCardCtx,
|
|
g_pReaderStatusArray[dwRdrSt].rgbAtr,
|
|
NULL,
|
|
0,
|
|
(LPTSTR)&szCardName,
|
|
&dwAutoAllocate);
|
|
if (SCARD_S_SUCCESS != lReturn || NULL == szCardName)
|
|
{
|
|
cout << TEXT("Unknown Card.");
|
|
}
|
|
else
|
|
{
|
|
LPCTSTR szName = szCardName;
|
|
bool fNotFirst = false;
|
|
for (szName = FirstString(szName); NULL != szName; szName = NextString(szName))
|
|
{
|
|
if (fNotFirst) cout << TEXT(", ");
|
|
cout << szName;
|
|
fNotFirst = true;
|
|
}
|
|
}
|
|
|
|
if (NULL != szCardName)
|
|
{
|
|
SCardFreeMemory(g_hSCardCtx, (PVOID)szCardName);
|
|
}
|
|
|
|
}
|
|
|
|
cout << TEXT("\n") << endl;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GetCertContext -- called by DisplayCerts
|
|
PCCERT_CONTEXT GetCertContext(HCRYPTPROV* phProv, HCRYPTKEY* phKey, DWORD dwKeySpec)
|
|
{
|
|
PCCERT_CONTEXT pCertCtx = NULL;
|
|
LONG lResult = SCARD_S_SUCCESS;
|
|
BOOL fSts = FALSE;
|
|
|
|
PCERT_PUBLIC_KEY_INFO pInfo = NULL;
|
|
CRYPT_KEY_PROV_INFO KeyProvInfo;
|
|
LPSTR szContainerName = NULL;
|
|
LPSTR szProvName = NULL;
|
|
LPWSTR wszContainerName = NULL;
|
|
LPWSTR wszProvName = NULL;
|
|
DWORD cbContainerName, cbProvName;
|
|
LPBYTE pbCert = NULL;
|
|
DWORD cbCertLen;
|
|
int nLen = 0;
|
|
|
|
//
|
|
// Get the cert from this key
|
|
//
|
|
|
|
fSts = CryptGetKeyParam(
|
|
*phKey,
|
|
KP_CERTIFICATE,
|
|
NULL,
|
|
&cbCertLen,
|
|
0);
|
|
if (!fSts)
|
|
{
|
|
lResult = GetLastError();
|
|
if (ERROR_MORE_DATA != lResult)
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
lResult = SCARD_S_SUCCESS;
|
|
pbCert = (LPBYTE)LocalAlloc(LPTR, cbCertLen);
|
|
if (NULL == pbCert)
|
|
{
|
|
return NULL;
|
|
}
|
|
fSts = CryptGetKeyParam(
|
|
*phKey,
|
|
KP_CERTIFICATE,
|
|
pbCert,
|
|
&cbCertLen,
|
|
0);
|
|
if (!fSts)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Convert the certificate into a Cert Context.
|
|
//
|
|
pCertCtx = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
pbCert,
|
|
cbCertLen);
|
|
if (NULL == pCertCtx)
|
|
{
|
|
lResult = GetLastError();
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Perform public key check
|
|
//
|
|
|
|
if (g_fPublicKeyCheck) // -key
|
|
{
|
|
cout << "\nPerforming public key matching test...\n";
|
|
|
|
DWORD dwPCBsize = 0;
|
|
|
|
fSts = CryptExportPublicKeyInfo(
|
|
*phProv, // in
|
|
dwKeySpec, // in
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, // in
|
|
NULL,
|
|
&dwPCBsize // in, out
|
|
);
|
|
if (!fSts)
|
|
{
|
|
lResult = GetLastError();
|
|
|
|
TCHAR sz[256];
|
|
sprintf(sz,"CryptExportPublicKeyInfo failed: 0x%x\n ", lResult);
|
|
cout << sz;
|
|
|
|
goto ErrorExit;
|
|
}
|
|
if (dwPCBsize == 0)
|
|
{
|
|
lResult = SCARD_E_UNEXPECTED; // huh?
|
|
|
|
cout << "CryptExportPublicKeyInfo succeeded but returned size==0\n";
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
pInfo = (PCERT_PUBLIC_KEY_INFO)LocalAlloc(LPTR, dwPCBsize);
|
|
if (NULL == pInfo)
|
|
{
|
|
lResult = E_OUTOFMEMORY;
|
|
cout << "Could not complete key test; out of memory.\n";
|
|
goto ErrorExit;
|
|
}
|
|
|
|
fSts = CryptExportPublicKeyInfo(
|
|
*phProv,
|
|
dwKeySpec,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
pInfo,
|
|
&dwPCBsize
|
|
);
|
|
if (!fSts)
|
|
{
|
|
lResult = GetLastError();
|
|
|
|
TCHAR sz[256];
|
|
sprintf(sz,"CryptExportPublicKeyInfo failed: 0x%x\n ", lResult);
|
|
cout << sz;
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
fSts = CertComparePublicKeyInfo(
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
pInfo, // from the private keyset
|
|
&(pCertCtx->pCertInfo->SubjectPublicKeyInfo) // public key from cert
|
|
);
|
|
if (!fSts)
|
|
{
|
|
lResult = GetLastError();
|
|
goto ErrorExit;
|
|
}
|
|
|
|
cout << "Public key matching test succeeded.\n";
|
|
|
|
}
|
|
|
|
//
|
|
// Associate cryptprovider w/ the private key property of this cert
|
|
//
|
|
|
|
// ... need the container name
|
|
|
|
fSts = CryptGetProvParam(
|
|
*phProv,
|
|
PP_CONTAINER,
|
|
NULL, // out
|
|
&cbContainerName, // in/out
|
|
0);
|
|
if (!fSts)
|
|
{
|
|
lResult = GetLastError();
|
|
goto ErrorExit;
|
|
}
|
|
szContainerName = (LPSTR)LocalAlloc(LPTR, cbContainerName);
|
|
fSts = CryptGetProvParam(
|
|
*phProv,
|
|
PP_CONTAINER,
|
|
(PBYTE)szContainerName,
|
|
&cbContainerName,
|
|
0);
|
|
if (!fSts)
|
|
{
|
|
lResult = GetLastError();
|
|
goto ErrorExit;
|
|
}
|
|
nLen = MultiByteToWideChar(
|
|
GetACP(),
|
|
MB_PRECOMPOSED,
|
|
szContainerName,
|
|
-1,
|
|
NULL,
|
|
0);
|
|
if (0 < nLen)
|
|
{
|
|
wszContainerName = (LPWSTR)LocalAlloc(LPTR, nLen*sizeof(WCHAR));
|
|
|
|
nLen = MultiByteToWideChar(
|
|
GetACP(),
|
|
MB_PRECOMPOSED,
|
|
szContainerName,
|
|
-1,
|
|
wszContainerName,
|
|
nLen);
|
|
if (0 == nLen)
|
|
{
|
|
lResult = GetLastError();
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
// ... need the provider name
|
|
|
|
fSts = CryptGetProvParam(
|
|
*phProv,
|
|
PP_NAME,
|
|
NULL, // out
|
|
&cbProvName, // in/out
|
|
0);
|
|
if (!fSts)
|
|
{
|
|
lResult = GetLastError();
|
|
goto ErrorExit;
|
|
}
|
|
szProvName = (LPSTR)LocalAlloc(LPTR, cbProvName);
|
|
fSts = CryptGetProvParam(
|
|
*phProv,
|
|
PP_NAME,
|
|
(PBYTE)szProvName, // out
|
|
&cbProvName, // in/out
|
|
0);
|
|
if (!fSts)
|
|
{
|
|
lResult = GetLastError();
|
|
goto ErrorExit;
|
|
}
|
|
nLen = MultiByteToWideChar(
|
|
GetACP(),
|
|
MB_PRECOMPOSED,
|
|
szProvName,
|
|
-1,
|
|
NULL,
|
|
0);
|
|
if (0 < nLen)
|
|
{
|
|
wszProvName = (LPWSTR)LocalAlloc(LPTR, nLen*sizeof(WCHAR));
|
|
|
|
nLen = MultiByteToWideChar(
|
|
GetACP(),
|
|
MB_PRECOMPOSED,
|
|
szProvName,
|
|
-1,
|
|
wszProvName,
|
|
nLen);
|
|
if (0 == nLen)
|
|
{
|
|
lResult = GetLastError();
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the cert context properties to reflect the prov info
|
|
//
|
|
|
|
KeyProvInfo.pwszContainerName = wszContainerName;
|
|
KeyProvInfo.pwszProvName = wszProvName;
|
|
KeyProvInfo.dwProvType = PROV_RSA_FULL;
|
|
KeyProvInfo.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
|
|
KeyProvInfo.cProvParam = 0;
|
|
KeyProvInfo.rgProvParam = NULL;
|
|
KeyProvInfo.dwKeySpec = dwKeySpec;
|
|
|
|
fSts = CertSetCertificateContextProperty(
|
|
pCertCtx,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
0,
|
|
(void *)&KeyProvInfo);
|
|
if (!fSts)
|
|
{
|
|
lResult = GetLastError();
|
|
|
|
// the cert's been incorrectly created -- scrap it.
|
|
CertFreeCertificateContext(pCertCtx);
|
|
pCertCtx = NULL;
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
|
|
|
|
ErrorExit:
|
|
|
|
if (NULL != pInfo)
|
|
{
|
|
LocalFree(pInfo);
|
|
}
|
|
if(NULL != szContainerName)
|
|
{
|
|
LocalFree(szContainerName);
|
|
}
|
|
if(NULL != szProvName)
|
|
{
|
|
LocalFree(szProvName);
|
|
}
|
|
if(NULL != wszContainerName)
|
|
{
|
|
LocalFree(wszContainerName);
|
|
}
|
|
if(NULL != wszProvName)
|
|
{
|
|
LocalFree(wszProvName);
|
|
}
|
|
|
|
return pCertCtx;
|
|
}
|
|
|
|
/*++
|
|
|
|
DisplayChainInfo:
|
|
|
|
This code verifies that the SC cert is valid.
|
|
Uses identical code to KDC cert chaining engine.
|
|
|
|
Author:
|
|
|
|
Todds
|
|
--*/
|
|
DWORD
|
|
DisplayChainInfo(PCCERT_CONTEXT pCert)
|
|
{
|
|
|
|
|
|
BOOL fRet = FALSE;
|
|
DWORD dwErr = 0;
|
|
TCHAR sz[256];
|
|
CERT_CHAIN_PARA ChainParameters = {0};
|
|
LPSTR ClientAuthUsage = KERB_PKINIT_CLIENT_CERT_TYPE;
|
|
PCCERT_CHAIN_CONTEXT ChainContext = NULL;
|
|
|
|
ChainParameters.cbSize = sizeof(CERT_CHAIN_PARA);
|
|
ChainParameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
|
|
ChainParameters.RequestedUsage.Usage.cUsageIdentifier = 1;
|
|
ChainParameters.RequestedUsage.Usage.rgpszUsageIdentifier = &ClientAuthUsage;
|
|
|
|
if (!CertGetCertificateChain(
|
|
HCCE_LOCAL_MACHINE,
|
|
pCert,
|
|
NULL, // evaluate at current time
|
|
NULL, // no additional stores
|
|
&ChainParameters,
|
|
CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
|
|
NULL, // reserved
|
|
&ChainContext
|
|
))
|
|
{
|
|
dwErr = GetLastError();
|
|
sprintf(sz,"CertGetCertificateChain failed: 0x%x\n ", dwErr);
|
|
cout << sz;
|
|
}
|
|
else
|
|
{
|
|
if (ChainContext->TrustStatus.dwErrorStatus != CERT_TRUST_NO_ERROR)
|
|
{
|
|
dwErr = ChainContext->TrustStatus.dwErrorStatus;
|
|
sprintf(sz,"CertGetCertificateChain TrustStatus failed, see wincrypt.h: 0x%x\n ", dwErr);
|
|
cout << sz;
|
|
}
|
|
|
|
}
|
|
|
|
if (ChainContext != NULL)
|
|
{
|
|
CertFreeCertificateChain(ChainContext);
|
|
}
|
|
|
|
return dwErr;
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// DisplayCerts
|
|
void DisplayCerts()
|
|
{
|
|
_ASSERTE(0 < g_nKeys);
|
|
|
|
// For each reader that has a card, load the CSP and display the cert
|
|
|
|
for (DWORD dw = 0; dw < g_dwNumReaders; dw++)
|
|
{
|
|
LPTSTR szCardName = NULL;
|
|
LPTSTR szCSPName = NULL;
|
|
|
|
if(0 >= g_pReaderStatusArray[dw].cbAtr)
|
|
{
|
|
// no point to do anymore work in this iteration
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Inform user of current test
|
|
//
|
|
cout << TEXT("\n=======================================================\n")
|
|
<< TEXT("Analyzing card in reader: ")
|
|
<< g_pReaderStatusArray[dw].szReader
|
|
<< TEXT("\n");
|
|
|
|
// Get the name of the card
|
|
|
|
DWORD dwAutoAllocate = SCARD_AUTOALLOCATE;
|
|
LONG lReturn = SCardListCards(g_hSCardCtx,
|
|
g_pReaderStatusArray[dw].rgbAtr,
|
|
NULL,
|
|
0,
|
|
(LPTSTR)&szCardName,
|
|
&dwAutoAllocate);
|
|
|
|
if (SCARD_S_SUCCESS == lReturn)
|
|
{
|
|
dwAutoAllocate = SCARD_AUTOALLOCATE;
|
|
lReturn = SCardGetCardTypeProviderName(
|
|
g_hSCardCtx,
|
|
szCardName,
|
|
SCARD_PROVIDER_CSP,
|
|
(LPTSTR)&szCSPName,
|
|
&dwAutoAllocate);
|
|
if (SCARD_S_SUCCESS != lReturn)
|
|
{
|
|
TCHAR szErr[16];
|
|
sprintf(szErr, "0x%X", lReturn);
|
|
cout << TEXT("Error on SCardGetCardTypeProviderName for ")
|
|
<< szCardName
|
|
<< TEXT(": ")
|
|
<< szErr
|
|
<< TEXT("\n");
|
|
}
|
|
}
|
|
|
|
// Prepare FullyQualifiedContainerName for CryptAcCntx call
|
|
|
|
TCHAR szFQCN[256];
|
|
sprintf(szFQCN, "\\\\.\\%s\\", g_pReaderStatusArray[dw].szReader);
|
|
HCRYPTPROV hProv = NULL;
|
|
|
|
if (SCARD_S_SUCCESS == lReturn)
|
|
{
|
|
BOOL fSts = CryptAcquireContext(
|
|
&hProv,
|
|
szFQCN, // default container via reader
|
|
szCSPName,
|
|
PROV_RSA_FULL,
|
|
CRYPT_SILENT);
|
|
|
|
// Enumerate the keys user specified and display the certs...
|
|
|
|
if (fSts)
|
|
{
|
|
for (int n=0; n<g_nKeys; n++)
|
|
{
|
|
// Which keyset is this?
|
|
LPCTSTR szKeyset = AT_KEYEXCHANGE==g_rgKeySet[n]?g_szEx:g_szSig;
|
|
HCRYPTKEY hKey = NULL;
|
|
|
|
// Get the key
|
|
fSts = CryptGetUserKey(
|
|
hProv,
|
|
g_rgKeySet[n],
|
|
&hKey);
|
|
if (!fSts)
|
|
{
|
|
lReturn = GetLastError();
|
|
if (NTE_NO_KEY == lReturn)
|
|
{
|
|
cout << TEXT("No ")
|
|
<< szKeyset
|
|
<< TEXT(" cert for reader: ")
|
|
<< g_pReaderStatusArray[dw].szReader
|
|
<< TEXT("\n");
|
|
|
|
}
|
|
else
|
|
{
|
|
TCHAR sz[256];
|
|
sprintf(sz,"An error (0x%X) occurred opening the ", lReturn);
|
|
cout << sz
|
|
<< szKeyset
|
|
<< TEXT(" key for reader: ")
|
|
<< g_pReaderStatusArray[dw].szReader
|
|
<< TEXT("\n");
|
|
}
|
|
|
|
// No point to work on this keyset anymore
|
|
continue;
|
|
}
|
|
|
|
// Get the cert for this key
|
|
PCCERT_CONTEXT pCertCtx = NULL;
|
|
|
|
pCertCtx = GetCertContext(&hProv, &hKey, g_rgKeySet[n]);
|
|
|
|
if (NULL != pCertCtx)
|
|
{
|
|
|
|
//
|
|
// If desired, attempt to build a certificate chain
|
|
//
|
|
if (g_fChain)
|
|
{
|
|
cout << TEXT("\nPerforming cert chain verification...\n");
|
|
if (S_OK != DisplayChainInfo(pCertCtx)) {
|
|
cout << TEXT("Cert did not chain!\n") << endl;
|
|
} else {
|
|
cout << TEXT("--- chain: Chain verifies.\n") << endl;
|
|
}
|
|
}
|
|
|
|
// call common UI to display m_pCertContext
|
|
// ( from cryptui.h ( cryptui.dll ) )
|
|
TCHAR szTitle[300];
|
|
sprintf(szTitle,
|
|
"%s : %s",
|
|
g_pReaderStatusArray[dw].szReader,
|
|
szKeyset);
|
|
|
|
CRYPTUI_VIEWCERTIFICATE_STRUCT CertViewInfo;
|
|
memset( &CertViewInfo, 0, sizeof( CertViewInfo ) );
|
|
|
|
CertViewInfo.dwSize = (sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCT));
|
|
CertViewInfo.hwndParent = NULL;
|
|
CertViewInfo.szTitle = szTitle;
|
|
CertViewInfo.dwFlags = CRYPTUI_DISABLE_EDITPROPERTIES |
|
|
CRYPTUI_DISABLE_ADDTOSTORE;
|
|
CertViewInfo.pCertContext = pCertCtx;
|
|
|
|
BOOL fThrowAway = FALSE;
|
|
fSts = CryptUIDlgViewCertificate(&CertViewInfo, &fThrowAway);
|
|
|
|
// clean up certcontext
|
|
CertFreeCertificateContext(pCertCtx);
|
|
|
|
cout << TEXT("Displayed ")
|
|
<< szKeyset
|
|
<< TEXT(" cert for reader: ")
|
|
<< g_pReaderStatusArray[dw].szReader
|
|
<< TEXT("\n");
|
|
}
|
|
else
|
|
{
|
|
cout << TEXT("No cert retrieved for reader: ")
|
|
<< g_pReaderStatusArray[dw].szReader
|
|
<< TEXT("\n");
|
|
}
|
|
|
|
// clean up stuff
|
|
if (NULL != hKey)
|
|
{
|
|
CryptDestroyKey(hKey);
|
|
hKey = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TCHAR szErr[16];
|
|
sprintf(szErr, "0x%X", GetLastError());
|
|
cout << TEXT("Error on CryptAcquireContext for ")
|
|
<< szCSPName
|
|
<< TEXT(": ")
|
|
<< szErr
|
|
<< TEXT("\n");
|
|
|
|
}
|
|
}
|
|
|
|
// Clean up
|
|
|
|
if (NULL != szCSPName)
|
|
{
|
|
SCardFreeMemory(g_hSCardCtx, (PVOID)szCSPName);
|
|
szCSPName = NULL;
|
|
}
|
|
if (NULL != szCardName)
|
|
{
|
|
SCardFreeMemory(g_hSCardCtx, (PVOID)szCardName);
|
|
szCardName = NULL;
|
|
}
|
|
if (NULL != hProv)
|
|
{
|
|
CryptReleaseContext(hProv, 0);
|
|
hProv = NULL;
|
|
}
|
|
} // end for
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
main:
|
|
|
|
This is the main entry point for the test program.
|
|
It runs the test. Nice and simple, borrowed from DBarlow
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 11/10/1997
|
|
|
|
Revisions:
|
|
|
|
AMatlosz 2/26/98
|
|
|
|
--*/
|
|
|
|
void __cdecl
|
|
main(DWORD cArgs,LPCTSTR rgszArgs[])
|
|
{
|
|
//init globals & locals
|
|
g_nKeys = 0;
|
|
g_rgKeySet[0] = g_rgKeySet[1] = 0;
|
|
g_hSCardCtx = NULL;
|
|
g_szReaderName = NULL;
|
|
g_fReaderNameAllocd = false;
|
|
g_dwNumReaders = 0;
|
|
g_pReaderStatusArray = NULL;
|
|
|
|
if (!ProcessCommandLine(cArgs, rgszArgs))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (IsCalaisRunning())
|
|
{
|
|
DisplayReaderList();
|
|
|
|
if (0 < g_nKeys)
|
|
{
|
|
DisplayCerts();
|
|
}
|
|
}
|
|
|
|
cout << TEXT("\ndone.") << endl;
|
|
|
|
// clean up globals
|
|
|
|
if (g_fReaderNameAllocd && NULL != g_szReaderName)
|
|
{
|
|
SCardFreeMemory(g_hSCardCtx, (PVOID)g_szReaderName);
|
|
}
|
|
if (NULL != g_hSCardCtx)
|
|
{
|
|
SCardReleaseContext(g_hSCardCtx);
|
|
}
|
|
}
|