Now we are a few years into EMV mandates in the US, we all have one or more EMV chip cards in our wallet and have used them in stores.
In the old days, the curious bunch bought magnetic card readers to see what’s encoded in the mag stripe. These mag card readers, and many of the similar used in restaurants and stores, simply emulate keyboard input, so what's read when a card is swiped is sent through keyboard I/O to the operating system. Thus, opening Notepad allows us to see what's in the mag stripe.
Payment card footprint is ISO/IEC 7810 ID-1 standard. Payment card with Chip is conforming to ISO/IEC 7816, which is also called a Smart Card. Some of the professional grade laptops come with a built-in smart card slot (for access cards), but any USB smart card reader will do. For example, this one for $15. Most of them work with Windows and Mac, but if you are on Linux, chances are they will also work, but you might want to dig a little deeper.
You can certainly write your own software to interact with the reader. Or you can download and use free Smart Card Shell from CardContact Developer Network. You can get access to their git repository if you register with their developer network and store the access key in a SmartCard HSM.
Smart Card Shell is written in Java, so you want to have a JRE on your computer. The latest OpenJDK 14 works smoothly.
Once installed, there are 2 ways to run the shell. scsh3 (or scsh3.cmd) runs the shell in a command line console; scsh3gui (or scsh3gui.cmd) runs a simple GUI which has a a nice "trace" tab that logs not only what you explicitly print in your script, but also the raw interaction with the card.
Since we are interested in EMV, Smart Card Shell also provides EMV abstraction library to work with them.
You can git clone or download the scripts from https://github.com/CardContact/scsh-scripts
Now, insert an EMV chip card into your smart card reader, fire up the shell, and load the emv/dump.js script (make sure you have the right path to where the script is):
load("scripts/emv/dump.js");
Congratulations! Now you have successfully peeked into your EMV card!
Let's look at dump.js
load("emv.js");
load("emvView.js");
emv.js abstracts the operations supported by EMV, emvView.js pretty formats the data for display.
var card = new Card(_scsh3.reader);
card.reset(Card.RESET_COLD);
Card is what Smart Card Shell provides as an abstraction to interact with smart cards. RESET_COLD is to power off and on to the card.
e.selectPSE(false);
var aid = e.getAID();
if (aid != null) {
e.selectADF(aid);
} else {
e.tryAID();
}
The very first step of an EMV processing is to select a Payment Service Envrionment (PSE). In general, there are contact and contactless environments. Since we are using a card reader which by definition is contact, selectPSE() with false to indicate it's not contactless.
An EMV card may support one or many "Applications" which are denoted by Application ID (AID). For example, Visa Credit has an AID, Visa Debit has a different AID, MasterCard has many AIDs for different products, etc. On a single card, it can support multiple AIDs, for example, both credit and debit; multiple AIDs are priorized.
Terminals have supported AIDs as provisioned by acquirers. So this is a handshake for the terminal and card to agree on which AID to process on. The complete list of AIDs can be found here. The sample script that simulates a terminal supports 3 AIDs, which can be found in emv.js:
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" };
Each AID has specific File Control Information (FCI), which can be retrieved from card. FCI denotes how terminals can read the application data from the card. This can be seen from the tryAID() function in emv.js:
var fci = this.select(aid, true);
if (fci.length > 0) {
this.cardDE[EMV.AID] = aid;
this.decodeFCI(fci);
}
Card can also decide which data are required from terminal before terminals start to read application data. Terminals format these Processing Data Object List (PDOL) and send them to cards in Get Processing Options operation. This is done in initApplProc() function in emv.js:
var pdol = this.cardDE[EMV.PDOL];
var pdolenc = null;
if (typeof(pdol) != "undefined") {
pdolenc = this.createDOL(pdol);
var length = pdolenc.length
var length = length.toString(HEX);
if (pdolenc.length <= 0xF) {
length = "0".concat(length);
}
var length = new ByteString(length, HEX);
pdolenc = new ByteString("83", HEX).concat(length).concat(pdolenc);
print(pdolenc);
}
var data = this.getProcessingOptions(pdolenc);
Get Processing Options returns Application Interchange Profile (AIP), which processing steps are supported (card authentication, cardholder verification, etc.) for this transaction.
Now, the terminal can read the application data from the card. Application File Locator (AFL) has the instruction on how to read the data. AFL also indicates which data read are used in Data Authentication (DA) process. These are encoded in the 4 bytes for every Short File Identifier (SFI) inside AFL.
This is in emv.js:
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("Record No. " + 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--;
}
At this point, we have all the code needed to read application data from EMV cards!
Let's go through the output.
<----------------------------Display Data Elements-----------------------------
Application Identifier (AID) - card: A000000025010801
Application Label: 414D45524943414E2045585052455353 - AMERICAN EXPRESS
Track 2 Equivalent Data (Magnetic Strip):
Primary Account Number: 3712*******1009
Expiration Date (YYMM): 2010
Service Code: 201
Discretionary Data: 15107427500000
Application Primary Account Number (PAN): 3712*******1009F
This part shows my American Express card, its AID, the track 2 data (track 2 is what's normally encoded in the mag stripe of a card, and is what's being transmitted for processing), and my PAN. Note I masked mine, but you should see the full PAN.
Application Interchange Profile: 3C00
Byte 1:
DDA supported (b6)
Cardholder verification is supported (b5)
Terminal risk management is to be performed (b4)
Issuer authentication is supported (b3)
Byte 2:
AIP data here:
Application Priority Indicator: 01
This selected AID has the highest priority, if there are multiple AIDs matching between terminal and card.
Card Risk Management Data Object List 1 (CDOL1): 9F02069F03069F1A0295055F2A029A039C019F3704
9f02 - 6 - Authorised amount of the transaction (excluding adjustments)
9f03 - 6 - Secondary amount associated with the transaction representing a cashback amount
9f1a - 2 - Terminal Country Code
95 - 5 - Terminal Verification Results
5f2a - 2 - Transaction Currency Code
9a - 3 - Transaction Date
9c - 1 - Transaction Type
9f37 - 4 - Unpredictable Number
Card Risk Management Data Object List 2 (CDOL2): 8A029F02069F03069F1A0295055F2A029A039C019F3704
8a - 2 - Authorisation Response Code
9f02 - 6 - Authorised amount of the transaction (excluding adjustments)
9f03 - 6 - Secondary amount associated with the transaction representing a cashback amount
9f1a - 2 - Terminal Country Code
95 - 5 - Terminal Verification Results
5f2a - 2 - Transaction Currency Code
9a - 3 - Transaction Date
9c - 1 - Transaction Type
9f37 - 4 - Unpredictable Number
Card Risk Management Data Object List (CDOL) are the data elements needed to generate Application Cryptogram (AC). CDOL1 is the requirement to generate Application ReQuest Cryptogram (ARQC) by card and sent to issuer for authorization; CDOL2 is the requirement to generate Application ResPonse Cryptogram (ARPC) by issuer and returned in authorization message.
Cardholder Verification Method (CVM) List: 000000000000000042011E031F0200000000000000000000
Apply succeeding CV Rule if this CVM is unsucccessful
Enciphered PIN verified online
If unattended cash
Fail cardholder verification if this CVM is unsuccessful
Signature (paper)
If terminal supports the CVM
Fail cardholder verification if this CVM is unsuccessful
No CVM required
If not unattended cash and not manual cash and not purchase with cashback
Fail cardholder verification if this CVM is unsuccessful
Fail CVM processing
Always
Cardholder Verification Methods (CVM) is a prioritized list of rules.
For example, the first rule says if this card is used in an unattended cash transaction, require encrypted PIN online, if it fails, not the end of the world, try the next verification method that's applicable. The next one in line is "Signature (paper)" if terminal supports it. But most likely an unattended cash transaction wouldn't have the signature capability, for unattended cash, it will likely skip it.
The next one is "No CVM equired" but the condition explicitly excludes unattended cash. The final one is always "Fail CVM processing". So, in nutshell, for unattended cash transaction, one has to successfully pass online encrypted PIN verification.
If the transaction is credit card in store, it will activate "Signature (paper)" rule, the terminal will print a receipt with signature line, and instructs the store clerk to obtain customer signature.
If the transaction is credit card without cashback at a vending machine, it will activate "No CMV Required" rule, which doesn't need cardholder verification.
Certification Authority Public Key Index: 0F
Issuer Public Key Certificate: B0A3DCCD60AEEE9EEF61209A655F2E9646B8E8B8FF0F3315CE61BB942702F7D0ED9E6D512AD92D4AD8480B926553926EE50EF47B17E4428A778E7E7EA1C933FD03272D29B8D07E4C54928F169B672242524383A60836A04A70489F8B7AFA70AFD4C989A6BD1A0E25D7B4521D7D08920FC45E087375BEBD4AC04949A101C0A131CBDE121F7FE7E7A0E9730B9A5D0CE730C359D960420DDA241788D6BEE14D663D29176C9367D215B149208E2AF5D94099
Issuer Public Key Remainder: 24E5B52B
Issuer Public Key Exponent: 03
Application Currency Code: 0840
ICC Public Key Certificate: 83A1898AF7DE8CD7F8FD7BF008A17FB9612158DC1189EC4EF897BFD99271DAD2DD62087958C44FCA05DC069D6E3555BBA4A89B01ED089BC6796E93E2069574EF416F3C9C622D39B2C60A544E7B44F5FA1DD94AA84C6D47FB4C31A71FC5249AAD1DD5891C01BF5FB8E3EA620D6CA6519274F392B431E3F85ACBABBE60CDE3D8CE5ACABAEA5626540B2B79923D222914F8
ICC Public Key Exponent: 03
ICC Public Key Remainder: C14D885E3ADAC2431E49
Dynamic Data Authentication Data Object List (DDOL): 9F3704
9f37 - 4 - Unpredictable Number
Static Data Authentication Tag List: 82
Certification Authority (CA) Public Keys are loaded on terminals by acquirers. CA in EMV context are card schemes (Visa, MasterCard, AMEX, etc.), each can have multiple public keys. Therefore an index is needed to indicate which public key is used to provision this card. The full list of CA public keys can be found here.
CA Public Key is used by terminal to restore Issuer Public Key from the Issuer Public Key Certificate.
The data structure holding Issuer Public Key is often too small for the complete key, therefore, the remainder in Issuer Public Key Remainder needs to be concatenated to the restored Issuer Public Key for completeness.
Similarly, for cards that support offline Dynamic Data Authentication, the ICC Public Key is also embedded in the card in the format of ICC Public Key Certificate. Issuer Public Key is used to restore ICC Public Key from ICC Public Key Certificate.
Similarly, ICC Public Key Remainder contains the overflow of the key.
Dynamic Data Authentication Data Object List (DDOL) denotes which data elements need to be used to run a Dynamic Data Authentication. In this case it's an unpreditable (random) number.
Static Data Authentication Tag List is the piece of original data together with ICC Public Key that are signed into the ICC Public Key Certificate. It is needed to verify if the ICC Public Key Certificate is authentic.
Application File Locator: 0801010008020201080405001002020018030300
SFI: 1
First/Only Record Number: 1
Last Record Number: 1
Number of records involved in offline data authentication: 0
SFI: 1
First/Only Record Number: 2
Last Record Number: 2
Number of records involved in offline data authentication: 1
SFI: 1
First/Only Record Number: 4
Last Record Number: 5
Number of records involved in offline data authentication: 0
SFI: 2
First/Only Record Number: 2
Last Record Number: 2
Number of records involved in offline data authentication: 0
SFI: 3
First/Only Record Number: 3
Last Record Number: 3
Number of records involved in offline data authentication: 0
AFL indicates how to read application data from the card, and which ones are used in data authentication (see above)
Application Usage Control: FF00
Byte 1:
Valid at terminals other than ATMs
Valid at ATMs
Valid for international services
Valid for domestic services
Valid for international goods
Valid for domestic goods
Valid for international cash transactions
Valid for domestic cash transactions
Byte 2:
The card also dictates which use cases are supported. If a terminal's use case isn't supported in this list, terminal should fail the transaction.
A sample script doemv.js is also included in the git repository. This script not only dumps the data from EMV cards, but also attempts to
Note that many new EMV cards do not support SDA (like mine). If your dump of AIP says only DDA is supported, please comment out the SDA code invocation in doemv.js:
//d.verifySSAD(issuerPublicKeyModulus);
Also important, the CA Public Keys stored in git repository are incomplete, in fact, it only contains a subset of Visa public keys. So in order to support your card, you may need to supplement it with the public key needed by your card.
To find which CA public key is needed, add a debug print in dataAuthentication.js to print out rid and index:
DataAuthentication.prototype.getSchemePublicKey = function() {
var rid = this.getRID();
var index = this.getPubKeyIndex();
print("rid="+rid+", index="+index);
Then look up the CA Public Key here by rid and index. For example, my AMEX card's rid is A000000025 and index is 0F, so the missing public key is
C8D5AC27A5E1FB89978C7C6479AF993AB3800EB243996FBB2AE26B67B23AC482C4B746005A51AFA7D2D83E894F591A2357B30F85B85627FF15DA12290F70F05766552BA11AD34B7109FA49DE29DCB0109670875A17EA95549E92347B948AA1F045756DE56B707E3863E59A6CBE99C1272EF65FB66CBB4CFF070F36029DD76218B21242645B51CA752AF37E70BE1A84FF31079DC0048E928883EC4FADD497A719385C2BBBEBC5A66AA5E5655D18034EC5
and key length is 1408.
Add a new XML inside schemepublickey directory (this directory is in parallel to emv.js), similar to the Visa public key XMLs already there. Make sure you replace the followings correctly:
Then, in doemv.js, add the new XML to the public key list:
var d = new DataAuthentication(e);
d.addSchemePublicKey(new ByteString("A000000003", HEX), 1, new Key("schemepublickeys/kp_visa_1024_01.xml"));
d.addSchemePublicKey(new ByteString("A000000003", HEX), 7, new Key("schemepublickeys/kp_visa_1152_07.xml"));
d.addSchemePublicKey(new ByteString("A000000003", HEX), 8, new Key("schemepublickeys/kp_visa_1408_08.xml"));
d.addSchemePublicKey(new ByteString("A000000003", HEX), 9, new Key("schemepublickeys/kp_visa_1984_09.xml"));
// add more ...
// add more ...
// add more ...
What's illustrated and explained in this article is the tip of an iceberg. EMV specification is gigantic and complicated and sometimes confusing.
Here are some useful links:
Have fun!
Previously published at https://www.linkedin.com/pulse/examining-your-emv-chip-cards-kenny-shi/