Click here to Skip to main content
15,867,308 members
Articles / Mobile Apps

Smart Card Framework for .NET

Rate me:
Please Sign up or sign in to vote.
4.74/5 (36 votes)
26 Aug 2011CPOL12 min read 525.5K   31.6K   172   125
Describes an XML framework for .NET to program Smart Card applications.

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 byteLength in bytesDescription
Class1 Class byte
Ins1Instruction byte
P11Parameter 1
P21Parameter 2
P31This parameter is either the length of the sent data or the length of the expected data
DataNData to send to the card

The card will respond to a command with an array of bytes.

BytesLengthDescription
Data0 to 255Response data
SW1, SW22Command 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:

XML
<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] (yyth 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:

XML
<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:

XML
<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:

C#
SequenceParameter seqParam = new SequenceParameter();

// Process Apdu: VerifyCHV
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.

C#
/// <summary>
/// Process a simple APDU command, Parameters
/// can be provided in the APDUParam object
/// </summary>
/// <param name="command">APDU command name</param>
/// <param name="apduParam">Parameters for the command</param>
/// <returns>An APDUResponse object with the response of the card </returns>
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.

C#
/// <summary>
/// Process an APDU sequence and execute each
/// of its commands in the sequence order
/// </summary>
/// <param name="apduSequenceName">Name of the sequence to play</param>
/// <param name="seqParam">An array of SequenceParam
/// object used as parameters for the sequence</param>
/// <returns>APDUResponse object of the last command executed</returns>
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
BytesDescriptionMandatory/OptionalLength
1 to XAlpha identifierOX bytes
X + 1Length of phone number stringM1 byte
X + 2TON & NPIM1 byte
X + 3 to X + 12Phone number stringM10 bytes
X + 13CCP identifierM1 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:

C#
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:

Image 1

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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Connect In Private
Singapore Singapore
Software Architect, COM, .NET and Smartcard based security specialist.

I've been working in the software industry since I graduated in Electrical and Electronics Engineering. I chose software because I preferred digital to analog.

I started to program with 6802 machine code and evolved to the current .NET technologies... that was a long way.

For more than 20 years I have always worked in technical positions as I simply like to get my hands dirty and crack my brain when things don't go right!

After 12 years in the smart card industry I can claim a strong knowledge in security solutions based on those really small computers!
I've been back into business to design the licensing system for the enterprise solution for Consistel using a .NET smart card (yes they can run .NET CLR!)

I'm currently designing a micro-payment solution using the NXP DESFire EV1 with the ACSO6 SAM of ACS. I can then add a full proficient expertise on those systems and NFC payments.
This technology being under strict NDA by NXP I cannot publish any related article about it, however I can provide professional consulting for it.

You can contact me for professional matter by using the forum or via my LinkedIn profile.

Comments and Discussions

 
QuestionHow do you get the user PIV from a Smartcard using APDU commands? Pin
Member 1467957612-Dec-19 10:11
Member 1467957612-Dec-19 10:11 
AnswerAdditional Info on: How do you get the user PIV from a Smartcard using APDU commands? Pin
Member 1467957612-Dec-19 10:39
Member 1467957612-Dec-19 10:39 
QuestionCannot get access to Part 1 Pin
Michel111712849-Oct-17 22:05
Michel111712849-Oct-17 22:05 
QuestionCalculate CMAC Pin
Ibpet1115-Sep-16 5:58
Ibpet1115-Sep-16 5:58 
GOD Bless you for the solution you made available free

I need your assistance on how to calculate c-mac before sending the External authenticate command.

I have been able to generate my Kenc,Kmac,Kdek, Senc,Smac,Sdek. I also have the code to get the Card Cryptogram and the Host Cryptogram.
Can you please help me with the code for the cmac?
QuestionUsing HID OMNIKEY 3121 Smart card reader with 4th generation smart card. Getting 6E00 error everytime Pin
Manjitchavan11-Aug-15 22:46
Manjitchavan11-Aug-15 22:46 
QuestionInsurance smart card Pin
Ali Bagherzadeh25-Jun-15 22:10
Ali Bagherzadeh25-Jun-15 22:10 
QuestionHow To use Smart card in asp.net or in client server enviroment Pin
chanchalsingh7-Jan-15 16:31
chanchalsingh7-Jan-15 16:31 
AnswerRe: How To use Smart card in asp.net or in client server enviroment Pin
orouit23-Jan-15 16:50
professionalorouit23-Jan-15 16:50 
QuestionACR122 U error : Index was outside the bounds of the array. Pin
andre agrifa8-Jul-14 21:53
andre agrifa8-Jul-14 21:53 
AnswerRe: ACR122 U error : Index was outside the bounds of the array. Pin
Member 1015533525-Aug-14 8:17
Member 1015533525-Aug-14 8:17 
QuestionNothing happening Pin
Taneth1-Jul-13 12:48
professionalTaneth1-Jul-13 12:48 
AnswerRe: Nothing happening Pin
Member 351717920-Nov-16 22:09
Member 351717920-Nov-16 22:09 
QuestionError 6 onConnect Pin
valse27-May-13 8:24
valse27-May-13 8:24 
AnswerRe: Error 6 onConnect Pin
orouit27-May-13 16:36
professionalorouit27-May-13 16:36 
Questiongetting 69 85 for get response and 6D00 for Read Binary Pin
MAU7878-Jan-13 1:29
MAU7878-Jan-13 1:29 
Questionproblem with contacless cards Pin
Luiz Felipe Sanches Gonçalves13-Jul-12 9:00
Luiz Felipe Sanches Gonçalves13-Jul-12 9:00 
AnswerRe: problem with contacless cards Pin
orouit11-Aug-12 1:45
professionalorouit11-Aug-12 1:45 
GeneralRe: problem with contacless cards Pin
LuizOFOCA2-Jan-14 5:59
LuizOFOCA2-Jan-14 5:59 
QuestionVerify Smart Card Pin Pin
boomporter27-Apr-12 8:30
boomporter27-Apr-12 8:30 
AnswerRe: Verify Smart Card Pin Pin
orouit17-May-12 1:34
professionalorouit17-May-12 1:34 
QuestionHow to get the ICCID Pin
Member 880410310-Apr-12 9:15
Member 880410310-Apr-12 9:15 
AnswerRe: How to get the ICCID Pin
orouit24-Apr-12 16:37
professionalorouit24-Apr-12 16:37 
QuestionC# Web Project with SmartCard integration Pin
cetintas31-Mar-12 7:52
cetintas31-Mar-12 7:52 
AnswerRe: C# Web Project with SmartCard integration Pin
orouit24-Apr-12 16:37
professionalorouit24-Apr-12 16:37 
QuestionVerify ADM pin Pin
ralienpp7-Feb-12 3:02
ralienpp7-Feb-12 3:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.