Previous Post | Next Post | EMV Tags List |
EMV Transaction an Introduction | EMV Transaction: Step 2.) Initiate application processing | EMV Tags List |
Step 1 : Application Selection
Before the 1st step of Application Selection, we need to reset the EMV chip card, lets see how that happens.
Answer To Reset (ATR)
Resetting the card
Before any communication with the card, we need to reset the card. There are two ways of resetting.Cold Reset:
The cold reset is the initial start of all communication between the card and the reader. If the card is already powered up, then a cold reset will first deactivate power supply. Then power is supplied to the card and the reset line is used to signal a reset to the chip. The terminal then waits for an answer (ATR).
Warm Reset:
During warm reset the terminal is sending a reset signal to the card without disconnecting power supply.
After the reset signal from the terminal, the card will answer with a byte string called ATR. This string contains certain information about the card which are necessary for the communication between card and terminal. After a warm reset the card answers with a different ATR, e.g. to switch to a slower communication rate.
Example:
0000 3B FF 18 00 FF 81 31 FE 45 65 63 0D 02 50 02 80 ;.....1.Eec..P.. 0010 00 08 37 70 20 10 05 00 B2 ..7p ....
Example:
TS : 3B Direct logic TO : FF K = 15 byte [historical characters] TA1 : 18 Fi/f = 372/ 5 [clock rate conversion factor / max. frequency (MHz)] Di = 12 [bit rate conversion factor] TB1 : 00 pa = 4 % [programming voltage accurancy] I = 25 mA [maximum current] P = 0 V [programming voltage] TC1 : FF N = 255 etu [extra guardtime] TD1 : 81 T = T=1 [protocol type] TD2 : 31 T = T=1 [protocol type] TA3 : FE IFSC = 254 [information field size] TB3 : 45 CWT = 43 etu [character waiting time] BWT = 12 etu [block waiting time]
65630D025002800008377020100500 ec..P....7p ...The first byte of the string is the initial character "T0". It defines which of the two transmission technique, "direct convention (3B)" or "indirect convention (3F)", should be used. In our case we have the byte 3B and a direct convention.
The second byte is the format character T0. Here we obtain the length of the historical characters. In our ATR the last 15 bytes are the historical characters. They contain some information e.g. the card's features and operating system version.
TA1 to TC3 are interface characters. They are necessary to determine the transmission between the card and the terminal. They contains informations like voltage, transmission rates and timeouts.
TA3 determines the information field size. The terminal used this value to determine the max. size of a block send to the card.
The character TB3 is relevant for the character and block waiting time. The character waiting time is the max. timeout between two subsequent bytes and the block waiting the time between two subsequent blocks.
If the waiting time is higher than determined, then terminal will issue an timeout error.
All waiting times are expressed as Elementary Time Unit (ETU), which is the time required to transmit a single bit. The default communication rate is 9600 bits per second, which translates to an ETU of 1/9600 seconds.
In simple words,
-Physical data transportation is done over an I/O channel.
-The convention of passing data is specified in the Initail Character (TS) transmitted by integrated chip card in Answer To Reset.
-Number of characters returned by ICC at ATR varies depending on transmission protocols & values supported.
-Two basic ATR are T = 0 (character mode) & T = 1 (block protocol) (in above example we get T0).
-ICC returning one of the two modes confirms correct operation & interoperability in terminals.
If you don't understand this ATR thing, don't worry...its not needed further.
Only thing you need to remember is that on inserting the EMV chip card into a EMV card slot you should get a successful Answer To Reset for your Cold Reset. If you dont then there's some problem in your card or your device.
========================================================================
Reading EMV
An application in ICC has a set of items of information within files. This information is accessible to terminal only after successful application selection.
(here item of information means Data Elements identified by a name or Tag)
For Application Selection lets have a quick view of the file structure within the chip card.
(here item of information means Data Elements identified by a name or Tag)
For Application Selection lets have a quick view of the file structure within the chip card.
File Structure
The files on a smart card are organized in a tree structure. The topmost file is the Master File (MF). The MF has one or more Application Definition Files (ADF). Inside of an ADF are Applicaton Elementary Files (AEF or EF) that contain data.You can quickly select an ADF with the Application Identifier (AID). Within an ADF you can select AEFs with the Short File Identifier (SFI). The SFI help us read the records in a file.
ISO/IEC 7816 defines a process for application selection. The intent of application selection was to allow cards to contain completely different applications, for example GSM and EMV. EMV however took application selection to be a way of identifying the type of product, so that all product issuers (Visa, MasterCard etc.) have to have their own application. The way application selection is prescribed in EMV is a frequent source of interoperability problems between cards and terminals.
An application identifier (AID) is used to address an application (ADF) in the card. An AID consists of a registered application provider identifier(RID) of five bytes, which is issued by the ISO/IEC 7816-5 registration authority. This is followed by a proprietary application identifier extension (PIX) which enables the application provider to differentiate between the different applications offered. The AID is printed on all EMV cardholder receipts.
Additional ADF's defined under the control of other application providers may be present in thd card, but will not have RID's assigned for payment systems.
The common Payment System Environment PSE, for all financial or banking cards has Directory name as
"1PAY.SYS.DDF01" which may or may not be a MF. This Directory (DDF-Directory Defination File) has entries for other ADF's. Files revealed by this PSE assures international operability.
In case the card is an NFC card then it will have PPSE (Paypass Payment System Environment) as
"2PAY.SYS.DDF01" and not "1PAY.SYS.DDF01"
Additional ADF's defined under the control of other application providers may be present in thd card, but will not have RID's assigned for payment systems.
The common Payment System Environment PSE, for all financial or banking cards has Directory name as
"1PAY.SYS.DDF01" which may or may not be a MF. This Directory (DDF-Directory Defination File) has entries for other ADF's. Files revealed by this PSE assures international operability.
In case the card is an NFC card then it will have PPSE (Paypass Payment System Environment) as
"2PAY.SYS.DDF01" and not "1PAY.SYS.DDF01"
Card scheme | RID | Product | PIX | AID |
---|---|---|---|---|
Visa | A000000003 | Visa credit or debit | 1010 | A0000000031010 |
Visa Electron | 2010 | A0000000032010 | ||
V PAY | 2020 | A0000000032020 | ||
Plus | 8010 | A0000000038010 | ||
MasterCard | A000000004 | MasterCard credit or debit | 1010 | A0000000041010 |
MasterCard[4] | 9999 | A0000000049999 | ||
Maestro (debit card) | 3060 | A0000000043060 | ||
Cirrus (interbank network) | 6000 | A0000000046000 | ||
UK Domestic Maestro - Switch (debit card) | A000000005 | Maestro UK | 0001 | A0000000050001 |
Solo | 0002 | A0000000050002 | ||
American Express | A000000025 | American Express | 01 | A00000002501 |
RuPay (India) | A000000524 | RuPay | 1010 | A0000005241010 |
Discover | A000000152 | Discover | 3010 | A0000001523010 |
Interac (Canada) | A000000277 | Debit card | 1010 | A0000002771010 |
JCB | A000000065 | Japan Credit Bureau | 1010 | A0000000651010 |
LINK (UK) ATM network | A000000029 | ATM card | 1010 | A0000000291010 |
Dankort (Denmark) | A000000121 | Debit card | 1010 | A0000001211010 |
CoGeBan (Italy) | A000000141 | PagoBANCOMAT | 0001 | A0000001410001 |
Banrisul (Brazil) | A000000154 | Banricompras Debito | 4442 | A0000001544442 |
ZKA (Germany) | A000000359 | Girocard | 1010028001 | A0000003591010028001 |
CB card (France) | A000000042 | CB card | 1010 | A0000000421010 |
SPAN2 (Saudi Arabia) | A000000228 | SPAN | 1010 | A0000002282010/1010 |
Application Selection
Application Selection is the first step after the Answer to Reset. It has the function to select the ADF for the transaction process.There are two ways to get the right ADF:
Method 1.)
If the card supports the Payment System Environment (PSE), the terminal reads out the necessary
information to select the ADF.
Method 2.)
If there is no PSE, the terminal will use a list of AIDs and get the right by trying.
Method 1:
The PSE Way...
To read the card's data we have to select the ADF first. We'll do this with a SELECT Command APDU.
The SELECT command supports the following options :
Description
0x00
Class Byte
0xA4
Instruction Byte :
SELECT Command
0x04
Parameter 1 :
Select a directory by name.
0x00
Parameter 2 :
0x00 when you write the complete AID Name.
0x0E
Lc = Length of data to be sent to the card :0x0E (i.e.) 14
AID
Data bytes to be sent to the card :
Directory name (AID) in bytes of "1PAY.SYS.DDF01"
0x00
Le = Number of data bytes expected in the response :
Set to 0x00 to retrieve the complete response of up to 256 bytes.
the byte array for "1PAY.SYS.DDF01" is { 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31 }
1 | P | A | Y | . | S | Y | S | . | D | D | F | 0 | 1 |
0x31 | 0x50 | 0x41 | 0x59 | 0x2E | 0x53 | 0x59 | 0x53 | 0x2E | 0x44 | 0x44 | 0x46 | 0x30 | 0x31 |
COMMAND:
00 A4 04 00 0E 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31 00
On sending this C-APDU if you receive SW1 = 0x90 & SW2 = 0x00
then you have received a successful response.
SW1/SW2=9000 (Normal processing : No error) with some response.
RESPONSE HEX:
6F 15 84 0E 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31 A5 03 88 01 01
The data structure of any response from the card will be in TLV Format.
[T] Tag
[L] Length
[V] Value
Tag: 0x6F File Control Information
(FCI) Template
|
Length: 0x15 i.e. 21
|
Value: 84 0E 31 50 41 59 2E 53 59 53
2E 44 44 46 30 31 A5 03 88 01 01
|
|
Tag: 0x84 Dedicated File (DF) Name
|
Length: 0x0E i.e. 14
|
Value: 31 50 41 59 2E 53
59 53 2E 44 44 46 30 31
|
|
Tag: 0xA5 File Control Information (FCI) Proprietary Template
|
Length: 0x03 i.e. 3
|
Value: 88 01 01
|
|
Tag: 0x88 Short File Identifier (SFI)
|
Length: 0x01 i.e. 1
|
Value: 01
|
Here's a link for List of all Tags that may appear in an Response >> EMV Tags List
You may get response with slight variations depending on the card you are using
for example;
RESPONSE HEX :
6F 20 84 0E 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31 A5 0E 88 01 02 5F 2D 04 6E 6F 65 6E 9F 11 01 01
Here the difference is FCI returned more data (length= 0E i.e 14) which contains
Tag 0x88 (SFI) Value 0x02
Tag 5F2D (Language Preference) Value 0x6E 0x6F 0x65 0x6E
i.e. ascii value of following characters 'n' 'o' 'e' 'n' stands for "norwegian"
Tag 9F11 (Issuer Code Table Index) Value 0x01
Returned 9000 as SW1 SW2 for this command means, the selection was successful and the card supports the PSE method (Method 1 - Payment System Environment).
Now we need to Read out the necessary information to select the ADF, for which we will need the SFI value we got in the response. (you may get different SFI values for different cards, in first response example SFI is 0x01 where as in 2nd response example SFI is 0x02)
Read data records using SFI received:
Read Records 1 to 16 (i.e. 0x01 to 0x10) for the SFI you received.
If we get response other than (SW1/SW2 = 9000) then, stop reading and break from the reading loop.
COMMAND: 0x00, 0xB2, recnum, [(sfi << 0x03) | 0x04], 0x00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
YET TO COMPLETE THE REMAINING PART OF THIS POST... :(
Read EMV
To read all data from the card, you can use the script contained in the following section:Line 06try
{
var card = new Card(_scsh3.reader);
card.reset(Card.RESET_COLD);
var aid = new ByteString("A0000000041010", HEX); // MC
// var aid = new ByteString("A0000000031010", HEX); // VISA
// var aid = new ByteString("1PAY.SYS.DDF01", ASCII);
var fcp = card.sendApdu(0x00, 0xA4, 0x04, 0x00, aid, 0x00, [0x9000]);
print("FCP returned in SELECT: ", new ASN1(fcp));
for (var sfi = 1; sfi <= 31; sfi++)
{
for (var rec = 1; rec <= 16; rec++)
{
var tlv = card.sendApdu(0x00, 0xB2, rec, (sfi << 3) | 4, 0x00);
if (card.SW == 0x9000)
{
print("SFI " + sfi.toString(16) + " record #" + rec);
try
{
var asn = new ASN1(tlv);
print(asn);
}
catch(e)
{
print(tlv.toString(HEX));
}
}
}
}
}
catch(e)
{
print("Exception reading from Credit Card Application: " + e.toString());
}
This script works either with Mastercard or VISA because both cards are using different AIDs. You'll need to activate the AID that matches your card.
Line 13
The card.sendAPDU() method supports a further parameter, which is used to define a list of expected SW codes. [0x9000] defines a list with a single 0x9000 entry.
Line 17
Now we create a loop that starts with the first AEF (SFI=1) and ends with SFI 31.
Line 19
In a second loop the record number of every AEF will be iterated from 1 to 16.
Line 21
With the READ RECORD command issued using card.sendApdu() we can obtain the data.
Parameter
Description
0x00
Class byte
0xB2
Instruction byte
READ RECORD Command
rec
Parameter 1 byte. It contains the record number.
(sfi << 3) | 4
Parameter P2 byte. The first 5 bits contain the SFI and the last three bits are set to 1,0,0, which means that P1 is a record number.
To calculate the P2 parameter, the SFI will be shift three bits to the left and combinated with a '4'
e.g.
00000001
00001000 <<3
00000100 | 4
00001100 = 0x0C
0x00
Le byte. It is '00' so up to 256 bytes are expected.
Line 22
If the statusword has the value 0x9000 the command was successful and the tlv object will be printed.
============================
Data Structure
ASN.1 - Abstract Syntax Notation One
ASN.1 is a formal language to describe data structures. It consists of primitive data objects (boolean, integer, UTF8 string) that can be constructed to define more complex data structures (Sequences, Sets).e.g.
Record ::= SEQUENCE { Name::= UTF8 String Age::= Integer Vegetarian::= Boolean OPTIONAL Smoker::= [0] Boolean OPTIONAL }Based on ASN.1, instances of data structures can be defined:
Record { Name::= "Möller" Age::= "30" Vegetarian::= "false" Smoker::= "true" }
TLV - [T]ag [L]ength [V]alue
To encode ASN.1 instances in a computer readable form, a notation called TLV is used. Every data object consists of a tag, a length byte and the value/data.The tag defines, for example, if the object is an integer, boolean or something else.
Tag 30 : Sequence OC : UTF8 String 02 : Integer 01 : Boolean
Here we have the ASN.1 example from above encoded as TLV structure: 30 11 OC 06 4D 7E 6C 6C 65 72 02 01 1E 01 01 00 80 01 00 which means Tag Length Value 30 11 Sequence with a length of 17 bytes OC 06 4D 7E 6C 6C 65 72 UTF8 String with a length of 6 bytes and the value Möller 02 01 1E Integer with a length of 1 and the value 30 01 01 00 Optional Boolean with the value false 80 01 FF Optional Boolean with the value true
Coding of the Tag
b8
b7
b6
b5
b4
b3
b2
b1
Meaning
0
0
universal class
0
1
application class
1
0
context specific class
1
1
private class
0
primitiv data object
1
constructed data object
x
x
x
x
x
tag value
1
1
1
1
1
tag continoues on a 2nd byte
Optional Byte 2:
b8
b7
b6
b5
b4
b3
b2
b1
explanation
x
b8 = 0 : this is the last byte of the tag
x
x
x
x
x
x
x
tag value
Tags are divided into four classes defined by b8 and b7.
The universal class contains basic data types like integer, boolean, etc.
The application class is used for data elements defined by an application specification or industry standard (e.g. EMV).
The context specific class is used for data elements that are unique within it's enclosing context (Like the concept of local variables in a programming language). For example the second optional boolean "smoker" is a context specific class so that it has a tag different from "vegetarian".
The private class is used for all privately defined data objects.
Example
The SEQEUNCE tag '30' decodes to : b8 b7 b6 b5 b4 b3 b2 b1 0 0 = universal class 1 = constructed 1 0 0 0 0 = tag value 0011 0000 '30' --------------- The UTF8 String tag '0C' decoded: b8 b7 b6 b5 b4 b3 b2 b1 0 0 = universal class 0 = primitive 0 1 1 0 0 = tag value 0000 1100 '0C'
Length field
Depending on the length of the value field we have one or more bytes in the length field.The length field has the following structure:
Number of length bytes | Length of value | Coding |
---|---|---|
1 | 0-127 | 0xxxxxx |
2 | 128-255 | 10000001 xxxxxxxx |
3 | 256-65535 | 10000010 xxxxxxxx xxxxxxxx |
Here we have two examples read from a credit card using the reademv.js script:
Example 1:
A2 C: 00 A4 04 00 - SELECT Lc=7 0005 A0 00 00 00 04 10 10 ....... Le=0 R: SW1/SW2=9000 (Normal processing: No error) Lr=28 0000 6F 1A 84 07 A0 00 00 00 04 10 10 A5 0F 50 0A 4D o............P.M 0010 61 73 74 65 72 43 61 72 64 87 01 01 asterCard... // We will focus on the response value: 6F 1A 84 07 A0 00 00 00 04 10 10 A5 0F 50 0A 4D 61 73 74 65 72 43 61 72 64 87 01 01Tag: "6F"
Application class
Primitive data object
Length: "1A"
'1A' = binary 00011010 = decimal 26 . There are 26 value bytes
Value:
"84 07 A0 00 00 00 04 10 10 A5 0F 50 0A 4D 61 73 74 65 72 43 61 72 64 87 01 01"
Example 2:
A2 C: 00 B2 01 1C - READ RECORD Le=0 R: SW1/SW2=9000 (Normal processing: No error) Lr=195 0000 70 81 C0 8F 01 04 9F 32 01 03 92 24 9F FB FB 7F p......2...$.... 0010 EE C7 B0 43 67 B3 E4 C6 71 C3 0B 4A EE AD A2 C1 ...Cg...q..J.... 0020 93 49 58 DD 61 04 D1 50 EA FD 3C 05 2C 97 0E 8D .IX.a..P..<.,... 0030 90 81 90 52 D7 78 E3 33 2B 72 0F 4F E4 1D 7C 1B ...R.x.3+r.O..|. 0040 ED 06 45 EA 7D EF 14 E4 E3 6F 80 90 A1 42 B7 E1 ..E.}....o...B.. 0050 B1 7D DE CF AA 80 FC B4 BF 04 1C 2D 44 04 AD 1E .}.........-D... 0060 7F 19 C9 56 5B 93 7F 5E B5 02 90 6F EE 32 F5 21 ...V[..^...o.2.! 0070 E5 32 AB FC 37 F0 46 1E 91 AA 46 79 8D 74 C4 BA .2..7.F...Fy.t.. 0080 FA 08 81 A3 0E 1F 9B B8 7A B7 85 C7 E2 9A 45 46 ........z.....EF 0090 D1 B7 FD 6F 98 A4 65 19 FB 7F 53 20 3A 93 AA C9 ...o..e...S :... 00A0 5C 5B 53 B8 CC 6E 9A D3 DB C9 25 CC 72 B9 6E DD \[S..n....%.r.n. 00B0 78 3B B0 D7 B6 E8 E9 78 BB 35 5E 45 5E 7A 5B CA x;.....x.5^E^z[. 00C0 57 C4 95 W..Tag: "70"
Application class
Constructed data object
Length: "81 C0"
1st byte '81' = binary 10000001 . There are two length bytes in the range 128 and 255.
2nd byte 'C0' = binary 11000000 = decimal 192. There are 192 value bytes.
Value:
"8F 01 04 9F 32 01 03 92 24 9F FB FB 7F EE C7 B0 43 67 B3 E4 C6 71 C3 0B 4A EE AD A2 C1 04 D1 50 EA FD 3C 05 2C 97 0E 8D 78 E3 33 2B 72 0F 4F E4 1D 7C 1B EF 14 E4 E3 6F 80 90 A1 42 B7 E1 B1 7D DE CF AA 80 FC B4 BF 04 1C 2D 44 04 AD 1E 7F 19 C9 56 5B 93 7F 5E B5 02 90 6F EE 32 F5 21 E5 32 AB FC 37 F0 46 1E 91 AA 46 79 8D 74 C4 BA FA 08 81 A3 0E 1F 9B B8 7A B7 85 C7 E2 9A 45 46 D1 B7 FD 6F 98 A4 65 19 FB 7F 53 20 3A 93 AA C9 5C 5B 53 B8 CC 6E 9A D3 DB C9 25 CC 72 B9 6E DD 78 3B B0 D7 B6 E8 E9 78 BB 35 5E 45 5E 7A 5B CA 57 C4 95"
===================================
Using the PSE method
/** * Send SELECT APDU */ EMV.prototype.select = function(dfname, first) { var fci = this.card.sendApdu (0x00, 0xA4, 0x04, (first ? 0x00 : 0x02), dfname, 0x00); return(fci); } /** * Send READ RECORD APDU * * Return empty ByteString if no data was read */ EMV.prototype.readRecord = function(sfi, recno) { var data = this.card.sendApdu(0x00, 0xB2, recno, (sfi << 3) | 0x04, 0); if (this.card.SW1 == 0x6C) { var data = this.card.sendApdu (0x00, 0xB2, recno, (sfi << 3) | 0x04, this.card.SW2); } return(data); }First we select the PSE (1PAY.SYS.DDF01)
/** * Select and read Payment System Environment on either * contact or contactless card */ EMV.prototype.selectPSE = function(contactless) { this.PSE = null; var dfname = (contactless ? EMV.PSE2 : EMV.PSE1); var fci = this.select(dfname, true); print(fci); if (fci.length == 0) { GPSystem.trace("No " + dfname.toString(ASCII) + " found"); return; }
A2 C: 00 A4 04 00 - SELECT Lc=14 0005 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31 1PAY.SYS.DDF01 Le=0 R: SW1/SW2=9000 (Normal processing: No error) Lr=23 0000 6F 15 84 0E 31 50 41 59 2E 53 59 53 2E 44 44 46 o...1PAY.SYS.DDF 0010 30 31 A5 03 88 01 01 01.....The selection was successful (SW1/SW2=9000), so the card supports the PSE method.
Get the SFI
To process we need the SFI.Therefore we have to decode first the returned FCI.
// Decode FCI Template var tl = new TLVList(fci, TLV.EMV); var t = tl.index(0);
var t: 6F 15 84 0E 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31 A5 03 88 01 01
assert(t.getTag() == EMV.FCI); // EMV.FCI = 0x6F var tl = new TLVList(t.getValue(), TLV.EMV); assert(tl.length >= 2);
var tl: 84 0E 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31 A5 03 88 01 01
// Decode DF Name t = tl.index(0);
var t: 84 0E 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31
assert(t.getTag() == EMV.DFNAME); // EMV.DFNAME = 0x84;
// Decode FCI Proprietary Template t = tl.index(1);
var t: A5 03 88 01 01
assert(t.getTag() == EMV.FCI_ISSUER); // EMV.FCI_ISSUER = 0xA5; var tl = new TLVList(t.getValue(), TLV.EMV);
// Decode SFI of the Directory Elementary File t = tl.index(0);
var t: 88 01 01
assert(t.getTag() == EMV.SFI); // EMV.SFI = 0x88; var sfi = t.getValue(); assert(sfi.length == 1); sfi = sfi.byteAt(0);
sfi: 0x01
this.PSE = new Array();
Read Records
Now we create a loop to read all records in this AEF, started with record number 1.// Read all records from Directory Elementary File var recno = 1; do { var data = this.readRecord(sfi, recno++); if (data.length > 0) { var tl = new TLVList(data, TLV.EMV); assert(tl.length == 1); var t = tl.index(0); assert(t.getTag() == EMV.TEMPLATE); var tl = new TLVList(t.getValue(), TLV.EMV); assert(tl.length >= 1); for (var i = 0; i < tl.length; i++) { var t = tl.index(i); assert(t.getTag() == 0x61); this.PSE.push(new TLVList(t.getValue(), TLV.EMV)); } } } while (data.length > 0); }At this time we have two entries in this PSE:
61 1F 4F 08 A0 00 00 00 25 01 05 01 50 10 50 65 72 73 6F 6E 61 6C 20 41 63 63 6F 75 6E 74 87 01 01and
61 1E 4F 07 A0 00 00 00 29 10 10 50 10 50 65 72 73 6F 6E 61 6C 20 41 63 63 6F 75 6E 74 87 01 02
Check Priority
Every entry contains an AID. Now we proof which of them have they highest priority./** * Return array of PSE entries or null if none defined */ EMV.prototype.getPSE = function() { return this.PSE; } /** * Return AID of application with highest priority or null if no PSE defined */ EMV.prototype.getAID = function() { var prio = 0xFFFF; var aid = null; var pse = e.getPSE(); if (pse == null) { return null; } // Iterate through PSE entries for (var i = 0; i < pse.length; i++) { var t = pse[i].find(EMV.AID); assert(t != null); var entryAid = t.getValue(); print(entryAid); var t = pse[i].find(EMV.LABEL); assert(t != null); print(t.getValue().toString(ASCII)); var entryPrio = 0xFFFE; var t = pse[i].find(EMV.PRIORITY); if (t != null) { entryPrio = t.getValue().toUnsigned(); entryPrio &= 0x0F; } if (entryPrio < prio) { prio = entryPrio; aid = entryAid; } } this.cardDE[EMV.AID] = aid; return aid; }In the first run the value for the entryPrio is: 0x01. 0x01 &= 0x0F is 0x01. 0x01 is less than 0xFFFF and from this it follows that 0x01 is now the prio and the aid is now the entryAid.
In the second run the value for the entryPrio is: 0x02. 0x02 &= 0x0F is 0x02. 0x02 is greater than 0x01, the priority of this entry is lower.
Final Selection
Select The ADF with the given AID./** * Select application and return FCI */ EMV.prototype.selectADF = function(aid) { var fci = this.select(aid, true); print(fci); this.cardDE[EMV.AID] = aid; }
Using a list of AIDs
First we select the PSE (1PAY.SYS.DDF01)/** * Select and read Payment System Environment on either * contact or contactless card */ EMV.prototype.selectPSE = function(contactless) { this.PSE = null; var dfname = (contactless ? EMV.PSE2 : EMV.PSE1); var fci = this.select(dfname, true); print(fci); if (fci.length == 0) { GPSystem.trace("No " + dfname.toString(ASCII) + " found"); return; }
96 C: 00 A4 04 00 - SELECT Lc=14 0005 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31 1PAY.SYS.DDF01 Le=0 R: SW1/SW2=6A82 (Checking error: File not found) Lr=0 No 1PAY.SYS.DDF01 foundThe selection failed because the ADF doesn't exist (SW1/SW2=6A82). The terminal uses now a list of AIDs to select the right ADF.
The terminal starts with the first AID in the Array. If the selection failed the terminal tries the next AID.
/** * Try a list of predefined AID in order to select an application */ EMV.prototype.tryAID = function() { for (var i = 0; i < EMV.AIDLIST.length; i++) { var le = EMV.AIDLIST[i]; var aid = new ByteString(le.aid, HEX); var fci = this.select(aid, true); if (fci.length > 0) { this.cardDE[EMV.AID] = aid; return; } } } // EMV.AIDLIST: EMV.AIDLIST = new Array(); EMV.AIDLIST[0] = { aid : "A00000002501", partial : true, name : "AMEX" }; EMV.AIDLIST[1] = { aid : "A0000000031010", partial : false, name : "VISA" }; EMV.AIDLIST[2] = { aid : "A0000000041010", partial : false, name : "MC" };
96 C: 00 A4 04 00 - SELECT Lc=6 0005 A0 00 00 00 25 01 ....%. Le=0 R: SW1/SW2=6A82 (Checking error: File not found) Lr=0 96 C: 00 A4 04 00 - SELECT Lc=7 0005 A0 00 00 00 03 10 10 ....... Le=0 R: SW1/SW2=9000 (Normal processing: No error) Lr=42 0000 6F 28 84 07 A0 00 00 00 03 10 10 A5 1D 50 04 56 o(...........P.V 0010 49 53 41 87 01 01 9F 38 0C 9F 33 03 9F 1A 02 9F ISA....8..3..... 0020 35 01 9F 40 05 5F 2D 02 64 65 5..@._-.de
====================================================================
Initiate Application Process
Initiate Application Process is the next step after the Application Selection. It initiates the transaction process and provides to the card a Processing Options Data Object List (PDOL) which contains necessary data. The card returns the Application Interchange Profile (AIP) and the Application File Locator (AFL). The AIP shows which Application are supported by the card. The AFL list all files that are required for the Transaction.Script
EMV.prototype.initApplProc = function() { // Create PDOL var data = this.getProcessingOptions(null); print(data); var tl = new TLVList(data, TLV.EMV); assert(tl.length == 1); var t = tl.index(0); if (t.getTag() == EMV.RMTF1) { // Format 1 0x80 this.cardDE[EMV.AIP] = t.getValue().left(2); this.cardDE[EMV.AFL] = t.getValue().bytes(2); } else { assert(t.getTag() == EMV.RMTF2); // Format 2 0x77 tl = new TLVList(t.getValue(), TLV.EMV); assert(tl.length >= 2); this.addCardDEFromList(tl); } }Get Processing Options
/** * Send GET PROCESSING OPTION APDU * * */ EMV.prototype.getProcessingOptions = function(pdol) { if (pdol == null) { //var pdol = new ByteString("8300", HEX); // OTHER var pdol = new ByteString("830B0000000000000000000000", HEX); // VISA } var data = this.card.sendApdu(0x80, 0xA8, 0x00, 0x00, pdol, 0); return(data); } The Get Processin Options command initiates the transaction within the card. The card returns the AIP and AFL.The command has the following structure:
Code | Value |
---|---|
CLA | '80' |
INS | 'A8' |
P1 | '00'; all other values are RFU |
P2 | '00'; all other values are RFU |
Lc | var. |
Data | PDOL related data |
Le | '00' |
PDOL
The data the terminal should send to the card is given in the PDOL. The PDOL is stored in the FCI of the ADF and has the tag '9F38'. The PDOL only contains the expected tagname and length.Here an example for VISA cards:
FCI: 6F [ APPLICATION 15 ] IMPLICIT SEQUENCE SIZE( 40 ) 84 [ CONTEXT 4 ] SIZE( 7 ) 0000 A0 00 00 00 03 10 10 ....... A5 [ CONTEXT 5 ] IMPLICIT SEQUENCE SIZE( 29 ) 50 [ APPLICATION 16 ] SIZE( 4 ) 0000 56 49 53 41 VISA 87 [ CONTEXT 7 ] SIZE( 1 ) 0000 01 . 9F38 [ CONTEXT 56 ] SIZE( 12 ) 0000 9F 33 03 9F 1A 02 9F 35 01 9F 40 05 .3.....5..@. // PDOL 5F2D [ APPLICATION 45 ] SIZE( 2 ) 0000 64 65 This VISA-Card needs for the transaction the following data:
Tag | Name | Length |
---|---|---|
'9F33' | Terminal Capabilities | '03' |
'9F1A' | Terminal Country Code | '02' |
'9F35' | Terminal Type | '01' |
'9F40' | Additional Terminal Capabilities | '05' |
96 C: 80 A8 00 00 - UNKNOWN_INS Lc=13 0005 83 0B 00 00 00 00 00 00 00 00 00 00 00 ............. Le=0 R: SW1/SW2=9000 (Normal processing: No error) Lr=36 0000 77 22 82 02 78 00 94 1C 10 01 04 00 10 05 05 00 w"..x........... 0010 08 06 06 01 08 07 07 01 08 08 09 01 08 0A 0A 00 ................ 0020 08 01 04 00 The initApplProc function extract now the AIP and AFL information of the response and store them in the cardDE array. The response can have two different formats with ever tag '80' or tag '77'. In this case the data in the response have the tag '77' and will be processed by the function addCardDEFromList which stores the AIP and AFL in the cardDE array.
EMV.prototype.addCardDEFromList = function(tlvlist) { for (var i = 0; i < tlvlist.length; i++) { var t = tlvlist.index(i); print(t.getTag().toString(16) + " - " + t.getValue()); this.cardDE[t.getTag()] = t.getValue(); } }
=========================================================
Read Application Data
This function reads all data from the Application File Locator (AFL). The AFL identifies the files and records which are necessary for the transaction.AFL
Structure
Every 4 bytes stick together.Byte | Function |
---|---|
1 | Short File Identifier The five most significant bits are the SFI. The three least significant bits are set to zero. Example: '10' 00010000 >>3 = 00000010 = '02' = SFI |
2 | Start Record |
3 | End Record |
4 | Number of records included in data authentication beginning from the Start Record |
Script
/** * Read application data as indicated in the Application File Locator * Collect input to data authentication * */ EMV.prototype.readApplData = function() { // Application File Locator must exist assert(typeof(this.cardDE[EMV.AFL]) != "undefined"); var afl = this.cardDE[EMV.AFL]; // Must be a multiple of 4 assert((afl.length & 0x03) == 0); // Collect input to data authentication var da = new ByteBuffer(); while(afl.length > 0) { var sfi = afl.byteAt(0) >> 3; // Short file identifier var srec = afl.byteAt(1); // Start record var erec = afl.byteAt(2); // End record var dar = afl.byteAt(3); // Number of records included in // data authentication for (; srec <= erec; srec++) { // Read all indicated records var data = this.readRecord(sfi, srec); print(data); // Decode template var tl = new TLVList(data, TLV.EMV); assert(tl.length == 1); var t = tl.index(0); assert(t.getTag() == EMV.TEMPLATE); // Add data authentication input if (dar > 0) { if (sfi <= 10) { // Only value da.append(t.getValue()); } else { // Full template da.append(data); } dar--; } // Add card based data elements to internal list var tl = new TLVList(t.getValue(), TLV.EMV); this.addCardDEFromList(tl); } // Continue with next entry in AFL afl = afl.bytes(4); } this.daInput = da.toByteString(); print(this.daInput); }The function always extract the first 4 bytes of the bytestring. That is why the length of the AFL bytestring has to be a multiple of 4. With a read record command and the bytes from the start record to the end record will be read. If start and end record are equal, there is only one record. The records will be stored in the cardDE array without the EMV.TEMPLATE (tag: '70' and length).
The data marked by the fourth byte will be stored in the da bytebuffer. If the SFI is greater as 10, the whole record will be stored in the bytebuffer. The data in the bytebuffer will be need for dynamic data authentication.
After this the 4 bytes of the AFL bytestring will be removed. This process will be repeated untill the AFL bytestring is empty.
Biometrics
RFID
Links to some POS systems to use in your projects:
Verifone POS:
https://www.alibaba.com/trade/search?fsb=y&IndexArea=product_en&CatId=&SearchText=verifone+vx520+vx680+vx675
Verifone Latest POS devices:
https://www.verifone.com/en/us/portables-and-transportables
Ingenico POS devices:
https://www.amazon.com/s?k=ingenico
Ingenico Latest POS devices:
https://www.ingenico.com/pos-solutions#smart-pos
mPOS devices :
https://www.alibaba.com/trade/search?fsb=y&IndexArea=product_en&CatId=&SearchText=mpos
https://dir.indiamart.com/impcat/mpos-machine.html
**NOTE:
Only purchasing POS devices is not enough for a project. You also require to purchase the software SDK & its license from the respective device vendor, which is required to develop credit/debit/giftcard application on the device.
To compare which device are best for your project:
There are many new POS system manufacturers coming up now. But I can say from my experience Verifone & Ingenico provide one of the best POS systems in the world.
Excellent blog to refer EMV related concepts.
ReplyDeleteGreat work.
regards,
Raj
Thank you..
Deletethat was a great motivater...
I will try to complete this blog soon :)
Hi Pushpak, while verification process of ICC Public Certificate, is Data located by the AFL needs to be consider for hash computation.
ReplyDeleteand if how to get the AFL(Application File Locator)
Regards
Dino
To get data from AFL, you need to fire Read Commands (B2) with the correct SFI until you extract data from all records.
DeleteYes we have to hash the data located by AFL & compare our hash with the recovered hash for ICC Public Certificate verification.
1.) We concatenate the data located through AFL.
2.) Hash the concatenated data as per the hash algorithm indicator.
3.) Compare our new hash with the recovered hash. If both are equal Dynamic Data Authentication is successful.
Here is the data from AFL you need to hash :-
Certificate Format : 2
Application PAN : XXXX XXXX XXXX XXXX
Certificate Expiration Date : (MMYY)
Certificate Serial Number : XXXXX
Hash Algorithm Indicator : 1 (=SHA-1)
ICC Public Key Algorithm Indicator : 1 (=RSA)
ICC Public Key Length : say 1000 bits
ICC Public Key Exponent Length : 3
ICC Public Key : data as per key length.
SDA Tag List Data
you can check this site for more emv information:
http://code.google.com/p/javaemvreader/wiki/ExampleOutput
Nice blog about EMV. Read it, I understand more. Thanks.
ReplyDeleteHi Pushpak,
ReplyDeleteWhat happen if card contains application with same priority,In that case how would automatic application selection will behave?
How priority of applications are decided?
does it make a difference to application selection if the application is credit application such as visa credit app?
DF Name: A000000003101008
Application Priority Indicator: 81
Your answer is greatly appreciated.
Thanks,
Ashutosh
Hi Pushpak!
ReplyDeleteCan you share the details about offline PIN validations Please..!
Hi Pushpak ,
ReplyDeleteJust a small correction in the posting, PPSE is not Paypass Payment System Environment it is Proximity Payment System Environment
thanks and in which block and how user data is stored in master card???
ReplyDeleteVery interesting topic, can you post some further information on this subject.
ReplyDeleteslim wallet
I am Varun from India, I am having issues with Reading Rupay Cards. Is there a way i can get in touch with you.
ReplyDeleteMy intention is just to read the Card number. Apart from the AID, is there any other changes for reading the PAN or card number. Can you help understand the APDUs for achieving my requirements.