519 lines
11 KiB
C++
519 lines
11 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1998 - 1999
|
|
//
|
|
// File: ifdtest.h
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
|
|
|
// Status codes
|
|
#define IFDSTATUS_SUCCESS 0
|
|
#define IFDSTATUS_FAILED 1
|
|
#define IFDSTATUS_CARD_UNKNOWN 2
|
|
#define IFDSTATUS_TEST_UNKNOWN 3
|
|
#define IFDSTATUS_NO_PROVIDER 4
|
|
#define IFDSTATUS_NO_FUNCTION 5
|
|
#define IFDSTATUS_END 7
|
|
|
|
// query codes
|
|
#define IFDQUERY_CARD_TESTED 0
|
|
#define IFDQUERY_CARD_NAME 1
|
|
#define IFDQUERY_TEST_RESULT 2
|
|
|
|
#define READER_TYPE_WDM "WDM PnP"
|
|
#define READER_TYPE_NT "NT 4.00"
|
|
#define READER_TYPE_VXD "Win9x VxD"
|
|
|
|
#define OS_WINNT4 "Windows NT 4.0"
|
|
#define OS_WINNT5 "Windows NT 5.0"
|
|
#define OS_WIN95 "Windows 95"
|
|
#define OS_WIN98 "Windows 98"
|
|
|
|
#define MAX_NUM_ATR 3
|
|
|
|
// Prototypes
|
|
void LogMessage(PCHAR in_pchFormat, ...);
|
|
void LogOpen(PCHAR in_pchLogFile);
|
|
void TestStart(PCHAR in_pchFormat, ...);
|
|
void TestCheck(BOOL in_bResult, PCHAR in_pchFormat, ...);
|
|
void TestEnd(void);
|
|
BOOL TestFailed(void);
|
|
BOOL ReaderFailed(void);
|
|
CString & GetOperatingSystem(void);
|
|
|
|
void
|
|
TestCheck(
|
|
ULONG in_lResult,
|
|
const PCHAR in_pchOperator,
|
|
const ULONG in_uExpectedResult,
|
|
ULONG in_uResultLength,
|
|
ULONG in_uExpectedLength,
|
|
UCHAR in_chSw1,
|
|
UCHAR in_chSw2,
|
|
UCHAR in_chExpectedSw1,
|
|
UCHAR in_chExpectedSw2,
|
|
PBYTE in_pchData,
|
|
PBYTE in_pchExpectedData,
|
|
ULONG in_uDataLength
|
|
);
|
|
|
|
extern "C" {
|
|
|
|
LONG MapWinErrorToNtStatus(ULONG in_uErrorCode);
|
|
}
|
|
|
|
//
|
|
// some useful macros
|
|
//
|
|
#define TEST_END() {TestEnd(); if(TestFailed()) return IFDSTATUS_FAILED;}
|
|
|
|
#define TEST_CHECK_SUCCESS(Text, Result) \
|
|
TestCheck( \
|
|
Result == ERROR_SUCCESS, \
|
|
"%s.\nReturned %8lxH (NTSTATUS %8lxH)\nExpected 0H (NTSTATUS 0H)", \
|
|
Text, \
|
|
Result, \
|
|
MapWinErrorToNtStatus(Result) \
|
|
);
|
|
|
|
#define TEST_CHECK_NOT_SUPPORTED(Text, Result) \
|
|
TestCheck( \
|
|
Result == ERROR_NOT_SUPPORTED, \
|
|
"%s.\nReturned %8lxH (NTSTATUS %8xH)\nExpected %38xH (NTSTATUS %8lxH)", \
|
|
Text, \
|
|
Result, \
|
|
MapWinErrorToNtStatus(Result), \
|
|
ERROR_NOT_SUPPORTED, \
|
|
MapWinErrorToNtStatus(ERROR_NOT_SUPPORTED) \
|
|
);
|
|
//
|
|
// Class definitions
|
|
//
|
|
class CAtr {
|
|
|
|
UCHAR m_rgbAtr[SCARD_ATR_LENGTH];
|
|
ULONG m_uAtrLength;
|
|
|
|
public:
|
|
CAtr() {
|
|
|
|
m_uAtrLength = 0;
|
|
memset(m_rgbAtr, 0, SCARD_ATR_LENGTH);
|
|
}
|
|
|
|
CAtr(
|
|
BYTE in_rgbAtr[],
|
|
ULONG in_uAtrLength
|
|
)
|
|
{
|
|
*this = CAtr();
|
|
m_uAtrLength = min(SCARD_ATR_LENGTH, in_uAtrLength);
|
|
memcpy(m_rgbAtr, in_rgbAtr, m_uAtrLength);
|
|
}
|
|
|
|
PCHAR GetAtrString(PCHAR io_pchBuffer);
|
|
PBYTE GetAtr(PBYTE *io_pchBuffer, PULONG io_puAtrLength) {
|
|
|
|
*io_pchBuffer = (PBYTE) m_rgbAtr;
|
|
*io_puAtrLength = m_uAtrLength;
|
|
return (PBYTE) m_rgbAtr;
|
|
}
|
|
|
|
ULONG GetLength() {
|
|
|
|
return m_uAtrLength;
|
|
}
|
|
|
|
operator==(const CAtr& a) {
|
|
|
|
return (m_uAtrLength &&
|
|
a.m_uAtrLength == m_uAtrLength &&
|
|
memcmp(m_rgbAtr, a.m_rgbAtr, m_uAtrLength) == 0);
|
|
}
|
|
|
|
operator!=(const CAtr& a) {
|
|
|
|
return !(*this == a);
|
|
}
|
|
};
|
|
|
|
class CReader {
|
|
|
|
// device name. E.g. SCReader0
|
|
CString m_CDeviceName;
|
|
|
|
// Name of the reader to be tested. E.g. Bull
|
|
CString m_CVendorName;
|
|
|
|
// Name of the reader to be tested. E.g. Bull
|
|
CString m_CIfdType;
|
|
|
|
// Atr of the current card
|
|
class CAtr m_CAtr;
|
|
|
|
// handle to the reader device
|
|
HANDLE m_hReader;
|
|
|
|
// Overlapped structure used by DeviceIoControl
|
|
OVERLAPPED m_Ovr;
|
|
|
|
// Overlapped structure used by WaitFor...
|
|
OVERLAPPED m_OvrWait;
|
|
|
|
// io-request struct used for transmissions
|
|
SCARD_IO_REQUEST m_ScardIoRequest;
|
|
|
|
// Storage area for smart card i/o
|
|
UCHAR m_rgbReplyBuffer[1024];
|
|
|
|
// size of the reply buffer
|
|
ULONG m_uReplyBufferSize;
|
|
|
|
// Number of bytes returned by the card
|
|
ULONG m_uReplyLength;
|
|
|
|
// function used by WaitForCardInsertion|Removal
|
|
LONG WaitForCard(const ULONG);
|
|
|
|
LONG StartWaitForCard(const ULONG);
|
|
|
|
LONG PowerCard(ULONG in_uMinorIoControlCode);
|
|
|
|
BOOL m_fDump;
|
|
|
|
public:
|
|
CReader();
|
|
|
|
// Close reader
|
|
void Close(void);
|
|
|
|
// power functions
|
|
LONG CReader::ColdResetCard(void) {
|
|
|
|
return PowerCard(SCARD_COLD_RESET);
|
|
}
|
|
|
|
LONG CReader::WarmResetCard(void) {
|
|
|
|
return PowerCard(SCARD_WARM_RESET);
|
|
}
|
|
|
|
LONG CReader::PowerDownCard(void) {
|
|
|
|
return PowerCard(SCARD_POWER_DOWN);
|
|
}
|
|
|
|
PBYTE GetAtr(PBYTE *io_pchBuffer, PULONG io_puAtrLength) {
|
|
|
|
return m_CAtr.GetAtr(io_pchBuffer, io_puAtrLength);
|
|
}
|
|
|
|
PCHAR GetAtrString(PCHAR io_pchBuffer) {
|
|
|
|
return m_CAtr.GetAtrString(io_pchBuffer);
|
|
}
|
|
|
|
HANDLE GetHandle(void) {
|
|
|
|
return m_hReader;
|
|
}
|
|
|
|
CString &GetDeviceName(void) {
|
|
|
|
return m_CDeviceName;
|
|
}
|
|
|
|
LONG VendorIoctl(CString &o_CAnswer);
|
|
CString &GetVendorName(void);
|
|
CString &GetIfdType(void);
|
|
ULONG GetDeviceUnit(void);
|
|
LONG GetState(PULONG io_puState);
|
|
|
|
// Open the reader
|
|
BOOL Open(
|
|
CString &in_CReaderName
|
|
);
|
|
|
|
// (Re)Open reader using the existing name
|
|
BOOL Open(void);
|
|
|
|
//
|
|
// Set size of the reply buffer
|
|
// (Only for testing purposes)
|
|
//
|
|
void SetReplyBufferSize(ULONG in_uSize) {
|
|
|
|
if (in_uSize > sizeof(m_rgbReplyBuffer)) {
|
|
|
|
m_uReplyBufferSize = sizeof(m_rgbReplyBuffer);
|
|
|
|
} else {
|
|
|
|
m_uReplyBufferSize = in_uSize;
|
|
}
|
|
}
|
|
|
|
// assigns an ATR
|
|
void SetAtr(PBYTE in_pchAtr, ULONG in_uAtrLength) {
|
|
|
|
m_CAtr = CAtr(in_pchAtr, in_uAtrLength);
|
|
}
|
|
|
|
// returns the ATR of the current card
|
|
class CAtr &GetAtr() {
|
|
|
|
return m_CAtr;
|
|
}
|
|
|
|
// set protocol to be used
|
|
LONG SetProtocol(const ULONG in_uProtocol);
|
|
|
|
// transmits an APDU to the reader/card
|
|
LONG Transmit(
|
|
PBYTE in_pchRequest,
|
|
ULONG in_uRequestLength,
|
|
PBYTE *out_pchReply,
|
|
PULONG out_puReplyLength
|
|
);
|
|
|
|
// wait to insert card
|
|
LONG WaitForCardInsertion() {
|
|
|
|
return WaitForCard(IOCTL_SMARTCARD_IS_PRESENT);
|
|
};
|
|
|
|
// wait to remove card
|
|
LONG WaitForCardRemoval() {
|
|
|
|
return WaitForCard(IOCTL_SMARTCARD_IS_ABSENT);
|
|
};
|
|
|
|
LONG StartWaitForCardRemoval() {
|
|
|
|
return StartWaitForCard(IOCTL_SMARTCARD_IS_ABSENT);
|
|
};
|
|
|
|
LONG StartWaitForCardInsertion() {
|
|
|
|
return StartWaitForCard(IOCTL_SMARTCARD_IS_PRESENT);
|
|
};
|
|
|
|
LONG FinishWaitForCard(const BOOL in_bWait);
|
|
|
|
void SetDump(BOOL in_fOn) {
|
|
|
|
m_fDump = in_fOn;
|
|
}
|
|
};
|
|
|
|
class CCardProvider {
|
|
|
|
// Start of list pointer
|
|
static class CCardProvider *s_pFirst;
|
|
|
|
// Pointer to next provider
|
|
class CCardProvider *m_pNext;
|
|
|
|
// name of the card to be tested
|
|
CString m_CCardName;
|
|
|
|
// atr of this card
|
|
CAtr m_CAtr[3];
|
|
|
|
// test no to run
|
|
ULONG m_uTestNo;
|
|
|
|
// max number of tests
|
|
ULONG m_uTestMax;
|
|
|
|
// This flag indicates that the card test was unsuccessful
|
|
BOOL m_bTestFailed;
|
|
|
|
// This flag indicates that the card has been tested
|
|
BOOL m_bCardTested;
|
|
|
|
// set protocol function
|
|
ULONG ((*m_pSetProtocol)(class CCardProvider&, class CReader&));
|
|
|
|
// set protocol function
|
|
ULONG ((*m_pCardTest)(class CCardProvider&, class CReader&));
|
|
|
|
public:
|
|
|
|
// Constructor
|
|
CCardProvider(void);
|
|
|
|
// Constructor to be used by plug-in
|
|
CCardProvider(void (*pEntryFunction)(class CCardProvider&));
|
|
|
|
// Method that mangages all card tests
|
|
void CardTest(class CReader&, ULONG in_uTestNo);
|
|
|
|
// return if there are still untested cards
|
|
BOOL CardsUntested(void);
|
|
|
|
// List all cards that have not been tested
|
|
void ListUntestedCards(void);
|
|
|
|
// Assigns a friendly name to a card
|
|
void SetCardName(CHAR in_rgchCardName[]);
|
|
|
|
// Set ATR of the card
|
|
void SetAtr(PBYTE in_rgbAtr, ULONG in_uAtrLength);
|
|
|
|
// Assign callback functions
|
|
void SetProtocol(ULONG ((in_pFunction)(class CCardProvider&, class CReader&))) {
|
|
|
|
m_pSetProtocol = in_pFunction;
|
|
}
|
|
|
|
void SetCardTest(ULONG ((in_pFunction)(class CCardProvider&, class CReader&))) {
|
|
|
|
m_pCardTest = in_pFunction;
|
|
}
|
|
|
|
// returns the test number to perform
|
|
ULONG GetTestNo(void) {
|
|
|
|
return m_uTestNo;
|
|
}
|
|
|
|
BOOL IsValidAtr(CAtr in_CAtr) {
|
|
|
|
for (int i = 0; i < MAX_NUM_ATR; i++) {
|
|
|
|
if (m_CAtr[i] == in_CAtr) {
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
};
|
|
|
|
// represents a list of all installed readers
|
|
class CReaderList {
|
|
|
|
// number of constructor calls to avoid multiple build of reader list
|
|
static ULONG m_uRefCount;
|
|
|
|
// number of currently installed readers
|
|
static ULONG m_uNumReaders;
|
|
|
|
// pointer to array of reader list
|
|
static class CReaderList **m_pList;
|
|
|
|
ULONG m_uCurrentReader;
|
|
|
|
CString m_CDeviceName;
|
|
CString m_CPnPType;
|
|
CString m_CVendorName;
|
|
CString m_CIfdType;
|
|
|
|
public:
|
|
|
|
CReaderList();
|
|
CReaderList(
|
|
CString &in_CDeviceName,
|
|
CString &in_CPnPType,
|
|
CString &in_CVendorName,
|
|
CString &in_CIfdType
|
|
);
|
|
~CReaderList();
|
|
|
|
void AddDevice(
|
|
CString in_pchDeviceName,
|
|
CString in_pchPnPType
|
|
);
|
|
|
|
CString &GetVendorName(ULONG in_uIndex);
|
|
CString &GetDeviceName(ULONG in_uIndex);
|
|
CString &GetIfdType(ULONG in_uIndex);
|
|
CString &GetPnPType(ULONG in_uIndex);
|
|
|
|
ULONG GetNumReaders(void) {
|
|
|
|
return m_uNumReaders;
|
|
}
|
|
};
|
|
|
|
// This structure represents the T=0 result file of a smart card
|
|
typedef struct _T0_RESULT_FILE_HEADER {
|
|
|
|
// Offset to first test result
|
|
UCHAR Offset;
|
|
|
|
// Number of times the card has been reset
|
|
UCHAR CardResetCount;
|
|
|
|
// Version number of this card
|
|
UCHAR CardMajorVersion;
|
|
UCHAR CardMinorVersion;
|
|
|
|
} T0_RESULT_FILE_HEADER, *PT0_RESULT_FILE_HEADER;
|
|
|
|
typedef struct _T0_RESULT_FILE {
|
|
|
|
//
|
|
// The following structures store the results
|
|
// of the tests. Each result comes with the
|
|
// reset count when the test was performed.
|
|
// This is used to make sure that we read not
|
|
// the result from an old test, maybe even
|
|
// performed with another reader/driver.
|
|
//
|
|
struct {
|
|
|
|
UCHAR Result;
|
|
UCHAR ResetCount;
|
|
|
|
} TransferAllBytes;
|
|
|
|
struct {
|
|
|
|
UCHAR Result;
|
|
UCHAR ResetCount;
|
|
|
|
} TransferNextByte;
|
|
|
|
struct {
|
|
|
|
UCHAR Result;
|
|
UCHAR ResetCount;
|
|
|
|
} Read256Bytes;
|
|
|
|
struct {
|
|
|
|
UCHAR Result;
|
|
UCHAR ResetCount;
|
|
|
|
} Case1Apdu;
|
|
|
|
struct {
|
|
|
|
UCHAR Result;
|
|
UCHAR ResetCount;
|
|
|
|
} RestartWorkWaitingTime;
|
|
|
|
struct {
|
|
|
|
UCHAR Result;
|
|
UCHAR ResetCount;
|
|
|
|
} PTS;
|
|
|
|
struct {
|
|
|
|
UCHAR Result;
|
|
UCHAR ResetCount;
|
|
|
|
} PTSDataCheck;
|
|
|
|
} T0_RESULT_FILE, *PT0_RESULT_FILE;
|