smartcard basic

Resetting the card

https://medium.com/@psk_dream/%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99-python-3-%E0%B8%95%E0%B8%B4%E0%B8%94%E0%B8%95%E0%B9%88%E0%B8%AD%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B9%80%E0%B8%84%E0%B8%A3%E0%B8%B7%E0%B9%88%E0%B8%AD%E0%B8%87%E0%B8%AD%E0%B9%88%E0%B8%B2%E0%B8%99%E0%B8%9A%E0%B8%B1%E0%B8%95%E0%B8%A3-%E0%B8%9B%E0%B8%A3%E0%B8%B0%E0%B8%8A%E0%B8%B2%E0%B8%8A%E0%B8%99-c9ef4980733a


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:

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.

Offline Transaction

Online Transaction