Writing A Smartcard Library
Writing A Smartcard Library
Writing A Smartcard Library
In this article we are going to develop a Smart Card Library that will ease the development of Smart Card Applications using the Win32 SDK and/or MFC. This assumes that youre familiar with Win32 and MFC. The library builds upon the available support for Smart Cards in Windows by providing an Object Oriented wrapper over the WinSCard API. One advantage of
using this library is the layered approach, which isolates the core APIs available to non-Win32 conformant languages like java to access this library through JNI (Java Native Interfaces). If youve already developed some applications using the APIs exposed by WinSCard.dll then youll be well aware of the complexities involved and here is an attempt to ease them. NOTE Before you begin, go ahead and download the support file. Microsoft has provided several enhancements toward the use of PCSC conformant Smart Cards with the operating systems releases made after Windows 2000.There is available a COM wrapper and Smart Card Base Components provided as a part of this enhancements. The heart of this Subsystem is the WinSCard.dll which exposes raw APIs for managing and accessing PCSC compliant Smart Card readers. In order to take a quick look at what it exposes, you can just use the Dependency Walker. Below is a Snapshot of the same.
Figure 1: The API exports by WinSCard.dll There are around 60 exports from this DLL and cover most parts of the PCSC specification. Here we would try encapsulating some of the core APIs to develop an object-oriented wrapper that we can use to develop MFC applications that use Smart Cards. Let's first talk about how one writes an application with just the WinSCard.dll raw APIs and then we'll move to writing the OO Wrapper. As mentioned above the core of the Win32 Smart Card subsystem is the WinSCard.dll, which exposes a number of APIs for Smart Card access and Reader Configuration. The typical steps to access a Smart Card with the raw API's would be as under: Use the SCardEstablishContext API to get a Context Handle associated with a reader. You need this because the other APIs need you to pass a context handle as parameter. Later using the SCardConnect API you obtain hCard that is handle to a card. Just like above you need this handle to communicate with the Card. You may then use SCardStatus with the above hCard value to get the status of the card before you actually start with some transaction. You then use SCardTransmit API to send APDU to the associated card and retrieve the response at the same time. You'll need the hCard value here too. After you're done using the Card you use the SCardDisconnect API to disconnect from the Card using the hCard value associated with the card. Then this hCard value is no longer valid and you should do a SCardConnect call again to retrieve a new handle in case you want to reconnect again Finally when you don't need the connection with the reader device you just call the SCardReleaseContext API to release the Context handle associated with the reader. It's fine as long as you're writing a small application but as your business logic grows so would be the calls and references to the WinSCard APIs and it's really not advisable even for a medium project going over 3000LOC. Moreover it's solely up to the programmer to put the data in a format that is dictated by the WinSCard APIs. It was a lot of hit and trial the first time I wrote an application in this way. Sooner or later you find that you're not writing good code if you follow this approach. Compare this approach to the object oriented approach where in you've a number of class like in the diagram below that encapsulate one or more Smart Card objects. The CPSCSCReader class encapsulates a Reader object, which is responsible for managing reader connections, keeping the status updated internally and sending/receiving data to/from the card. There are a few helper classes too like CPCSCCommand, which encapsulates an APDU (Application Protocol Data
Unit) object and CRegListDlg, which enables you to select a reader from those connected to your machine. You can skim through the code for these classes or run the demo application to see them in action.
Figure 2: The CPCSCReader class and Members The class snapshot above gives us the clear picture of what it encapsulates and what methods we can invoke to communicate with the physical reader and the inserted card. In order to open a physical reader you must know the name with which it's configured. I've assumed in code that it's stored in the registry at the key: HKEY_CURRENT_USERDSCPCSCReader as in the snapshot below:
Figure 3: The CPCSReader class and Members You can always modify the code to suit your need and requirements. It's just meant to be a demonstration and you are free to evolve it in any way you like. You can double click the RegReader.reg file to make the keys and alter them as you like. CPCSCReader members int OpenReader(CString&) This method opens the reader specified by the CString parameter, which holds the name of the reader to be opened. The return value is an int with the following meanings Call Status 0 Reader not opened : Failed 1 Reader Opened Successfully 3 Reader Opened Successfully 4 Reader Opened Successfully Card Status Card is not inserted Card is inserted Card is inserted Card is inserted Reader Status Reader is not powered on Reader is powered on Reader is not powered on reader is powered on
int CloseReader(CString& strReaderName) It Closes the Reader Opened earlier by a call to OpenReader.The return value is either 0 or 1 indicating success or failure. Zero means failure because the Context could not be released and one means that the context was released successfully and that the reader closed successfully and it also asserts that that no card is present and reader is not powered on. void SendCommandToCard(CPCSCCommand&) This is the workhorse of the whole library and wraps the raw API SCardTransmit. It takes CPCSCCommand reference as parameter and the response is returned in that too. BOOL SendCommandToCard(CString&, CString&) Same as above but for ease of use takes a CString as Command APDU and returns the response and Status words in another CString. void GetReaderStatus() It's not actually implemented but one should send a 00 60 10 00 00 as Command and interpret the response from Card.
BOOL IsCardPresent() Returns true if Card is inserted in the reader else returns false. BOOL IsReaderPowerd() Returns true if Reader is powered on else returns false. CString m_strReaderName Holds the Reader name with which it was opened. See OpenReader() code for more details. int m_bReaderPowerdOn This is Boolean member variable to hold the status of power of reader. int m_bCardInserted; This is Boolean member variable to hold the card presence status of reader.
Figure 4: The CRed ListDlg class and Members This class just presents a UI (user Interface) to select a reader from the installed readers. The readers displayed in this selection dialog are picked from the registry settings displayed above (Figure 2). For a snapshot of this UI element refer to figure 5. You can modify the code to display the readers from an entirely different location or even an ini file. It's solely dependent on the requirements one may have. But as Microsoft implements t this way I thought it'd be better if I stick to the registry.
4 sur 7
22/11/2011 16:19
Figure 5: The CPCSCCommand class and Members The CPCSCCommand Class This class encapsulates an APDU object. That is it takes care of the data sent and received from the card. Although I've provided a CString override of the SendCommandToCard() method but I'd recommend using the CPCSCCommand class. The members with the prefix m_ are the actual data units that constitute the APDU and the remaining methods just set or retrieve them. The code for this class is straightforward and you can take a look to get a better understanding.
Figure 6: The SCardDemo application snapshot The demo application demonstrates the use if these classes and you can even use it as a starting point for your Smart Card enabled application. It allows you to first select a reader from the available ones and then fires one command automatically and displays you the response in a Messagebox. Once you've selected a reader you can just type in an APDU in the Command String field and then press the Send Button to sent it to the card and retrieve the response in the Response field as displayed in the snapshot above. The Library Code The Library code is in two modules, namely DSCPCSC.dll and DSCPCSCOO.dll. The DSCPCSC.dll is a pure Win32 DLL and exports four APIs int WINAPI OpenReaderConnection(char* strNameReader, long status) int WINAPI CloseReaderConnection(char* strNameReader, long status) long WINAPI SendCommand(char * strReader, unsigned char* strCommand, int nLengthCmd, long status, unsigned char & strResponse, int & nResponseLen) long WINAPI GetReaderAttribute(char* strReaderName, unsigned long attId, unsigned char& pAttribute, int nAttLength) These are the core APIs that do the real work and for a better understanding I'd recommend you to browse through the code once. The other module, DSCPCSCOO.dll, is a MFC extension library and exports all the classes that we discussed above. As a refresher I'll list them again here. CPCSCReader The Reader Class, which encapsulates the functionality of a Smart Card Reader. CPCSCCommand The APDU or Command Object which encapsulates the APDU Commands functionality that are sent to the card. CRegListDlg This class encapsulates the UI to select a reader from the installed readers on the system. Points of interest The first module is a Pure Win32 library and as I developed the second module DSCPCSCOO.dll as an OO wrapper over it one can use JNI to develop a java wrapper over it and even write Java Applications that re Smart Card enabled.