|
|
/*++
Copyright (C) Microsoft Corporation, 1996 - 1999
Module Name:
scdrvtst
Abstract:
IOCTL test program for smart card driver.
Author:
Klaus Schutz (kschutz) Dec-1996
Revision History:
--*/
#include <afx.h>
#include <afxtempl.h>
#include <winioctl.h>
#include <conio.h>
#include <winsmcrd.h>
#include "ifdtest.h"
class CCardList;
// This represents a single function of a card
class CCardFunction { CString m_CName; CHAR m_chShortCut; CByteArray m_CData; CCardFunction *m_pCNextFunction;
public: CCardFunction( CString &in_CName, CHAR in_chShortCut, CByteArray &in_CData ); friend CCardList; };
// This is a single card
class CCard { CString m_CName; CHAR m_chShortCut; CCardFunction *m_pCFirstFunction; CCard *m_pCNextCard;
public: CCard( CString & in_CCardName, CHAR in_chShortCut );
friend CCardList; };
// This implements a list of cards
class CCardList {
CString m_CScriptFileName; CCard *m_pCFirstCard; CCard *m_pCCurrentCard; ULONG m_uNumCards;
public: CCardList(CString &in_CScriptFileName);
void AddCard( CString &in_CardName, CHAR in_chShortCut );
void AddCardFunction( CString &in_CFunctionName, CHAR in_chShortCut, CByteArray &l_pCData );
void ShowCards( void (__cdecl *in_pCallBack)(void *in_pContext, PCHAR in_pchCardName), void *in_pContext );
BOOL SelectCard(CHAR in_chShortCut); void ReleaseCard(void); CString GetCardName(void); ULONG GetNumCards(void) { return m_uNumCards; } BOOL IsCardSelected(void); BOOL ListFunctions(void); CByteArray *GetApdu(CHAR in_chShortCut); };
CCardFunction::CCardFunction( CString &in_CName, CHAR in_chShortCut, CByteArray &in_CData ) /*++
Adds a function to the current card --*/ { m_CName = in_CName; m_chShortCut = in_chShortCut; m_CData.Copy(in_CData); m_pCNextFunction = NULL; }
CCard::CCard( CString &in_CCardName, CHAR in_chShortCut ) /*++
Routine Description:
Constructor for a new card
Arguments:
CardName - Reference to card to add in_uPos - index of shortcut key
Return Value:
--*/ { m_CName = in_CCardName; m_chShortCut = in_chShortCut; m_pCNextCard = NULL; m_pCFirstFunction = NULL; } void CCardList::AddCard( CString &in_CCardName, CHAR in_chShortCut ) /*++
Routine Description: Adds a new card to CardList
Arguments: in_CCardName - Reference to card to add
--*/ { CCard *l_pCNewCard = new CCard(in_CCardName, in_chShortCut);
if (m_pCFirstCard == NULL) {
m_pCFirstCard = l_pCNewCard;
} else {
CCard *l_pCCurrent = m_pCFirstCard; while (l_pCCurrent->m_pCNextCard) {
l_pCCurrent = l_pCCurrent->m_pCNextCard; }
l_pCCurrent->m_pCNextCard = l_pCNewCard; }
m_pCCurrentCard = l_pCNewCard; m_uNumCards += 1; }
void CCardList::AddCardFunction( CString &in_CFunctionName, CHAR in_chShortCut, CByteArray &in_pCData ) /*++
Routine Description: Adds a new function to the current card
Arguments: in_CCardName - Reference to card to add in_chShortCut - Shortcut key
Return Value:
--*/ { CCardFunction *l_pCNewFunction = new CCardFunction( in_CFunctionName, in_chShortCut, in_pCData );
if (m_pCCurrentCard->m_pCFirstFunction == NULL) {
m_pCCurrentCard->m_pCFirstFunction = l_pCNewFunction;
} else {
CCardFunction *l_pCCurrent = m_pCCurrentCard->m_pCFirstFunction; while (l_pCCurrent->m_pCNextFunction) {
l_pCCurrent = l_pCCurrent->m_pCNextFunction; }
l_pCCurrent->m_pCNextFunction = l_pCNewFunction; } }
CCardList::CCardList( CString &in_CScriptFileName ) /*++
Routine Description:
Adds a new function to the current card
Arguments:
CardName - Reference to card to add in_uPos - index of shortcut key
Return Value:
--*/ { CStdioFile l_CScriptFile; CHAR l_rgchBuffer[255], l_chKey; ULONG l_uLineNumber = 0; BOOL l_bContinue = FALSE; CByteArray l_Data; CString l_CCommand; m_pCFirstCard = NULL; m_pCCurrentCard = NULL; if (l_CScriptFile.Open(in_CScriptFileName, CFile::modeRead) == NULL) {
printf("Script file cannot be opened: %s\n", in_CScriptFileName); return; }
m_CScriptFileName = in_CScriptFileName; while (l_CScriptFile.ReadString(l_rgchBuffer, sizeof(l_rgchBuffer) - 1)) {
try {
CString l_CLine(l_rgchBuffer); CString l_CCommandApdu;
l_uLineNumber += 1;
if (l_CLine.GetLength() != 0 && l_CLine[0] == '#') { // comment line found, skip this line
continue; }
// Get rid of leading and trailing spaces
l_CLine.TrimLeft(); l_CLine.TrimRight();
int l_ichStart = l_CLine.Find('['); int l_ichKey = l_CLine.Find('&'); int l_ichEnd = l_CLine.Find(']');
if(l_ichStart == 0 && l_ichKey > 0 && l_ichEnd > l_ichKey + 1) {
//
// Add new card to list
//
CString l_CardName;
// Change card name from [&Card] to [C]ard
l_CardName = l_CLine.Mid(l_ichStart + 1, l_ichKey - l_ichStart - 1) + '[' + l_CLine[l_ichKey + 1] + ']' + l_CLine.Mid(l_ichKey + 2, l_ichEnd - l_ichKey - 2); AddCard( l_CardName, l_CardName[l_ichKey] );
} else if (l_ichStart == -1 && l_ichKey >= 0 && l_ichEnd == -1) {
//
// Add new function to current card
//
// Get function name
CString l_CToken = l_CLine.SpanExcluding(",");
// Search for shurtcut key
l_ichKey = l_CToken.Find('&');
if (l_ichKey == -1) {
throw "Missing '&' in function name"; }
l_chKey = l_CToken[l_ichKey + 1];
// Change card function from &Function to [F]unction
l_CCommand = l_CToken.Mid(l_ichStart + 1, l_ichKey - l_ichStart - 1) + '[' + l_CToken[l_ichKey + 1] + ']' + l_CToken.Right(l_CToken.GetLength() - l_ichKey - 2); LONG l_lComma = l_CLine.Find(','); if (l_lComma == -1) {
throw "Missing command APDU";
} else { l_CCommandApdu = l_CLine.Right(l_CLine.GetLength() - l_lComma - 1); }
} else if (l_bContinue) {
l_CCommandApdu = l_CLine;
} else if (l_CLine.GetLength() != 0 && l_CLine[0] != '#') {
throw "Line invalid"; } if (l_CCommandApdu != "") { do {
CHAR l_chData; l_CCommandApdu.TrimLeft();
ULONG l_uLength = l_CCommandApdu.GetLength();
if (l_uLength >= 3 && l_CCommandApdu[0] == '\'' && l_CCommandApdu[2] == '\'') {
// add ascsii character like 'c'
l_chData = l_CCommandApdu[1]; l_Data.Add(l_chData); } else if(l_uLength >= 3 && l_CCommandApdu[0] == '\"' && l_CCommandApdu.Right(l_uLength - 2).Find('\"') != -1) {
// add string like "string"
for (INT l_iIndex = 1; l_CCommandApdu[l_iIndex] != '\"'; l_iIndex++) {
l_Data.Add(l_CCommandApdu[l_iIndex]); }
} else if (l_CCommandApdu.SpanIncluding("0123456789abcdefABCDEF").GetLength() == 2) {
sscanf(l_CCommandApdu, "%2x", &l_chData); l_Data.Add(l_chData);
} else { l_CCommandApdu = l_CCommandApdu.SpanExcluding(","); static CString l_CError; l_CError = "Illegal value found: " + l_CCommandApdu; throw (PCHAR) (LPCSTR) l_CError; } l_ichStart = l_CCommandApdu.Find(','); if (l_ichStart != -1) { l_CCommandApdu = l_CLine.Right(l_CCommandApdu.GetLength() - l_ichStart - 1); }
} while (l_ichStart != -1);
if (l_CLine.Find('\\') != -1) { // we have to read more data from the file
l_bContinue = TRUE;
} else {
if (m_pCCurrentCard == NULL) {
throw "Card command found, but no card defined"; } AddCardFunction( l_CCommand, l_chKey, l_Data );
l_CCommand = ""; l_Data.RemoveAll(); l_bContinue = FALSE; } } } catch (PCHAR in_pchError){ printf( "%s (%d): %s\n", in_CScriptFileName, l_uLineNumber, in_pchError );
l_CCommand = ""; l_Data.RemoveAll(); l_bContinue = FALSE; } }
m_pCCurrentCard = NULL; }
void CCardList::ShowCards( void (__cdecl *in_pCallBack)(void *in_pContext, PCHAR in_pchCardName), void *in_pContext ) { CCard *l_pCCurrentCard = m_pCFirstCard;
if (l_pCCurrentCard == NULL) {
return; }
while(l_pCCurrentCard) {
(*in_pCallBack) (in_pContext, (PCHAR) (LPCSTR) l_pCCurrentCard->m_CName);
l_pCCurrentCard = l_pCCurrentCard->m_pCNextCard; } }
BOOL CCardList::ListFunctions( void ) /*++
List all card functions --*/ { if (m_pCCurrentCard == NULL) return FALSE;
CCardFunction *l_pCCurrentFunction = m_pCCurrentCard->m_pCFirstFunction;
while(l_pCCurrentFunction) {
printf(" %s\n", (LPCSTR) l_pCCurrentFunction->m_CName); l_pCCurrentFunction = l_pCCurrentFunction->m_pCNextFunction; }
return TRUE; }
BOOL CCardList::SelectCard( CHAR in_chShortCut ) /*++
Routine Description: Selectd a card by shorcut
Arguments: chShortCut - Shortcut key Return Value: TRUE - card found and selected FALSE - no card with that shortcut found
--*/ { m_pCCurrentCard = m_pCFirstCard;
while(m_pCCurrentCard) {
if (m_pCCurrentCard->m_chShortCut == in_chShortCut) {
return TRUE; }
m_pCCurrentCard = m_pCCurrentCard->m_pCNextCard; }
m_pCCurrentCard = NULL;
return FALSE; }
void CCardList::ReleaseCard( void ) { m_pCCurrentCard = NULL; }
BOOL CCardList::IsCardSelected( void ) { return (m_pCCurrentCard != NULL); }
CString CCardList::GetCardName( void ) { CString l_CCardName; INT l_iLeft = m_pCCurrentCard->m_CName.Find('['); INT l_iLength = m_pCCurrentCard->m_CName.GetLength();
l_CCardName = m_pCCurrentCard->m_CName.Left(l_iLeft) + m_pCCurrentCard->m_CName[l_iLeft + 1] + m_pCCurrentCard->m_CName.Right(l_iLength - l_iLeft - 3);
return l_CCardName; }
CByteArray * CCardList::GetApdu( CHAR in_chShortCut ) { CCardFunction *l_pCCurrentFunction = m_pCCurrentCard->m_pCFirstFunction;
while(l_pCCurrentFunction) {
if (l_pCCurrentFunction->m_chShortCut == in_chShortCut) {
return &l_pCCurrentFunction->m_CData; }
l_pCCurrentFunction = l_pCCurrentFunction->m_pCNextFunction; }
return NULL; }
void ManualTest( CReader &in_CReader ) { CCardList l_CCardList(CString("ifdtest.dat")); ULONG l_uRepeat = 0; LONG l_lResult; CHAR l_chSelection; PUCHAR l_pbResult; ULONG l_uState, l_uPrevState; CString l_CAnswer; CString l_CCardStates[] = { "Unknown", "Absent", "Present" , "Swallowed", "Powered", "Negotiable", "Specific" }; BOOL l_bWaitForInsertion, l_bWaitForRemoval;
while (TRUE) {
ULONG l_uResultLength = 0;
printf("Manual reader test\n"); printf("------------------\n");
if (l_CCardList.IsCardSelected()) {
printf("%s Commands:\n", l_CCardList.GetCardName()); l_CCardList.ListFunctions(); printf("Other Commands:\n"); printf(" [r]epeat command\n"); printf(" E[x]it\n");
} else { printf("Reader Commands:\n"); printf(" Protocol: T=[0], T=[1]\n"); printf(" Power : [c]oldReset, Power[d]own, Warm[r]eset\n"); printf(" Card : [p]resent, [a]bsent, [s]tatus\n"); printf(" PwrMngnt: [h]ibernation\n"); printf(" Test : [v]endor IOCTL\n"); if (l_CCardList.GetNumCards() != 0) { printf("Card Commands:\n"); l_CCardList.ShowCards((void (__cdecl *)(void *,char *)) printf, " %s\n"); } printf("Other Commands:\n"); printf(" E[x]it\n"); }
printf( "\n[%s|%s|%ld] - Command: ", in_CReader.GetVendorName(), in_CReader.GetIfdType(), in_CReader.GetDeviceUnit() );
l_chSelection = (CHAR) _getche(); putchar('\n');
if (l_CCardList.IsCardSelected()) {
switch (l_chSelection) {
case 'x': l_CCardList.ReleaseCard(); continue;
case 'r': printf("Enter repeat count: "); scanf("%2d", &l_uRepeat);
if (l_uRepeat > 99) {
l_uRepeat = 0; } printf("Enter command: "); l_chSelection = (CHAR) _getche();
// no bbreak;
default: CByteArray *l_pCData;
if((l_pCData = l_CCardList.GetApdu(l_chSelection)) != NULL) { l_lResult = in_CReader.Transmit( l_pCData->GetData(), (ULONG) l_pCData->GetSize(), &l_pbResult, &l_uResultLength );
} else {
printf("Invalid Selection"); continue; } break; }
} else {
switch(l_chSelection){ case '0': printf("Changing to T=0"); l_lResult = in_CReader.SetProtocol(SCARD_PROTOCOL_T0); break;
case '1': printf("Changing to T=1"); l_lResult = in_CReader.SetProtocol(SCARD_PROTOCOL_T1); break; case 'c': printf("Cold reset"); l_lResult = in_CReader.ColdResetCard(); in_CReader.GetAtr(&l_pbResult, &l_uResultLength); break;
case 'r': printf("Warm reset"); l_lResult = in_CReader.WarmResetCard(); in_CReader.GetAtr(&l_pbResult, &l_uResultLength); break; case 'd': printf("Power down"); l_lResult = in_CReader.PowerDownCard(); break;
case 'h': printf("Hibernation test...(1 min)\nHibernate machine now!"); l_uPrevState = SCARD_UNKNOWN; l_bWaitForInsertion = FALSE; l_bWaitForRemoval = FALSE; for (l_uRepeat = 0; l_uRepeat < 60; l_uRepeat++) { l_lResult = in_CReader.GetState(&l_uState);
l_lResult = in_CReader.FinishWaitForCard(FALSE);
if (l_uPrevState != SCARD_UNKNOWN && l_lResult == ERROR_SUCCESS) {
printf("\n Card %s", l_bWaitForInsertion ? "inserted" : "removed"); l_uPrevState = SCARD_UNKNOWN; l_bWaitForInsertion = FALSE; l_bWaitForRemoval = FALSE; }
if (l_uState == SCARD_ABSENT) {
if (l_bWaitForInsertion == FALSE) {
l_lResult = in_CReader.StartWaitForCardInsertion(); l_bWaitForInsertion = TRUE; l_bWaitForRemoval = FALSE; }
} else { if (l_bWaitForRemoval == FALSE) {
l_lResult = in_CReader.StartWaitForCardRemoval(); l_bWaitForRemoval = TRUE; l_bWaitForInsertion = FALSE; } }
if (l_uState != l_uPrevState) {
printf("\n %s", l_CCardStates[l_uState]); } if (l_uState >= SCARD_PRESENT && l_uState < SCARD_NEGOTIABLE) {
l_lResult = in_CReader.ColdResetCard(); } if (l_uState == SCARD_NEGOTIABLE) {
l_lResult = in_CReader.SetProtocol( SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 ); } printf("."); l_uPrevState = l_uState;
LONG l_uGoal = clock() + CLOCKS_PER_SEC; while(l_uGoal > clock()) ; } printf("\nPlease %s card", l_uState >= SCARD_PRESENT ? "remove" : "insert"); in_CReader.FinishWaitForCard(TRUE); printf("\n"); continue; break; case 's': printf("Get state"); l_lResult = in_CReader.GetState(&l_uState); printf("Get state 1"); l_pbResult = (PBYTE) &l_uState; l_uResultLength = sizeof(ULONG); break;
case 'a': printf("Waiting for removal..."); l_lResult = in_CReader.WaitForCardRemoval(); break;
case 'p': printf("Waiting for insertion..."); l_lResult = in_CReader.WaitForCardInsertion(); break;
case 'v': printf("Test Vendor IOCTL..."); l_lResult = in_CReader.VendorIoctl(l_CAnswer); l_pbResult = (PUCHAR) ((LPCSTR) l_CAnswer); l_uResultLength = l_CAnswer.GetLength(); break; case 'x': exit(0); default: // Try to select a card
if (l_CCardList.SelectCard(l_chSelection) == FALSE) {
printf("Invalid selection\n"); } l_uRepeat = 0; continue; } }
printf( "\nReturn value: %lxh (NTSTATUS %lxh)\n", l_lResult, MapWinErrorToNtStatus(l_lResult) );
if (l_lResult == ERROR_SUCCESS && l_uResultLength) {
ULONG l_uIndex, l_uLine, l_uCol; // The I/O request has data returned
printf("Data returned (%ld bytes):\n %04x: ", l_uResultLength, 0);
for (l_uLine = 0, l_uIndex = 0; l_uLine < ((l_uResultLength - 1) / 8) + 1; l_uLine++) {
for (l_uCol = 0, l_uIndex = l_uLine * 8; l_uCol < 8; l_uCol++, l_uIndex++) { printf( l_uIndex < l_uResultLength ? "%02x " : " ", l_pbResult[l_uIndex] ); }
putchar(' ');
for (l_uCol = 0, l_uIndex = l_uLine * 8; l_uCol < 8; l_uCol++, l_uIndex++) {
printf( l_uIndex < l_uResultLength ? "%c" : " ", isprint(l_pbResult[l_uIndex]) ? l_pbResult[l_uIndex] : '.' ); }
putchar('\n'); if (l_uIndex < l_uResultLength) {
printf(" %04x: ", l_uIndex + 1); } } } putchar('\n'); } }
|