smartcard basic
Resetting the card
To perform any communication with the card, we will need to obtain a card object. A card object is created using the new Card() constructor. The constructor accepts a card reader name as parameter. The predefined variable _scsh3.reader contains the default reader name.
var card = new Card(_scsh3.reader);
Now we can 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.
In our case we want a cold reset.
var atr = card.reset(Card.RESET_COLD);
ATR - Answer to Reset
After the reset signal from the terminal, the card will answer with a bytestring 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.
To get the data the card was sending, we use the class ATR. There are two methods to extract details from the ATR: "toByteString()" and "toString()".
var atrbin = atr.toByteString(); print(atrbin);
Expample:
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 ....
For more details use the method "toString()"
print(atr.toString());
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 twi 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.
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) 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).
APDU - Application Protocol Data Unit
After the reset, the communication between terminal and card works with APDUs.
Command APDU
The terminal sends a command APDU to the card. This command has a mandatory header and an optional body.
Response APDU
The card will execute the command and send a response APDU back to the terminal. The response APDU has an optional body consisting of data and a mandatory trailer with two status bytes "SW1" and "SW2". SW1 and SW2 combined are the status word (SW). If the status word has the value 0x9000 (SW1 = 0x90, SW2=0x00), the command was successfully executed by the card.
Data
Body
SW 1
SW 2
Trailer
Case 1 to 4
There are four different cases of APDU:
Case 1
Command: Header
Response: Trailer
Case 2
Command: Header + Le
Response: Data + Trailer
Case 3
Command: Header + Data
Response: Trailer
Case 4
Command: Header + Data + Le
Response: Data + Trailer
Read EMV Script
To read all data from the card, you can use the script contained in the following section:
try { 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());}
Line 06
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
To read the card's data we have to select the right ADF first. We'll do this with a SELECT command encoded as case 4 command APDU and transmitted using card.sendApdu():
The SELECT command supports the following options :
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.
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.
Tag30 : 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 Value30 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
Optional Byte 2:
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:
For length encodings > 127, the first byte contains the number of subsequent bytes, while the most significant bit is set to 1. The actual length is then encoded as integer value on the subsequent bytes with the most significant byte first.
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 01
Tag: "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"
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. If the card supports the Payment System Environment (PSE), the terminal reads out the necessary information to select the ADF.
If there is no PSE, the terminal will use a list of AIDs and get the right by trying.
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 01
and
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 found
The 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:
Source: EMV Book 3
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:
The PDOL related bytestring has the tag '83', the length byte and the concatenated data from the list above without tag and length bytes as value. In this case we set the value to zero.
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.
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.
Static Data Authentication (SDA)
SDA ensures the authenticity of ICC data. After SDA it is sure that the data from the ICC is real and hasn't changed by anyone.
But SDA doesn't assure the uniqueness of ICC data.
SDA is a digital signature scheme working with asymmetric cryptograhpy. Asymmetric cryptography uses a pair of keys. If you encode something with the first key, you can only decode it with the second key. The pair of keys is divided into a public and a private key. With the private key the issuer can "sign" critical data on ICC. Only the issuer knows the private key. The public key is not secret. Every terminal has the public key and can decode the signed data. If it conforms to the specification the data is authentic and has not changed.
In this figure we see the detailed process of authentication:
The Static application data will be signed with the Issuer Private Key (S1) and stored in Signed Application Data (SSAD). The corresponding Issuer Public Key (P1) will be stored in the Issuer PK Certificate. To verify that S1 and P1 are made by the Issuer, the Issuer PK Certificate is signed with a Certification Authority Private Key (SCA). The Certification Authority Public Key (PCA) is stored in the IC Terminal.
For SDA the terminals decrypt the Issuer PK Certificate with the PCA key. If the decryption was successful, the terminal extracts the P1 key to decrypt the SSAD. SDA was successful if the IC Terminal verifies the SSAD.
Retrieval of Certification Authority Public Key
For SDA we need first the Registered Application Provider Identifier (RID) to recognize whether we have a MasterCard or Visa Card because both have different public keys. To get the RID we extract the first five bytes of the Application Identifier (AID).
/** * Get RID from EMV data model * * @type ByteString * @return the 5 byte RID */ SDA.prototype.getRID = function() { var aid = this.emv.cardDE[EMV.AID]; var rid = aid.left(5); return(rid); }
The next step is to read the Certification Authority Public Key Index from the ICC. Each issuer have serveral public keys. The index reveal us which of them we need to process.
/** * Get the Public Key Index * * @type Number * @return the Public Key Index */ SDA.prototype.getPubKeyIndex = function() { var index = this.emv.cardDE[0x8F]; var index = index.toUnsigned(); return(index); }
Finally this function will return the public key:
/** * Get the public key * *@type Key *@return the public key */ SDA.prototype.getSchemePublicKey = function() { var rid = this.getRID(); var index = this.getPubKeyIndex(); var key = this.schemePublicKeyTable[rid.toString(HEX)][index]; return(key); }
Retrieval of Issuer Public Key
With the Certification Authority Public Key we decode the Issuer PK Certificate on the condition that both have the same length.
/** * Decrypt the Issuer PK Certificate * * @ return the decrypted Issuer PK Certificate */ SDA.prototype.decryptIssuerPKCertificate = function() { var certificate = this.emv.cardDE[0x90]; var key = this.getSchemePublicKey(); var decryptedCertificate = crypto.decrypt(key, Crypto.RSA, certificate); return(decryptedCertificate); }
The certificate contains the following data:
Issuer Public Key Certificate 0000 6A 02 45 70 96 FF 12 09 00 40 E2 01 01 80 03 EC j.Ep.....@...... 0010 59 32 AD A1 C4 C2 57 11 15 CC 11 C8 7B FD 9B 7E Y2....W.....{..~ 0020 98 A3 33 EB F1 C1 5B A2 52 9E 03 A3 E1 A0 2D BA ..3...[.R.....-. 0030 F7 CB 7E 20 A9 9E B0 F8 F3 C0 AB 20 30 67 07 D3 ..~ ....... 0g.. 0040 A4 52 02 E8 77 FC 0F B9 BC D9 0D 8E EE EE 89 BB .R..w........... 0050 12 05 C9 C8 C6 DF 12 C9 F8 D7 88 F8 62 2C BE FF ............b,.. 0060 D7 7F A0 39 D4 63 C7 89 2D 76 D1 D9 37 80 9B 1F ...9.c..-v..7... 0070 9C 83 AA D4 BE AD 95 5A 70 0D C4 A7 68 50 BD BC .......Zp...hP..
* NCA = Number of Bytes of Certifiacation Authority Public Key
* NI = Number of Bytes of Issuer Public Key Modulus
After decoding we have to proof 12 steps until we get the Issuer Public Key Modulus. The key consists of the leftmost digits of the Issuer Public Key which are stored in the certificate and the Issuer Public Key Remainder stored in an AEF file of the ICC. To get the Issuer Public Key Modulus concatenate the leftmost digits with the Issuer Public Key Remainder.
/** * Retrieval of Issuer Public Key * * @type Key * @return the Issuer Public Key */ SDA.prototype.retrievalIssuerPublicKey = function() { var key = this.getSchemePublicKey(); var modulus = key.getComponent(Key.MODULUS); var cert = this.decryptIssuerPKCertificate(); // Step 1: Issuer Public Key Certificate and // Certification Authority Public Key Modulus have the same length assert(cert.length == modulus.length); // Step 2: The Recovered Data Trailer is equal to 'BC' assert(cert.byteAt(modulus.length - 1) == 0xBC); // Step 3: The Recovered Data Header is equal to '6A' assert(cert.byteAt(0) == 0x6A); // Step 4: The Certificate Format is equal to '02' assert(cert.byteAt(1) == 0x02); // Step 5: Concatenation of Certificate Format through Issuer Public Key // or Leftmost Digits of the Issuer Public Key, // followed by the Issuer Public Key Remainder (if present), // and the Issuer Public Key Exponent var list; list = cert.bytes(1, 14 + (modulus.length - 36)); var remainder = this.emv.cardDE[0x92]; var exponent = this.emv.cardDE[0x9F32]; var remex = remainder.concat(exponent); list = list.concat(remex); // Step 6: Generate hash from concatenation var hashConcat = this.crypto.digest(Crypto.SHA_1, list); // Step 7: Compare the hash result with the recovered hash result. // They have to be equal var hashCert = cert.bytes(15 + (modulus.length - 36), 20); assert(hashCert.equals(hashConcat)); // Step 8: Verify that the Issuer Identifier matches the lefmost 3-8 PAN digits var pan = this.emv.cardDE[0x5A]; pan = pan.left(4); var panCert = cert.bytes(2, 4); var panCert = panCert.toString(HEX); var pan = pan.toString(HEX); for(var i = 0; i < 8; i++) { if(panCert.charAt(i) == 'F') { var panCert = panCert.substr(0, i); var pan = pan.substr(0, i); } } assert(pan == panCert); // Step 9: Verify that the last day of the month specified in the // Certification Expiration Date is equal to or later than today's date. // Step 10: Optional step // Step 11: Check the Issuer Public Key Algorithm Indicator var pkAlgorithmIndicator = cert.byteAt(12); // Step 12: Concatenate the Leftmost Digits of the Issuer Public Key // and the Issuer Public Key Remainder (if present) // to obtain the Issuer Public Key Modulus var leftmostDigits = cert.bytes(15, (modulus.length - 36)); var issuerPublicKeyModulus = leftmostDigits.concat(remainder); return(issuerPublicKeyModulus); }
Verification of Signed Static Application Data
We decode the Signed Static Application Data (SSAD) with the Issuer Public Key from the step before.
The decrypted SSAD contains the following data:
Signed Static Application Data 0000 6A 03 01 D1 79 BB BB BB BB BB BB BB BB BB BB BB j...y........... 0010 BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB ................ 0020 BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB ................ 0030 BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB ................ 0040 BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB ................ 0050 BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB ................ 0060 BB BB BB BB BB BB BB BB BB BB BB BC 93 56 B5 63 .............V.c 0070 68 FF C2 C9 48 E7 12 A7 C7 8A A1 3E D8 49 42 BC h...H......>.IB.
Now we have to proof 7 steps. If all steps were successful, SDA was successful:
/** * Verification of Signed Static Application Data * * @param {Key} key the Issuer Public Key */ SDA.prototype.verifySSAD = function(issuerPublicKeyModulus) { var issuerPublicKeyModulus = issuerPublicKeyModulus; // The Issuer Public Key consists of the Issuer Public Key Modulus // from the step before and the Issuer Public Key Exponent // read from the ICC. var key = new Key(); key.setType(Key.PUBLIC); key.setComponent(Key.MODULUS, issuerPublicKeyModulus); key.setComponent(Key.EXPONENT, this.emv.cardDE[0x9F32]); // Signed Static Application Data read from the ICC var SSAD = this.emv.cardDE[0x93]; // Step 1: Signed Static Application Data and Issuer Public Key Modulus // have the same length assert(SSAD.length == issuerPublicKeyModulus.length); // Step 2: The Recovered Data Trailer is equal to 'BC' var decryptedSSAD = crypto.decrypt(key, Crypto.RSA, SSAD); assert(decryptedSSAD.byteAt(decryptedSSAD.length -1) == 0xBC); // Step 3: The Recovered Data Header is equal to '6A' assert(decryptedSSAD.byteAt(0) == 0x6A); // Step 4: The Signed Data Format is equal to '03' assert(decryptedSSAD.byteAt(1) == 0x03); // Step 5: Concatenation of Signed Data Format, Hash Algorithm Indicator, // Data Authentication Code, Pad Pattern, the data listed by the AFL // and finally the SDA Tag List var list = decryptedSSAD.bytes(1, (decryptedSSAD.length - 22)); var daInput = this.emv.getDAInput(); var sdaTagList = this.emv.cardDE[0x9F4A]; if(typeof(sdaTagList != "undefined")) { for(var i = 0; i < sdaTagList.length; i++) { var tag = sdaTagList.byteAt(i); var value = new ByteBuffer(); value = value.append(this.emv.cardDE[tag]); } } list = list.concat(daInput); if(value != 0) { value = value.toByteString(); list = list.concat(value); } // Step 6: Generate hash from concatenation var hashConcat = this.crypto.digest(Crypto.SHA_1, list); // Step 7: Compare recovered hash with generated hash. Store the // Data Authentication Code from SSAD in tag '9F45' var hashSSAD = decryptedSSAD.bytes(decryptedSSAD.length - 21, 20); assert(hashConcat.equals(hashSSAD)); this.emv.cardDE[0x9F45] = decryptedSSAD.bytes(3, 2); print("SDA was successful"); }
Dynamic Data Authentication
Dynamic Data Authentication (DDA) is a more securer way of authentication because it authenticates the card itself. After the authentication we can trust on the uniqueness of the card.
SDA guarantees that data on cards is valid because we trust a high level certification authority which signs the data. But an attacker can record a card session and build for example a new virtuel card.
In contrast to SDA the card creates during the DDA process an own signature with their private key (SIC). This signature is different in every card session because it contains a random number generated by the terminal. The corresponding public key is stored in an ICC Public Key Certificate signed by the Certification Authority. With the public key we can proof the signature on genuineness.
Contrast between SDA and DDA
Authentication Process
The dynamic authentication process is related to SDA.
With PCA the terminal proofs the signature of the Issuer PK Certificate and extract the P1 key. The terminal proofs with P1 the signature of the ICC PK Certificate to get the PIC key. Now it is time to send an Internal Authenticate command to the card that contains a random number and initiates the card to compute the signature (Signed Dynamic Application Data/SDAD). With the PIC key the terminal checks the SDAD for guineness.
The retrieval of ICC Public Key starts after the Retrieval of Certification Authority Public Key and Retrieval of Issuer Public Key described in the chapter SDA.
First we have to decrypt the ICC Public Key Certificate.
DataAuthentication.prototype.retrievalICCPublicKey = function(issuerPublicKeyModulus) { var issuerPublicKeyModulus = issuerPublicKeyModulus; var key = new Key(); key.setType(Key.PUBLIC); key.setComponent(Key.MODULUS, issuerPublicKeyModulus); key.setComponent(Key.EXPONENT, this.emv.cardDE[0x9F32]); var iccCert = this.emv.cardDE[0x9F46];
The decrypted certificate contains the following data:
ICC Public Key Certificate: 0000 6A 04 45 70 96 54 32 00 43 03 FF FF 07 09 50 33 j.Ep.T2.C.....P3 0010 D6 01 01 80 03 C9 DE 79 AC 4E 62 D5 38 30 DB 3D .......y.Nb.80.= 0020 50 B8 7A 88 88 6F 74 11 D1 44 47 C8 88 46 93 F7 P.z..ot..DG..F.. 0030 0B C5 B3 A2 63 E4 0D 14 7A A3 10 47 33 73 73 B9 ....c...z..G3ss. 0040 5D 0B 05 61 44 00 45 F2 D7 E5 0D C5 83 C6 04 9A ]..aD.E......... 0050 7B 37 B8 E1 48 D6 09 6A B7 8F D9 2F C3 27 01 2B {7..H..j.../.'.+ 0060 6B FD 43 AB 02 76 E3 11 C7 3E 17 1E A7 C8 04 21 k.C..v...>.....! 0070 85 55 D8 0C 4F E8 D1 DC F0 7D 1C D5 61 46 57 BC .U..O....}..aFW.
Retrieval of ICC Public Key (PIC)
With step 1 to 4 we check whether the decryption was succesful.
//Step 1: ICC Public Key Certificate and Issuer Public Key Modulus have the same length assert(iccCert.length == issuerPublicKeyModulus.length); //Step 2: The Recovered Data Trailer is equal to 'BC' var decryptedICC = crypto.decrypt(key, Crypto.RSA, iccCert); assert(decryptedICC.byteAt(decryptedICC.length - 1) == 0xBC); //Step 3: The Recovered Data Header is equal to '6A' assert(decryptedICC.byteAt(0) == 0x6A); //Step 4: The Certificate Format is equal to '04' assert(decryptedICC.byteAt(1) == 0x04);
Step 5 implements the concatenation which is necessary to apply the hash algorithm in the next step.
For the concatenation we need from the ICC Public Key Certificate:
Certificate Format
Application PAN
Certificate Expiration Date
Certificate Serial Number
Hash Algorithm Indicator
ICC Public Key Algorithm Indicator
ICC Public Key Lnegth
ICC Public Key Exponent Length
ICC Public Key or Leftmost Digits of the ICC Public Key
Also we need
ICC Public Key Remainder (if present)
ICC Public Key Exponent
Data located by the AFL
SDA Tag List
// Step 5: Concatenation var list = decryptedICC.bytes(1, (decryptedICC.length - 22)); var remainder = this.emv.cardDE[0x9F48]; var exponent = this.emv.cardDE[0x9F47]; var remex = remainder.concat(exponent); list = list.concat(remex); var daInput = this.emv.getDAInput(); list = list.concat(daInput); var sdaTagList = this.emv.cardDE[0x9F4A]; if(typeof(sdaTagList != "undefined")) { var value = new ByteBuffer(); for(var i = 0; i < sdaTagList.length; i++) { var tag = sdaTagList.byteAt(i); value = value.append(this.emv.cardDE[tag]); } value = value.toByteString(); list = list.concat(value); } // Step 6: Generate hash from concatenation var hashConcat = this.crypto.digest(Crypto.SHA_1, list); // Step 7: Compare recovered hash with generated hash var hashICC = decryptedICC.bytes(decryptedICC.length - 21, 20); assert(hashConcat.equals(hashICC)); // Step 8: Verify that the Issuer Identifier matches the lefmost 3-8 PAN digits var pan = this.emv.cardDE[0x5A]; var panCert = decryptedICC.bytes(2, 10); var panCert = panCert.toString(HEX); var pan = pan.toString(HEX); for(var i = 0; i < 20; i++) { if(panCert.charAt(i) == 'F') { var panCert = panCert.substr(0, i); var pan = pan.substr(0, i); } } assert(pan == panCert); // Step 9: Verify that the last day of the month specified // in the Certification Expiration Date is equal to or later than today's date. // Not proved, so you can test your expired cards. // Step 10: Check the ICC Public Key Algorithm Indicator var pkAlgorithmIndicator = decryptedICC.byteAt(18);
If step 5 to 10 were successful we can start concatenating the ICC Public Key (PIC).
// Step 11: Concatenate the Leftmost Digits of the ICC Public Key //and the ICC Public Key Remainder (if present) to obtain the ICC Public Key Modulus var modulus = key.getComponent(Key.MODULUS); var leftmostDigits = decryptedICC.bytes(21, (modulus.length - 42)); var iccPublicKeyModulus = leftmostDigits.concat(remainder); return(iccPublicKeyModulus) }
Internal Authenticate
The Internal Authenticate command initiates the card to sign with their Privat Key (SIC) Dynamic Application Data and a random number generated by the terminal. The card will return the Signed Dynamic Application Data.
Structure of the Internal Authenticate command:
Dynamic Data Authentication
DataAuthentication.prototype.dynamicDataAuthentication = function(iccPublicKeyModulus){ var iccPublicKeyModulus = iccPublicKeyModulus; var Data = crypto.generateRandom(4); var internalAuthenticate = card.sendApdu(0x00, 0x88, 0x00, 0x00, Data, 0x00); var asn = new ASN1(internalAuthenticate); var tag = asn.find(0x9F4B); var SDAD = tag.value;
Signed Dynamic Application Data
Now we decode the Signed Dynamic Application Data
var picKey = new Key(); picKey.setType(Key.PUBLIC); picKey.setComponent(Key.MODULUS, iccPublicKeyModulus); picKey.setComponent(Key.EXPONENT, this.emv.cardDE[0x9F47]); var decryptedSDAD = crypto.decrypt(picKey, Crypto.RSA, SDAD);
Decrypted SDAD: 0000 6A 05 01 09 08 0C 1E 38 91 B9 1B E7 62 BB BB BB j......8....b... 0010 BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB ................ 0020 BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB ................ 0030 BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB ................ 0040 BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB ................ 0050 BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB ................ 0060 BB BB BB BB BB BB BB BB BB BB BB 33 C2 28 11 71 ...........3.(.q 0070 05 9A D4 2A 9A B1 EF 66 93 E8 86 7B 30 AF CF BC ...*...f...{0...
If the following 7 steps were successful, DDA was successful.
//Step 1: SDAD and ICC Public Key Modulus have the same length assert(SDAD.length == iccPublicKeyModulus.length); //Step 2: The Recovered Data Trailer is equal to 'BC' assert(decryptedSDAD.byteAt(decryptedSDAD.length - 1) == 0xBC); //Step 3: The Recovered Data Header is equal to '6A' assert(decryptedSDAD.byteAt(0) == 0x6A); //Step 4: The Signed Data Format is equal to '05' assert(decryptedSDAD.byteAt(1) == 0x05); //Step 5: Concatenation of Signed Data Format, Hash Algorithm Indicator, // ICC Dynamic Data Length, ICC Dynamic Data, Pad Pattern, random number var LDD = decryptedSDAD.byteAt(3); var list = decryptedSDAD.bytes(1, 3 + LDD + decryptedSDAD.length - LDD - 25); list = list.concat(Data); //Step 6: Genereate hash from concatenation var hashConcat = this.crypto.digest(Crypto.SHA_1, list); //Step 7: Compare recovered hash with generated hash var hashSDAD = decryptedSDAD.bytes(decryptedSDAD.length - 21, 20); assert(hashConcat.equals(hashSDAD)); print("DDA was successful"); }
Processing Restrictions
Processing Restrictions checks whether card and terminal are compatible. That comprises:
Application Version Number
Application Usage Control
Application Effective/ Expiration Dates Checking
Thefore the terminal just reads the corresponding files from the card. The terminal has the possibility to reject the transaction. If incompatibility occurs the incident will be written in the Terminal Verification Results (TVR).
The terminal shall examine the Application Version Number on the card. If there is no version number, the terminal shall continue transaction processing. If the version numbers between card and terminal are different, the terminal shall set the "ICC and terminal have different application versions" bit in the TVR to 1.
Application Usage Control on the card determines for which transactions the card is authorised.
In the Application Usage Control is defined whether the card can be used with Automated Teller Machines or with other terminals. Furthermore is defined whether cash transactions, purchase of goods, purchase of services or cashback amounts are freed for national and or international use.
If the Application Effective Date is present and the current date is less than the Application Effective Date, the terminal shall set the "Application not yet effective" bit in the TVR to 1.
If the current date is greater than the Application Expiration Date, the terminal shall set the "Expired aaplication" bit in the TVR to 1.
Cardholder Verification
Cardholder verification ensures that no third-parties using the card.
The card has a Cardholder Verification Method List (CVM List) to inform the terminal wether and which verification methods have to be executed.
If a CVM failed or was not executed the corresponding bit in the TVR has to be set to 1.
The CVM List has an anmount and a second amount field of each 4 bytes. Both amount fields have an implicit decimal pointer which is determined in the Application Currency Code.
Following there is a variable length list of Cardholder Verification Rules (CV Rules). Each CV Rule is consisting of two bytes.
CV Rule Byte 1
Source: EMV Book 3
Structure of CVM List
Application Version Number
Application Usage Control
Application Effective/ Expiration Dates Checking
CV Rule Byte 2
Source: EMV Book 3
X is referred to the amount field
Y is referred to the second amount field
Cardholder Verification Method (CVM) List: 00000000000000005E031F03 Apply succeeding CV Rule if this CVM is unsucccessful Signature (paper) If terminal supports the CVM Fail cardholder verification if this CVM is unsuccessful No CVM required If terminal supports the CVM
Terminal Risk Management
Terminal Risk Management shall protect the Issuer and the acquirer from fraud.
Therefor the terminal
checks the floor limit
select a random transaction for online processing
checks the Velocity
The terminal can save the Application PAN, the transaction amount, the Application PAN Sequence Number and the Transaction Date to prevent split sales. During the transaction the terminal can check the log for entries, sum up the most recent amounts and check if the floor limit is exceeding.
If the sum/current amount is greater than or equal to the Terminal Floor Limit, the "Transaction exceeds floor limit" bit in the TVR shall set to 1.
The Terminal will select accidently a transaction for online processing. It has a Threshold Value, depending on the amount is higher or lower than the Threshold Value there are different percentages of selection. If the transaciton shall completed online, the corresponding bit in the TVR shall set to 1.
After a certain number of offline transactions the next transaction shall be proceed online.
The soft cap of offline transactions is written in the The Lower Consecutive Offline Limit. After that the next transaction shall be approved online if the terminal has an online ability, if not the transaction will be completed offline.
The Upper Consecutive Offline Limit is the hard cap after that no more offline transactions can be executed.
To check for velocity the terminal needs:
Lower Consecutive Offline Limit (Tag: 9F14)
Upper Consecutive Offline Limit (Tag: 9F23)
Application Transaction Counter (ATC)
Last Online ATC Register
If there are no Lower/Upper Consecutive Offline Limit data objetcts on the card, the terminal shall skip velocity checking. To get the ATC and Last Online ATC Register we send a Get Data command to the card.
Get Data Command
The Last Online ATC Register has the ATC value of the last transaction went online. To check whether the limit is exceeded, the terminal takes the difference between the ATC and the Last Online ATC Register. Then compare the result with the Lower/Upper Consecutive Offline Limit.
If there is an online decision the corresponding TVR bit shall set to 1.
Terminal Action Analysis
The terminal has to decides either to proceed the transaction offline, to go online or to reject the transaction. The Terminal will send the decision with a Generate AC command to the card.
The decision is based on the Transaction Verification Results. There are several lists called Issuer Action Code (IAC) and Terminal Action Code (TAC) which give a directive to evaluate the TVR.
IAC, TAC and TVR have the same structure.
Source: EMV Book 3
Byte 1:
Example for a CVM List
Structure
Floor Limit
Random Transaction Selection
Velocity Checking
Byte 2:
Byte 3:
Byte 4:
Byte 5:
Issuer Action Code - Online, Denial, Default
There are three kinds of every IAC/TAC list: Online, Denial and Default.
IAC - Online
This specifies the issuer's conditions to approve a transaction online.
Example:
Issuer Action Code - Online: FC68BC9800 Byte 1: Offline data authentication was not performed (b8) SDA failed (b7) ICC data missing (b6) Card appears on terminal exception file (b5) DDA failed (b4) CDA failed (b3) Byte 2: Expired application (b7) Application not yet effective (b6) New card (b4) Byte 3: Cardholder verification was not successful (b8) PIN Try Limit exceeded (b6) PIN entry required and PIN pad not present or not working (b5) PIN entry required, PIN pad present, but PIN was not entered (b4) Online PIN entered (b3) Byte 4: Transaction exceeds floor limit (b8) Transaction selected randomly for online processing (b5) Merchant forced transaction online (b4) Byte 5:
TVR byte two b7 is set to 1 (New Card). This match with byte two b7 from the Issuer Action Code - Online.
As a Result of this the Terminal will decide to proceed the transaction online.
IAC - Denial
This specifies the issuer's conditions to reject a transaction.
Example:
Issuer Action Code - Denial: 0010180000 Byte 1: Byte 2: Requested service not allowed for card product (b5) Byte 3: PIN entry required and PIN pad not present or not working (b5) PIN entry required, PIN pad present, but PIN was not entered (b4) Byte 4: Byte 5:
The transaction will be rejected, if byte three b5 is set to 1 in the TVR and IAC.
IAC - Default
If the Terminal has no online ability, the IAC - Default list specifies the issuers's conditions to reject a transaction.
Example:
Issuer Action Code - Default: FC40AC8000 Byte 1: Offline data authentication was not performed (b8) SDA failed (b7) ICC data missing (b6) Card appears on terminal exception file (b5) DDA failed (b4) CDA failed (b3) Byte 2: Expired application (b7) Byte 3: Cardholder verification was not successful (b8) PIN Try Limit exceeded (b6) PIN entry required, PIN pad present, but PIN was not entered (b4) Online PIN entered (b3) Byte 4: Transaction exceeds floor limit (b8) Byte 5:
If TVR and IAC both have byte four b8 set to 1 the transaction will be rejected.
The TAC specifies the terminal's conditions. It is similar to the IAC.
If the terminal made an decision, it will send with a Generate AC command to the card. Depending on the decision, the terminal requires different Application Cryptograms from the card.
Source: EMV Book 3
The Command Message has the following structure:
Terminal Action Code - Online, Denial, Default
Generate AC
Coding of P1:
The transaction-related data is depending on a Card Risk Management Data Objetct List 1(CDOL1).
This CDOL is given by the card. It contains the tagname and length of the expected data.
Card Risk Management Data Object List 1 (CDOL1): 9F02069F030695055F2A029A039C019F37049F4C089F4502 // Tag - Length - Meaning 9f02 - 06 - Authorised amount of the transaction (excluding adjustments) 9f03 - 06 - Secondary amount associated with the transaction representing a cashback amount 95 - 05 - Terminal Verification Results 5f2a - 02 - Transaction Currency Code 9a - 03 - Transaction Date 9c - 01 - Transaction Type 9f37 - 04 - Unpredictable Number 9f4c - 08 - ICC Dynamic Number 9f45 - 02 - Data Authentication Code
First we create an ByteString which corresponds to the CDOL1 above.
To obtain the ICC Dynamic Number we send a Get Challenge command to the card. The card will return an 8-byte unpredictable number.
var authorisedAmount = new ByteString("000000000001", HEX); var secondaryAmount = new ByteString("000000000000", HEX); var tvr = new ByteString("0000000000", HEX); var transCurrencyCode = new ByteString("0978", HEX); var transDate = new ByteString("090730", HEX); var transType = new ByteString("21", HEX); var unpredictableNumber = crypto.generateRandom(4); var iccDynamicNumber = card.sendApdu(0x00, 0x84, 0x00, 0x00, 0x00); var DataAuthCode = e.cardDE[0x9F45]; var Data = authorisedAmount.concat(secondaryAmount).concat(tvr) .concat(transCurrencyCode).concat(transDate) .concat(transType).concat(unpredictableNumber) .concat(iccDynamicNumber).concat(DataAuthCode);
Then we set P1 to '40', to request an Transaction Certificate (offline transaction) and execute the Generate AC command.
var p1 = 0x40; var generateAC = card.sendApdu(0x80, 0xAE, p1, 0x00, Data, 0x00);
The Generate AC command was succesful if the card returns SW1/SW2=9000.
96 C: 00 84 00 00 - GET CHALLENGE Le=0 R: SW1/SW2=9000 (Normal processing: No error) Lr=8 0000 8D 51 F4 6C 9F 40 5F 71 .Q.l.@_q 96 C: 80 AE 40 00 - UNKNOWN_INS Lc=37 0005 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................ 0015 00 09 78 09 07 30 21 2C 76 4F 65 8D 51 F4 6C 9F ..x..0!,vOe.Q.l. 0025 40 5F 71 D1 79 @_q.y Le=0 R: SW1/SW2=9000 (Normal processing: No error) Lr=32 0000 77 1E 9F 27 01 80 9F 36 02 02 13 9F 26 08 2D F3 w..'...6....&.-. 0010 83 3C 61 85 5B EA 9F 10 07 06 84 23 00 31 02 08 .<a.[......#.1..
Card Action Analysis
When the card gets the Generate AC command it will perform an own risk management and make a final decision whether the transaction process shall be complete offline, online or be rejected.
The decision will be send to the terminal in the response message of the Generate AC command.
There are two different formats for the data field returned in the response message.
Format 1, Tag '80'
The data object is a primitive data object. The value field consists of a concatenation of data objects without tag and length bytes.
The data objects are:
Cryptogram Information Data (CID)
Application Transaction Counter (ATC)
Application Cryptogram (AC)
Issuer Application Data (IAD) (optional data object)
Format 2, Tag '77'
The data object is a constructed data object. The value field contains TLV coded data objects. Mandatory data objects are:
Tag: '9F27' - Cryptogram Information Data (CID)
Tag: '9F36' - Application Transaction Counter (ATC)
Tag: '9F26' - Application Cryptogram (AC)
The CID reveal what kind of Application Cryptogramm is returned. It can optionally contain an advice message if the transaction will rejected.
Source: EMV Book 3
Coding of Cryptogram Information Data
Data Formats
Example
Example
R: SW1/SW2=9000 (Normal processing: No error) Lr=32 0000 77 1E 9F 27 01 80 9F 36 02 02 13 9F 26 08 2D F3 w..'...6....&.-. 0010 83 3C 61 85 5B EA 9F 10 07 06 84 23 00 31 02 08 .<a.[......#.1..
This is a format 2 response message to the Generate AC command.
It contains an ARQC which means that the transaction should be proceed online.
Completion
If the card answers on a Generate AC command with a TC, the transaction will be completed offline.
During the online processing the issuer can review and authorise or reject transactions.
The transaction will be completed with a second Generate AC command, sending either a TC or an AAC.