998 lines
32 KiB
C++
998 lines
32 KiB
C++
#include "smartcard.h"
|
|
#include "usbreader.h"
|
|
|
|
#pragma PAGEDCODE
|
|
CSmartCard::CSmartCard()
|
|
{
|
|
debug = kernel->createDebug();
|
|
memory = kernel->createMemory();
|
|
irp = kernel->createIrp();
|
|
lock = kernel->createLock();
|
|
system = kernel->createSystem();
|
|
if(lock) lock->initializeSpinLock(&CardLock);
|
|
poolingIrp = NULL;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
CSmartCard::~CSmartCard()
|
|
{
|
|
TRACE("Destroing SmartCard...\n");
|
|
if(memory) memory->dispose();
|
|
if(irp) irp->dispose();
|
|
if(lock) lock->dispose();
|
|
if(system) system->dispose();
|
|
if(debug) debug->dispose();
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
BOOL CSmartCard::smartCardConnect(CUSBReader* reader)
|
|
{
|
|
TRACE(" Connecting smartcard system...\n");
|
|
if(reader)
|
|
{ // Check if smartCard was already initialized...
|
|
if(!reader->isSmartCardInitialized())
|
|
{
|
|
PSMARTCARD_EXTENSION Smartcard;
|
|
NTSTATUS Status;
|
|
USHORT Len;
|
|
if(isWin98())
|
|
{// At this time string should be already initialized
|
|
Status = SmartcardCreateLink(&DosDeviceName,&reader->getDeviceName()->m_String);
|
|
TRACE("Gemplus USB reader registered with name %ws, status %X\n",DosDeviceName.Buffer,Status);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
TRACE("#### Failed to create Device link! Status %X\n", Status);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE("Registering reader interface at system...\n");
|
|
if(!reader->registerDeviceInterface(&GUID_CLASS_SMARTCARD))
|
|
{
|
|
TRACE("#### Failed to register device interface...\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
Smartcard = reader->getCardExtention();
|
|
TRACE("*** Reader reports Smartcard 0x%x\n",Smartcard);
|
|
this->reader = reader;
|
|
|
|
memory->zero(Smartcard,sizeof(SMARTCARD_EXTENSION));
|
|
|
|
Smartcard->ReaderExtension = (PREADER_EXTENSION)reader;
|
|
|
|
Smartcard->Version = SMCLIB_VERSION;
|
|
|
|
// Read the name from reader object!!!!!!!
|
|
Len = MAXIMUM_ATTR_STRING_LENGTH;
|
|
reader->getVendorName(Smartcard->VendorAttr.VendorName.Buffer,&Len);
|
|
Smartcard->VendorAttr.VendorName.Length = Len;
|
|
TRACE(" VENDOR NAME - %s\n",Smartcard->VendorAttr.VendorName.Buffer);
|
|
|
|
Len = MAXIMUM_ATTR_STRING_LENGTH;
|
|
reader->getDeviceType(Smartcard->VendorAttr.IfdType.Buffer,&Len);
|
|
Smartcard->VendorAttr.IfdType.Length = Len;
|
|
TRACE(" DEVICE TYPE - %s\n",Smartcard->VendorAttr.IfdType.Buffer);
|
|
|
|
// Clk frequency in KHz encoded as little endian integer
|
|
Smartcard->ReaderCapabilities.CLKFrequency.Default = SC_IFD_DEFAULT_CLK_FREQUENCY;
|
|
Smartcard->ReaderCapabilities.CLKFrequency.Max = SC_IFD_MAXIMUM_CLK_FREQUENCY;
|
|
|
|
Smartcard->ReaderCapabilities.DataRate.Default = SC_IFD_DEFAULT_DATA_RATE;
|
|
Smartcard->ReaderCapabilities.DataRate.Max = SC_IFD_MAXIMUM_DATA_RATE;
|
|
|
|
// reader could support higher data rates
|
|
Smartcard->ReaderCapabilities.DataRatesSupported.List = dataRatesSupported;
|
|
Smartcard->ReaderCapabilities.DataRatesSupported.Entries =
|
|
sizeof(dataRatesSupported) / sizeof(dataRatesSupported[0]);
|
|
|
|
Smartcard->VendorAttr.IfdVersion.BuildNumber = 0;
|
|
|
|
// store firmware revision in ifd version
|
|
Smartcard->VendorAttr.IfdVersion.VersionMajor = 0x01;
|
|
Smartcard->VendorAttr.IfdVersion.VersionMinor = 0x00;
|
|
Smartcard->VendorAttr.IfdSerialNo.Length = 0;
|
|
Smartcard->ReaderCapabilities.MaxIFSD = SC_IFD_MAXIMUM_IFSD;
|
|
|
|
// Now setup information in our deviceExtension
|
|
Smartcard->ReaderCapabilities.CurrentState = (ULONG) SCARD_UNKNOWN;
|
|
|
|
// TODO: get reader type from reader object!!!!!!!!!!!!!!
|
|
// Type of Reader - USB
|
|
Smartcard->ReaderCapabilities.ReaderType = SCARD_READER_TYPE_USB;
|
|
|
|
// This reader supports T=0 and T=1
|
|
Smartcard->ReaderCapabilities.SupportedProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
|
|
Smartcard->ReaderCapabilities.MechProperties = 0;
|
|
|
|
Smartcard->SmartcardRequest.BufferSize = MIN_BUFFER_SIZE;
|
|
Smartcard->SmartcardReply.BufferSize = MIN_BUFFER_SIZE;
|
|
Status = SmartcardInitialize(Smartcard);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
// It looks like SmartcardInitialize() resets DeviceObject field,
|
|
// So, we have to do it after the call.
|
|
Smartcard->VendorAttr.UnitNo = reader->getDeviceNumber();
|
|
Smartcard->OsData->DeviceObject = reader->getSystemDeviceObject();
|
|
|
|
TRACE(" Registered device %d with DeviceObject 0x%x\n",Smartcard->VendorAttr.UnitNo,Smartcard->OsData->DeviceObject);
|
|
|
|
// (note: RDF_CARD_EJECT and RDF_READER_SWALLOW are not supported)
|
|
// Well... Actually I could define methods at smartcard object as
|
|
// statics and make a link to them. It will work.
|
|
// The reason I created extenal C linkage functions - to
|
|
// separate smartcard system and our driver.
|
|
// I think driver actually may not care about smartcard extention and all
|
|
// settings required by smclib can be done inside our C wrappers and not
|
|
// inside driver objects...
|
|
Smartcard->ReaderFunction[RDF_TRANSMIT] = smartCard_Transmit;
|
|
Smartcard->ReaderFunction[RDF_SET_PROTOCOL] = smartCard_SetProtocol;
|
|
Smartcard->ReaderFunction[RDF_CARD_POWER] = smartCard_Power;
|
|
Smartcard->ReaderFunction[RDF_CARD_TRACKING] = smartCard_Tracking;
|
|
Smartcard->ReaderFunction[RDF_IOCTL_VENDOR] = smartCard_VendorIoctl;
|
|
|
|
reader->setSmartCardInitialized(TRUE);
|
|
TRACE(" ***** SmartCard system was initialized correctly! *****\n\n");
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRACE(" ##### FAILED to initialize smartcard system...\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE(" ##### Smartcard system already active...\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE(" ###### Invalid reader object...\n");
|
|
}
|
|
return FALSE;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
BOOL CSmartCard::smartCardStart()
|
|
{
|
|
return TRUE;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
VOID CSmartCard::smartCardDisconnect()
|
|
{
|
|
TRACE(" Disconnecting smartcard system...\n");
|
|
if(reader)
|
|
{
|
|
PSMARTCARD_EXTENSION Smartcard;
|
|
|
|
Smartcard = reader->getCardExtention();
|
|
if(Smartcard->OsData && Smartcard->OsData->NotificationIrp)
|
|
{
|
|
KIRQL keIrql;
|
|
|
|
PIRP poolingIrp = Smartcard->OsData->NotificationIrp;
|
|
TRACE("====== COMPLETING NOTIFICATION IRP %8.8lX \n\n",poolingIrp);
|
|
// Guard by spin lock!
|
|
lock->acquireSpinLock(&Smartcard->OsData->SpinLock, &keIrql);
|
|
Smartcard->OsData->NotificationIrp = NULL;
|
|
lock->releaseSpinLock(&Smartcard->OsData->SpinLock, keIrql);
|
|
|
|
lock->acquireCancelSpinLock(&keIrql);
|
|
irp->setCancelRoutine(poolingIrp, NULL);
|
|
lock->releaseCancelSpinLock(keIrql);
|
|
|
|
if (poolingIrp->Cancel) poolingIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
else poolingIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
poolingIrp->IoStatus.Information = 0;
|
|
irp->completeRequest(poolingIrp, IO_NO_INCREMENT);
|
|
}
|
|
//Unregister the device
|
|
if(isWin98())
|
|
{
|
|
TRACE("****** Removing device object name %ws \n",DosDeviceName.Buffer);
|
|
system->deleteSymbolicLink(&DosDeviceName);
|
|
}
|
|
else
|
|
{
|
|
TRACE("Setting reader interface state to FALSE...\n");
|
|
reader->unregisterDeviceInterface(reader->getDeviceInterfaceName());
|
|
}
|
|
|
|
|
|
SmartcardExit(Smartcard);
|
|
Smartcard->ReaderExtension = NULL;
|
|
reader->setSmartCardInitialized(FALSE);
|
|
|
|
reader = NULL;
|
|
TRACE(" SmartCard system was disconnected...\n");
|
|
}
|
|
};
|
|
|
|
// Declare Smclib system callbacks...
|
|
#pragma LOCKEDCODE
|
|
NTSTATUS smartCard_Transmit(PSMARTCARD_EXTENSION SmartcardExtension)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;;
|
|
BOOL Read = FALSE;
|
|
CUSBReader* Reader = (CUSBReader*) SmartcardExtension->ReaderExtension;
|
|
PSCARD_CARD_CAPABILITIES cardCapabilities = &SmartcardExtension->CardCapabilities;
|
|
ULONG selectedProtocol = cardCapabilities->Protocol.Selected;
|
|
ULONG protocolRequested = ((PSCARD_IO_REQUEST) SmartcardExtension->OsData->CurrentIrp->AssociatedIrp.SystemBuffer)->dwProtocol;
|
|
BYTE * pRequest = (BYTE *)SmartcardExtension->SmartcardRequest.Buffer;
|
|
BYTE * pReply = (BYTE *)SmartcardExtension->SmartcardReply.Buffer;
|
|
ULONG RequestLength = 0;
|
|
ULONG ReplyLength = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBG_PRINT ("smartCard_Transmit()\n");
|
|
if (!Reader || (selectedProtocol != protocolRequested))
|
|
{
|
|
DBG_PRINT (" smartCard_Transmit requested with invalid device state...\n");
|
|
return (STATUS_INVALID_DEVICE_STATE);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Reader->acquireRemoveLock())) return STATUS_INVALID_DEVICE_STATE;
|
|
|
|
__try
|
|
{
|
|
//Set the reply buffer length to 0.
|
|
*SmartcardExtension->IoRequest.Information = 0;
|
|
switch (selectedProtocol)
|
|
{
|
|
case SCARD_PROTOCOL_T0:
|
|
Status = SmartcardT0Request(SmartcardExtension);
|
|
|
|
RequestLength = SmartcardExtension->SmartcardRequest.BufferLength;
|
|
|
|
DBG_PRINT("T0 PROTOCOL: request length %d\n",RequestLength);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT ("smartCard_Transmit: SmartcardT0Request reports error 0x%x...\n",Status);
|
|
__leave;
|
|
}
|
|
if (SmartcardExtension->T0.Le > 0)
|
|
{
|
|
if (SmartcardExtension->T0.Le > SC_IFD_T0_MAXIMUM_LEX)
|
|
{
|
|
DBG_PRINT ("smartCard_Transmit:Expected length is too big - %d\n",SmartcardExtension->T0.Le);
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
__leave;
|
|
}
|
|
ReplyLength = SmartcardExtension->SmartcardReply.BufferSize;
|
|
if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock()))
|
|
{
|
|
__leave;
|
|
}
|
|
Status = Reader->reader_Read(pRequest,RequestLength,pReply,&ReplyLength);
|
|
Reader->reader_set_Idle();
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT ("smartCard_Transmit: reader_Read() reports error 0x%x\n",Status);
|
|
__leave;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (SmartcardExtension->T0.Lc > SC_IFD_T0_MAXIMUM_LC)
|
|
{
|
|
DBG_PRINT ("smartCard_Transmit:Command length is too big - %d\n",SmartcardExtension->T0.Lc);
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
__leave;
|
|
}
|
|
|
|
ReplyLength = SmartcardExtension->SmartcardReply.BufferSize;
|
|
if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock()))
|
|
{
|
|
DBG_PRINT ("smartCard_Transmit:Failed to get idle state...\n");
|
|
__leave;
|
|
}
|
|
|
|
if(!pRequest || ! RequestLength)
|
|
{
|
|
DBG_PRINT("\n Transmit: cardWrite() Buffer %x length %d\n",pRequest,RequestLength);
|
|
}
|
|
Status = Reader->reader_Write(pRequest,RequestLength,pReply,&ReplyLength);
|
|
Reader->reader_set_Idle();
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT ("smartCard_Transmit: reader_Write() reports error 0x%x\n",Status);
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
SmartcardExtension->SmartcardReply.BufferLength = ReplyLength;
|
|
|
|
DBG_PRINT ("T0 Reply length 0x%x\n",ReplyLength);
|
|
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
Status = SmartcardT0Reply(SmartcardExtension);
|
|
}
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT ("smartCard_Transmit: SmartcardT0Reply reports error 0x%x\n",Status);
|
|
}
|
|
break;
|
|
case SCARD_PROTOCOL_T1:
|
|
// Loop for the T=1 management
|
|
if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock()))
|
|
{
|
|
DBG_PRINT ("smartCard_Transmit:Failed to get idle state...\n");
|
|
__leave;
|
|
}
|
|
|
|
do
|
|
{
|
|
// Tell the lib function how many bytes I need for the prologue
|
|
SmartcardExtension->SmartcardRequest.BufferLength = 0;
|
|
|
|
Status = SmartcardT1Request(SmartcardExtension);
|
|
|
|
RequestLength = SmartcardExtension->SmartcardRequest.BufferLength;
|
|
|
|
ReplyLength = SmartcardExtension->SmartcardReply.BufferSize;
|
|
|
|
DBG_PRINT("T1 PROTOCOL: request, expected reply length %d, %d\n",RequestLength,ReplyLength);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT ("smartCard_Transmit: SmartcardT1Request reports error 0x%x...\n",Status);
|
|
Reader->reader_set_Idle();
|
|
__leave;
|
|
}
|
|
Status = Reader->reader_translate_request(pRequest,RequestLength,pReply,&ReplyLength, cardCapabilities, SmartcardExtension->T1.Wtx);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT ("smartCard_Transmit: reader_translate_request() reports error 0x%x\n",Status);
|
|
//return Status; no let smartcard assign proper status
|
|
}
|
|
|
|
if (SmartcardExtension->T1.Wtx)
|
|
{
|
|
// Set the reader BWI to the default value
|
|
Reader->setTransparentConfig(cardCapabilities,0);
|
|
}
|
|
|
|
// copy buffer(pass by ptr) n length
|
|
SmartcardExtension->SmartcardReply.BufferLength = ReplyLength;
|
|
|
|
Status = SmartcardT1Reply(SmartcardExtension);
|
|
if ((Status != STATUS_MORE_PROCESSING_REQUIRED) && (Status != STATUS_SUCCESS) )
|
|
{
|
|
DBG_PRINT ("smartCard_Transmit: SmartcardT1Reply reports error 0x%x\n",Status);
|
|
}
|
|
} while (Status == STATUS_MORE_PROCESSING_REQUIRED);
|
|
|
|
Reader->reader_set_Idle();
|
|
break;
|
|
default:
|
|
Status = STATUS_DEVICE_PROTOCOL_ERROR;
|
|
__leave;
|
|
}
|
|
}// Try block
|
|
|
|
__finally
|
|
{
|
|
Reader->releaseRemoveLock();
|
|
}
|
|
return Status;
|
|
};
|
|
|
|
#pragma LOCKEDCODE
|
|
NTSTATUS smartCard_VendorIoctl(PSMARTCARD_EXTENSION SmartcardExtension)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;;
|
|
CUSBReader* Reader = (CUSBReader*) SmartcardExtension->ReaderExtension;
|
|
ULONG ControlCode = SmartcardExtension->MajorIoControlCode;
|
|
PUCHAR pRequest = (PUCHAR) SmartcardExtension->IoRequest.RequestBuffer;
|
|
ULONG RequestLength = SmartcardExtension->IoRequest.RequestBufferLength;
|
|
PUCHAR pReply = (PUCHAR)SmartcardExtension->IoRequest.ReplyBuffer;
|
|
ULONG ReplyLength = SmartcardExtension->IoRequest.ReplyBufferLength;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBG_PRINT ("smartCard_VendorIoctl()\n");
|
|
|
|
if (!Reader)
|
|
{
|
|
DBG_PRINT ("smartCard_VendorIoctl: Reader is not ready...\n");
|
|
return (STATUS_INVALID_DEVICE_STATE);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Reader->acquireRemoveLock())) return STATUS_INVALID_DEVICE_STATE;
|
|
|
|
*SmartcardExtension->IoRequest.Information = 0;
|
|
|
|
__try
|
|
{
|
|
switch(ControlCode)
|
|
{
|
|
// For IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE and IOCTL_VENDOR_SMARTCARD_SET_ATTRIBUTE
|
|
// Vendor attribut use by the device
|
|
case IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE:
|
|
case IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE:
|
|
if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock()))
|
|
{
|
|
DBG_PRINT ("smartCard_VendorIoctl:Failed to get idle state...\n");
|
|
__leave;
|
|
}
|
|
|
|
Status = Reader->reader_VendorAttribute(ControlCode,pRequest,RequestLength,pReply,&ReplyLength);
|
|
|
|
Reader->reader_set_Idle();
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT ("smartCard_VendorIoctl: reader_Attibute reports error 0x%x ...\n", Status);
|
|
ReplyLength = 0;
|
|
}
|
|
*SmartcardExtension->IoRequest.Information = ReplyLength;
|
|
break;
|
|
// For IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE
|
|
// Send a GemCore command to the reader
|
|
case IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE:
|
|
if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock()))
|
|
{
|
|
DBG_PRINT ("smartCard_VendorIoctl:Failed to get idle state...\n");
|
|
__leave;
|
|
}
|
|
|
|
Status = Reader->reader_Ioctl(ControlCode,pRequest,RequestLength,pReply,&ReplyLength);
|
|
|
|
Reader->reader_set_Idle();
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT ("smartCard_VendorIoctl: cardIoctl reports error 0x%x ...\n", Status);
|
|
ReplyLength = 0;
|
|
}
|
|
*SmartcardExtension->IoRequest.Information = ReplyLength;
|
|
|
|
break;
|
|
// For IOCTL_SMARTCARD_VENDOR_SWITCH_SPEED
|
|
// Change reader speed manually
|
|
case IOCTL_SMARTCARD_VENDOR_SWITCH_SPEED:
|
|
if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock()))
|
|
{
|
|
DBG_PRINT ("smartCard_VendorIoctl:Failed to get idle state...\n");
|
|
__leave;
|
|
}
|
|
|
|
Status = Reader->reader_SwitchSpeed(ControlCode,pRequest,RequestLength,pReply,&ReplyLength);
|
|
|
|
Reader->reader_set_Idle();
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT ("smartCard_VendorIoctl: reader_SwitchSpeed reports error 0x%x ...\n", Status);
|
|
ReplyLength = 0;
|
|
}
|
|
else
|
|
{
|
|
// Set value inside CardCabilities
|
|
BYTE NewTA1 = pRequest[0];
|
|
|
|
SmartcardExtension->CardCapabilities.Fl = NewTA1 >> 4;
|
|
SmartcardExtension->CardCapabilities.Dl = NewTA1 & 0x0F;
|
|
// Do not touch ClockRateConversion and BitRateAdjustment!
|
|
}
|
|
*SmartcardExtension->IoRequest.Information = ReplyLength;
|
|
|
|
break;
|
|
default:
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
__finally
|
|
{
|
|
Reader->releaseRemoveLock();
|
|
}
|
|
DBG_PRINT ("smartCard_VendorIoctl Exit Status=%x\n", Status);
|
|
return Status;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
// Examine if ATR identifies a specific mode (presence of TA2).
|
|
BOOLEAN CSmartCard::CheckSpecificMode(BYTE* ATR, DWORD ATRLength)
|
|
{
|
|
DWORD pos, len;
|
|
|
|
|
|
// ATR[1] is T0. Examine precense of TD1.
|
|
if (ATR[1] & 0x80)
|
|
{
|
|
// Find position of TD1.
|
|
pos = 2;
|
|
if (ATR[1] & 0x10)
|
|
pos++;
|
|
if (ATR[1] & 0x20)
|
|
pos++;
|
|
if (ATR[1] & 0x40)
|
|
pos++;
|
|
|
|
// Here ATR[pos] is TD1. Examine presence of TA2.
|
|
if (ATR[pos] & 0x10)
|
|
{
|
|
// To be of any interest an ATR must contains at least
|
|
// TS, T0, TA1, TD1, TA2 [+ T1 .. TK] [+ TCK]
|
|
// Find the maximum length of uninteresting ATR.
|
|
if (ATR[pos] & 0x0F)
|
|
len = 5 + (ATR[1] & 0x0F);
|
|
else
|
|
len = 4 + (ATR[1] & 0x0F); // In protocol T=0 there is no TCK.
|
|
|
|
if (ATRLength > len) // Interface bytes requires changes.
|
|
{
|
|
if ((ATR[pos+1] & 0x10) == 0) // TA2 asks to use interface bytes.
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
} // CheckSpecificMode
|
|
|
|
|
|
#pragma LOCKEDCODE
|
|
NTSTATUS smartCard_Power(PSMARTCARD_EXTENSION SmartcardExtension)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;;
|
|
CUSBReader* Reader = (CUSBReader*) SmartcardExtension->ReaderExtension; //TO CHANGE LATER...
|
|
ULONG ControlCode = SmartcardExtension->MinorIoControlCode;
|
|
PUCHAR pReply = (PUCHAR)SmartcardExtension->IoRequest.ReplyBuffer;
|
|
ULONG ReplyLength = SmartcardExtension->IoRequest.ReplyBufferLength;
|
|
KIRQL oldirql;
|
|
ULONG State;
|
|
CSmartCard* smartcard = NULL;
|
|
|
|
DBG_PRINT ("smartCard_Power()\n");
|
|
if (!Reader)
|
|
{
|
|
DBG_PRINT ("smartCard_ReaderPower(): Reader is not ready...\n");
|
|
return STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Reader->acquireRemoveLock())) return STATUS_INVALID_DEVICE_STATE;
|
|
|
|
smartcard = Reader->getSmartCard();
|
|
|
|
*SmartcardExtension->IoRequest.Information = 0;
|
|
if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock()))
|
|
{
|
|
DBG_PRINT ("smartCard_Power:Failed to get idle state...\n");
|
|
Reader->releaseRemoveLock();
|
|
return Status;
|
|
}
|
|
Status = Reader->reader_Power(ControlCode,pReply,&ReplyLength, FALSE);
|
|
Reader->reader_set_Idle();
|
|
switch(ControlCode)
|
|
{
|
|
case SCARD_POWER_DOWN:
|
|
{
|
|
if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock()))
|
|
{
|
|
DBG_PRINT ("smartCard_Power:Failed to get idle state...\n");
|
|
Reader->releaseRemoveLock();
|
|
return Status;
|
|
}
|
|
State = Reader->reader_UpdateCardState();
|
|
if(smartcard)
|
|
{
|
|
KeAcquireSpinLock(smartcard->getCardLock(), &oldirql);
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
|
|
SmartcardExtension->CardCapabilities.ATR.Length = 0;
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = State;
|
|
KeReleaseSpinLock(smartcard->getCardLock(), oldirql);
|
|
}
|
|
Reader->reader_set_Idle();
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT ("smartCard_ReaderPower: cardPower down reports error 0x%x ...\n", Status);
|
|
}
|
|
Reader->releaseRemoveLock();
|
|
return Status;
|
|
}
|
|
break;
|
|
case SCARD_COLD_RESET:
|
|
case SCARD_WARM_RESET:
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT ("smartCard_ReaderPower: cardPower up reports error 0x%x ...\n", Status);
|
|
|
|
*SmartcardExtension->IoRequest.Information = 0;
|
|
KeAcquireSpinLock(smartcard->getCardLock(), &oldirql);
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
|
|
SmartcardExtension->CardCapabilities.ATR.Length = 0;
|
|
if(Status==STATUS_NO_MEDIA)
|
|
{
|
|
DBG_PRINT("############# Reporting CARD ABSENT!... #############\n");
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_ABSENT;
|
|
}
|
|
KeReleaseSpinLock(smartcard->getCardLock(), oldirql);
|
|
|
|
Reader->releaseRemoveLock();
|
|
return Status;
|
|
}
|
|
if(pReply && ReplyLength && (pReply[0]==0x3B || pReply[0]==0x3F) )
|
|
{
|
|
if ((SmartcardExtension->SmartcardReply.BufferSize>=ReplyLength) &&
|
|
(sizeof(SmartcardExtension->CardCapabilities.ATR.Buffer)>=ReplyLength))
|
|
{
|
|
|
|
DBG_PRINT("Setting SMCLIB info...\n");
|
|
// Set information...
|
|
*SmartcardExtension->IoRequest.Information = ReplyLength;
|
|
// Set reply...
|
|
RtlCopyMemory(SmartcardExtension->SmartcardReply.Buffer,pReply,ReplyLength);
|
|
SmartcardExtension->SmartcardReply.BufferLength = ReplyLength;
|
|
// Set ATR...
|
|
RtlCopyMemory(SmartcardExtension->CardCapabilities.ATR.Buffer,pReply,ReplyLength);
|
|
SmartcardExtension->CardCapabilities.ATR.Length = (UCHAR) ReplyLength;
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
|
|
// Parse the ATR string in order to check if it as valid
|
|
// and to find out if the card uses invers convention
|
|
Status = SmartcardUpdateCardCapabilities(SmartcardExtension);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT("UpdateCardCaps() reports error 0x%x\n", Status);
|
|
Status = 0;
|
|
}
|
|
|
|
// Check if Specific mode is present in TA2
|
|
DBG_PRINT("=========== Checking specific mode....\n");
|
|
if(smartcard->CheckSpecificMode(SmartcardExtension->CardCapabilities.ATR.Buffer,
|
|
SmartcardExtension->CardCapabilities.ATR.Length))
|
|
{ // Use automatic protocol switching!
|
|
if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock()))
|
|
{
|
|
DBG_PRINT ("smartCard_Power:Failed to get idle state...\n");
|
|
Reader->releaseRemoveLock();
|
|
return Status;
|
|
}
|
|
|
|
Status = Reader->reader_Power(ControlCode,pReply,&ReplyLength, TRUE);
|
|
|
|
Reader->reader_set_Idle();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// ERROR!!!!!
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
*SmartcardExtension->IoRequest.Information = 0;
|
|
DBG_PRINT ("smartCard_ReaderPower: Failed to copy ATR because of short ATR or Reply buffer...\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//ERROR!!!!
|
|
Status = STATUS_UNRECOGNIZED_MEDIA;
|
|
*SmartcardExtension->IoRequest.Information = 0;
|
|
DBG_PRINT ("smartCard_ReaderPower: Failed to get card ATR...\n");
|
|
KeAcquireSpinLock(smartcard->getCardLock(), &oldirql);
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
|
|
SmartcardExtension->CardCapabilities.ATR.Length = 0;
|
|
KeReleaseSpinLock(smartcard->getCardLock(), oldirql);
|
|
}
|
|
Reader->releaseRemoveLock();
|
|
return Status;
|
|
break;
|
|
}
|
|
Reader->releaseRemoveLock();
|
|
return STATUS_INVALID_PARAMETER;
|
|
};
|
|
|
|
#pragma LOCKEDCODE
|
|
NTSTATUS smartCard_SetProtocol(PSMARTCARD_EXTENSION SmartcardExtension)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;;
|
|
CUSBReader* Reader = (CUSBReader*) SmartcardExtension->ReaderExtension;
|
|
ULONG ProtocolMask = SmartcardExtension->MinorIoControlCode;
|
|
|
|
PAGED_CODE();
|
|
DBG_PRINT ("smartCard_SetProtocol()\n");
|
|
|
|
*SmartcardExtension->IoRequest.Information = 0;
|
|
if (!Reader)
|
|
{
|
|
DBG_PRINT ("######## smartCard_SetProtocol: Reader is not ready...\n");
|
|
return (STATUS_INVALID_DEVICE_STATE);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Reader->acquireRemoveLock())) return STATUS_INVALID_DEVICE_STATE;
|
|
|
|
if(SmartcardExtension->CardCapabilities.Protocol.Supported & ProtocolMask & SCARD_PROTOCOL_T1)
|
|
DBG_PRINT ("******* T1 PROTOCOL REQUESTED ******\n");
|
|
if(SmartcardExtension->CardCapabilities.Protocol.Supported & ProtocolMask & SCARD_PROTOCOL_T0)
|
|
DBG_PRINT ("******* T0 PROTOCOL REQUESTED ******\n");
|
|
|
|
// Check if the card is already in specific state
|
|
// and if the caller wants to have the already selected protocol.
|
|
// We return success if this is the case.
|
|
if (SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC &&
|
|
(SmartcardExtension->CardCapabilities.Protocol.Selected & ProtocolMask))
|
|
{
|
|
DBG_PRINT ("Requested protocol %d already was setted.\n",SmartcardExtension->CardCapabilities.Protocol.Selected);
|
|
Reader->releaseRemoveLock();
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock()))
|
|
{
|
|
Reader->releaseRemoveLock();
|
|
return Status;
|
|
}
|
|
|
|
do {
|
|
// Select T=1 or T=0 and indicate that pts1 follows
|
|
// What is the protocol selected
|
|
DBG_PRINT ("Smartcard: SetProtocol Loop\n");
|
|
|
|
if(SmartcardExtension->CardCapabilities.Protocol.Supported & ProtocolMask & SCARD_PROTOCOL_T1)
|
|
{
|
|
|
|
DBG_PRINT ("******* SETTING T1 PROTOCOL ******\n");
|
|
Status = Reader->reader_SetProtocol(SCARD_PROTOCOL_T1, PROTOCOL_MODE_MANUALLY);
|
|
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T1;
|
|
DBG_PRINT ("******* T1 PROTOCOL WAS SET ******\n");
|
|
}
|
|
|
|
} else if(SmartcardExtension->CardCapabilities.Protocol.Supported & ProtocolMask & SCARD_PROTOCOL_T0)
|
|
{
|
|
// T0 selection
|
|
DBG_PRINT ("******* SETTING T0 PROTOCOL ******\n");
|
|
Status = Reader->reader_SetProtocol(SCARD_PROTOCOL_T0, PROTOCOL_MODE_MANUALLY);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T0;
|
|
DBG_PRINT ("******* T0 PROTOCOL WAS SET ******\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
DBG_PRINT ("smartCard_SetProtocol: BAD protocol selection...\n");
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
|
|
|
|
// close only once
|
|
Reader->reader_set_Idle();
|
|
|
|
Reader->releaseRemoveLock();
|
|
return Status;
|
|
}
|
|
|
|
// Fail to negociate PPS, try PTS_TYPE_DEFAULT
|
|
if( ! NT_SUCCESS(Status))
|
|
{
|
|
if (SmartcardExtension->CardCapabilities.PtsData.Type != PTS_TYPE_DEFAULT)
|
|
{
|
|
DBG_PRINT ("Smartcard: SetProtocol: PPS failed. Trying default parameters...\n");
|
|
|
|
//
|
|
// The card did either NOT reply or it replied incorrectly
|
|
// so try default values.
|
|
// Set PtsData Type to Default and do a cold reset
|
|
//
|
|
SmartcardExtension->CardCapabilities.PtsData.Type = PTS_TYPE_DEFAULT;
|
|
|
|
Status = Reader->reader_SetProtocol(ProtocolMask, PROTOCOL_MODE_DEFAULT);
|
|
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
Status = SmartcardUpdateCardCapabilities(SmartcardExtension);
|
|
}
|
|
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
DBG_PRINT ("Smartcard: SetProtocol PPS default succeed, TRY AGAIN\n");
|
|
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
}
|
|
}
|
|
} while ( Status == STATUS_MORE_PROCESSING_REQUIRED );
|
|
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
|
|
DBG_PRINT ("smartCard_SetProtocol: SUCCCESS Finish transaction\n");
|
|
// Now indicate that we're in specific mode
|
|
// and return the selected protocol to the caller
|
|
//
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC;
|
|
|
|
*(PULONG) SmartcardExtension->IoRequest.ReplyBuffer =
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected;
|
|
|
|
*SmartcardExtension->IoRequest.Information =
|
|
sizeof(SmartcardExtension->CardCapabilities.Protocol.Selected);
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_DEVICE_PROTOCOL_ERROR;
|
|
// We failed to connect at any protocol. Just report error.
|
|
DBG_PRINT ("smartCard_SetProtocol: Failed to set any protocol...\n");
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
|
|
}
|
|
|
|
// Unblock set protocol
|
|
Reader->reader_set_Idle();
|
|
Reader->releaseRemoveLock();
|
|
return Status;
|
|
};
|
|
|
|
|
|
// Callback function to cancel tracking Irp
|
|
#pragma LOCKEDCODE
|
|
NTSTATUS smartCard_CancelTracking(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{ // OnCancelPendingIoctl
|
|
CUSBReader* Reader = (CUSBReader*)DeviceObject->DeviceExtension;
|
|
PIRP notificationIrp;
|
|
CSmartCard* card = NULL;
|
|
PSMARTCARD_EXTENSION SmartcardExtention = NULL;
|
|
KIRQL ioIrql;
|
|
KIRQL keIrql;
|
|
|
|
DBG_PRINT ("######### SmartCard: Cancelling card tracking...\n");
|
|
DBG_PRINT ("######### SmartCard: DeviceObject reported - 0x%x, IRP - 0x%x\n",DeviceObject,Irp);
|
|
DBG_PRINT ("######### SmartCard: Reader reported - 0x%x\n",Reader);
|
|
|
|
if (!NT_SUCCESS(Reader->acquireRemoveLock())) return STATUS_INVALID_DEVICE_STATE;
|
|
|
|
notificationIrp = NULL;
|
|
card = Reader->getSmartCard();
|
|
notificationIrp = card->getPoolingIrp();
|
|
SmartcardExtention = Reader->getCardExtention();
|
|
|
|
ASSERT(Irp == notificationIrp);
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
DBG_PRINT("######### SmartCard: notificationIrp - 0x%x\n",Irp);
|
|
KeAcquireSpinLock(&SmartcardExtention->OsData->SpinLock,&keIrql);
|
|
notificationIrp = SmartcardExtention->OsData->NotificationIrp;
|
|
SmartcardExtention->OsData->NotificationIrp = NULL;
|
|
KeReleaseSpinLock(&SmartcardExtention->OsData->SpinLock,keIrql);
|
|
|
|
if (notificationIrp)
|
|
{
|
|
DBG_PRINT("####### CancelTracking: Completing NotificationIrp %lxh\n",notificationIrp);
|
|
IoAcquireCancelSpinLock(&ioIrql);
|
|
IoSetCancelRoutine(notificationIrp, NULL);
|
|
IoReleaseCancelSpinLock(ioIrql);
|
|
// finish the request
|
|
notificationIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
notificationIrp->IoStatus.Information = 0;
|
|
IoCompleteRequest(notificationIrp, IO_NO_INCREMENT);
|
|
}
|
|
Reader->releaseRemoveLock();
|
|
return STATUS_CANCELLED;
|
|
}
|
|
|
|
|
|
|
|
#pragma LOCKEDCODE
|
|
NTSTATUS smartCard_Tracking(PSMARTCARD_EXTENSION Smartcard)
|
|
{
|
|
KIRQL oldIrql;
|
|
CUSBReader* Reader = (CUSBReader*) Smartcard->ReaderExtension;
|
|
DBG_PRINT ("SmartCard: Card tracking...\n");
|
|
if (!Reader) return STATUS_INVALID_DEVICE_STATE;
|
|
|
|
if (!NT_SUCCESS(Reader->acquireRemoveLock())) return STATUS_INVALID_DEVICE_STATE;
|
|
|
|
if(Smartcard->MajorIoControlCode == IOCTL_SMARTCARD_IS_PRESENT)
|
|
{
|
|
Reader->setNotificationState(SCARD_SWALLOWED);
|
|
DBG_PRINT ("SmartCard: WAITING FOR INSERTION!\n");
|
|
}
|
|
else
|
|
{
|
|
Reader->setNotificationState(SCARD_ABSENT);
|
|
DBG_PRINT ("SmartCard: WAITING FOR REMOVAL!\n");
|
|
}
|
|
|
|
if(!Smartcard->OsData || !Smartcard->OsData->NotificationIrp)
|
|
{
|
|
DBG_PRINT ("SmartCard: ========== CARD TRACKING CALLED WITH ZERO IRP!!!!!\n");
|
|
Reader->releaseRemoveLock();
|
|
return STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
|
|
DBG_PRINT("######### SmartCard: POOLING IRP - %8.8lX \n",Smartcard->OsData->NotificationIrp);
|
|
CSmartCard* card = Reader->getSmartCard();
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
IoSetCancelRoutine(Smartcard->OsData->NotificationIrp, smartCard_CancelTracking);
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
if(card) card->setPoolingIrp(Smartcard->OsData->NotificationIrp);
|
|
Reader->releaseRemoveLock();
|
|
return STATUS_PENDING;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
VOID CSmartCard::completeCardTracking()
|
|
{
|
|
PSMARTCARD_EXTENSION Smartcard;
|
|
ULONG CurrentState;
|
|
ULONG ExpectedState;
|
|
KIRQL ioIrql;
|
|
KIRQL keIrql;
|
|
PIRP poolingIrp;
|
|
|
|
//DEBUG_START();//Force to debug even if thread disabled it...
|
|
|
|
TRACE("SmartCard: completeCardTracking() ...\n");
|
|
Smartcard = reader->getCardExtention();
|
|
CurrentState = reader->getCardState();
|
|
ExpectedState = reader->getNotificationState();
|
|
|
|
TRACE("SMCLIB Card state is %x\n",Smartcard->ReaderCapabilities.CurrentState);
|
|
TRACE("Current Card state is %x\n",CurrentState);
|
|
TRACE("ExpectedState is %x\n",ExpectedState);
|
|
|
|
if(Smartcard && Smartcard->OsData)
|
|
{
|
|
lock->acquireSpinLock(&Smartcard->OsData->SpinLock, &keIrql);
|
|
if(CurrentState < SCARD_SWALLOWED)
|
|
{
|
|
Smartcard->ReaderCapabilities.CurrentState = CurrentState;
|
|
}
|
|
else
|
|
{
|
|
if(Smartcard->ReaderCapabilities.CurrentState<=SCARD_SWALLOWED)
|
|
{
|
|
Smartcard->ReaderCapabilities.CurrentState = CurrentState;
|
|
}
|
|
}
|
|
|
|
TRACE("NEW SMCLIB card state is %x\n",Smartcard->ReaderCapabilities.CurrentState);
|
|
lock->releaseSpinLock(&Smartcard->OsData->SpinLock, keIrql);
|
|
}
|
|
|
|
poolingIrp = NULL;
|
|
if((ExpectedState!= SCARD_UNKNOWN) && (ExpectedState == CurrentState))
|
|
{
|
|
DEBUG_START();//Force to debug even if thread disabled it...
|
|
TRACE("\n=======Expected state %d is reached=====\n\n",ExpectedState);
|
|
// Desired state reached...
|
|
if(Smartcard->OsData && Smartcard->OsData->NotificationIrp)
|
|
{
|
|
setPoolingIrp(NULL);
|
|
reader->setNotificationState(SCARD_UNKNOWN);
|
|
|
|
TRACE("====== COMPLETING NOTIFICATION =========\n");
|
|
// Finish requested notification!.....
|
|
lock->acquireSpinLock(&Smartcard->OsData->SpinLock, &keIrql);
|
|
poolingIrp = Smartcard->OsData->NotificationIrp;
|
|
lock->releaseSpinLock(&Smartcard->OsData->SpinLock, keIrql);
|
|
if(poolingIrp)
|
|
{
|
|
TRACE("====== COMPLETING NOTIFICATION IRP %8.8lX \n\n",poolingIrp);
|
|
lock->acquireCancelSpinLock(&ioIrql);
|
|
irp->setCancelRoutine(poolingIrp, NULL);
|
|
lock->releaseCancelSpinLock(ioIrql);
|
|
|
|
if(poolingIrp->Cancel)
|
|
poolingIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
else
|
|
poolingIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
poolingIrp->IoStatus.Information = 0;
|
|
lock->acquireSpinLock(&Smartcard->OsData->SpinLock, &keIrql);
|
|
Smartcard->OsData->NotificationIrp = NULL;
|
|
lock->releaseSpinLock(&Smartcard->OsData->SpinLock, keIrql);
|
|
irp->completeRequest(poolingIrp,IO_NO_INCREMENT);
|
|
}
|
|
}
|
|
}
|
|
}
|