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.
1112 lines
28 KiB
1112 lines
28 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1996 - 2001
|
|
//
|
|
// File: scinfo.cpp
|
|
//
|
|
// 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.
|
|
//
|
|
// SCInfo -- describes the RM status and displays each available sc cert(s)
|
|
//
|
|
// The following options are always enabled:
|
|
// 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:
|
|
// winscard.lib
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
|
|
#pragma hdrstop
|
|
|
|
#include <winscard.h>
|
|
#include <winsvc.h>
|
|
#include <cryptui.h>
|
|
|
|
#include "cscsp.h"
|
|
|
|
#define __dwFILE__ __dwFILE_CERTUTIL_SCINFO_CPP__
|
|
|
|
|
|
#define wszSCARDSERVICE L"SCardSvr"
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// IsSCardSvrRunning checks the registry and queries the service for status
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
IsSCardSvrRunning()
|
|
{
|
|
HRESULT hr;
|
|
WCHAR const *pwszError = NULL;
|
|
UINT idmsg = IDS_SMARTCARD_NOTRUNNING; // "The Microsoft Smart Card Resource Manager is not running."
|
|
|
|
HANDLE hSCardSvrStarted = NULL;
|
|
HMODULE hDll = GetModuleHandle(L"winscard.dll");
|
|
|
|
typedef HANDLE (WINAPI FNSCARDACCESSSTARTEDEVENT)(VOID);
|
|
FNSCARDACCESSSTARTEDEVENT *pfnSCardAccessStartedEvent;
|
|
|
|
pfnSCardAccessStartedEvent = (FNSCARDACCESSSTARTEDEVENT *)
|
|
GetProcAddress(hDll, "SCardAccessStartedEvent");
|
|
|
|
if (NULL == pfnSCardAccessStartedEvent)
|
|
{
|
|
hr = myHLastError();
|
|
pwszError = L"GetProcAddress";
|
|
_JumpErrorStr(hr, error, "GetProcAddress", L"SCardAccessStartedEvent");
|
|
}
|
|
hSCardSvrStarted = (*pfnSCardAccessStartedEvent)();
|
|
if (NULL == hSCardSvrStarted)
|
|
{
|
|
hr = myHLastError();
|
|
if (S_OK == hr)
|
|
{
|
|
hr = E_HANDLE;
|
|
}
|
|
pwszError = L"SCardAccessStartedEvent";
|
|
_JumpError(hr, error, "SCardAccessStartedEvent");
|
|
}
|
|
hr = WaitForSingleObject(hSCardSvrStarted, 1000);
|
|
if (WAIT_OBJECT_0 != hr)
|
|
{
|
|
hr = myHError(hr);
|
|
pwszError = L"WaitForSingleObject";
|
|
_JumpError(hr, error, "WaitForSingleObject");
|
|
}
|
|
idmsg = IDS_SMARTCARD_RUNNING; // "The Microsoft Smart Card Resource Manager is running."
|
|
hr = S_OK;
|
|
|
|
error:
|
|
|
|
// Display status
|
|
|
|
wprintf(myLoadResourceString(idmsg));
|
|
wprintf(wszNewLine);
|
|
if (S_OK != hr)
|
|
{
|
|
// IDS_SERVICEPAUSED; // "Service is paused."
|
|
// IDS_SERVICESTOPPED; // "Service is stopped."
|
|
cuPrintErrorAndString(
|
|
pwszError,
|
|
IDS_SERVICEUNKNOWNSTATE, // "Service is in an unknown state."
|
|
hr,
|
|
NULL);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeReaderList(
|
|
IN SCARDCONTEXT hSCard,
|
|
IN WCHAR *pwszzReaderNameAlloc,
|
|
IN SCARD_READERSTATE *prgReaderState)
|
|
{
|
|
if (NULL != hSCard)
|
|
{
|
|
if (NULL != pwszzReaderNameAlloc)
|
|
{
|
|
SCardFreeMemory(hSCard, pwszzReaderNameAlloc);
|
|
}
|
|
SCardReleaseContext(hSCard);
|
|
}
|
|
if (NULL != prgReaderState)
|
|
{
|
|
LocalFree(prgReaderState);
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// BuildReaderList tries to set *phSCard and get a list of currently available
|
|
// smart card readers.
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
BuildReaderList(
|
|
OPTIONAL IN WCHAR const *pwszReaderName,
|
|
OUT SCARDCONTEXT *phSCard,
|
|
OUT WCHAR **ppwszzReaderNameAlloc,
|
|
OUT SCARD_READERSTATE **pprgReaderState,
|
|
OUT DWORD *pcReaders)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
DWORD dwAutoAllocate;
|
|
SCARDCONTEXT hSCard = NULL;
|
|
WCHAR *pwszzReaderNameAlloc = NULL;
|
|
SCARD_READERSTATE *prgReaderState = NULL;
|
|
DWORD cReaders;
|
|
|
|
*phSCard = NULL;
|
|
*ppwszzReaderNameAlloc = NULL;
|
|
*pcReaders = 0;
|
|
*pprgReaderState = NULL;
|
|
|
|
wprintf(myLoadResourceString(IDS_SCREADER_STATUS_COLON));
|
|
wprintf(wszNewLine);
|
|
|
|
// Acquire global SCARDCONTEXT from resource manager if possible
|
|
|
|
hr = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hSCard);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintAPIError(L"SCardEstablishContext", hr);
|
|
wprintf(myLoadResourceString(IDS_SC_USER_SCOPE));
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_SC_NO_LIST));
|
|
wprintf(wszNewLine);
|
|
_JumpError(hr, error, "SCardEstablishContext");
|
|
}
|
|
|
|
// Build a readerstatus array from either a list of readers; or use the one
|
|
// the user specified
|
|
|
|
cReaders = 1;
|
|
if (NULL == pwszReaderName)
|
|
{
|
|
dwAutoAllocate = SCARD_AUTOALLOCATE;
|
|
hr = SCardListReaders(
|
|
hSCard,
|
|
SCARD_DEFAULT_READERS,
|
|
(WCHAR *) &pwszzReaderNameAlloc,
|
|
&dwAutoAllocate);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintAPIError(L"SCardListReaders", hr);
|
|
wprintf(myLoadResourceString(IDS_SC_LIST_FAILED));
|
|
wprintf(wszNewLine);
|
|
|
|
if (SCARD_E_NO_READERS_AVAILABLE == hr)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_SC_LIST_FAILED_NO_READERS));
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_SC_LIST_FAILED_GENERIC));
|
|
}
|
|
wprintf(wszNewLine);
|
|
_JumpError(hr, error, "SCardListReaders");
|
|
}
|
|
|
|
// Build a readerstatus array...
|
|
|
|
cReaders = 0;
|
|
if (NULL != pwszzReaderNameAlloc)
|
|
{
|
|
for (
|
|
pwszReaderName = pwszzReaderNameAlloc;
|
|
L'\0' != *pwszReaderName;
|
|
pwszReaderName += wcslen(pwszReaderName) + 1)
|
|
{
|
|
cReaders++;
|
|
}
|
|
}
|
|
pwszReaderName = pwszzReaderNameAlloc;
|
|
}
|
|
prgReaderState = (SCARD_READERSTATE *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
cReaders * sizeof(**pprgReaderState));
|
|
if (NULL == prgReaderState)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
wprintf(myLoadResourceString(IDS_SC_READERS_COLON));
|
|
wprintf(L" %u\n", cReaders);
|
|
for (i = 0; i < cReaders; i++)
|
|
{
|
|
wprintf(L" %u: %ws\n", i, pwszReaderName);
|
|
prgReaderState[i].szReader = const_cast<WCHAR *>(pwszReaderName);
|
|
prgReaderState[i].dwCurrentState = SCARD_STATE_UNAWARE;
|
|
pwszReaderName += wcslen(pwszReaderName) + 1;
|
|
}
|
|
|
|
// ...And get the reader status from the resource manager
|
|
|
|
hr = SCardGetStatusChange(
|
|
hSCard,
|
|
INFINITE, // hardly
|
|
prgReaderState,
|
|
cReaders);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintAPIError(L"SCardGetStatusChange", hr);
|
|
_JumpError(hr, error, "SCardGetStatusChange");
|
|
}
|
|
*phSCard = hSCard;
|
|
hSCard = NULL;
|
|
|
|
*ppwszzReaderNameAlloc = pwszzReaderNameAlloc;
|
|
pwszzReaderNameAlloc = NULL;
|
|
|
|
*pprgReaderState = prgReaderState;
|
|
prgReaderState = NULL;
|
|
|
|
*pcReaders = cReaders;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
FreeReaderList(hSCard, pwszzReaderNameAlloc, prgReaderState);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// DisplayReaderList displays the status for a list of readers.
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
DisplayReaderList(
|
|
IN SCARDCONTEXT hSCard,
|
|
IN SCARD_READERSTATE const *prgReaderState,
|
|
IN DWORD cReaders)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
DWORD dwAutoAllocate;
|
|
UINT idsMsg;
|
|
|
|
// Display all reader information
|
|
|
|
for (i = 0; i < cReaders; i++)
|
|
{
|
|
DWORD dwState;
|
|
WCHAR const *pwszSep;
|
|
static WCHAR const s_wszSep[] = L" | ";
|
|
|
|
//--- reader: readerName
|
|
|
|
wprintf(myLoadResourceString(IDS_SC_MINUS_READER_COLON));
|
|
wprintf(L" %ws\n", prgReaderState[i].szReader);
|
|
|
|
//--- status: /bits/
|
|
|
|
wprintf(myLoadResourceString(IDS_SC_MINUS_STATUS_COLON));
|
|
dwState = prgReaderState[i].dwEventState;
|
|
|
|
pwszSep = L" ";
|
|
if (SCARD_STATE_UNKNOWN & dwState)
|
|
{
|
|
wprintf(L"%wsSCARD_STATE_UNKNOWN", pwszSep);
|
|
pwszSep = s_wszSep;
|
|
}
|
|
if (SCARD_STATE_UNAVAILABLE & dwState)
|
|
{
|
|
wprintf(L"%wsSCARD_STATE_UNAVAILABLE", pwszSep);
|
|
pwszSep = s_wszSep;
|
|
}
|
|
if (SCARD_STATE_EMPTY & dwState)
|
|
{
|
|
wprintf(L"%wsSCARD_STATE_EMPTY", pwszSep);
|
|
pwszSep = s_wszSep;
|
|
}
|
|
if (SCARD_STATE_PRESENT & dwState)
|
|
{
|
|
wprintf(L"%wsSCARD_STATE_PRESENT", pwszSep);
|
|
pwszSep = s_wszSep;
|
|
}
|
|
if (SCARD_STATE_EXCLUSIVE & dwState)
|
|
{
|
|
wprintf(L"%wsSCARD_STATE_EXCLUSIVE", pwszSep);
|
|
pwszSep = s_wszSep;
|
|
}
|
|
if (SCARD_STATE_INUSE & dwState)
|
|
{
|
|
wprintf(L"%wsSCARD_STATE_INUSE", pwszSep);
|
|
pwszSep = s_wszSep;
|
|
}
|
|
if (SCARD_STATE_MUTE & dwState)
|
|
{
|
|
wprintf(L"%wsSCARD_STATE_MUTE", pwszSep);
|
|
pwszSep = s_wszSep;
|
|
}
|
|
if (SCARD_STATE_UNPOWERED & dwState)
|
|
{
|
|
wprintf(L"%wsSCARD_STATE_UNPOWERED", pwszSep);
|
|
}
|
|
wprintf(wszNewLine);
|
|
|
|
//--- status: what scstatus would say
|
|
|
|
// NO CARD
|
|
|
|
if (SCARD_STATE_EMPTY & dwState) // SC_STATUS_NO_CARD
|
|
{
|
|
idsMsg = IDS_SC_STATUS_NO_CARD;
|
|
}
|
|
|
|
// CARD in reader: SHARED, EXCLUSIVE, FREE, UNKNOWN ?
|
|
|
|
else
|
|
if (SCARD_STATE_PRESENT & dwState)
|
|
{
|
|
if (SCARD_STATE_MUTE & dwState) // SC_STATUS_UNKNOWN
|
|
{
|
|
idsMsg = IDS_SC_STATUS_UNKNOWN;
|
|
}
|
|
else
|
|
if (SCARD_STATE_INUSE & dwState)
|
|
{
|
|
if (dwState & SCARD_STATE_EXCLUSIVE & dwState)
|
|
{
|
|
// SC_STATUS_EXCLUSIVE
|
|
|
|
idsMsg = IDS_SC_STATUS_BUSY;
|
|
}
|
|
else // SC_STATUS_SHARED
|
|
{
|
|
idsMsg = IDS_SC_STATUS_SHARED;
|
|
}
|
|
}
|
|
else // SC_SATATUS_AVAILABLE
|
|
{
|
|
idsMsg = IDS_SC_STATUS_AVAILABLE;
|
|
}
|
|
}
|
|
// READER ERROR: at this point, something's gone wrong
|
|
else // SCARD_STATE_UNAVAILABLE & dwState -- SC_STATUS_ERROR
|
|
{
|
|
|
|
idsMsg = IDS_SC_STATUS_NO_RESPONSE;
|
|
}
|
|
wprintf(myLoadResourceString(IDS_SC_MINUS_STATUS_COLON));
|
|
wprintf(L" ");
|
|
wprintf(myLoadResourceString(idsMsg));
|
|
wprintf(wszNewLine);
|
|
|
|
// card name(s):
|
|
|
|
wprintf(myLoadResourceString(IDS_SC_MINUS_CARD_COLON));
|
|
if (0 < prgReaderState[i].cbAtr)
|
|
{
|
|
WCHAR *pwszCardName = NULL;
|
|
|
|
// Get the name of the card
|
|
|
|
dwAutoAllocate = SCARD_AUTOALLOCATE;
|
|
hr = SCardListCards(
|
|
hSCard,
|
|
prgReaderState[i].rgbAtr,
|
|
NULL,
|
|
0,
|
|
(WCHAR *) &pwszCardName,
|
|
&dwAutoAllocate);
|
|
if (S_OK != hr || NULL == pwszCardName)
|
|
{
|
|
wprintf(L" ");
|
|
wprintf(myLoadResourceString(IDS_SC_UNKNOWN_CARD));
|
|
}
|
|
else
|
|
{
|
|
WCHAR const *pwszName;
|
|
|
|
pwszSep = L"";
|
|
for (
|
|
pwszName = pwszCardName;
|
|
L'\0' != *pwszName;
|
|
pwszName += wcslen(pwszName) + 1)
|
|
{
|
|
wprintf(L"%ws %ws", pwszSep, pwszName);
|
|
pwszSep = L",";
|
|
}
|
|
}
|
|
if (NULL != pwszCardName)
|
|
{
|
|
SCardFreeMemory(hSCard, pwszCardName);
|
|
}
|
|
}
|
|
wprintf(wszNewLine);
|
|
}
|
|
hr = S_OK;
|
|
|
|
//error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myCryptGetProvParamToUnicode(
|
|
IN HCRYPTPROV hProv,
|
|
IN DWORD dwParam,
|
|
OUT WCHAR **ppwszOut,
|
|
IN DWORD dwFlags)
|
|
{
|
|
HRESULT hr;
|
|
char *psz = NULL;
|
|
DWORD cb;
|
|
|
|
*ppwszOut = NULL;
|
|
if (!CryptGetProvParam(hProv, dwParam, NULL, &cb, 0))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptGetProvParam");
|
|
}
|
|
|
|
psz = (char *) LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == psz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
if (!CryptGetProvParam(hProv, dwParam, (BYTE *) psz, &cb, 0))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptGetProvParam");
|
|
}
|
|
|
|
if (!myConvertSzToWsz(ppwszOut, psz, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "myConvertSzToWsz");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != psz)
|
|
{
|
|
LocalFree(psz);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// GetCertContext -- called by DisplayCerts
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
GetCertContext(
|
|
IN HCRYPTPROV hProv,
|
|
IN HCRYPTKEY hKey,
|
|
IN DWORD dwKeySpec,
|
|
IN WCHAR const *pwszKeyType,
|
|
OUT CERT_CONTEXT const **ppCert)
|
|
{
|
|
HRESULT hr;
|
|
CERT_CONTEXT const *pCert = NULL;
|
|
CERT_PUBLIC_KEY_INFO *pKey = NULL;
|
|
CRYPT_KEY_PROV_INFO KeyProvInfo;
|
|
WCHAR *pwszContainerName = NULL;
|
|
WCHAR *pwszProvName = NULL;
|
|
BYTE *pbCert = NULL;
|
|
DWORD cbCert;
|
|
DWORD cbKey;
|
|
|
|
*ppCert = NULL;
|
|
|
|
// Get the cert from this key
|
|
|
|
if (!CryptGetKeyParam(hKey, KP_CERTIFICATE, NULL, &cbCert, 0))
|
|
{
|
|
hr = myHLastError();
|
|
if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) != hr)
|
|
{
|
|
_JumpError(hr, error, "CryptGetKeyParam");
|
|
}
|
|
}
|
|
pbCert = (BYTE *) LocalAlloc(LMEM_FIXED, cbCert);
|
|
if (NULL == pbCert)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
if (!CryptGetKeyParam(hKey, KP_CERTIFICATE, pbCert, &cbCert, 0))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptGetKeyParam");
|
|
}
|
|
|
|
// Convert the certificate into a Cert Context.
|
|
|
|
pCert = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
pbCert,
|
|
cbCert);
|
|
if (NULL == pCert)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertCreateCertificateContext");
|
|
}
|
|
|
|
// Perform public key check
|
|
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_FORMAT_SC_TESTING_MATCH), pwszKeyType);
|
|
wprintf(wszNewLine);
|
|
|
|
if (!CryptExportPublicKeyInfo(
|
|
hProv,
|
|
dwKeySpec,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
NULL,
|
|
&cbKey)) // in, out
|
|
{
|
|
hr = myHLastError();
|
|
cuPrintAPIError(L"CryptExportPublicKeyInfo", hr);
|
|
_JumpError(hr, error, "CryptExportPublicKeyInfo");
|
|
}
|
|
if (0 == cbKey)
|
|
{
|
|
hr = SCARD_E_UNEXPECTED; // huh?
|
|
wprintf(
|
|
myLoadResourceString(IDS_SC_SIZE_ZERO),
|
|
L"CryptExportPublicKeyInfo");
|
|
wprintf(wszNewLine);
|
|
_JumpError(hr, error, "zero info size");
|
|
}
|
|
|
|
pKey = (CERT_PUBLIC_KEY_INFO *) LocalAlloc(LMEM_FIXED, cbKey);
|
|
if (NULL == pKey)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
if (!CryptExportPublicKeyInfo(
|
|
hProv,
|
|
dwKeySpec,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
pKey,
|
|
&cbKey))
|
|
{
|
|
hr = myHLastError();
|
|
cuPrintAPIError(L"CryptExportPublicKeyInfo", hr);
|
|
_JumpError(hr, error, "CryptExportPublicKeyInfo");
|
|
}
|
|
|
|
if (!CertComparePublicKeyInfo(
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
pKey, // from the private keyset
|
|
&pCert->pCertInfo->SubjectPublicKeyInfo)) // cert public key
|
|
{
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_SC_KEYPROVINFO_KEY));
|
|
wprintf(wszNewLine);
|
|
cuDumpPublicKey(pKey);
|
|
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_SC_CERT_KEY));
|
|
wprintf(wszNewLine);
|
|
cuDumpPublicKey(&pCert->pCertInfo->SubjectPublicKeyInfo);
|
|
|
|
// by design, CertComparePublicKeyInfo doesn't set last error!
|
|
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "CertComparePublicKeyInfo");
|
|
}
|
|
wprintf(myLoadResourceString(IDS_SC_KEY_MATCHES));
|
|
wprintf(wszNewLine);
|
|
|
|
// Associate cryptprovider w/ the private key property of this cert
|
|
// ... need the container name
|
|
|
|
hr = myCryptGetProvParamToUnicode(
|
|
hProv,
|
|
PP_CONTAINER,
|
|
&pwszContainerName,
|
|
0);
|
|
_JumpIfError(hr, error, "myCryptGetProvParamToUnicode");
|
|
|
|
// ... need the provider name
|
|
|
|
hr = myCryptGetProvParamToUnicode(hProv, PP_NAME, &pwszProvName, 0);
|
|
_JumpIfError(hr, error, "myCryptGetProvParamToUnicode");
|
|
|
|
// Set the cert context properties to reflect the prov info
|
|
|
|
KeyProvInfo.pwszContainerName = pwszContainerName;
|
|
KeyProvInfo.pwszProvName = pwszProvName;
|
|
KeyProvInfo.dwProvType = PROV_RSA_FULL;
|
|
KeyProvInfo.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
|
|
KeyProvInfo.cProvParam = 0;
|
|
KeyProvInfo.rgProvParam = NULL;
|
|
KeyProvInfo.dwKeySpec = dwKeySpec;
|
|
|
|
if (!CertSetCertificateContextProperty(
|
|
pCert,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
0,
|
|
(VOID *) &KeyProvInfo))
|
|
{
|
|
hr = myHLastError();
|
|
|
|
// the cert's been incorrectly created -- scrap it.
|
|
|
|
_JumpError(hr, error, "CertSetCertificateContextProperty");
|
|
}
|
|
hr = cuDumpCertKeyProviderInfo(g_wszPad2, pCert, NULL, NULL);
|
|
_PrintIfError(hr, "cuDumpCertKeyProviderInfo");
|
|
|
|
if (!g_fCryptSilent)
|
|
{
|
|
if (AT_SIGNATURE == dwKeySpec)
|
|
{
|
|
hr = myValidateKeyForSigning(
|
|
hProv,
|
|
&pCert->pCertInfo->SubjectPublicKeyInfo,
|
|
CALG_SHA1);
|
|
}
|
|
else
|
|
{
|
|
hr = myValidateKeyForEncrypting(
|
|
hProv,
|
|
&pCert->pCertInfo->SubjectPublicKeyInfo,
|
|
CALG_RC4);
|
|
}
|
|
if (S_OK != hr)
|
|
{
|
|
if (SCARD_W_CANCELLED_BY_USER != hr)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_ERR_PRIVATEKEY_MISMATCH)); // "ERROR: Certificate public key does NOT match private key"
|
|
wprintf(wszNewLine);
|
|
//_JumpError(hr, error, "myValidateKeyForEncrypting");
|
|
_PrintError(hr, "myValidateKeyForEncrypting");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_PRIVATEKEY_VERIFIES));
|
|
wprintf(wszNewLine);
|
|
}
|
|
}
|
|
*ppCert = pCert;
|
|
pCert = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pbCert)
|
|
{
|
|
LocalFree(pbCert);
|
|
}
|
|
if (NULL != pKey)
|
|
{
|
|
LocalFree(pKey);
|
|
}
|
|
if (NULL != pwszContainerName)
|
|
{
|
|
LocalFree(pwszContainerName);
|
|
}
|
|
if (NULL != pwszProvName)
|
|
{
|
|
LocalFree(pwszProvName);
|
|
}
|
|
if (NULL != pCert)
|
|
{
|
|
CertFreeCertificateContext(pCert);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// DisplayChainInfo -- This code verifies that the SC cert is valid.
|
|
// Uses identical code to KDC cert chaining engine.
|
|
//
|
|
// Author: Todds
|
|
//--------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DisplayChainInfo(
|
|
IN CERT_CONTEXT const *pCert)
|
|
{
|
|
HRESULT hr;
|
|
CERT_CHAIN_PARA ChainParameters;
|
|
char *pszSCUsage = szOID_KP_SMARTCARD_LOGON;
|
|
CERT_CHAIN_CONTEXT const *pChainContext = NULL;
|
|
DWORD VerifyState;
|
|
|
|
ZeroMemory(&ChainParameters, sizeof(ChainParameters));
|
|
ChainParameters.cbSize = sizeof(ChainParameters);
|
|
ChainParameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
|
|
ChainParameters.RequestedUsage.Usage.cUsageIdentifier = 1;
|
|
ChainParameters.RequestedUsage.Usage.rgpszUsageIdentifier = &pszSCUsage;
|
|
|
|
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
|
|
&pChainContext))
|
|
{
|
|
hr = myHLastError();
|
|
cuPrintAPIError(L"CertGetCertificateChain", hr);
|
|
_JumpError(hr, error, "CertGetCertificateChain");
|
|
}
|
|
if (CERT_TRUST_NO_ERROR != pChainContext->TrustStatus.dwErrorStatus)
|
|
{
|
|
wprintf(
|
|
L"CertGetCertificateChain(dwErrorStatus) = 0x%x\n",
|
|
pChainContext->TrustStatus.dwErrorStatus);
|
|
wprintf(myLoadResourceString(IDS_SC_BAD_CHAIN));
|
|
wprintf(wszNewLine);
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_SC_GOOD_CHAIN));
|
|
wprintf(wszNewLine);
|
|
}
|
|
|
|
hr = cuVerifyCertContext(
|
|
pCert, // pCert
|
|
NULL, // hStoreCA
|
|
1, // cApplicationPolicies
|
|
&pszSCUsage, // apszApplicationPolicies
|
|
0, // cIssuancePolicies
|
|
NULL, // apszIssuancePolicies
|
|
TRUE, // fNTAuth
|
|
&VerifyState);
|
|
_JumpIfError(hr, error, "cuVerifyCertContext");
|
|
|
|
error:
|
|
if (NULL != pChainContext)
|
|
{
|
|
CertFreeCertificateChain(pChainContext);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DisplayReaderCertAndKey(
|
|
IN SCARD_READERSTATE const *pReaderState,
|
|
IN HCRYPTPROV hProv,
|
|
IN DWORD dwKeySpec,
|
|
IN WCHAR const *pwszKeyType,
|
|
IN WCHAR const *pwszCardName,
|
|
IN WCHAR const *pwszCSPName)
|
|
{
|
|
HRESULT hr;
|
|
HCRYPTKEY hKey = NULL;
|
|
CERT_CONTEXT const *pCert = NULL;
|
|
DWORD cwc;
|
|
WCHAR *pwszTitle = NULL;
|
|
CRYPTUI_VIEWCERTIFICATE_STRUCT CertViewInfo;
|
|
|
|
// Get the key
|
|
|
|
if (!CryptGetUserKey(hProv, dwKeySpec, &hKey))
|
|
{
|
|
hr = myHLastError();
|
|
cuPrintAPIError(L"CryptGetUserKey", hr);
|
|
if (NTE_NO_KEY == hr)
|
|
{
|
|
wprintf(
|
|
myLoadResourceString(IDS_FORMAT_SC_NO_KEY_COLON),
|
|
pwszKeyType);
|
|
}
|
|
else
|
|
{
|
|
wprintf(
|
|
myLoadResourceString(IDS_FORMAT_SC_CANNOT_OPEN_KEY_COLON),
|
|
pwszKeyType);
|
|
}
|
|
wprintf(L" %ws\n", pReaderState->szReader);
|
|
_JumpError2(hr, error, "CryptGetUserKey", NTE_NO_KEY);
|
|
}
|
|
|
|
// Get the cert for this key
|
|
|
|
hr = GetCertContext(hProv, hKey, dwKeySpec, pwszKeyType, &pCert);
|
|
if (S_OK != hr)
|
|
{
|
|
wprintf(
|
|
myLoadResourceString(IDS_FORMAT_SC_NO_CERT_COLON),
|
|
pwszKeyType);
|
|
wprintf(L" %ws\n", pReaderState->szReader);
|
|
_JumpError(hr, error, "GetCertContext");
|
|
}
|
|
|
|
// Attempt to build a certificate chain
|
|
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_SC_VALIDATING_CHAIN));
|
|
wprintf(wszNewLine);
|
|
|
|
DisplayChainInfo(pCert);
|
|
|
|
// call common UI to display Cert Context
|
|
// (from cryptui.h (cryptui.dll))
|
|
|
|
if (!g_fCryptSilent)
|
|
{
|
|
cwc = wcslen(pReaderState->szReader) +
|
|
2 +
|
|
wcslen(pwszKeyType);
|
|
pwszTitle = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(cwc + 1) * sizeof(WCHAR));
|
|
if (NULL == pwszTitle)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
swprintf(
|
|
pwszTitle,
|
|
L"%ws: %ws",
|
|
pReaderState->szReader,
|
|
pwszKeyType);
|
|
|
|
ZeroMemory(&CertViewInfo, sizeof(CertViewInfo));
|
|
CertViewInfo.dwSize = sizeof(CertViewInfo);
|
|
//CertViewInfo.hwndParent = NULL;
|
|
CertViewInfo.szTitle = pwszTitle;
|
|
CertViewInfo.dwFlags = CRYPTUI_DISABLE_EDITPROPERTIES |
|
|
CRYPTUI_DISABLE_ADDTOSTORE |
|
|
CRYPTUI_ENABLE_REVOCATION_CHECKING;
|
|
CertViewInfo.pCertContext = pCert;
|
|
|
|
CryptUIDlgViewCertificate(&CertViewInfo, NULL);
|
|
CertFreeCertificateContext(pCert);
|
|
}
|
|
wprintf(
|
|
myLoadResourceString(IDS_FORMAT_SC_CERT_DISPLAYED_COLON),
|
|
pwszKeyType);
|
|
wprintf(L" %ws\n", pReaderState->szReader);
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszTitle)
|
|
{
|
|
LocalFree(pwszTitle);
|
|
}
|
|
if (NULL != hKey)
|
|
{
|
|
CryptDestroyKey(hKey);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DisplayReaderCert(
|
|
IN SCARDCONTEXT hSCard,
|
|
IN SCARD_READERSTATE const *pReaderState)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
DWORD dwAutoAllocate;
|
|
WCHAR wszFQCN[256];
|
|
HCRYPTPROV hProv = NULL;
|
|
WCHAR *pwszCardName = NULL;
|
|
WCHAR *pwszCSPName = NULL;
|
|
|
|
if (0 >= pReaderState->cbAtr)
|
|
{
|
|
hr = S_OK;
|
|
goto error; // no point to do any more work on this reader
|
|
}
|
|
|
|
// Inform user of current test
|
|
|
|
wprintf(L"\n=======================================================\n");
|
|
wprintf(myLoadResourceString(IDS_SC_ANALYZING_CARD_COLON));
|
|
wprintf(L" %ws\n", pReaderState->szReader);
|
|
|
|
// Get the name of the card
|
|
|
|
dwAutoAllocate = SCARD_AUTOALLOCATE;
|
|
hr = SCardListCards(
|
|
hSCard,
|
|
pReaderState->rgbAtr,
|
|
NULL, // rgguidInterfaces
|
|
0, // cguidInterfaceCount
|
|
(WCHAR *) &pwszCardName, // mszCards
|
|
&dwAutoAllocate); // pcchCards
|
|
_JumpIfError(hr, error, "SCardListCards");
|
|
|
|
dwAutoAllocate = SCARD_AUTOALLOCATE;
|
|
hr = SCardGetCardTypeProviderName(
|
|
hSCard,
|
|
pwszCardName,
|
|
SCARD_PROVIDER_CSP,
|
|
(WCHAR *) &pwszCSPName,
|
|
&dwAutoAllocate);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintAPIError(L"SCardGetCardTypeProviderName", hr);
|
|
wprintf(
|
|
myLoadResourceString(IDS_FORMAT_SC_CANNOT_GET_CSP),
|
|
pwszCardName);
|
|
_JumpError(hr, error, "SCardGetCardTypeProviderName");
|
|
}
|
|
|
|
// Prepare FullyQualifiedContainerName for CryptAcquireContext call
|
|
|
|
swprintf(wszFQCN, L"\\\\.\\%ws\\", pReaderState->szReader);
|
|
|
|
if (!CryptAcquireContext(
|
|
&hProv,
|
|
wszFQCN, // default container via reader
|
|
pwszCSPName,
|
|
PROV_RSA_FULL,
|
|
g_fCryptSilent? CRYPT_SILENT : 0))
|
|
{
|
|
hr = myHLastError();
|
|
wprintf(L"%ws:\n", pReaderState->szReader);
|
|
wprintf(L"%ws:\n", pwszCSPName);
|
|
cuPrintAPIError(L"CryptAcquireContext", hr);
|
|
_JumpError(hr, error, "SCardGetCardTypeProviderName");
|
|
}
|
|
|
|
// Enumerate the keys user specified and display the certs...
|
|
|
|
hr = DisplayReaderCertAndKey(
|
|
pReaderState,
|
|
hProv,
|
|
AT_SIGNATURE,
|
|
L"AT_SIGNATURE",
|
|
pwszCardName,
|
|
pwszCSPName);
|
|
_PrintIfError2(hr, "DisplayReaderCertAndKey", NTE_NO_KEY);
|
|
|
|
hr2 = DisplayReaderCertAndKey(
|
|
pReaderState,
|
|
hProv,
|
|
AT_KEYEXCHANGE,
|
|
L"AT_KEYEXCHANGE",
|
|
pwszCardName,
|
|
pwszCSPName);
|
|
_PrintIfError2(hr2, "DisplayReaderCertAndKey", NTE_NO_KEY);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
hr2 = S_OK;
|
|
}
|
|
|
|
// ignore NTE_NO_KEY if the other key type exists or has a different error:
|
|
|
|
if (NTE_NO_KEY == hr)
|
|
{
|
|
hr = hr2;
|
|
_PrintIfError2(hr, "DisplayReaderCertAndKey", NTE_NO_KEY);
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszCSPName)
|
|
{
|
|
SCardFreeMemory(hSCard, pwszCSPName);
|
|
}
|
|
if (NULL != pwszCardName)
|
|
{
|
|
SCardFreeMemory(hSCard, pwszCardName);
|
|
}
|
|
if (NULL != hProv)
|
|
{
|
|
CryptReleaseContext(hProv, 0);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// DisplayCerts
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
DisplayCerts(
|
|
IN SCARDCONTEXT hSCard,
|
|
IN SCARD_READERSTATE const *prgReaderState,
|
|
IN DWORD cReaders)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
DWORD i;
|
|
|
|
// For each reader that has a card, load the CSP and display the cert
|
|
|
|
hr = S_OK;
|
|
for (i = 0; i < cReaders; i++)
|
|
{
|
|
hr2 = DisplayReaderCert(hSCard, &prgReaderState[i]);
|
|
_PrintIfError(hr2, "DisplayReaderCert");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// verbSCInfo -- This is the main entry point for the smart card test program.
|
|
// Nice and simple, borrowed from DBarlow
|
|
//
|
|
// Author: Doug Barlow (dbarlow) 11/10/1997
|
|
//
|
|
// Revisions:
|
|
// AMatlosz 2/26/98
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
verbSCInfo(
|
|
IN WCHAR const *pwszOption,
|
|
OPTIONAL IN WCHAR const *pwszReaderName,
|
|
IN WCHAR const *pwszArg2,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
SCARDCONTEXT hSCard = NULL;
|
|
WCHAR *pwszzReaderNameAlloc = NULL;
|
|
SCARD_READERSTATE *prgReaderState = NULL;
|
|
DWORD cReaders;
|
|
|
|
hr = IsSCardSvrRunning();
|
|
_JumpIfError(hr, error, "IsSCardSvrRunning");
|
|
|
|
hr = BuildReaderList(
|
|
pwszReaderName,
|
|
&hSCard,
|
|
&pwszzReaderNameAlloc,
|
|
&prgReaderState,
|
|
&cReaders);
|
|
_PrintIfError(hr, "BuildReaderList");
|
|
|
|
hr2 = DisplayReaderList(hSCard, prgReaderState, cReaders);
|
|
_PrintIfError(hr2, "DisplayReaderList");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
|
|
hr2 = DisplayCerts(hSCard, prgReaderState, cReaders);
|
|
_PrintIfError(hr2, "DisplayCerts");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_DONE));
|
|
wprintf(wszNewLine);
|
|
|
|
error:
|
|
FreeReaderList(hSCard, pwszzReaderNameAlloc, prgReaderState);
|
|
return(hr);
|
|
}
|