2101 lines
53 KiB
C++
2101 lines
53 KiB
C++
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <conio.h>
|
|
|
|
#include <afx.h>
|
|
#include <afxtempl.h>
|
|
|
|
#include <winioctl.h>
|
|
#include <winsmcrd.h>
|
|
|
|
#include "ifdtest.h"
|
|
|
|
class CCardProvider *CCardProvider::s_pFirst;
|
|
|
|
#define INSERT_CARD "Please insert smart card"
|
|
#define REMOVE_CARD "Please remove smart card"
|
|
|
|
PCHAR
|
|
CAtr::GetAtrString(
|
|
PCHAR in_pchBuffer
|
|
)
|
|
{
|
|
for (ULONG i = 0; i < m_uAtrLength; i++) {
|
|
|
|
sprintf(in_pchBuffer + i * 3, "%02X ", m_rgbAtr[i]);
|
|
}
|
|
|
|
return in_pchBuffer;
|
|
}
|
|
|
|
CCardProvider::CCardProvider(
|
|
void
|
|
)
|
|
{
|
|
m_pNext = NULL;
|
|
m_uTestNo = 0;
|
|
m_bCardTested = FALSE;
|
|
m_bTestFailed = FALSE;
|
|
m_pSetProtocol = NULL;
|
|
m_pCardTest = NULL;
|
|
}
|
|
|
|
CCardProvider::CCardProvider(
|
|
void (*in_pEntryFunction)(class CCardProvider&)
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Constructor for class CCardProvider.
|
|
This constructor is called for every card that is to be tested.
|
|
It creates a new instance and appends it to a singly linked list
|
|
|
|
Arguments:
|
|
|
|
Pointer to function that registers all test functions
|
|
|
|
--*/
|
|
{
|
|
class CCardProvider *l_pCardProvider;
|
|
|
|
*this = CCardProvider();
|
|
|
|
if (s_pFirst == NULL) {
|
|
|
|
s_pFirst = new CCardProvider;
|
|
l_pCardProvider = s_pFirst;
|
|
|
|
} else {
|
|
|
|
l_pCardProvider = s_pFirst;
|
|
|
|
while (l_pCardProvider->m_pNext) {
|
|
|
|
l_pCardProvider = l_pCardProvider->m_pNext;
|
|
}
|
|
|
|
l_pCardProvider->m_pNext = new CCardProvider;
|
|
l_pCardProvider = l_pCardProvider->m_pNext;
|
|
}
|
|
|
|
(*in_pEntryFunction)(*l_pCardProvider);
|
|
}
|
|
|
|
BOOL
|
|
CCardProvider::CardsUntested(
|
|
void
|
|
)
|
|
{
|
|
class CCardProvider *l_pCCardProvider = s_pFirst;
|
|
|
|
while (l_pCCardProvider) {
|
|
|
|
if (l_pCCardProvider->m_bCardTested == FALSE) {
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
l_pCCardProvider = l_pCCardProvider->m_pNext;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
CCardProvider::CardTest(
|
|
class CReader& io_pCReader,
|
|
ULONG in_uTestNo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls every registered card provider in the list until one of
|
|
the providers indicates that it recognized the card
|
|
|
|
Arguments:
|
|
|
|
io_pCReader - reference to the test structure
|
|
|
|
Return Value:
|
|
|
|
IFDSTATUS value
|
|
|
|
--*/
|
|
{
|
|
class CCardProvider *l_pCCardProvider = s_pFirst;
|
|
ULONG l_uStatus;
|
|
|
|
while (l_pCCardProvider) {
|
|
|
|
if ( l_pCCardProvider->IsValidAtr(io_pCReader.GetAtr()) ) {
|
|
|
|
if (l_pCCardProvider->m_bCardTested) {
|
|
|
|
// We tested this card already
|
|
LogMessage("Card has been tested already. Please remove the card");
|
|
return;
|
|
}
|
|
|
|
l_pCCardProvider->m_bCardTested = TRUE;
|
|
LogMessage(
|
|
"\nTesting card %s",
|
|
(LPCSTR) l_pCCardProvider->m_CCardName
|
|
);
|
|
|
|
if (l_pCCardProvider->m_pSetProtocol == NULL) {
|
|
|
|
return;
|
|
}
|
|
|
|
// Call card provider function
|
|
l_uStatus = (*l_pCCardProvider->m_pSetProtocol)(
|
|
*l_pCCardProvider,
|
|
io_pCReader
|
|
);
|
|
|
|
if (l_uStatus == IFDSTATUS_END) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (l_uStatus != IFDSTATUS_SUCCESS) {
|
|
|
|
return;
|
|
}
|
|
|
|
// Check if the card test function pointer exists
|
|
if (l_pCCardProvider->m_pCardTest == NULL) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (in_uTestNo) {
|
|
|
|
// user wants to run only a single test
|
|
l_pCCardProvider->m_uTestNo = in_uTestNo;
|
|
|
|
LogMessage("Test No. %2d", l_pCCardProvider->m_uTestNo);
|
|
|
|
// Call card provider function
|
|
l_uStatus = (*l_pCCardProvider->m_pCardTest)(
|
|
*l_pCCardProvider,
|
|
io_pCReader
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
// run the whole test set
|
|
for (l_pCCardProvider->m_uTestNo = 1; ;l_pCCardProvider->m_uTestNo++) {
|
|
|
|
LogMessage("Test No. %2d", l_pCCardProvider->m_uTestNo);
|
|
|
|
// Call card provider function
|
|
l_uStatus = (*l_pCCardProvider->m_pCardTest)(
|
|
*l_pCCardProvider,
|
|
io_pCReader
|
|
);
|
|
|
|
if (l_uStatus != IFDSTATUS_SUCCESS) {
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
l_pCCardProvider = l_pCCardProvider->m_pNext;
|
|
}
|
|
|
|
PCHAR l_rgbAtrBuffer = new CHAR[256];
|
|
|
|
LogMessage("Card unknown!");
|
|
LogMessage(" CURRENT CARD");
|
|
LogMessage(" %s", io_pCReader.GetAtrString(l_rgbAtrBuffer));
|
|
|
|
for (l_pCCardProvider = s_pFirst;
|
|
l_pCCardProvider;
|
|
l_pCCardProvider = l_pCCardProvider->m_pNext) {
|
|
|
|
if (l_pCCardProvider->m_bCardTested == FALSE) {
|
|
|
|
LogMessage(" * %s", (LPCSTR) l_pCCardProvider->m_CCardName);
|
|
for (int i = 0; i < MAX_NUM_ATR && l_pCCardProvider->m_CAtr[i].GetLength(); i++) {
|
|
|
|
LogMessage(" %s", l_pCCardProvider->m_CAtr[i].GetAtrString(l_rgbAtrBuffer));
|
|
}
|
|
}
|
|
}
|
|
|
|
delete l_rgbAtrBuffer;
|
|
|
|
LogMessage("Please remove card");
|
|
}
|
|
|
|
void
|
|
CCardProvider::ListUntestedCards(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Prints a list of all cards that have not been tested
|
|
|
|
--*/
|
|
{
|
|
class CCardProvider *l_pCCardProvider = s_pFirst;
|
|
|
|
while (l_pCCardProvider) {
|
|
|
|
if (l_pCCardProvider->m_bCardTested == FALSE) {
|
|
|
|
LogMessage(" * %s", (LPCSTR) l_pCCardProvider->m_CCardName);
|
|
}
|
|
|
|
l_pCCardProvider = l_pCCardProvider->m_pNext;
|
|
}
|
|
}
|
|
|
|
void
|
|
CCardProvider::SetAtr(
|
|
BYTE in_rgbAtr[],
|
|
ULONG in_uAtrLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Sets the ATR of the card
|
|
|
|
Arguments:
|
|
in_rgchAtr - the atr string
|
|
in_uAtrLength - length of the atr
|
|
|
|
--*/
|
|
{
|
|
for (int i = 0; i < MAX_NUM_ATR; i++) {
|
|
|
|
if (m_CAtr[i].GetLength() == 0) {
|
|
|
|
m_CAtr[i] = CAtr(in_rgbAtr, in_uAtrLength);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CCardProvider::SetCardName(
|
|
CHAR in_rgchCardName[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Sets a friendly name for the card
|
|
|
|
Arguments:
|
|
in_rgchCardName - Friendly name for the card
|
|
|
|
--*/
|
|
{
|
|
m_CCardName = in_rgchCardName;
|
|
}
|
|
|
|
void
|
|
CheckCardMonitor(
|
|
CReader &in_CReader
|
|
)
|
|
{
|
|
ULONG l_lResult, l_uReplyLength, l_lTestNo = 1;
|
|
time_t l_lStartTime;
|
|
BOOL l_bResult;
|
|
OVERLAPPED l_Ovr;
|
|
HANDLE l_hReader = in_CReader.GetHandle();
|
|
|
|
l_Ovr.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
ResetEvent(l_Ovr.hEvent);
|
|
|
|
LogMessage("=============================");
|
|
LogMessage("Part A: Checking card monitor");
|
|
LogMessage("=============================");
|
|
|
|
LogMessage(" << %s", REMOVE_CARD);
|
|
in_CReader.WaitForCardRemoval();
|
|
TestStart("%2d. %s", l_lTestNo++, INSERT_CARD);
|
|
l_lResult = in_CReader.WaitForCardInsertion();
|
|
TEST_CHECK_SUCCESS("Reader failed card insertion monitor", l_lResult);
|
|
TestEnd();
|
|
|
|
TestStart("%2d. IOCTL_SMARTCARD_IS_PRESENT", l_lTestNo++);
|
|
l_bResult = DeviceIoControl (
|
|
l_hReader,
|
|
IOCTL_SMARTCARD_IS_PRESENT,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&l_uReplyLength,
|
|
&l_Ovr
|
|
);
|
|
|
|
TestCheck(
|
|
l_bResult == TRUE,
|
|
"DeviceIoControl should return TRUE with card inserted"
|
|
);
|
|
TestEnd();
|
|
|
|
TestStart("%2d. %s", l_lTestNo++, REMOVE_CARD);
|
|
l_lResult = in_CReader.WaitForCardRemoval();
|
|
TEST_CHECK_SUCCESS("Reader failed card removal monitor", l_lResult);
|
|
TestEnd();
|
|
|
|
TestStart("%2d. IOCTL_SMARTCARD_IS_ABSENT", l_lTestNo++);
|
|
l_bResult = DeviceIoControl (
|
|
l_hReader,
|
|
IOCTL_SMARTCARD_IS_ABSENT,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&l_uReplyLength,
|
|
&l_Ovr
|
|
);
|
|
|
|
TestCheck(
|
|
l_bResult == TRUE,
|
|
"DeviceIoControl should return TRUE with card removed"
|
|
);
|
|
TestEnd();
|
|
|
|
TestStart("%2d. Insert and remove a smart card repeatedly", l_lTestNo++);
|
|
|
|
for (l_lStartTime = time(NULL); time(NULL) - l_lStartTime < 15;) {
|
|
|
|
l_lResult = in_CReader.ColdResetCard();
|
|
#ifdef insert_remove_alternate
|
|
l_bResult = DeviceIoControl (
|
|
l_hReader,
|
|
IOCTL_SMARTCARD_IS_PRESENT,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&l_uReplyLength,
|
|
&l_Ovr
|
|
);
|
|
|
|
SetLastError(0);
|
|
|
|
l_bResult = GetOverlappedResult(
|
|
l_hReader,
|
|
&l_Ovr,
|
|
&l_uReplyLength,
|
|
FALSE
|
|
);
|
|
|
|
l_lResult = GetLastError();
|
|
|
|
TestCheck(
|
|
l_bResult == TRUE && l_lResult == ERROR_SUCCESS ||
|
|
l_bResult == FALSE &&
|
|
(l_lResult == ERROR_IO_INCOMPLETE ||
|
|
l_lResult == ERROR_BUSY ||
|
|
l_lResult == ERROR_IO_PENDING),
|
|
"Reader failed card insertion monitor.\nReturned %2lxH",
|
|
l_lResult
|
|
);
|
|
|
|
l_bResult = DeviceIoControl (
|
|
l_hReader,
|
|
IOCTL_SMARTCARD_IS_ABSENT,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&l_uReplyLength,
|
|
&l_Ovr
|
|
);
|
|
|
|
SetLastError(0);
|
|
|
|
l_bResult = GetOverlappedResult(
|
|
l_hReader,
|
|
&l_Ovr,
|
|
&l_uReplyLength,
|
|
FALSE
|
|
);
|
|
|
|
l_lResult = GetLastError();
|
|
|
|
TestCheck(
|
|
l_bResult == TRUE && l_lResult == ERROR_SUCCESS ||
|
|
l_bResult == FALSE &&
|
|
(l_lResult == ERROR_IO_INCOMPLETE ||
|
|
l_lResult == ERROR_BUSY ||
|
|
l_lResult == ERROR_IO_PENDING),
|
|
"Reader failed card removal monitor:\nReturned %2lxH",
|
|
l_lResult
|
|
);
|
|
#endif
|
|
}
|
|
#ifdef insert_remove_alternate
|
|
l_bResult = GetOverlappedResult(
|
|
l_hReader,
|
|
&l_Ovr,
|
|
&l_uReplyLength,
|
|
TRUE
|
|
);
|
|
#endif
|
|
TestEnd();
|
|
|
|
LogMessage("Press any key to continue");
|
|
_getch();
|
|
|
|
if (ReaderFailed()) {
|
|
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
void
|
|
CheckReader(
|
|
CReader &in_CReader
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks the attributes of a reader.
|
|
Once with card inserted and then without
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
BOOL l_bResult;
|
|
ULONG l_iIndex, l_uReplyLength, l_lTestNo = 1, l_uStart, l_uEnd;
|
|
OVERLAPPED l_Ovr;
|
|
UCHAR l_rgbReplyBuffer[512];
|
|
HANDLE l_hReader = in_CReader.GetHandle();
|
|
|
|
l_Ovr.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
ResetEvent(l_Ovr.hEvent);
|
|
|
|
#define ATTR(x) #x, x
|
|
|
|
struct {
|
|
|
|
PCHAR m_pchName;
|
|
ULONG m_uType;
|
|
|
|
} l_aAttr[] = {
|
|
|
|
ATTR(SCARD_ATTR_VENDOR_NAME),
|
|
ATTR(SCARD_ATTR_VENDOR_IFD_TYPE),
|
|
ATTR(SCARD_ATTR_DEVICE_UNIT),
|
|
ATTR(SCARD_ATTR_ATR_STRING),
|
|
ATTR(SCARD_ATTR_DEFAULT_CLK),
|
|
ATTR(SCARD_ATTR_MAX_CLK),
|
|
ATTR(SCARD_ATTR_DEFAULT_DATA_RATE),
|
|
ATTR(SCARD_ATTR_MAX_DATA_RATE),
|
|
ATTR(SCARD_ATTR_MAX_IFSD),
|
|
ATTR(SCARD_ATTR_CURRENT_PROTOCOL_TYPE),
|
|
ATTR(SCARD_ATTR_PROTOCOL_TYPES),
|
|
0, 0,
|
|
ATTR(SCARD_ATTR_ATR_STRING),
|
|
ATTR(SCARD_ATTR_CURRENT_PROTOCOL_TYPE)
|
|
};
|
|
|
|
LogMessage("=======================");
|
|
LogMessage("Part B: Checking reader");
|
|
LogMessage("=======================");
|
|
|
|
BOOL l_bCardInserted = FALSE;
|
|
LogMessage(" << %s", REMOVE_CARD);
|
|
in_CReader.WaitForCardRemoval();
|
|
|
|
TestStart("%2d. Device name", l_lTestNo++);
|
|
|
|
CString l_COperatingSystem = GetOperatingSystem();
|
|
|
|
if (l_COperatingSystem == OS_WINNT4) {
|
|
|
|
TestCheck(
|
|
in_CReader.GetDeviceName().Left(12) == "\\\\.\\SCReader",
|
|
"Device name is not NT 4.0 compliant"
|
|
);
|
|
|
|
} else if (l_COperatingSystem == OS_WIN95 ||
|
|
l_COperatingSystem == OS_WIN98) {
|
|
|
|
// there is no special naming convention for Win9x
|
|
|
|
} else {
|
|
|
|
TestCheck(
|
|
in_CReader.GetDeviceName().Find("{50dd5230-ba8a-11d1-bf5d-0000f805f530}") != -1,
|
|
"Device name is not WDM PnP compliant"
|
|
);
|
|
}
|
|
TestEnd();
|
|
|
|
TestStart(
|
|
"%2d. Null pointer check",
|
|
l_lTestNo++
|
|
);
|
|
|
|
for (l_iIndex = 0; l_aAttr[l_iIndex].m_pchName; l_iIndex++) {
|
|
|
|
// try to crash reader by using null pointers as arguments
|
|
l_bResult = DeviceIoControl (
|
|
l_hReader,
|
|
IOCTL_SMARTCARD_GET_ATTRIBUTE,
|
|
&l_aAttr[l_iIndex].m_uType,
|
|
sizeof(ULONG),
|
|
NULL,
|
|
1000,
|
|
&l_uReplyLength,
|
|
&l_Ovr
|
|
);
|
|
|
|
ULONG l_lResult = GetLastError();
|
|
|
|
TestCheck(
|
|
l_lResult == ERROR_INSUFFICIENT_BUFFER ||
|
|
l_lResult == ERROR_BAD_COMMAND,
|
|
"IOCTL_SMARTCARD_GET_ATTRIBUTE (%lxh) should fail\nReturned %2lxH (NTSTATUS %lxH)\nExpected %2lxH (NTSTATUS %lxH)\nor %2lxH (NTSTATUS %lxH)",
|
|
l_aAttr[l_iIndex].m_uType & 0xFFFF,
|
|
l_lResult,
|
|
MapWinErrorToNtStatus(l_lResult),
|
|
ERROR_INSUFFICIENT_BUFFER,
|
|
MapWinErrorToNtStatus(ERROR_BAD_COMMAND),
|
|
ERROR_BAD_COMMAND,
|
|
MapWinErrorToNtStatus(ERROR_BAD_COMMAND)
|
|
);
|
|
}
|
|
TestEnd();
|
|
|
|
for (l_iIndex = 0; l_iIndex < sizeof(l_aAttr) / sizeof(l_aAttr[0]); l_iIndex++) {
|
|
|
|
if (l_aAttr[l_iIndex].m_pchName == 0) {
|
|
|
|
TestStart("%2d. Close driver with I/O-request still pending", l_lTestNo++);
|
|
|
|
// Check if the reader correctly terminates pending io-requests
|
|
l_bResult = DeviceIoControl (
|
|
l_hReader,
|
|
IOCTL_SMARTCARD_IS_PRESENT,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&l_uReplyLength,
|
|
&l_Ovr
|
|
);
|
|
|
|
TestCheck(
|
|
l_bResult == FALSE,
|
|
"Wait for present succeeded with no card inserted"
|
|
);
|
|
|
|
// With the pending i/o request close and re-open the driver
|
|
in_CReader.Close();
|
|
l_bResult = in_CReader.Open();
|
|
|
|
TestCheck(
|
|
l_bResult,
|
|
"Reader failed to terminate pending i/o request"
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
if (TestFailed()) {
|
|
|
|
// If the open failed we can't contiue
|
|
exit(GetLastError());
|
|
}
|
|
|
|
l_hReader = in_CReader.GetHandle();
|
|
|
|
LogMessage(" >> Please insert 'IBM PC/SC Compliance Test Card'");
|
|
in_CReader.WaitForCardInsertion();
|
|
l_bCardInserted = TRUE;
|
|
|
|
// Cold reset
|
|
TestStart("%2d. Cold reset", l_lTestNo++);
|
|
l_uStart = clock();
|
|
LONG l_lResult = in_CReader.ColdResetCard();
|
|
l_uEnd = clock();
|
|
TEST_CHECK_SUCCESS("Cold reset failed", l_lResult);
|
|
TestCheck(
|
|
(l_uEnd - l_uStart) / CLOCKS_PER_SEC <= 2,
|
|
"Cold reset took too long.\nElapsed time %ld sec\nExpected time %ld sec",
|
|
(l_uEnd - l_uStart) / CLOCKS_PER_SEC,
|
|
2
|
|
);
|
|
TestEnd();
|
|
|
|
if (TestFailed()) {
|
|
|
|
exit(l_lResult);
|
|
}
|
|
|
|
// Set protocol
|
|
TestStart("%2d. Set protocol to T0 | T1", l_lTestNo++);
|
|
l_lResult = in_CReader.SetProtocol(
|
|
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1
|
|
);
|
|
TEST_CHECK_SUCCESS("Set protocol failed", l_lResult);
|
|
TestEnd();
|
|
continue;
|
|
}
|
|
|
|
TestStart("%2d. %s", l_lTestNo++, l_aAttr[l_iIndex].m_pchName);
|
|
|
|
SetLastError(0);
|
|
*(PULONG) l_rgbReplyBuffer = 0;
|
|
|
|
l_bResult = DeviceIoControl (
|
|
l_hReader,
|
|
IOCTL_SMARTCARD_GET_ATTRIBUTE,
|
|
&l_aAttr[l_iIndex].m_uType,
|
|
sizeof(ULONG),
|
|
l_rgbReplyBuffer,
|
|
sizeof(l_rgbReplyBuffer),
|
|
&l_uReplyLength,
|
|
&l_Ovr
|
|
);
|
|
|
|
if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
|
|
|
|
//
|
|
// The I/O request returned pending, so
|
|
// wait until the request is finished
|
|
//
|
|
SetLastError(0);
|
|
|
|
l_bResult = GetOverlappedResult(
|
|
l_hReader,
|
|
&l_Ovr,
|
|
&l_uReplyLength,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
if (GetLastError() != ERROR_SUCCESS) {
|
|
|
|
l_bResult = FALSE;
|
|
|
|
} else {
|
|
|
|
l_rgbReplyBuffer[l_uReplyLength] = 0;
|
|
}
|
|
|
|
LONG l_lResult = GetLastError();
|
|
|
|
switch (l_aAttr[l_iIndex].m_uType) {
|
|
|
|
case SCARD_ATTR_VENDOR_NAME:
|
|
TEST_CHECK_SUCCESS(
|
|
"Ioctl SCARD_ATTR_VENDOR_NAME failed",
|
|
l_lResult
|
|
);
|
|
TestCheck(
|
|
strlen((PCHAR) l_rgbReplyBuffer) != 0,
|
|
"No vendor name defined"
|
|
);
|
|
TestEnd();
|
|
break;
|
|
|
|
case SCARD_ATTR_VENDOR_IFD_TYPE:
|
|
TEST_CHECK_SUCCESS(
|
|
"Ioctl SCARD_ATTR_VENDOR_IFD_TYPE failed",
|
|
l_lResult
|
|
);
|
|
TestCheck(
|
|
strlen((PCHAR) l_rgbReplyBuffer) != 0,
|
|
"No ifd type defined"
|
|
);
|
|
TestEnd();
|
|
break;
|
|
|
|
case SCARD_ATTR_DEVICE_UNIT:
|
|
TEST_CHECK_SUCCESS(
|
|
"Ioctl SCARD_ATTR_DEVICE_UNIT failed",
|
|
l_lResult
|
|
);
|
|
TestCheck(
|
|
*(PULONG) l_rgbReplyBuffer < 4,
|
|
"Invalid value: %ld (0 - 3)",
|
|
*(PULONG) l_rgbReplyBuffer
|
|
);
|
|
TestEnd();
|
|
break;
|
|
|
|
case SCARD_ATTR_ATR_STRING:
|
|
if (l_bCardInserted) {
|
|
|
|
TEST_CHECK_SUCCESS(
|
|
"Ioctl SCARD_ATTR_ATR_STRING failed",
|
|
l_lResult
|
|
);
|
|
|
|
} else {
|
|
|
|
TestCheck(
|
|
l_bResult == FALSE,
|
|
"Reader returned ATR with no card inserted"
|
|
);
|
|
}
|
|
TestEnd();
|
|
break;
|
|
|
|
case SCARD_ATTR_DEFAULT_CLK:
|
|
case SCARD_ATTR_MAX_CLK:
|
|
TEST_CHECK_SUCCESS(
|
|
"Ioctl SCARD_ATTR_DEFAULT_CLK/SCARD_ATTR_MAX_CLK failed",
|
|
l_lResult
|
|
);
|
|
TestCheck(
|
|
*(PULONG) l_rgbReplyBuffer >= 1000 && *(PULONG) l_rgbReplyBuffer <= 20000,
|
|
"Invalid value %ld (1000 - 20000)",
|
|
*(PULONG) l_rgbReplyBuffer
|
|
);
|
|
TestEnd();
|
|
break;
|
|
|
|
case SCARD_ATTR_DEFAULT_DATA_RATE:
|
|
case SCARD_ATTR_MAX_DATA_RATE:
|
|
TEST_CHECK_SUCCESS(
|
|
"Ioctl SCARD_ATTR_DEFAULT_DATA_RATE/SCARD_ATTR_MAX_DATA_RATE failed",
|
|
l_lResult
|
|
);
|
|
TestEnd();
|
|
break;
|
|
|
|
case SCARD_ATTR_MAX_IFSD:
|
|
TEST_CHECK_SUCCESS(
|
|
"Ioctl SCARD_ATTR_MAX_IFSD failed",
|
|
l_lResult
|
|
);
|
|
TestCheck(
|
|
*(PULONG) l_rgbReplyBuffer >= 1 && *(PULONG) l_rgbReplyBuffer <= 254,
|
|
"Invalid value: %ld (1 - 254)",
|
|
*(PULONG) l_rgbReplyBuffer
|
|
);
|
|
TestEnd();
|
|
break;
|
|
|
|
case SCARD_ATTR_PROTOCOL_TYPES:
|
|
TEST_CHECK_SUCCESS(
|
|
"Ioctl SCARD_ATTR_PROTOCOL_TYPES failed",
|
|
l_lResult
|
|
);
|
|
|
|
// check if the reader at least supports T=0 and T=1
|
|
TestCheck(
|
|
(*(PULONG) l_rgbReplyBuffer & SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1) ==
|
|
(SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1),
|
|
"Reader must support T=0 and T=1"
|
|
);
|
|
TestEnd();
|
|
break;
|
|
|
|
case SCARD_ATTR_CURRENT_PROTOCOL_TYPE:
|
|
|
|
if (l_bCardInserted) {
|
|
|
|
TEST_CHECK_SUCCESS(
|
|
"Ioctl SCARD_ATTR_CURRENT_PROTOCOL_TYPE failed",
|
|
l_lResult
|
|
);
|
|
|
|
TestCheck(
|
|
*(PULONG) l_rgbReplyBuffer != 0,
|
|
"Reader returned no protocol"
|
|
);
|
|
|
|
} else {
|
|
|
|
// Check that without a card the current protocol is set to 0
|
|
TestCheck(
|
|
l_bResult == FALSE,
|
|
"Ioctl SCARD_ATTR_CURRENT_PROTOCOL_TYPE failed should fail with no card inserted"
|
|
);
|
|
}
|
|
TestEnd();
|
|
break;
|
|
|
|
default:
|
|
TestCheck(
|
|
l_bResult,
|
|
"Ioctl returned %lxh",
|
|
GetLastError()
|
|
);
|
|
TestEnd();
|
|
break;
|
|
}
|
|
}
|
|
|
|
LogMessage(" << %s", REMOVE_CARD);
|
|
in_CReader.WaitForCardRemoval();
|
|
LogMessage(" << Please insert smart card BACKWARDS");
|
|
in_CReader.WaitForCardInsertion();
|
|
|
|
TestStart("%2d. IOCTL_SMARTCARD_GET_STATE", l_lTestNo++);
|
|
ULONG l_uState;
|
|
|
|
l_bResult = DeviceIoControl (
|
|
l_hReader,
|
|
IOCTL_SMARTCARD_GET_STATE,
|
|
NULL,
|
|
0,
|
|
&l_uState,
|
|
sizeof(l_uState),
|
|
&l_uReplyLength,
|
|
&l_Ovr
|
|
);
|
|
|
|
LONG l_lResult = GetLastError();
|
|
|
|
TestCheck(
|
|
l_bResult,
|
|
"IOCTL_SMARTCARD_GET_STATE failed.\nReturned %8lxH (NTSTATUS %8lxH).\nExpected %8lxH (NTSTATUS %8lxH)",
|
|
l_lResult,
|
|
MapWinErrorToNtStatus(l_lResult),
|
|
ERROR_SUCCESS,
|
|
MapWinErrorToNtStatus(ERROR_SUCCESS)
|
|
);
|
|
|
|
TestCheck(
|
|
l_uState <= SCARD_SWALLOWED,
|
|
"Invalid reader state.\nReturned %d\nExpected <= %d",
|
|
l_uState,
|
|
SCARD_SWALLOWED
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
TestStart("%2d. Cold reset", l_lTestNo++);
|
|
l_uStart = clock();
|
|
l_lResult = in_CReader.ColdResetCard();
|
|
l_uEnd = clock();
|
|
|
|
TestCheck(
|
|
l_lResult == ERROR_UNRECOGNIZED_MEDIA,
|
|
"Cold reset failed.\nReturned %8lxH (NTSTATUS %8lxH).\nExpected %8lxH (NTSTATUS %8lxH)",
|
|
l_lResult,
|
|
MapWinErrorToNtStatus(l_lResult),
|
|
ERROR_UNRECOGNIZED_MEDIA,
|
|
MapWinErrorToNtStatus(ERROR_UNRECOGNIZED_MEDIA)
|
|
);
|
|
|
|
TestCheck(
|
|
(l_uEnd - l_uStart) / CLOCKS_PER_SEC <= 2,
|
|
"Cold reset took too long.\nElapsed time %ld sec\nExpected time %ld sec",
|
|
(l_uEnd - l_uStart) / CLOCKS_PER_SEC,
|
|
2
|
|
);
|
|
|
|
TestEnd();
|
|
}
|
|
|
|
void
|
|
SimulateResMngr(
|
|
CReader &in_CReader
|
|
)
|
|
{
|
|
BOOL l_bWaitForPresent = FALSE, l_bWaitForAbsent = FALSE, l_bResult;
|
|
BOOL l_bMustWait = FALSE, l_bPoweredDown = FALSE;
|
|
ULONG l_uState, l_uStatus, l_uReplyLength, l_uStateExpected = SCARD_ABSENT, l_lTestNo = 1;
|
|
ULONG l_uMinorIoctl;
|
|
OVERLAPPED l_Ovr, l_OvrWait;
|
|
HANDLE l_hReader = in_CReader.GetHandle();
|
|
|
|
l_Ovr.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
ResetEvent(l_Ovr.hEvent);
|
|
|
|
l_OvrWait.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
ResetEvent(l_OvrWait.hEvent);
|
|
|
|
LogMessage("===================================");
|
|
LogMessage("Part C: Resource Manager Simulation");
|
|
LogMessage("===================================");
|
|
|
|
LogMessage(" << %s", REMOVE_CARD);
|
|
in_CReader.WaitForCardRemoval();
|
|
|
|
while (TRUE) {
|
|
|
|
TestStart("%2d. IOCTL_SMARTCARD_GET_STATE", l_lTestNo++);
|
|
|
|
l_bResult = DeviceIoControl (
|
|
l_hReader,
|
|
IOCTL_SMARTCARD_GET_STATE,
|
|
NULL,
|
|
0,
|
|
&l_uState,
|
|
sizeof(l_uState),
|
|
&l_uReplyLength,
|
|
&l_Ovr
|
|
);
|
|
|
|
LONG l_lResult = GetLastError();
|
|
|
|
TestCheck(
|
|
l_bResult,
|
|
"IOCTL_SMARTCARD_GET_STATE failed.\nReturned %8lxH (NTSTATUS %8lxH).\nExpected %8lxH (NTSTATUS %8lxH)",
|
|
l_lResult,
|
|
MapWinErrorToNtStatus(l_lResult),
|
|
ERROR_SUCCESS,
|
|
MapWinErrorToNtStatus(ERROR_SUCCESS)
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
if (l_bWaitForPresent) {
|
|
|
|
TestStart("%2d. %s", l_lTestNo++, INSERT_CARD);
|
|
|
|
l_bResult = GetOverlappedResult(
|
|
l_hReader,
|
|
&l_OvrWait,
|
|
&l_uReplyLength,
|
|
TRUE
|
|
);
|
|
|
|
l_lResult = GetLastError();
|
|
|
|
TestCheck(
|
|
l_bResult,
|
|
"Card insertion monitor failed.\nReturned %8lxH (NTSTATUS %8lxH).\nExpected %8lxH (NTSTATUS %8lxH)",
|
|
l_lResult,
|
|
MapWinErrorToNtStatus(l_lResult),
|
|
ERROR_SUCCESS,
|
|
MapWinErrorToNtStatus(ERROR_SUCCESS)
|
|
);
|
|
l_lResult = GetLastError();
|
|
|
|
TestEnd();
|
|
|
|
l_bWaitForPresent = FALSE;
|
|
continue;
|
|
}
|
|
|
|
if (l_bWaitForAbsent) {
|
|
|
|
if (l_bMustWait) {
|
|
|
|
TestStart("%2d. %s", l_lTestNo++, REMOVE_CARD);
|
|
|
|
} else {
|
|
|
|
TestStart("%2d. GetOverlappedResult", l_lTestNo++);
|
|
}
|
|
|
|
l_bResult = GetOverlappedResult(
|
|
l_hReader,
|
|
&l_OvrWait,
|
|
&l_uReplyLength,
|
|
l_bMustWait
|
|
);
|
|
|
|
if (l_bMustWait == FALSE) {
|
|
|
|
TestCheck(
|
|
l_bResult == FALSE,
|
|
"Smart card not removed"
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
if (TestFailed()) {
|
|
|
|
return;
|
|
}
|
|
|
|
} else {
|
|
|
|
l_lResult = GetLastError();
|
|
|
|
TestCheck(
|
|
l_bResult,
|
|
"Card removal monitor failed.\nReturned %8lxH (NTSTATUS %8lxH).\nExpected %8lxH (NTSTATUS %8lxH)",
|
|
l_lResult,
|
|
MapWinErrorToNtStatus(l_lResult),
|
|
ERROR_SUCCESS,
|
|
MapWinErrorToNtStatus(ERROR_SUCCESS)
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
if (TestFailed()) {
|
|
|
|
return;
|
|
}
|
|
l_bWaitForAbsent = FALSE;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
TestStart("%2d. Checking reader status", l_lTestNo++);
|
|
|
|
switch (l_uState) {
|
|
|
|
case SCARD_UNKNOWN:
|
|
TestCheck(FALSE, "Reader returned illegal state SCARD_UNKNOWN");
|
|
TestEnd();
|
|
return;
|
|
|
|
case SCARD_ABSENT:
|
|
TestCheck(
|
|
l_uStateExpected == SCARD_ABSENT,
|
|
"Invalid reader state.\nCurrent state = %d\nExpected state = %d",
|
|
l_uState,
|
|
l_uStateExpected
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
if (TestFailed()) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (l_bMustWait) {
|
|
|
|
return;
|
|
}
|
|
|
|
TestStart("%2d. IOCTL_SMARTCARD_IS_PRESENT", l_lTestNo++);
|
|
|
|
l_bResult = DeviceIoControl (
|
|
l_hReader,
|
|
IOCTL_SMARTCARD_IS_PRESENT,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&l_uReplyLength,
|
|
&l_OvrWait
|
|
);
|
|
|
|
TestCheck(
|
|
GetLastError() == ERROR_IO_PENDING,
|
|
"Monitor is supposed to return ERROR_IO_PENDING (%lxh)",
|
|
GetLastError()
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
if (TestFailed()) {
|
|
|
|
return;
|
|
}
|
|
|
|
l_bWaitForPresent = TRUE;
|
|
l_uStateExpected = SCARD_PRESENT;
|
|
break;
|
|
|
|
case SCARD_PRESENT:
|
|
case SCARD_SWALLOWED:
|
|
case SCARD_POWERED:
|
|
if (l_bPoweredDown) {
|
|
|
|
TestCheck(
|
|
l_uStateExpected <= SCARD_POWERED,
|
|
"Invalid reader state.\nCurrent state = %d\nExpected state <= %d",
|
|
l_uState,
|
|
l_uStateExpected
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
if (TestFailed()) {
|
|
|
|
return;
|
|
}
|
|
|
|
l_bMustWait = TRUE;
|
|
l_uStateExpected = SCARD_ABSENT;
|
|
break;
|
|
}
|
|
|
|
TestCheck(
|
|
l_uStateExpected > SCARD_ABSENT,
|
|
"Invalid reader state.\nCurrent state = %d\nExpected state <= %d",
|
|
l_uState,
|
|
l_uStateExpected
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
if (TestFailed()) {
|
|
|
|
return;
|
|
}
|
|
|
|
TestStart("%2d. IOCTL_SMARTCARD_IS_ABSENT", l_lTestNo++);
|
|
l_bResult = DeviceIoControl (
|
|
l_hReader,
|
|
IOCTL_SMARTCARD_IS_ABSENT,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&l_uReplyLength,
|
|
&l_OvrWait
|
|
);
|
|
|
|
l_lResult = GetLastError();
|
|
|
|
TestCheck(
|
|
l_bResult == FALSE,
|
|
"IOCTL_SMARTCARD_IS_ABSENT should fail.\nReturned %8lxH (NTSTATUS %8lxH).\nExpected %8lxH (NTSTATUS %8lxH)",
|
|
l_lResult,
|
|
MapWinErrorToNtStatus(l_lResult),
|
|
ERROR_IO_PENDING,
|
|
MapWinErrorToNtStatus(ERROR_IO_PENDING)
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
l_bWaitForAbsent = TRUE;
|
|
TestStart("%2d. Cold reset card", l_lTestNo++);
|
|
l_uStatus = in_CReader.ColdResetCard();
|
|
TEST_CHECK_SUCCESS("ColdReset", l_uStatus)
|
|
l_uStateExpected = SCARD_NEGOTIABLE;
|
|
|
|
TestEnd();
|
|
|
|
if (TestFailed()) {
|
|
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case SCARD_NEGOTIABLE:
|
|
TestCheck(
|
|
l_bPoweredDown == FALSE,
|
|
"Invalid reader state.\nCurrent state = %d\nExpected state = %d",
|
|
l_uState,
|
|
SCARD_PRESENT
|
|
);
|
|
|
|
TestCheck(
|
|
l_uStateExpected > SCARD_ABSENT,
|
|
"Invalid reader state.\nCurrent state = %d\nExpected state <= %d",
|
|
l_uState,
|
|
l_uStateExpected
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
if (TestFailed()) {
|
|
|
|
return;
|
|
}
|
|
|
|
TestStart("%2d. Set protocol to T0 | T1", l_lTestNo++);
|
|
|
|
l_uStatus = in_CReader.SetProtocol(
|
|
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1
|
|
);
|
|
|
|
TestCheck(
|
|
l_uStatus == ERROR_SUCCESS,
|
|
"Protocol selection failed with error %lxh",
|
|
GetLastError()
|
|
);
|
|
TestEnd();
|
|
|
|
if (TestFailed()) {
|
|
|
|
return;
|
|
}
|
|
l_uStateExpected = SCARD_SPECIFIC;
|
|
break;
|
|
|
|
case SCARD_SPECIFIC:
|
|
TestCheck(
|
|
l_bPoweredDown == FALSE,
|
|
"Invalid reader state.\nCurrent state = %d\nExpected state = %d",
|
|
l_uState,
|
|
SCARD_PRESENT
|
|
);
|
|
|
|
TestCheck(
|
|
l_uStateExpected > SCARD_ABSENT,
|
|
"Invalid reader state.\nReturned %d\nExpected < %d",
|
|
l_uState,
|
|
l_uStateExpected
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
if (TestFailed()) {
|
|
|
|
return;
|
|
}
|
|
|
|
TestStart("%2d. IOCTL_SMARTCARD_POWER (SCARD_POWER_DOWN)", l_lTestNo++);
|
|
l_uMinorIoctl = SCARD_POWER_DOWN;
|
|
SetLastError(0);
|
|
l_bResult = DeviceIoControl (
|
|
l_hReader,
|
|
IOCTL_SMARTCARD_POWER,
|
|
&l_uMinorIoctl,
|
|
sizeof(l_uMinorIoctl),
|
|
NULL,
|
|
0,
|
|
&l_uReplyLength,
|
|
&l_Ovr
|
|
);
|
|
|
|
if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
|
|
|
|
SetLastError(0);
|
|
|
|
l_bResult = GetOverlappedResult(
|
|
l_hReader,
|
|
&l_Ovr,
|
|
&l_uReplyLength,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
l_lResult = GetLastError();
|
|
|
|
TEST_CHECK_SUCCESS("IOCTL_SMARTCARD_POWER failed", l_lResult);
|
|
TestEnd();
|
|
|
|
l_uStateExpected = SCARD_PRESENT;
|
|
l_bPoweredDown = TRUE;
|
|
break;
|
|
|
|
default:
|
|
TestCheck(
|
|
FALSE,
|
|
"Reader returned invalid state %d",
|
|
l_uState
|
|
);
|
|
TestEnd();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
PowerManagementTest(
|
|
CReader &in_CReader,
|
|
ULONG in_uWaitTime
|
|
)
|
|
{
|
|
LONG l_lResult;
|
|
ULONG l_uState, l_uPrevState, l_uRepeat;
|
|
ULONG l_uDuration = 30;
|
|
|
|
if (in_uWaitTime > 30 && in_uWaitTime < 120) {
|
|
|
|
l_uDuration = in_uWaitTime;
|
|
}
|
|
|
|
LogMessage("=============================");
|
|
LogMessage("Part E: Power Management Test");
|
|
LogMessage("=============================");
|
|
|
|
LogMessage("Note: Each test cycle takes %ld seconds!", l_uDuration);
|
|
LogMessage(" << %s", REMOVE_CARD);
|
|
in_CReader.WaitForCardRemoval();
|
|
|
|
LogMessage("Test 1: DO NOT INSERT smart card during hibernate mode");
|
|
TestStart("Card out / card out - Hibernate now");
|
|
|
|
l_lResult = in_CReader.StartWaitForCardInsertion();
|
|
l_lResult = in_CReader.GetState(&l_uPrevState);
|
|
|
|
for (l_uRepeat = 0; l_uRepeat < l_uDuration; l_uRepeat++) {
|
|
|
|
l_lResult = in_CReader.GetState(&l_uState);
|
|
|
|
LONG l_uGoal = clock() + CLOCKS_PER_SEC;
|
|
while(l_uGoal > clock())
|
|
;
|
|
printf("\x08\x08%2ld", l_uDuration - l_uRepeat);
|
|
}
|
|
printf("\x08\x08 ");
|
|
|
|
l_lResult = in_CReader.FinishWaitForCard(FALSE);
|
|
|
|
TestCheck(
|
|
l_lResult == ERROR_IO_INCOMPLETE,
|
|
"GetOverlappedResult failed\nReturned %8lx\nExpected %8lx",
|
|
l_lResult,
|
|
ERROR_IO_INCOMPLETE
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
TestStart("%s", INSERT_CARD);
|
|
l_lResult = in_CReader.FinishWaitForCard(TRUE);
|
|
TEST_CHECK_SUCCESS("Reader failed card insertion", l_lResult);
|
|
TestEnd();
|
|
|
|
TestStart("Checking reader status");
|
|
l_lResult = in_CReader.GetState(&l_uState);
|
|
TEST_CHECK_SUCCESS("Reader failed IOCTL_SMARTCARD_GET_STATE", l_lResult);
|
|
|
|
TestCheck(
|
|
l_uState > SCARD_ABSENT,
|
|
"Invalid reader state.\nReturned %d\nExpected > %d",
|
|
l_uState,
|
|
SCARD_ABSENT
|
|
);
|
|
TestEnd();
|
|
|
|
//
|
|
// Test 2
|
|
//
|
|
|
|
LogMessage("Test 2: REMOVE smart card DURING hibernate mode");
|
|
TestStart("Card in / card out - Hibernate now");
|
|
|
|
l_lResult = in_CReader.StartWaitForCardRemoval();
|
|
l_lResult = in_CReader.GetState(&l_uPrevState);
|
|
|
|
for (l_uRepeat = 0; l_uRepeat < l_uDuration; l_uRepeat++) {
|
|
|
|
l_lResult = in_CReader.GetState(&l_uState);
|
|
|
|
LONG l_uGoal = clock() + CLOCKS_PER_SEC;
|
|
while(l_uGoal > clock())
|
|
;
|
|
printf("\x08\x08%2ld", l_uDuration - l_uRepeat);
|
|
}
|
|
printf("\x08\x08 ");
|
|
|
|
l_lResult = in_CReader.FinishWaitForCard(FALSE);
|
|
|
|
TEST_CHECK_SUCCESS(
|
|
"GetOverlappedResult failed",
|
|
l_lResult
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
TestStart("Checking reader status");
|
|
l_lResult = in_CReader.GetState(&l_uState);
|
|
TEST_CHECK_SUCCESS("Reader failed IOCTL_SMARTCARD_GET_STATE", l_lResult);
|
|
|
|
TestCheck(
|
|
l_uState == SCARD_ABSENT,
|
|
"Invalid reader state.\nReturned %d\nExpected %d",
|
|
l_uState,
|
|
SCARD_ABSENT
|
|
);
|
|
TestEnd();
|
|
|
|
LogMessage(" >> %s", INSERT_CARD);
|
|
in_CReader.WaitForCardInsertion();
|
|
|
|
//
|
|
// Test 3
|
|
//
|
|
LogMessage("Test 3: DO NOT REMOVE smart card during hibernate mode");
|
|
TestStart("Card in / card in - Hibernate now");
|
|
|
|
l_lResult = in_CReader.StartWaitForCardRemoval();
|
|
l_lResult = in_CReader.GetState(&l_uPrevState);
|
|
|
|
for (l_uRepeat = 0; l_uRepeat < l_uDuration; l_uRepeat++) {
|
|
|
|
l_lResult = in_CReader.GetState(&l_uState);
|
|
|
|
LONG l_uGoal = clock() + CLOCKS_PER_SEC;
|
|
while(l_uGoal > clock())
|
|
;
|
|
printf("\x08\x08%2ld", l_uDuration - l_uRepeat);
|
|
}
|
|
printf("\x08\x08 ");
|
|
|
|
l_lResult = in_CReader.FinishWaitForCard(FALSE);
|
|
|
|
TEST_CHECK_SUCCESS(
|
|
"GetOverlappedResult failed",
|
|
l_lResult
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
TestStart("Checking reader status");
|
|
l_lResult = in_CReader.GetState(&l_uState);
|
|
TEST_CHECK_SUCCESS("Reader failed IOCTL_SMARTCARD_GET_STATE", l_lResult);
|
|
|
|
TestCheck(
|
|
l_uState >= SCARD_PRESENT,
|
|
"Invalid reader state.\nReturned %d\nExpected > %d",
|
|
l_uState,
|
|
SCARD_ABSENT
|
|
);
|
|
TestEnd();
|
|
|
|
LogMessage(" << %s", REMOVE_CARD);
|
|
in_CReader.WaitForCardRemoval();
|
|
|
|
//
|
|
// Test 4
|
|
//
|
|
|
|
LogMessage("Test 4: INSERT smart card DURING hibernate mode");
|
|
TestStart("Card out / card in - Hibernate now");
|
|
|
|
l_lResult = in_CReader.StartWaitForCardInsertion();
|
|
l_lResult = in_CReader.GetState(&l_uPrevState);
|
|
|
|
for (l_uRepeat = 0; l_uRepeat < l_uDuration; l_uRepeat++) {
|
|
|
|
l_lResult = in_CReader.GetState(&l_uState);
|
|
|
|
LONG l_uGoal = clock() + CLOCKS_PER_SEC;
|
|
while(l_uGoal > clock())
|
|
;
|
|
printf("\x08\x08%2ld", l_uDuration - l_uRepeat);
|
|
}
|
|
printf("\x08\x08 ");
|
|
l_lResult = in_CReader.FinishWaitForCard(FALSE);
|
|
|
|
TEST_CHECK_SUCCESS(
|
|
"GetOverlappedResult failed",
|
|
l_lResult
|
|
);
|
|
|
|
TestEnd();
|
|
|
|
TestStart("Checking reader status");
|
|
l_lResult = in_CReader.GetState(&l_uState);
|
|
TEST_CHECK_SUCCESS("Reader failed IOCTL_SMARTCARD_GET_STATE", l_lResult);
|
|
|
|
TestCheck(
|
|
l_uState >= SCARD_PRESENT,
|
|
"Invalid reader state.\nReturned %d\nExpected > %d",
|
|
l_uState,
|
|
SCARD_ABSENT
|
|
);
|
|
TestEnd();
|
|
}
|
|
|
|
class CArgv {
|
|
|
|
int m_iArgc;
|
|
char **m_pArgv;
|
|
BOOL *m_pfRef;
|
|
|
|
public:
|
|
|
|
CArgv(int in_iArgc, char **in_pArgv);
|
|
|
|
int OptionExist(PCHAR);
|
|
|
|
PCHAR ParameterExist(PCHAR);
|
|
|
|
PCHAR CheckParameters(CString);
|
|
|
|
PCHAR CArgv::ParameterUnused(void);
|
|
};
|
|
|
|
|
|
CArgv::CArgv(
|
|
int in_iArgc,
|
|
char **in_pArgv
|
|
)
|
|
{
|
|
m_iArgc = in_iArgc;
|
|
m_pArgv = in_pArgv;
|
|
m_pfRef = new BOOL[in_iArgc];
|
|
memset(m_pfRef, 0, sizeof(BOOL) * in_iArgc);
|
|
}
|
|
|
|
CArgv::OptionExist(
|
|
PCHAR in_pchParameter
|
|
)
|
|
{
|
|
for (int i = 0; i < m_iArgc; i++) {
|
|
|
|
if (m_pArgv[i][0] == '-' || m_pArgv[i][0] == '/') {
|
|
|
|
int j = 1;
|
|
|
|
while (m_pArgv[i][j] && m_pArgv[i][j] != ' ') {
|
|
|
|
if (strncmp(m_pArgv[i] + j, in_pchParameter, strlen(m_pArgv[i] + j)) == 0) {
|
|
|
|
m_pfRef[i] = TRUE;
|
|
return i;
|
|
}
|
|
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
PCHAR
|
|
CArgv::ParameterExist(
|
|
PCHAR in_pchParameter
|
|
)
|
|
{
|
|
if (int i = OptionExist(in_pchParameter)) {
|
|
|
|
m_pfRef[i + 1] = TRUE;
|
|
return m_pArgv[i + 1];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PCHAR
|
|
CArgv::CheckParameters(
|
|
CString in_CParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Checks if the command line includes in invalid/unknown parameter
|
|
|
|
--*/
|
|
{
|
|
int i, l_iPos;
|
|
|
|
for (i = 1; i < m_iArgc; i++) {
|
|
|
|
if ((l_iPos = in_CParameters.Find(m_pArgv[i])) == -1) {
|
|
|
|
return m_pArgv[i];
|
|
}
|
|
|
|
if (l_iPos + 3 < in_CParameters.GetLength() &&
|
|
in_CParameters[l_iPos + 3] == '*') {
|
|
|
|
// skip the next parameter
|
|
i += 1;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
PCHAR
|
|
CArgv::ParameterUnused(
|
|
void
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for (i = 1; i < m_iArgc; i++) {
|
|
|
|
if (m_pfRef[i] == FALSE) {
|
|
|
|
return m_pArgv[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
CString &
|
|
GetOperatingSystem(
|
|
void
|
|
)
|
|
{
|
|
static CString l_COperatingSystem;
|
|
OSVERSIONINFO VersionInformation;
|
|
|
|
if (l_COperatingSystem.GetLength() == 0) {
|
|
|
|
VersionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
if (GetVersionEx(&VersionInformation) == FALSE) {
|
|
|
|
l_COperatingSystem += "Unknown";
|
|
|
|
} else {
|
|
|
|
if (VersionInformation.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
|
|
|
|
if (VersionInformation.dwMinorVersion == 0) {
|
|
|
|
l_COperatingSystem += OS_WIN95;
|
|
|
|
} else {
|
|
|
|
l_COperatingSystem += OS_WIN98;
|
|
}
|
|
|
|
} else if (VersionInformation.dwPlatformId == VER_PLATFORM_WIN32_NT) {
|
|
|
|
if (VersionInformation.dwMajorVersion <= 4) {
|
|
|
|
l_COperatingSystem += OS_WINNT4;
|
|
|
|
} else {
|
|
|
|
l_COperatingSystem += OS_WINNT5;
|
|
}
|
|
|
|
} else {
|
|
|
|
l_COperatingSystem += "Unknown";
|
|
}
|
|
}
|
|
}
|
|
|
|
return l_COperatingSystem;
|
|
}
|
|
|
|
CString &
|
|
SelectReader(
|
|
void
|
|
)
|
|
{
|
|
CReaderList l_CReaderList;
|
|
ULONG l_uIndex, l_uReader;
|
|
ULONG l_uNumReaders = l_CReaderList.GetNumReaders();
|
|
static CString l_CEmpty("");
|
|
|
|
if (l_uNumReaders == 0) {
|
|
|
|
return l_CEmpty;
|
|
}
|
|
|
|
if (l_uNumReaders == 1) {
|
|
|
|
return l_CReaderList.GetDeviceName(0);
|
|
}
|
|
|
|
CString l_CLetter;
|
|
|
|
printf("\n");
|
|
printf(" Vendor IfdType Type\n");
|
|
printf(" -----------------------------------------------------\n");
|
|
|
|
for (l_uIndex = 0; l_uIndex < l_uNumReaders; l_uIndex++) {
|
|
|
|
INT l_iLetterPos;
|
|
INT l_iLength = l_CReaderList.GetVendorName(l_uIndex).GetLength();
|
|
CString l_CVendorName = l_CReaderList.GetVendorName(l_uIndex);
|
|
|
|
for (l_iLetterPos = 0;
|
|
l_iLetterPos < l_CVendorName.GetLength();
|
|
l_iLetterPos++) {
|
|
|
|
CHAR l_chLetter = l_CVendorName[l_iLetterPos];
|
|
|
|
if (l_chLetter == ' ' || l_chLetter == 'x') {
|
|
|
|
continue;
|
|
}
|
|
|
|
if (l_CLetter.Find(l_chLetter) == -1) {
|
|
|
|
l_CLetter += l_chLetter;
|
|
break;
|
|
}
|
|
}
|
|
if (l_iLetterPos >= l_iLength) {
|
|
|
|
l_CVendorName += (CHAR) (l_uIndex + '0') ;
|
|
l_iLetterPos = l_iLength;
|
|
}
|
|
|
|
printf(
|
|
" %s[%c]%-*s %-20s %8s\n",
|
|
(LPCSTR) l_CVendorName.Left(l_iLetterPos),
|
|
l_CVendorName[l_iLetterPos],
|
|
20 - l_iLetterPos,
|
|
l_CVendorName.Right(l_iLength - l_iLetterPos - 1),
|
|
(LPCSTR) l_CReaderList.GetIfdType(l_uIndex),
|
|
(LPCSTR) l_CReaderList.GetPnPType(l_uIndex)
|
|
);
|
|
}
|
|
|
|
putchar('\n');
|
|
do {
|
|
|
|
printf("\rSelect reader: \010");
|
|
|
|
CHAR l_chInput = (CHAR) _getche();
|
|
if (l_chInput == 3) {
|
|
|
|
exit(-1);
|
|
}
|
|
|
|
l_uReader = l_CLetter.Find(l_chInput);
|
|
|
|
} while(l_uReader == -1);
|
|
|
|
printf("\n");
|
|
|
|
return l_CReaderList.GetDeviceName(l_uReader);
|
|
}
|
|
|
|
CString
|
|
SelectReader(
|
|
CString &in_CVendorName
|
|
)
|
|
{
|
|
CReaderList l_CReaderList;
|
|
ULONG l_uIndex;
|
|
ULONG l_uNumReaders = l_CReaderList.GetNumReaders();
|
|
CString l_CVendorName = in_CVendorName;
|
|
|
|
l_CVendorName.MakeLower();
|
|
|
|
for (l_uIndex = 0; l_uIndex < l_uNumReaders; l_uIndex++) {
|
|
|
|
CString l_CVendorListName = l_CReaderList.GetVendorName(l_uIndex);
|
|
l_CVendorListName.MakeLower();
|
|
|
|
if (l_CVendorListName.Find(l_CVendorName) != -1) {
|
|
|
|
return l_CReaderList.GetDeviceName(l_uIndex);
|
|
}
|
|
}
|
|
|
|
return CString("");
|
|
}
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
//
|
|
// StopService()
|
|
//
|
|
// PURPOSE : This function attempts to stop a service. It will fail
|
|
// the service has any dependent services.
|
|
// It also allows a timeout
|
|
// value to be passed, to prevent a scenario in which a
|
|
// service shutdown hangs, and in turn the application
|
|
// stopping the service hangs.
|
|
//
|
|
// PARAMETERS: hSCM - open handle to the service control manager
|
|
// hService - open handle to the service to be stopped
|
|
// dwTimeout - maximum time (in milliseconds) to wait
|
|
// for the service and its dependencies to stop
|
|
//
|
|
// RETURN VALUE: TRUE if the service is successfully stopped
|
|
//
|
|
//**********************************************************************
|
|
|
|
BOOL StopService( SC_HANDLE hSCM, SC_HANDLE hService,
|
|
DWORD dwTimeout ) {
|
|
|
|
SERVICE_STATUS ss;
|
|
DWORD dwStartTime = GetTickCount();
|
|
|
|
// Make sure the service is not already stopped
|
|
if ( !QueryServiceStatus( hService, &ss ) )
|
|
return FALSE;
|
|
|
|
if ( ss.dwCurrentState == SERVICE_STOPPED )
|
|
return FALSE;
|
|
|
|
// If a stop is pending, just wait for it
|
|
while ( ss.dwCurrentState == SERVICE_STOP_PENDING ) {
|
|
|
|
Sleep( 5000 );
|
|
if ( !QueryServiceStatus( hService, &ss ) )
|
|
return FALSE;
|
|
|
|
if ( ss.dwCurrentState == SERVICE_STOPPED )
|
|
return FALSE;
|
|
|
|
if ( GetTickCount() - dwStartTime > dwTimeout )
|
|
return FALSE;
|
|
}
|
|
|
|
// Send a stop code to service
|
|
if ( !ControlService( hService, SERVICE_CONTROL_STOP, &ss ) )
|
|
return FALSE;
|
|
|
|
// Wait for the service to stop
|
|
while ( ss.dwCurrentState != SERVICE_STOPPED ) {
|
|
|
|
Sleep( 5000 );
|
|
if ( !QueryServiceStatus( hService, &ss ) )
|
|
return FALSE;
|
|
|
|
if ( ss.dwCurrentState == SERVICE_STOPPED )
|
|
break;
|
|
|
|
if ( GetTickCount() - dwStartTime > dwTimeout )
|
|
return FALSE;
|
|
}
|
|
|
|
// Return success
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
__cdecl
|
|
main(
|
|
int argc,
|
|
char* argv[]
|
|
)
|
|
{
|
|
CArgv l_CArgv(argc, argv);
|
|
BOOL l_bSuccess, l_fInvalidParameter = FALSE;
|
|
BOOL l_bStoppedScardsvr = FALSE; // true==> we succesfully stoped scardsvr service
|
|
SC_HANDLE l_hSCM = NULL;
|
|
SC_HANDLE l_hService = NULL;
|
|
|
|
LogMessage("Smart Card Reader Test Suite");
|
|
LogMessage("Version 2.0.5");
|
|
LogMessage("Copyright(c) Microsoft Corporation 1997 - 1999");
|
|
|
|
if(PCHAR l_pchArgv = l_CArgv.CheckParameters("-d -e -h -m -r * -sa -sb -sc -sd -se -t * -v * -w *")) {
|
|
|
|
LogMessage("Invalid Parameter '%s'", l_pchArgv);
|
|
l_fInvalidParameter = TRUE;
|
|
}
|
|
|
|
if (l_fInvalidParameter ||
|
|
|
|
l_CArgv.OptionExist("h")) {
|
|
|
|
LogMessage("IfdTest [-d] [-m] [-r name] [-sa] [-sb] [-sc] [-sd] [-se] [-ss] [-w sec] [-t test] [-v name]\n");
|
|
LogMessage(" -d dumps all i/o");
|
|
LogMessage(" -e ends (stops) scardsvr service");
|
|
LogMessage(" -m manual test");
|
|
LogMessage(" -r name opens reader using device name");
|
|
LogMessage(" -sa skips card monitor test");
|
|
LogMessage(" -sb skips general reader test");
|
|
LogMessage(" -sc skips resource manager simulation");
|
|
LogMessage(" -sd skips card tests");
|
|
LogMessage(" -se skips power management tests");
|
|
LogMessage(" -v name opens reader using vendor name");
|
|
LogMessage(" -t test runs only specific card test in part d");
|
|
LogMessage(" -w sec runs power management test using specified waiting time");
|
|
exit(-1);
|
|
}
|
|
|
|
static CReader l_CReader;
|
|
CString l_CDeviceName;
|
|
|
|
//
|
|
// sandysp 5/9/01: stop scardsvr service because open will fail if it's running
|
|
//
|
|
|
|
if (l_CArgv.OptionExist("e")) {
|
|
l_hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT );
|
|
if (l_hSCM) {
|
|
|
|
// Open the specified service
|
|
l_hService = OpenService( l_hSCM,
|
|
"scardsvr",
|
|
SERVICE_STOP | SERVICE_START | SERVICE_QUERY_STATUS );
|
|
if (l_hService) {
|
|
// Try to stop the service, specifying a 30 second timeout
|
|
l_bStoppedScardsvr = StopService( l_hSCM, l_hService, 30000 ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (PCHAR l_pchReader = l_CArgv.ParameterExist("r")) {
|
|
|
|
l_CDeviceName = CString("\\\\.\\") + CString(l_pchReader);
|
|
|
|
} else if (PCHAR l_pchVendorName = l_CArgv.ParameterExist("v")) {
|
|
|
|
CReaderList l_CReaderList;
|
|
l_CDeviceName = SelectReader(CString(l_pchVendorName));
|
|
|
|
} else {
|
|
|
|
CReaderList l_CReaderList;
|
|
l_CDeviceName = SelectReader();
|
|
}
|
|
|
|
if (l_CDeviceName == "") {
|
|
|
|
LogMessage("No reader found");
|
|
exit (-1);
|
|
}
|
|
|
|
l_bSuccess = l_CReader.Open(l_CDeviceName);
|
|
|
|
LogMessage(".");
|
|
if (l_bSuccess == FALSE) {
|
|
|
|
LogMessage("Can't open smart card reader");
|
|
exit (-1);
|
|
}
|
|
|
|
if (l_CArgv.OptionExist("d")) {
|
|
|
|
l_CReader.SetDump(TRUE);
|
|
}
|
|
|
|
void ManualTest(CReader &in_CReader);
|
|
if (l_CArgv.OptionExist("m")) {
|
|
|
|
ManualTest(l_CReader);
|
|
}
|
|
|
|
CCardProvider l_CCardProvider;
|
|
|
|
LogOpen("ifdtest");
|
|
|
|
time_t l_osBinaryTime;
|
|
time( &l_osBinaryTime );
|
|
CTime l_CTime( l_osBinaryTime );
|
|
|
|
LogMessage("Vendor: %s", l_CReader.GetVendorName());
|
|
LogMessage("Reader: %s", l_CReader.GetIfdType());
|
|
LogMessage(
|
|
"Date: %d/%02d/%02d",
|
|
l_CTime.GetMonth(),
|
|
l_CTime.GetDay(),
|
|
l_CTime.GetYear()
|
|
);
|
|
LogMessage(
|
|
"Time: %d:%02d",
|
|
l_CTime.GetHour(),
|
|
l_CTime.GetMinute()
|
|
);
|
|
LogMessage("OS: %s", (LPCSTR) GetOperatingSystem());
|
|
|
|
//
|
|
// Check if the reader properly supports
|
|
// card insertion and removal
|
|
//
|
|
if (l_CArgv.OptionExist("sa")) {
|
|
|
|
LogMessage("=================================");
|
|
LogMessage("Part A: Card monitor test skipped");
|
|
LogMessage("=================================");
|
|
|
|
} else {
|
|
|
|
CheckCardMonitor(l_CReader);
|
|
}
|
|
|
|
if (l_CArgv.OptionExist("sb")) {
|
|
|
|
LogMessage("===========================");
|
|
LogMessage("Part B: Reader test skipped");
|
|
LogMessage("===========================");
|
|
|
|
} else {
|
|
|
|
CheckReader(l_CReader);
|
|
}
|
|
|
|
if (l_CArgv.OptionExist("sc")) {
|
|
|
|
LogMessage("===========================================");
|
|
LogMessage("Part C: Resource Manager Simulation skipped");
|
|
LogMessage("===========================================");
|
|
|
|
} else {
|
|
|
|
// Check res manager behavior
|
|
SimulateResMngr(l_CReader);
|
|
}
|
|
|
|
if (l_CArgv.OptionExist("sd")) {
|
|
|
|
LogMessage("========================================");
|
|
LogMessage("Part D: Smart Card Provider Test skipped");
|
|
LogMessage("========================================");
|
|
|
|
} else {
|
|
|
|
ULONG l_uTestNo = 0;
|
|
PCHAR l_pchTestNo;
|
|
|
|
if (l_pchTestNo = l_CArgv.ParameterExist("t")) {
|
|
|
|
// The user wants us to run only one test
|
|
l_uTestNo = atoi(l_pchTestNo);
|
|
}
|
|
|
|
while (l_CCardProvider.CardsUntested()) {
|
|
|
|
LogMessage("================================");
|
|
LogMessage("Part D: Smart Card Provider Test");
|
|
LogMessage("================================");
|
|
|
|
LogMessage("Insert any of the following PC/SC Compliance Test Cards:");
|
|
l_CCardProvider.ListUntestedCards();
|
|
|
|
LogMessage(" >> %s", INSERT_CARD);
|
|
if (l_CReader.WaitForCardInsertion() != ERROR_SUCCESS) {
|
|
|
|
LogMessage("Reader failed card insertion monitor");
|
|
return -1;
|
|
}
|
|
|
|
// Reset the card
|
|
if (l_CReader.ColdResetCard() != ERROR_SUCCESS) {
|
|
|
|
LogMessage("Unable to reset smart card");
|
|
|
|
} else {
|
|
|
|
// Try to run tests with this card
|
|
l_CCardProvider.CardTest(l_CReader, l_uTestNo);
|
|
|
|
if (l_uTestNo != 0) {
|
|
|
|
// Quit the program if we only run one test.
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
LogMessage(" << %s", REMOVE_CARD);
|
|
if (l_CReader.WaitForCardRemoval() != ERROR_SUCCESS) {
|
|
|
|
LogMessage("Reader failed card removal monitor");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GetOperatingSystem() == OS_WINNT5) {
|
|
|
|
if (l_CArgv.OptionExist("se")) {
|
|
|
|
LogMessage("=====================================");
|
|
LogMessage("Part E: Power Management Test skipped");
|
|
LogMessage("=====================================");
|
|
|
|
} else {
|
|
|
|
ULONG l_uWaitTime = 0;
|
|
|
|
if (PCHAR l_pchWaitTime = l_CArgv.ParameterExist("w")) {
|
|
|
|
// The user wants us to run only one test
|
|
l_uWaitTime = atoi(l_pchWaitTime);
|
|
}
|
|
|
|
PowerManagementTest(l_CReader, l_uWaitTime);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Sandysp 5/9/01: restart smart card reader service if we stopped it
|
|
//
|
|
if (l_bStoppedScardsvr) {
|
|
StartService( l_hService, 0, NULL );
|
|
}
|
|
if ( l_hService )
|
|
CloseServiceHandle( l_hService );
|
|
|
|
if ( l_hSCM )
|
|
CloseServiceHandle( l_hSCM );
|
|
|
|
|
|
LogMessage("Reader %s the test", (ReaderFailed() ? "failed" : "passed"));
|
|
return 0;
|
|
} |