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.
837 lines
25 KiB
837 lines
25 KiB
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
|
|
|
|
File: SmartCard.cpp
|
|
|
|
Content: Implementation of helper routines for accessing certificates in
|
|
smart card. Functions in this module require that the Smart Card Base
|
|
Component v1.1 to be installed.
|
|
|
|
History: 12-06-2001 dsie created
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
#include "StdAfx.h"
|
|
#include "CAPICOM.h"
|
|
#include "SmartCard.h"
|
|
|
|
//
|
|
// typedefs for SCardXXX APIs.
|
|
//
|
|
typedef WINSCARDAPI LONG (WINAPI * PFNSCARDESTABLISHCONTEXT) (
|
|
IN DWORD dwScope,
|
|
IN LPCVOID pvReserved1,
|
|
IN LPCVOID pvReserved2,
|
|
OUT LPSCARDCONTEXT phContext);
|
|
|
|
typedef WINSCARDAPI LONG (WINAPI * PFNSCARDLISTREADERSA) (
|
|
IN SCARDCONTEXT hContext,
|
|
IN LPCSTR mszGroups,
|
|
OUT LPSTR mszReaders,
|
|
IN OUT LPDWORD pcchReaders);
|
|
|
|
typedef WINSCARDAPI LONG (WINAPI * PFNSCARDGETSTATUSCHANGEA) (
|
|
IN SCARDCONTEXT hContext,
|
|
IN DWORD dwTimeout,
|
|
IN OUT LPSCARD_READERSTATE_A rgReaderStates,
|
|
IN DWORD cReaders);
|
|
|
|
typedef WINSCARDAPI LONG (WINAPI * PFNSCARDLISTCARDSA) (
|
|
IN SCARDCONTEXT hContext,
|
|
IN LPCBYTE pbAtr,
|
|
IN LPCGUID rgquidInterfaces,
|
|
IN DWORD cguidInterfaceCount,
|
|
OUT LPSTR mszCards,
|
|
IN OUT LPDWORD pcchCards);
|
|
|
|
typedef WINSCARDAPI LONG (WINAPI* PFNSCARDGETCARDTYPEPROVIDERNAMEA) (
|
|
IN SCARDCONTEXT hContext,
|
|
IN LPCSTR szCardName,
|
|
IN DWORD dwProviderId,
|
|
OUT LPSTR szProvider,
|
|
IN OUT LPDWORD pcchProvider);
|
|
|
|
typedef WINSCARDAPI LONG (WINAPI* PFNSCARDFREEMEMORY) (
|
|
IN SCARDCONTEXT hContext,
|
|
IN LPVOID pvMem);
|
|
|
|
typedef WINSCARDAPI LONG (WINAPI * PFNSCARDRELEASECONTEXT) (
|
|
IN SCARDCONTEXT hContext);
|
|
|
|
//
|
|
// Function pointer to SCardXXX APIs.
|
|
//
|
|
static PFNSCARDESTABLISHCONTEXT pfnSCardEstablishContext = NULL;
|
|
static PFNSCARDLISTREADERSA pfnSCardListReadersA = NULL;
|
|
static PFNSCARDGETSTATUSCHANGEA pfnSCardGetStatusChangeA = NULL;
|
|
static PFNSCARDLISTCARDSA pfnSCardListCardsA = NULL;
|
|
static PFNSCARDGETCARDTYPEPROVIDERNAMEA pfnSCardGetCardTypeProviderNameA = NULL;
|
|
static PFNSCARDFREEMEMORY pfnSCardFreeMemory = NULL;
|
|
static PFNSCARDRELEASECONTEXT pfnSCardReleaseContext = NULL;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Local functions.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : AddCert
|
|
|
|
Synopsis : Add the specified certificate to the specified store.
|
|
|
|
Parameter: - IN LPCSTR szCSPName
|
|
|
|
CSP name string.
|
|
|
|
- IN LPCSTR szContainerName
|
|
|
|
Key container name string.
|
|
|
|
- IN DWORD dwKeySpec
|
|
|
|
AT_KEYEXCHANGZE or AT_SIGNATURE.
|
|
|
|
- IN LPBYTE pbEncodedCert
|
|
|
|
Pointer to encoded cert data to be added.
|
|
|
|
- IN DWORD cbEncodedCert
|
|
|
|
Length of encoded cert data.
|
|
|
|
- IN HCERTSTORE hCertStore
|
|
|
|
Handle of cert store where the cert will be added.
|
|
|
|
Remarks :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static HRESULT AddCert (IN LPCSTR szCSPName,
|
|
IN LPCSTR szContainerName,
|
|
IN DWORD dwKeySpec,
|
|
IN LPBYTE pbEncodedCert,
|
|
IN DWORD cbEncodedCert,
|
|
IN HCERTSTORE hCertStore)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
CComBSTR bstrCSPName;
|
|
CComBSTR bstrContainerName;
|
|
CRYPT_KEY_PROV_INFO KeyProvInfo;
|
|
|
|
DebugTrace("Entering AddCert().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(szCSPName);
|
|
ATLASSERT(szContainerName);
|
|
ATLASSERT(pbEncodedCert);
|
|
ATLASSERT(cbEncodedCert);
|
|
ATLASSERT(hCertStore);
|
|
|
|
//
|
|
// Create certificate context for the specified certificate.
|
|
//
|
|
if (!(pCertContext = ::CertCreateCertificateContext(CAPICOM_ASN_ENCODING,
|
|
pbEncodedCert,
|
|
cbEncodedCert)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertCreateCertificateContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Convert strings to UNICODE.
|
|
//
|
|
if (!(bstrCSPName = szCSPName))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: bstrCSPName = szCSPName failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
if (!(bstrContainerName = szContainerName))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: bstrContainerName = szContainerName failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Add the CSP & key container info. This is used by CAPI to load the
|
|
// CSP and find the keyset when the user indicates this certificate.
|
|
//
|
|
::ZeroMemory((LPVOID) &KeyProvInfo, sizeof(CRYPT_KEY_PROV_INFO));
|
|
KeyProvInfo.pwszContainerName = (LPWSTR) bstrContainerName;
|
|
KeyProvInfo.pwszProvName = (LPWSTR) bstrCSPName;
|
|
KeyProvInfo.dwProvType = PROV_RSA_FULL;
|
|
KeyProvInfo.dwFlags = 0;
|
|
KeyProvInfo.dwKeySpec = dwKeySpec;
|
|
|
|
if (!::CertSetCertificateContextProperty(pCertContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
0,
|
|
(const void *) &KeyProvInfo))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertSetCertificateContextProperty() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Put the cert in the store!
|
|
//
|
|
if (!::CertAddCertificateContextToStore(hCertStore,
|
|
pCertContext,
|
|
CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, // or CERT_STORE_ADD_NEW
|
|
NULL))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CertCreateCertificateContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pCertContext != NULL)
|
|
{
|
|
CertFreeCertificateContext(pCertContext);
|
|
}
|
|
|
|
DebugTrace("Leaving AddCert().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : GetCert
|
|
|
|
Synopsis : Get the cert from the specified CSP for the specified key type.
|
|
|
|
Parameter: - IN HCRYPTPROV hCryptProv
|
|
|
|
Crypto context returned by CryptAcquireContext().
|
|
|
|
- IN DWORD dwKeySpec
|
|
|
|
AT_KEYEXCHANGZE or AT_SIGNATURE.
|
|
|
|
- OUT LPBYTE * ppbEncodedCert
|
|
|
|
Ponter to pointer to encoded cert data. Upon success, the buffer
|
|
is automatically allocated and must be later freed by
|
|
CoTaskMemFree().
|
|
|
|
- OUT DWORD * pcbEncodedCert
|
|
|
|
Pointer to encoded cert data length. Upon success, receive the
|
|
length of the encoded cert data.
|
|
|
|
Remarks :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static HRESULT GetCert (IN HCRYPTPROV hCryptProv,
|
|
IN DWORD dwKeySpec,
|
|
OUT LPBYTE * ppbEncodedCert,
|
|
OUT DWORD * pcbEncodedCert)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HCRYPTKEY hCryptKey = NULL;
|
|
LPBYTE pbEncodedCert = NULL;
|
|
DWORD cbEncodedCert = 0;
|
|
|
|
DebugTrace("Entering GetCert().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(hCryptProv);
|
|
ATLASSERT(ppbEncodedCert);
|
|
ATLASSERT(pcbEncodedCert);
|
|
|
|
//
|
|
// Get key handle.
|
|
//
|
|
if (!::CryptGetUserKey(hCryptProv, dwKeySpec, &hCryptKey))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CryptGetUserKey() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Query certificate data length.
|
|
//
|
|
if (!::CryptGetKeyParam(hCryptKey,
|
|
KP_CERTIFICATE,
|
|
NULL, // NULL to query certificate data length
|
|
&cbEncodedCert,
|
|
0))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CryptGetKeyParam() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for certificate data.
|
|
//
|
|
if (!(pbEncodedCert = (LPBYTE) ::CoTaskMemAlloc(cbEncodedCert)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now read the certificate data.
|
|
//
|
|
if (!::CryptGetKeyParam(hCryptKey,
|
|
KP_CERTIFICATE,
|
|
pbEncodedCert,
|
|
&cbEncodedCert,
|
|
0))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CryptGetKeyParam() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Return encoded cert to caller.
|
|
//
|
|
*ppbEncodedCert = pbEncodedCert;
|
|
*pcbEncodedCert = cbEncodedCert;
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (hCryptKey)
|
|
{
|
|
::CryptDestroyKey(hCryptKey);
|
|
}
|
|
|
|
DebugTrace("Leaving GetCert().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pbEncodedCert)
|
|
{
|
|
::CoTaskMemFree((LPVOID) pbEncodedCert);
|
|
}
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : PropCert
|
|
|
|
Synopsis : Propagate the digital certificate associated with the specified
|
|
CSP and container name to the soecified store.
|
|
|
|
Parameter: - IN LPCSTR szCSPName
|
|
|
|
Pointer to Crypto Service Provider name string.
|
|
|
|
- IN LPCTSTR szContainerName
|
|
|
|
Pointer to key container name string.
|
|
|
|
- IN HCERTSTORE hCertStore
|
|
|
|
Handle of store to add the certificate to.
|
|
|
|
Remarks :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static HRESULT PropCert (IN LPCSTR szCSPName,
|
|
IN LPCSTR szContainerName,
|
|
IN HCERTSTORE hCertStore)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HCRYPTPROV hCryptProv = NULL;
|
|
DWORD rgdwKeys[] = {AT_KEYEXCHANGE, AT_SIGNATURE};
|
|
DWORD cbEncodedCert = 0;
|
|
LPBYTE pbEncodedCert = NULL;
|
|
DWORD i;
|
|
|
|
DebugTrace("Entering PropCert().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(szCSPName);
|
|
ATLASSERT(szContainerName);
|
|
ATLASSERT(hCertStore);
|
|
|
|
//
|
|
// Obtain the crypto context.
|
|
//
|
|
// CRYPT_SILENT forces the CSP to raise no UI. The fully qualified
|
|
// container name indicates which reader to connect to, so the
|
|
// user should not be prompted to insert or select a card.
|
|
//
|
|
if (!::CryptAcquireContextA(&hCryptProv,
|
|
szContainerName,
|
|
szCSPName,
|
|
PROV_RSA_FULL,
|
|
CRYPT_SILENT))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: CryptAcquireContextA() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// For each key pair found in the smart card, store the corresponding
|
|
// digital certificate to the specified store.
|
|
//
|
|
for (i = 0; i < ARRAYSIZE(rgdwKeys); i++)
|
|
{
|
|
//
|
|
// Get the certificate data.
|
|
//
|
|
if (FAILED(hr = ::GetCert(hCryptProv,
|
|
rgdwKeys[i],
|
|
&pbEncodedCert,
|
|
&cbEncodedCert)))
|
|
{
|
|
if (HRESULT_FROM_WIN32(NTE_NO_KEY) == hr)
|
|
{
|
|
//
|
|
// We are OK if there is no key of such type.
|
|
//
|
|
hr = S_OK;
|
|
continue;
|
|
}
|
|
|
|
DebugTrace("Error [%#x]: GetCert() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Add the certificate to the specified store.
|
|
//
|
|
if (FAILED(hr = ::AddCert(szCSPName,
|
|
szContainerName,
|
|
rgdwKeys[i],
|
|
pbEncodedCert,
|
|
cbEncodedCert,
|
|
hCertStore)))
|
|
{
|
|
DebugTrace("Error [%#x]: AddCert() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pbEncodedCert)
|
|
{
|
|
::CoTaskMemFree((LPVOID) pbEncodedCert), pbEncodedCert = NULL;
|
|
}
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (pbEncodedCert)
|
|
{
|
|
::CoTaskMemFree((LPVOID) pbEncodedCert);
|
|
}
|
|
|
|
if (hCryptProv)
|
|
{
|
|
::CryptReleaseContext(hCryptProv, 0);
|
|
}
|
|
|
|
DebugTrace("Leaving PropCert().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Exported functions.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : LoadFromSmartCard
|
|
|
|
Synopsis : Load all certificates from all smart card readers.
|
|
|
|
Parameter: HCERTSTORE hCertStore - Certificate store handle of store to
|
|
receive all the certificates.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT LoadFromSmartCard (HCERTSTORE hCertStore)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG lResult = 0;
|
|
DWORD dwNumReaders = 0;
|
|
DWORD dwAutoAllocate = SCARD_AUTOALLOCATE;
|
|
SCARDCONTEXT hContext = NULL;
|
|
LPSTR szReaderName = NULL;
|
|
LPSTR mszReaderNames = NULL;
|
|
LPSTR szCardName = NULL;
|
|
LPSTR szCSPName = NULL;
|
|
LPSTR szContainerName = NULL;
|
|
HMODULE hWinSCardDll = NULL;
|
|
LPSCARD_READERSTATE lpReaderStates = NULL;
|
|
|
|
DebugTrace("Entering LoadFromSmartCard().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(hCertStore);
|
|
|
|
//
|
|
// Load WinSCard.dll.
|
|
//
|
|
if (!(hWinSCardDll = ::LoadLibrary("WinSCard.dll")))
|
|
{
|
|
hr = CAPICOM_E_NOT_SUPPORTED;
|
|
|
|
DebugTrace("Error [%#x]: Smart Card Base Component (WinSCard.dll) not installed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Load all SCard APIs used.
|
|
//
|
|
if (!(pfnSCardEstablishContext = (PFNSCARDESTABLISHCONTEXT)
|
|
::GetProcAddress(hWinSCardDll, "SCardEstablishContext")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed for SCardEstablishContext.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!(pfnSCardListReadersA = (PFNSCARDLISTREADERSA)
|
|
::GetProcAddress(hWinSCardDll, "SCardListReadersA")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed for SCardListReadersA.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!(pfnSCardGetStatusChangeA = (PFNSCARDGETSTATUSCHANGEA)
|
|
::GetProcAddress(hWinSCardDll, "SCardGetStatusChangeA")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed for SCardStatusChangeA.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!(pfnSCardListCardsA = (PFNSCARDLISTCARDSA)
|
|
::GetProcAddress(hWinSCardDll, "SCardListCardsA")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed for SCardListCardsA.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!(pfnSCardGetCardTypeProviderNameA = (PFNSCARDGETCARDTYPEPROVIDERNAMEA)
|
|
::GetProcAddress(hWinSCardDll, "SCardGetCardTypeProviderNameA")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed for SCardGetCardTypeProviderNameA.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!(pfnSCardFreeMemory = (PFNSCARDFREEMEMORY)
|
|
::GetProcAddress(hWinSCardDll, "SCardFreeMemory")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed for SCardFreeMemory.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (!(pfnSCardReleaseContext = (PFNSCARDRELEASECONTEXT)
|
|
::GetProcAddress(hWinSCardDll, "SCardReleaseContext")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed for SCardReleaseContext.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Establish context with the resource manager.
|
|
//
|
|
if (SCARD_S_SUCCESS != (lResult = pfnSCardEstablishContext(SCARD_SCOPE_USER,
|
|
NULL,
|
|
NULL,
|
|
&hContext)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(lResult);
|
|
|
|
DebugTrace("Error [%#x]: SCardEstablishContext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get the list of all reader(s).
|
|
// Note: The buffer is automatically allocated and must be freed
|
|
// by SCardFreeMemory().
|
|
//
|
|
if (SCARD_S_SUCCESS != (lResult = pfnSCardListReadersA(hContext,
|
|
NULL,
|
|
(LPSTR) &mszReaderNames,
|
|
&dwAutoAllocate)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(lResult);
|
|
|
|
DebugTrace("Error [%#x]: SCardListReadersA() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Count number of readers.
|
|
//
|
|
for (dwNumReaders = 0, szReaderName = mszReaderNames; *szReaderName; dwNumReaders++)
|
|
{
|
|
szReaderName += ::strlen(szReaderName) + 1;
|
|
}
|
|
|
|
//
|
|
// Nothing to do if no reader.
|
|
//
|
|
if (0 < dwNumReaders)
|
|
{
|
|
DWORD i;
|
|
|
|
//
|
|
// Allocate memory for SCARD_READERSTATE array.
|
|
//
|
|
if (!(lpReaderStates = (LPSCARD_READERSTATE)
|
|
::CoTaskMemAlloc(dwNumReaders * sizeof(SCARD_READERSTATE))))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Prepare state array.
|
|
//
|
|
::ZeroMemory((LPVOID) lpReaderStates, dwNumReaders * sizeof(SCARD_READERSTATE));
|
|
|
|
for (i = 0, szReaderName = mszReaderNames; i < dwNumReaders; i++)
|
|
{
|
|
lpReaderStates[i].szReader = (LPCSTR) szReaderName;
|
|
lpReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
|
|
|
|
szReaderName += ::strlen(szReaderName) + 1;
|
|
}
|
|
|
|
//
|
|
// Initialize card status.
|
|
//
|
|
if (SCARD_S_SUCCESS != (lResult = pfnSCardGetStatusChangeA(hContext,
|
|
INFINITE,
|
|
lpReaderStates,
|
|
dwNumReaders)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(lResult);
|
|
|
|
DebugTrace("Error [%#x]: SCardGetStatusChangeA() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// For each card found, find the proper CSP and propagate the
|
|
// certificate(s) to the specified store.
|
|
//
|
|
for (i = 0; i < dwNumReaders; i++)
|
|
{
|
|
//
|
|
// Card in this reader?
|
|
//
|
|
if (!(lpReaderStates[i].dwEventState & SCARD_STATE_PRESENT))
|
|
{
|
|
//
|
|
// No card in this reader.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Get card name.
|
|
//
|
|
dwAutoAllocate = SCARD_AUTOALLOCATE;
|
|
if (SCARD_S_SUCCESS != (lResult = pfnSCardListCardsA(hContext,
|
|
lpReaderStates[i].rgbAtr,
|
|
NULL,
|
|
0,
|
|
(LPSTR) &szCardName,
|
|
&dwAutoAllocate)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(lResult);
|
|
|
|
DebugTrace("Error [%#x]: SCardListCardsA() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get card's CSP name.
|
|
//
|
|
dwAutoAllocate = SCARD_AUTOALLOCATE;
|
|
if (SCARD_S_SUCCESS != (lResult = pfnSCardGetCardTypeProviderNameA(hContext,
|
|
szCardName,
|
|
SCARD_PROVIDER_CSP,
|
|
(LPSTR) &szCSPName,
|
|
&dwAutoAllocate)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(lResult);
|
|
|
|
DebugTrace("Error [%#x]: SCardGetCardTypeProviderNameA() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Prepare fully qualified container name.
|
|
//
|
|
if (!(szContainerName = (LPSTR) ::CoTaskMemAlloc(sizeof("\\\\.\\") + 1 +
|
|
::strlen(lpReaderStates[i].szReader))))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
wsprintfA(szContainerName, "\\\\.\\%s\\", lpReaderStates[i].szReader);
|
|
|
|
//
|
|
// Propagate the cert.
|
|
//
|
|
if (FAILED(hr = ::PropCert(szCSPName, szContainerName, hCertStore)))
|
|
{
|
|
DebugTrace("Error [%#x]: PropCert() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (szContainerName)
|
|
{
|
|
::CoTaskMemFree((LPVOID) szContainerName), szContainerName = NULL;
|
|
}
|
|
if (szCSPName)
|
|
{
|
|
pfnSCardFreeMemory(hContext, (LPVOID) szCSPName), szCSPName = NULL;
|
|
}
|
|
if (szCardName)
|
|
{
|
|
pfnSCardFreeMemory(hContext, (LPVOID) szCardName), szCardName = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (szContainerName)
|
|
{
|
|
::CoTaskMemFree((LPVOID) szContainerName);
|
|
}
|
|
if (szCSPName)
|
|
{
|
|
pfnSCardFreeMemory(hContext, (LPVOID) szCSPName);
|
|
}
|
|
if (szCardName)
|
|
{
|
|
pfnSCardFreeMemory(hContext, (LPVOID) szCardName);
|
|
}
|
|
if (lpReaderStates)
|
|
{
|
|
::CoTaskMemFree((LPVOID) lpReaderStates);
|
|
}
|
|
if (mszReaderNames)
|
|
{
|
|
pfnSCardFreeMemory(hContext, (LPVOID) mszReaderNames);
|
|
}
|
|
if (hContext)
|
|
{
|
|
pfnSCardReleaseContext(hContext);
|
|
}
|
|
if (hWinSCardDll)
|
|
{
|
|
::FreeLibrary(hWinSCardDll);
|
|
}
|
|
|
|
DebugTrace("Leaving LoadFromSmartCard().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|