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.
561 lines
13 KiB
561 lines
13 KiB
#include <windows.h>
|
|
#include <wincrypt.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "basecsp.h"
|
|
#include "cardmod.h"
|
|
#include <dsysdbg.h>
|
|
|
|
#define wszTEST_CARD L"Wfsc Demo 3\0"
|
|
#define cMAX_READERS 20
|
|
|
|
//
|
|
// Need to define the dsys debug symbols since we're linking directly to the
|
|
// card interface lib which requires them.
|
|
//
|
|
DEFINE_DEBUG2(Basecsp)
|
|
|
|
//
|
|
// Functions defined in the card interface lib that we call.
|
|
//
|
|
extern DWORD InitializeCardState(PCARD_STATE);
|
|
extern void DeleteCardState(PCARD_STATE);
|
|
|
|
//
|
|
// Wrapper for making test calls.
|
|
//
|
|
#define TEST_CASE(X) { if (ERROR_SUCCESS != (dwSts = X)) { printf("%s", #X); goto Ret; } }
|
|
|
|
//
|
|
// Function: CspAllocH
|
|
//
|
|
LPVOID WINAPI CspAllocH(
|
|
IN SIZE_T cBytes)
|
|
{
|
|
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cBytes);
|
|
}
|
|
|
|
//
|
|
// Function: CspFreeH
|
|
//
|
|
void WINAPI CspFreeH(
|
|
IN LPVOID pMem)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, pMem);
|
|
}
|
|
|
|
//
|
|
// Function: CspReAllocH
|
|
//
|
|
LPVOID WINAPI CspReAllocH(
|
|
IN LPVOID pMem,
|
|
IN SIZE_T cBytes)
|
|
{
|
|
return HeapReAlloc(
|
|
GetProcessHeap(), HEAP_ZERO_MEMORY, pMem, cBytes);
|
|
}
|
|
|
|
//
|
|
// Critical Section Management
|
|
//
|
|
|
|
//
|
|
// Function: CspInitializeCriticalSection
|
|
//
|
|
DWORD CspInitializeCriticalSection(
|
|
IN CRITICAL_SECTION *pcs)
|
|
{
|
|
__try {
|
|
InitializeCriticalSection(pcs);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Function: CspEnterCriticalSection
|
|
//
|
|
DWORD CspEnterCriticalSection(
|
|
IN CRITICAL_SECTION *pcs)
|
|
{
|
|
__try {
|
|
EnterCriticalSection(pcs);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Function: CspLeaveCriticalSection
|
|
//
|
|
void CspLeaveCriticalSection(
|
|
IN CRITICAL_SECTION *pcs)
|
|
{
|
|
LeaveCriticalSection(pcs);
|
|
}
|
|
|
|
//
|
|
// Function: CspDeleteCriticalSection
|
|
//
|
|
void CspDeleteCriticalSection(
|
|
IN CRITICAL_SECTION *pcs)
|
|
{
|
|
DeleteCriticalSection(pcs);
|
|
}
|
|
|
|
int _cdecl main(int argc, char * argv[])
|
|
{
|
|
CARD_STATE CardState;
|
|
PCARD_DATA pCardData;
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PFN_CARD_ACQUIRE_CONTEXT pfnCardAcquireContext = NULL;
|
|
CARD_FREE_SPACE_INFO CardFreeSpaceInfo;
|
|
CARD_CAPABILITIES CardCapabilities;
|
|
CARD_KEY_SIZES CardKeySizes;
|
|
CONTAINER_INFO ContainerInfo;
|
|
LPWSTR pwsz = NULL;
|
|
DATA_BLOB dbOut;
|
|
BYTE rgb [] = { 0x3, 0x2, 0x1, 0x0 };
|
|
DATA_BLOB dbIn;
|
|
SCARDCONTEXT hContext = 0;
|
|
LPWSTR mszReaders = NULL;
|
|
DWORD cchReaders = SCARD_AUTOALLOCATE;
|
|
LPWSTR mszCards = NULL;
|
|
DWORD cchCards = SCARD_AUTOALLOCATE;
|
|
SCARD_READERSTATE rgReaderState [cMAX_READERS];
|
|
DWORD iReader = 0;
|
|
DWORD cchCurrent = 0;
|
|
DWORD dwProtocol = 0;
|
|
SCARDHANDLE hCard = 0;
|
|
BOOL fConnected = FALSE;
|
|
CARD_FILE_ACCESS_CONDITION Acl = EveryoneReadUserWriteAc;
|
|
BYTE rgbPin [] = { 0x00, 0x00, 0x00, 0x00 };
|
|
DATA_BLOB dbPin;
|
|
PBYTE pbKey = NULL;
|
|
DWORD cbKey = 0;
|
|
HCRYPTKEY hKey = 0;
|
|
HCRYPTPROV hProv = 0;
|
|
WCHAR rgwsz [MAX_PATH];
|
|
BYTE bContainerIndex = 0;
|
|
|
|
memset(&CardState, 0, sizeof(CardState));
|
|
memset(&CardFreeSpaceInfo, 0, sizeof(CardFreeSpaceInfo));
|
|
memset(&CardCapabilities, 0, sizeof(CardCapabilities));
|
|
memset(&ContainerInfo, 0, sizeof(ContainerInfo));
|
|
memset(&CardKeySizes, 0, sizeof(CardKeySizes));
|
|
memset(&dbOut, 0, sizeof(dbOut));
|
|
memset(rgReaderState, 0, sizeof(rgReaderState));
|
|
memset(&dbPin, 0, sizeof(dbPin));
|
|
|
|
dbPin.cbData = sizeof(rgbPin);
|
|
dbPin.pbData = rgbPin;
|
|
|
|
dbIn.cbData = sizeof(rgb);
|
|
dbIn.pbData = rgb;
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
//
|
|
// Get a list of readers
|
|
//
|
|
|
|
dwSts = SCardEstablishContext(
|
|
SCARD_SCOPE_USER, NULL, NULL, &hContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = SCardListReaders(
|
|
hContext,
|
|
NULL,
|
|
(LPWSTR) &mszReaders,
|
|
&cchReaders);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Get a list of cards
|
|
//
|
|
|
|
/*
|
|
dwSts = SCardListCards(
|
|
hContext, NULL, NULL, 0, (LPWSTR) &mszCards, &cchCards);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
*/
|
|
|
|
//
|
|
// Build the reader state array
|
|
//
|
|
|
|
for ( iReader = 0, cchReaders = 0;
|
|
iReader < (sizeof(rgReaderState) / sizeof(rgReaderState[0]))
|
|
&&
|
|
L'\0' != mszReaders[cchReaders];
|
|
iReader++)
|
|
{
|
|
rgReaderState[iReader].dwCurrentState = SCARD_STATE_UNAWARE;
|
|
rgReaderState[iReader].szReader = mszReaders + cchReaders;
|
|
|
|
cchReaders += 1 + wcslen(mszReaders);
|
|
}
|
|
|
|
//
|
|
// Find a card we can talk to
|
|
//
|
|
|
|
dwSts = SCardLocateCards(
|
|
hContext,
|
|
wszTEST_CARD,
|
|
rgReaderState,
|
|
iReader);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
while (0 != iReader && FALSE == fConnected)
|
|
{
|
|
iReader--;
|
|
|
|
if (SCARD_STATE_ATRMATCH & rgReaderState[iReader].dwEventState)
|
|
{
|
|
dwSts = SCardConnect(
|
|
hContext,
|
|
rgReaderState[iReader].szReader,
|
|
SCARD_SHARE_SHARED,
|
|
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
|
|
&hCard,
|
|
&dwProtocol);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
else
|
|
fConnected = TRUE;
|
|
}
|
|
}
|
|
|
|
if (FALSE == fConnected)
|
|
goto Ret;
|
|
|
|
//
|
|
// Initialize the card data structures
|
|
//
|
|
|
|
TEST_CASE(InitializeCardState(&CardState));
|
|
|
|
CardState.hCardModule = LoadLibrary(L"cardmod.dll");
|
|
|
|
if (INVALID_HANDLE_VALUE == CardState.hCardModule)
|
|
{
|
|
printf("LoadLibrary cardmod.dll");
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
pfnCardAcquireContext =
|
|
(PFN_CARD_ACQUIRE_CONTEXT) GetProcAddress(
|
|
CardState.hCardModule,
|
|
"CardAcquireContext");
|
|
|
|
if (NULL == pfnCardAcquireContext)
|
|
{
|
|
printf("GetProcAddress");
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
pCardData = (PCARD_DATA) CspAllocH(sizeof(CARD_DATA));
|
|
|
|
if (NULL == pCardData)
|
|
{
|
|
dwSts = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Ret;
|
|
}
|
|
|
|
pCardData->pwszCardName = wszTEST_CARD;
|
|
pCardData->hScard = hCard;
|
|
pCardData->hSCardCtx = hContext;
|
|
pCardData->dwVersion = CARD_DATA_CURRENT_VERSION;
|
|
pCardData->pfnCspAlloc = CspAllocH;
|
|
pCardData->pfnCspReAlloc = CspReAllocH;
|
|
pCardData->pfnCspFree = CspFreeH;
|
|
pCardData->pbAtr = rgReaderState[iReader].rgbAtr;
|
|
pCardData->cbAtr = rgReaderState[iReader].cbAtr;
|
|
|
|
TEST_CASE(pfnCardAcquireContext(pCardData, 0));
|
|
|
|
CardState.pCardData = pCardData;
|
|
|
|
TEST_CASE(InitializeCspCaching(&CardState));
|
|
|
|
//
|
|
// Now start tests
|
|
//
|
|
|
|
//
|
|
// Test 1: Container data caching
|
|
//
|
|
|
|
/*
|
|
TEST_CASE(CspEnumContainers(&CardState, 0, &pwsz));
|
|
|
|
CspFreeH(pwsz);
|
|
pwsz = NULL;
|
|
|
|
// Check cached call
|
|
TEST_CASE(CspEnumContainers(&CardState, 0, &pwsz));
|
|
|
|
CspFreeH(pwsz);
|
|
pwsz = NULL;
|
|
*/
|
|
|
|
//
|
|
// Create a private key blob to import to the card
|
|
//
|
|
|
|
if (! CryptAcquireContext(
|
|
&hProv, NULL, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
//
|
|
// For now, make this key really small so we're sure to not run out of
|
|
// space on wimpy test cards.
|
|
//
|
|
if (! CryptGenKey(
|
|
hProv, AT_KEYEXCHANGE, (384 << 16) | CRYPT_EXPORTABLE, &hKey))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
if (! CryptExportKey(
|
|
hKey, 0, PRIVATEKEYBLOB, 0, NULL, &cbKey))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
pbKey = (PBYTE) CspAllocH(cbKey);
|
|
|
|
if (NULL == pbKey)
|
|
{
|
|
dwSts = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Ret;
|
|
}
|
|
|
|
if (! CryptExportKey(
|
|
hKey, 0, PRIVATEKEYBLOB, 0, pbKey, &cbKey))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
//
|
|
// Now we'll be modifying card data, so we need to authenticate.
|
|
//
|
|
|
|
TEST_CASE(CspSubmitPin(
|
|
&CardState,
|
|
wszCARD_USER_USER,
|
|
dbPin.pbData,
|
|
dbPin.cbData,
|
|
NULL));
|
|
|
|
// CreateContainer call will invalidate current container-space cache items
|
|
TEST_CASE(CspCreateContainer(
|
|
&CardState,
|
|
bContainerIndex,
|
|
CARD_CREATE_CONTAINER_KEY_IMPORT,
|
|
AT_KEYEXCHANGE,
|
|
cbKey,
|
|
pbKey));
|
|
|
|
// Cached container enum should now be invalid
|
|
/*
|
|
TEST_CASE(CspEnumContainers(&CardState, 0, &pwsz));
|
|
|
|
CspFreeH(pwsz);
|
|
pwsz = NULL;
|
|
*/
|
|
|
|
//
|
|
// Test 2: File data caching
|
|
//
|
|
|
|
/*
|
|
TODO - re-enabled the EnumFiles tests once CardEnumFiles is correctly
|
|
implemented
|
|
|
|
pwsz = wszCSP_DATA_DIR_FULL_PATH;
|
|
TEST_CASE(CspEnumFiles(&CardState, 0, &pwsz));
|
|
|
|
CspFreeH(pwsz);
|
|
pwsz = NULL;
|
|
|
|
// Use cached data
|
|
pwsz = wszCSP_DATA_DIR_FULL_PATH;
|
|
TEST_CASE(CspEnumFiles(&CardState, 0, &pwsz));
|
|
|
|
CspFreeH(pwsz);
|
|
pwsz = NULL;
|
|
*/
|
|
|
|
// Create some test files just in case they don't already exist on
|
|
// this card.
|
|
wsprintf(
|
|
rgwsz, L"%s/File2", wszCSP_DATA_DIR_FULL_PATH);
|
|
|
|
dwSts = CspCreateFile(&CardState, rgwsz, Acl);
|
|
|
|
wsprintf(
|
|
rgwsz, L"%s/File1", wszCSP_DATA_DIR_FULL_PATH);
|
|
|
|
dwSts = CspCreateFile(&CardState, rgwsz, Acl);
|
|
|
|
// Write file should invalidate all cached file data
|
|
TEST_CASE(CspWriteFile(&CardState, rgwsz, 0, dbIn.pbData, dbIn.cbData));
|
|
|
|
// Invalidate cached file we just created
|
|
TEST_CASE(CspWriteFile(&CardState, rgwsz, 0, dbIn.pbData, dbIn.cbData));
|
|
|
|
// Cached file enum should now be invalid
|
|
/*
|
|
pwsz = wszCSP_DATA_DIR_FULL_PATH;
|
|
TEST_CASE(CspEnumFiles(&CardState, 0, &pwsz));
|
|
|
|
CspFreeH(pwsz);
|
|
pwsz = NULL;
|
|
*/
|
|
|
|
//
|
|
// Test 3: Get container info
|
|
//
|
|
|
|
ContainerInfo.dwVersion = CONTAINER_INFO_CURRENT_VERSION;
|
|
|
|
TEST_CASE(CspGetContainerInfo(&CardState, bContainerIndex, 0, &ContainerInfo));
|
|
|
|
// Caller won't free the key data buffers. Leave them for final cleanup.
|
|
if (ContainerInfo.pbKeyExPublicKey)
|
|
CspFreeH(ContainerInfo.pbKeyExPublicKey);
|
|
ContainerInfo.pbKeyExPublicKey = NULL;
|
|
|
|
if (ContainerInfo.pbSigPublicKey)
|
|
CspFreeH(ContainerInfo.pbSigPublicKey);
|
|
ContainerInfo.pbSigPublicKey = NULL;
|
|
|
|
// Use cached data
|
|
TEST_CASE(CspGetContainerInfo(&CardState, bContainerIndex, 0, &ContainerInfo));
|
|
|
|
if (ContainerInfo.pbKeyExPublicKey)
|
|
CspFreeH(ContainerInfo.pbKeyExPublicKey);
|
|
ContainerInfo.pbKeyExPublicKey = NULL;
|
|
|
|
if (ContainerInfo.pbSigPublicKey)
|
|
CspFreeH(ContainerInfo.pbSigPublicKey);
|
|
ContainerInfo.pbSigPublicKey = NULL;
|
|
|
|
//
|
|
// Test 4: Get Card Capabilities
|
|
//
|
|
|
|
CardCapabilities.dwVersion = CARD_CAPABILITIES_CURRENT_VERSION;
|
|
|
|
TEST_CASE(CspQueryCapabilities(&CardState, &CardCapabilities));
|
|
|
|
// Read cached
|
|
TEST_CASE(CspQueryCapabilities(&CardState, &CardCapabilities));
|
|
|
|
//
|
|
// Test 5: Read file
|
|
//
|
|
|
|
wsprintf(
|
|
rgwsz, L"%s/File1", wszCSP_DATA_DIR_FULL_PATH);
|
|
|
|
TEST_CASE(CspReadFile(&CardState, rgwsz, 0, &dbOut.pbData, &dbOut.cbData));
|
|
|
|
CspFreeH(dbOut.pbData);
|
|
memset(&dbOut, 0, sizeof(dbOut));
|
|
|
|
// Use cached data
|
|
TEST_CASE(CspReadFile(&CardState, rgwsz, 0, &dbOut.pbData, &dbOut.cbData));
|
|
|
|
CspFreeH(dbOut.pbData);
|
|
memset(&dbOut, 0, sizeof(dbOut));
|
|
|
|
wsprintf(
|
|
rgwsz, L"%s/File2", wszCSP_DATA_DIR_FULL_PATH);
|
|
|
|
// Invalidate all file-related cached data
|
|
TEST_CASE(CspDeleteFile(&CardState, 0, rgwsz));
|
|
|
|
wsprintf(
|
|
rgwsz, L"%s/File1", wszCSP_DATA_DIR_FULL_PATH);
|
|
|
|
// Re-read file from card
|
|
TEST_CASE(CspReadFile(&CardState, rgwsz, 0, &dbOut.pbData, &dbOut.cbData));
|
|
|
|
CspFreeH(dbOut.pbData);
|
|
memset(&dbOut, 0, sizeof(dbOut));
|
|
|
|
//
|
|
// Test 6: Query Key Sizes
|
|
//
|
|
|
|
CardKeySizes.dwVersion = CARD_KEY_SIZES_CURRENT_VERSION;
|
|
|
|
// Signature Keys
|
|
TEST_CASE(CspQueryKeySizes(&CardState, AT_SIGNATURE, 0, &CardKeySizes));
|
|
|
|
// Query cached
|
|
TEST_CASE(CspQueryKeySizes(&CardState, AT_SIGNATURE, 0, &CardKeySizes));
|
|
|
|
// Key Exchange Keys
|
|
TEST_CASE(CspQueryKeySizes(&CardState, AT_KEYEXCHANGE, 0, &CardKeySizes));
|
|
|
|
// Query cached
|
|
TEST_CASE(CspQueryKeySizes(&CardState, AT_KEYEXCHANGE, 0, &CardKeySizes));
|
|
|
|
Ret:
|
|
|
|
if (pbKey)
|
|
CspFreeH(pbKey);
|
|
if (hKey)
|
|
CryptDestroyKey(hKey);
|
|
if (hProv)
|
|
CryptReleaseContext(hProv, 0);
|
|
if (mszCards)
|
|
SCardFreeMemory(hContext, mszCards);
|
|
if (mszReaders)
|
|
SCardFreeMemory(hContext, mszReaders);
|
|
if (dbOut.pbData)
|
|
CspFreeH(dbOut.pbData);
|
|
if (pwsz)
|
|
CspFreeH(pwsz);
|
|
if (ERROR_SUCCESS != dwSts)
|
|
printf(" failed, 0x%x\n", dwSts);
|
|
|
|
// Static buffers were used, don't let them be freed
|
|
pCardData->pwszCardName = NULL;
|
|
pCardData->pbAtr = NULL;
|
|
|
|
DeleteCardState(&CardState);
|
|
|
|
return 0;
|
|
}
|
|
|