Introduction
In the first part, I described how to develop a set of classes with C# to wrap the PC/SC API of Windows. PC/SC is a set of APIs used to communicate with a Smart Card. Even if the classes are easier to use than the PC/SC functions, you still need to write code that is not always easy to understand. Communication with a Smart Card uses a protocol named APDU to send the commands to the card, they are called APDU commands. The framework I propose is designed to simplify the development of a Smart Card application. Most of the time, you would have to chain several commands to perform an action like reading or writing a file. With the framework I describe here, you can easily chain commands and then describe the Smart Card elements of your application with an XML description.
Background
This article assumes that you have read the Part 1 of this article and that you have some knowledge of XML. Even if not necessary, a basic knowledge of Smartcard programming can help.
The APDU command protocol
Most people have a mobile phone and so use a Smart Card every day. For example, when you enter your PIN on your mobile phone or read a phone number in your SIM card directory, your mobile sends a set of commands to the card to perform the action. An APDU command is a set of bytes that are send to the card that will respond with a code and eventually with the data you want to read.
APDU command description
An APDU command is basically composed of the following bytes:
APDU byte | Length in bytes | Description |
Class | 1 | Class byte |
Ins | 1 | Instruction byte |
P1 | 1 | Parameter 1 |
P2 | 1 | Parameter 2 |
P3 | 1 | This parameter is either the length of the sent data or the length of the expected data |
Data | N | Data to send to the card |
The card will respond to a command with an array of bytes.
Bytes | Length | Description |
Data | 0 to 255 | Response data |
SW1, SW2 | 2 | Command status |
An APDU command always returns at least two bytes that are the status bytes. When the command returns some data, the status bytes are the last two bytes returned by the command.
There are five different configurations to send commands to a card. They are categorized in two groups, commands that send data and commands that receive data.
APDU to send data
No data to send, no data to receive
CLASS
| INS
| P1
| P2
| P3
|
| SW1
| SW2
|
| | | | lgth = 0 | | 90
| 00
|
Sending data to the card
CLASS
| INS
| P1
| P2
| P3
| DATA with length datalgth |
| SW1
| SW2
|
| | | | datalgth | | | 90
| 00
|
If datalgth
= 0, it sends 256 bytes to the card.
On a normal execution, those commands will answer with 9000 or with an error code.
APDU to receive data
Receiving data of known length
CLASS
| INS
| P1
| P2
| P3
| | DATA of length datalgth
| SW1
| SW2
|
| | | | datalgth | | | 90
| 00
|
Receiving data of unknown length
When a command requests data from the card with an unknown number of bytes, you must first send the command with a length of 0 to get the number of bytes that the card will return. Then, you can call the GET RESPONSE
command with a request length lower or equal to the given length.
1 - Send the command with the requested length of 0.
CLASS
| INS
| P1
| P2
| P3
| |
| SW1
| SW2
|
| | | | 0
| | | 9F
| lgth
|
2 - Send the GET RESPONSE
with req_lgth
< lgth
.
CLASS
| INS
| P1
| P2
| P3
| | DATA of length req_lgth <= lgth
| SW1
| SW2
|
C0
|
| 0
| 0
| req_lgth
| | | 90
| 00
|
Sending data and receiving data of known or unknown length
This case is very similar to the previous one. The difference is that you are first sending a command that transmits data to the card. This command replies with a 9FXX code where XX indicates the length of the maximum data you can read with the GET RESPONSE
command.
1 - Send data to the card
CLASS
| INS
| P1
| P2
| P3
| DATA with length datalgth |
| SW1
| SW2
|
| | | | datalgth | | | 90
| 00
|
2 - Send the GET RESPONSE
with req_lgth
< lgth
.
CLASS
| INS
| P1
| P2
| P3
| | DATA of length req_lgth <= lgth
| SW1
| SW2
|
C0
|
| 0
| 0
| req_lgth
| | | 90
| 00
|
SIM card commands
The commands that can be sent to a SIM card are described in a specification called 3GPP TS 11.11 (a.k.a. GSM 11.11). I won't describe here the whole set of commands and the files of the SIM card. If you are interested in it, you can find a version of the GSM1111 here.
Here is a short list of the commands for a SIM card:
Class byte for GSM is A0, S indicates that data is sent to the card, and R that data is received from the card. All byte values are given in hexadecimal.
COMMAND
| INS
| p1
| P2
| P3
| S/R
|
SELECT | A4
| 00
| 00
| 02
| S/R
|
STATUS | F2
| 00
| 00
| lght
| R
|
|
|
|
|
|
|
READ BINARY | B0
| offset_high
| offset_low
| lgth
| R
|
UPDATE BINARY | D6
| offset_high
| offset_low
| lgth
| S
|
READ RECORD | B2
| rec_No
| mode
| lgth
| R
|
UPDATE RECORD | DC
| rec_No
| mode
| lgth
| S
|
|
|
|
|
|
|
VERIFY CHV | 20
| 00
| CHV_No
| 08
| S
|
CHANGE CHV | 24
| 00
| CHV_No
| 10
| S
|
|
|
|
|
|
|
RUN GSM ALGORITHM | 88
| 00
| 00
| 10
| S/R
|
|
|
|
|
|
|
GET RESPONSE | C0
| 00
| 00
| lgth
| R
|
Now, let us see how it is possible to write an XML framework to simplify the writing of Smart Card applications.
XML Framework for APDU Commands
The basic idea is to provide a simple and flexible framework in XML to describe APDU commands and write an application which can be a sequence of several commands or of sequences. A command is the atomic unit of description, it can be used alone or from a sequence if parameters need to be passed to the command itself.
APDU Ccommand
An atomic APDU command is represented with an XML element. APDU commands are assembled in a ApduList
document. The ApduList
and the Apdu
elements are defined by the following schema:
<xs:schema attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ApduList">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Apdu">
<xs:complexType>
<xs:attribute name="Name" type="xs:string" use="required" />
<xs:attribute name="Class" type="xs:string" use="required" />
<xs:attribute name="Ins" type="xs:string" use="required" />
<xs:attribute name="P1" type="xs:unsignedByte" use="required" />
<xs:attribute name="P2" type="xs:unsignedByte" use="required" />
<xs:attribute name="P3" type="xs:string" use="required" />
<xs:attribute name="Data" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
A command file contains a set of pre-defined APDU commands. A command can be played by its name after the APDU command list has been loaded. There are different types of commands; some commands can be played individually, and some need to use the result of a previous command.
When the P3
parameter represents the length of expected data from the command, its value can be the result of the previous call of a command, or the command should have to be replayed to get this variable value. Here is the syntax accepted by the parameter to handle this case:
P3 = "R,0:SW1?xx"
R indicates that the command must be replayed with a condition on the value of SW1
after a first call with P3
=0. If SW1
== xx
, the command will be replayed with P3
= SW2
.
<Apdu Name="Get OTP ID" Class="A0" Ins="1A"
P1="80" P2="2" Lc="0" Le="R,0:SW1?6C" Data="" />
P3 = "R,xx:DRyy"
R indicates that the command must be replayed, but without the condition this time. On the first call, P3
= xx
, then the command is replayed with P3 = xx + RespData[yy]
(yy
th data of the response, the first data index is 1 in the norm).
<Apdu Name="Get Status" Class="A0" Ins="F2" P1="0"
P2="0" Lc="0" Le="R,13:DR13" Data="" />
P3 = "SW2"
If SW1
== 0x9F on the previous call to a command, then this command is played using P3
= SW2
of the previous command.
<Apdu Name="Get Response" Class="A0" Ins="C0" P1="0" P2="0" P3="SW2" />
P3 = "DRxx"
If there were data from the previous command, xx
is used as the index in the response data to get the value of P3
. Le
= RespData[xx]
.
<Apdu Name="Read Binary" Class="A0" Ins="B0" P1="0" P2="0" P3="DR15" />
Sequence of Commands
A sequence of commands is used to chain atomic APDU commands or sequences. A sequence can use parameters that are given to commands that compose it. A SequenceList
describes a set of Sequence
elements that can be called in an application. The following schema describes a SequenceList
of Sequence
elements:
<xs:schema attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="SequenceList">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Sequence">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Command">
<xs:complexType>
<xs:attribute name="Apdu"
type="xs:string" use="optional" />
<xs:attribute name="P2"
type="xs:unsignedByte" use="optional" />
<xs:attribute name="Data"
type="xs:string" use="optional" />
<xs:attribute
name="Sequence" type="xs:string" use="optional" />
<xs:attribute name="P1"
type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="Name" type="xs:string" use="required" />
<xs:attribute name="PIN" type="xs:string" use="optional" />
<xs:attribute name="Record"
type="xs:unsignedByte" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
The Sequence
element allows you to pass parameters to a command or another Sequence
. The Sequence
uses a subelement that is Command
. A Command
is used to call an APDU with or without parameters. When a parameter is given in a Command
, it overrides the default parameter of the APDU element.
For example, if you want to verify a PIN code, you can use the following Sequence
:
<Sequence Name="Verify CHV1" PIN="FFFFFFFFFFFFFFFF">
<Command Apdu="Verify CHV" P2="1" Data="PIN"/>
</Sequence>
The class that is used to call this sequence allows you to give a value to the PIN
parameter. When the Command
is executed, the parameter Data
will get the value given for the parameter PIN.
A Sequence
parameter can take any name. In this version, the value of the parameter is a string that represents a set of byte values.
The code to call this Sequence
is the following:
SequenceParameter seqParam = new SequenceParameter();
Console.WriteLine("Sequence: Verify CHV1");
seqParam.Add("PIN", "31323334FFFFFFFF");
apduResp = player.ProcessSequence("Verify CHV1", seqParam);
Console.WriteLine(apduResp.ToString());
Now that we have seen how to declare the commands and chain them using the Sequence
element, I'm going to describe the code that takes advantage of this simple 'XML language'.
APDUPlayer: A C# Class to be Used with the XML Description
In order to use the XML format previously described, I have developed a simple C# class which is able to process APDU commands or APDU sequences.
The class APDUPlayer
has three constructors, and exposes a few public methods. The two most important methods are those that are used to execute an APDU command or a sequence of APDUs.
The following method is used to execute a single APDU command. The APDUParam
parameter can be used to modify a parameter of the APDU that was read from the XML description.
public APDUResponse ProcessCommand(string apduName, APDUParam apduParam);
This other method is used to execute a sequence of APDUs. The SequenceParameter
class is a list of parameter/value couple that are used as input parameters for the sequence to play.
public APDUResponse ProcessSequence(string apduSequenceName,
SequenceParameter seqParam);
Using this method has been shown previously.
A Sample Application to Read the Phone Book of a SIM Card
In my previous article, we read the phone book of a SIM card using the PC/SC wrapper I described, but this application was just getting the raw content of the phone book file (6F3A). In this sample, we are going to interpret the data of each record. The content of the phone record is the following:
This EF contains the Abbreviated Dialing Numbers (ADN). In addition, it contains identifiers of associated network/bearer capabilities and identifiers of extension records. It may also contain an associated alpha tagging.
Identifier: 6F3A
| Record length: X + 14 bytes |
Bytes | Description | Mandatory/Optional | Length |
1 to X | Alpha identifier | O | X bytes |
X + 1 | Length of phone number string | M | 1 byte |
X + 2 | TON & NPI | M | 1 byte |
X + 3 to X + 12 | Phone number string | M | 10 bytes |
X + 13 | CCP identifier | M | 1 byte |
X + 14 | Extension 1 record | | |
This specification has been taken from the GSM11.11 document that specifies the logic of the SIM card. We are going to extract from this description the information we need to get the phone number and its associated name.
The first bytes are the name that appears on your mobile phone with the phone number. It is a string using a coding close to the ASCII coding by default.
The fourteenth bytes that follow contain the phone number itself and some description bytes. The first byte is the length of the phone number in bytes, including the TON & NPI byte which indicates if the number is national (Ax, 8x) or international (9x).
The ten last bytes of this group contain the phone number itself. The coding is BCD where the bytes are in reverse order. If the number of digits is odd, then the last byte of number contains a F and the digit. For example, the number 015648327 is coded the following way: 10658423F7.
The two last bytes of the record contain data that are rarely used.
The class PhoneNumber
is a helper class provided to interpret the bytes of a phone number record. It is used the following way:
PhoneNumber phone = new PhoneNumber(apduResp.Data);
Console.WriteLine("ADN n°" + nI.ToString());
Console.WriteLine(phone.ToString());
The ToString
method gets a string of the content of the phone record in the following format, <name> : <number>.
The program ReadPhonebook is a console application that reads the tenth first phone numbers of the ADN file by default. You can read another number of records giving it as a parameter to the program.
Command line: ReadPhonebook P <pincode> <nbRecord>
The parameters are optional.
- P <pincode>: PIN code to present to the card. If you don't give this parameter, no PIN code will be presented to the card.
- <nbRecord>: Number of records to read. By default, the program reads 10 records.
Examples:
- ReadPhonebook P 1234 25, will present 1234 as the PIN and read 25 records.
- ReadPhonebook 50, reads 50 records, doesn't present any PIN.
- ReadPhonebook P 4567, presents 4567 as PIN and reads 10 records.
APDExchange Application
The APDUExchange Windows Forms application is a basic C# application that can be used to send any APDU command to a card. It is possible to type the command or use an APDUList
file to preload commands.
The application automatically detects card insertion or removal on demand. It uses the NativeCard implementation of the Smart Card API described in the previous article.
The Exchange APDU form looks like this:
If you want to send a command that is not in the APDU list, you just need to add the command to the file using the format previously described.
Points of Interest
I have been working in the Smart Card industry for quite some time, and I rarely find articles about this topic on the internet. As Smart Cards are now largely adopted and that some computers even have an embedded Smart Card reader, I thought it would be interesting to demonstrate how a simple XML framework could simplify the development of a Smart Card enabled application. You can use this code and extend the framework to your needs, and I hope that these articles have shown you that using Smart Cards could be quite simple.
History
- 5 Mar 2007 - Updated the
ExchangeAPDU
application to display the ATR value for the inserted card. Another evolution is to activate the card events for the selected reader if more than one reader is installed on your PC. The error message is displayed in hexa, it's easier to get the meaning using errorlookup. - 16 Aug 2011 - Added project updated for VS 2010
- 26 Aug 2011 - Added 64 bit project for Visual Studio 2008, 2010