#include #include #include #include #include #include "basecsp.h" #include "cardmod.h" #include #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; }