From 9206d3b0342c5d0a594715eab06f6db232329c8d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 20 Mar 2016 19:37:29 +0100 Subject: [PATCH] ADD: copied all EMV files from peter filmoores fork. Have not started with making it work in current fork. (a lot of work) --- armsrc/emvcard.h | 245 +++++ armsrc/emvcmd.c | 740 +++++++++++++ armsrc/emvcmd.h | 32 + armsrc/emvdataels.c | 127 +++ armsrc/emvdataels.h | 56 + armsrc/emvutil.c | 1837 +++++++++++++++++++++++++++++++++ armsrc/emvutil.h | 89 ++ armsrc/tlv.c | 78 ++ armsrc/tlv.h | 34 + common/emvtags.h | 249 +++++ traces/EMV/mastercardtags.txt | 5 + traces/EMV/testcard.txt | 4 + traces/EMV/visaCVN17.txt | 9 + traces/EMV/visaDCVV.txt | 9 + traces/EMV/visaEMV.txt | 9 + traces/EMV/visaFDDA.txt | 9 + traces/EMV/visatags.txt | 9 + 17 files changed, 3541 insertions(+) create mode 100644 armsrc/emvcard.h create mode 100644 armsrc/emvcmd.c create mode 100644 armsrc/emvcmd.h create mode 100644 armsrc/emvdataels.c create mode 100644 armsrc/emvdataels.h create mode 100644 armsrc/emvutil.c create mode 100644 armsrc/emvutil.h create mode 100644 armsrc/tlv.c create mode 100644 armsrc/tlv.h create mode 100644 common/emvtags.h create mode 100644 traces/EMV/mastercardtags.txt create mode 100644 traces/EMV/testcard.txt create mode 100644 traces/EMV/visaCVN17.txt create mode 100644 traces/EMV/visaDCVV.txt create mode 100644 traces/EMV/visaEMV.txt create mode 100644 traces/EMV/visaFDDA.txt create mode 100644 traces/EMV/visatags.txt diff --git a/armsrc/emvcard.h b/armsrc/emvcard.h new file mode 100644 index 00000000..7757949f --- /dev/null +++ b/armsrc/emvcard.h @@ -0,0 +1,245 @@ +//----------------------------------------------------------------------------- +// Peter Fillmore 2014 +// code derived off merloks mifare code +// +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// structure to hold EMV card and terminal parameters +//----------------------------------------------------------------------------- +#ifndef __EMVCARD_H +#define __EMVCARD_H + +//structure to hold received/set tag values +//variable data inputs have length specifiers +typedef struct { + //ISO14443-A card stuff + uint8_t ATQA[2]; //Answer to Request + uint8_t UID_len; + uint8_t UID[10]; + uint8_t SAK; + uint8_t ATS_len; //Answer to select + uint8_t ATS[256]; + //ATS + uint8_t TL; + uint8_t T0; + uint8_t TA1; + uint8_t TB1; + uint8_t TC1; + uint8_t* historicalbytes; + //PPS response + uint8_t PPSS; + //SFI 2 record 1 + uint8_t tag_4F_len; //length of AID + uint8_t tag_4F[16]; //Application Identifier (AID) + uint8_t tag_50_len; //length of application label + uint8_t tag_50[16]; //Application Label + uint8_t tag_56_len; //track1 length + uint8_t tag_56[76]; //Track 1 Data + uint8_t tag_57_len; //track2 equiv len + uint8_t tag_57[19]; //Track 2 Equivalent Data + uint8_t tag_5A_len; //PAN length + uint8_t tag_5A[10]; //Application Primary Account Number (PAN) + //uint8_t tag_6F[]; //File Control Information (FCI) Template + //uint8_t tag_70[255]; //Record Template + //uint8_t tag_77[]; //Response Message Template Format 2 + //uint8_t tag_80[]; //Response Message Template Format 1 + uint8_t tag_82[2]; //Application Interchange Profile AIP + //uint8_t tag_83[]; //Command Template + uint8_t tag_84_len; + uint8_t tag_84[16]; //DF Name + uint8_t tag_86_len; + uint8_t tag_86[261]; //Issuer Script Command + uint8_t tag_87[1]; //Application Priority Indicator + uint8_t tag_88[1]; //Short File Identifier + uint8_t tag_8A[2]; //Authorisation Response Code + uint8_t tag_8C_len; + uint8_t tag_8C[252]; //CDOL1 + uint8_t tag_8D_len; + uint8_t tag_8D[252]; //CDOL2 + uint8_t tag_8E_len; + uint8_t tag_8E[252]; //Cardholder Verification Method (CVM) List + uint8_t tag_8F[1]; //Certification Authority Public Key Index + uint8_t tag_90_len; + uint8_t tag_90[255]; //ssuer Public Key Certificate + uint8_t tag_92_len; + uint8_t tag_92[255]; //Issuer Public Key Remainder + uint8_t tag_93_len; + uint8_t tag_93[255]; //Signed Static Application Data + uint8_t tag_94_len; + uint8_t tag_94[252]; //Application File Locator AFL + uint8_t tag_95[5]; //Terminal Verification Results + uint8_t tag_97_len; + uint8_t tag_97[252]; //Transaction Certificate Data Object List (TDOL) + uint8_t tag_98[20]; //Transaction Certificate (TC) Hash Value + //assume 20 bytes, change after testing + uint8_t tag_99_len; + uint8_t tag_99[20]; //Transaction Personal Identification Number (PIN) Data + uint8_t tag_9A[3]; //Transaction Date + uint8_t tag_9B[2]; //Transaction Status Information + uint8_t tag_9C[1]; //Transaction Type + uint8_t tag_9D_len; + uint8_t tag_9D[16]; //Directory Definition File + + uint8_t tag_CD[3]; //Card Issuer Action Codes Paypass + uint8_t tag_CE[3]; + uint8_t tag_CF[3]; + + uint8_t tag_D7[3]; //Application Control (PayPass) + uint8_t tag_D8[2]; //Application Interchange Profile (PayPass) + uint8_t tag_D9_len; //Application File Locator (PayPass) + uint8_t tag_D9[16]; + uint8_t tag_DA[2]; //Static CVC3track1 + uint8_t tag_DB[2]; //Static CVC3track2 + uint8_t tag_DC[2]; //IVCVC3 CVC3track1 + uint8_t tag_DD[2]; //IVCVC3 CVC3track2 + + uint8_t tag_AF_len; + uint8_t tag_AF[255]; //Proprietary Information + + uint8_t tag_5F20_len; + uint8_t tag_5F20[26]; //Cardholder Name + uint8_t tag_5F24[3]; //Application Expiry Date + uint8_t tag_5F25[3]; //Application Effective Date YYMMDD + uint8_t tag_5F28[2]; //Issuer Country Code + uint8_t tag_5F2A[2]; //Transaction Currency Code + uint8_t tag_5F2D_len; + uint8_t tag_5F2D[8]; //Language Preference + uint8_t tag_5F30[2]; //Service Code + uint8_t tag_5F34[1]; //Application Primary Account Number (PAN) Sequence Number + uint8_t tag_5F36[2]; //ATC + uint8_t tag_5F50_len; + uint8_t tag_5F50[255]; //Issuer URL + uint8_t tag_5F54_len; + uint8_t tag_5F54[11]; //Bank Identifier Code (BIC) + uint8_t tag_9F01[6]; //Acquirer Identifier + uint8_t tag_9F02[6]; // Amount, Authorised (Numeric) + uint8_t tag_9F03[6]; //Amount, Other (Numeric) + uint8_t tag_9F04[4]; //Amount, Other (Binary) + uint8_t tag_9F05_len; + uint8_t tag_9F05[32]; //Application Discretionary Data + uint8_t tag_9F06_len; + uint8_t tag_9F06[16]; //AID terminal + uint8_t tag_9F07[2]; //Application Usage Control + uint8_t tag_9F08[2]; //Application Version Number + uint8_t tag_9F09[2]; //Application Version Number + //uint8_t tag_9F0A[2] + uint8_t tag_9F0B_len; + uint8_t tag_9F0B[45]; //Cardholder Name Extended + uint8_t tag_9F0D[5]; //Issuer Action Code - Default + uint8_t tag_9F0E[5]; //Issuer Action Code - Denial + uint8_t tag_9F0F[5]; //Issuer Action Code - Online + uint8_t tag_9F10_len; //Issuer Application Data + uint8_t tag_9F10[32]; + uint8_t tag_9F11[1]; //Issuer Code Table Index + uint8_t tag_9F12_len; + uint8_t tag_9F12[255]; //Application Preferred Name + uint8_t tag_9F13[2]; //Last Online Application Transaction Counter (ATC) Registerjk + uint8_t tag_9F14[1]; //Lower Consecutive Offline Limit + uint8_t tag_9F15[2]; //Merchant Category Code + uint8_t tag_9F16[15]; //Merchant Identifier + uint8_t tag_9F17[1]; //Personal Identification Number (PIN) Try Counter + uint8_t tag_9F18[4]; //Issuer Script Identifier + //uint8_t tag_9F19[] + uint8_t tag_9F1A[2]; //Terminal Country Code + uint8_t tag_9F1B[4]; //Terminal Floor Limit + uint8_t tag_9F1C[8]; //Terminal Identification + uint8_t tag_9F1D_len; + uint8_t tag_9F1D[8]; //Terminal Risk Management Data + uint8_t tag_9F1E[8]; //Interface Device (IFD) Serial Number + uint8_t tag_9F1F_len; + uint8_t tag_9F1F[255]; //Track 1 Discretionary Data + uint8_t tag_9F20_len; + uint8_t tag_9F20[255]; //Track 2 DD + uint8_t tag_9F21[3]; //Transaction Time + uint8_t tag_9F22[1]; //Certification Authority Public Key Index + uint8_t tag_9F23[1]; //Upper Consecutive Offline Limit + //uint8_t tag_9F24 + //uint8_t tag_9F25 + uint8_t tag_9F26[8]; //Application Cryptogram + uint8_t tag_9F27[1]; //Cryptogram Information Data + //uint8_t tag_9F28 + //uint8_t tag_9F29 + //uint8_t tag_9F2A + //uint8_t tag_9F2B + //uint8_t tag_9F2C + uint8_t tag_9F2D_len; + uint8_t tag_9F2D[255]; //Integrated Circuit Card (ICC) PIN Encipherment Public Key Certificate + uint8_t tag_9F2E[3]; //Integrated Circuit Card (ICC) PIN Encipherment Public Key Exponent + uint8_t tag_9F2F_len; + uint8_t tag_9F2F[255]; //Integrated Circuit Card (ICC) PIN Encipherment Public Key Remainder + //uint8_t tag_9F30 + //uint8_t tag_9F31 + uint8_t tag_9F32_len; + uint8_t tag_9F32[3]; //Issuer Public Key Exponent + uint8_t tag_9F33[3]; //Terminal Capabilities + uint8_t tag_9F34[3]; //Cardholder Verification Method (CVM) Results + uint8_t tag_9F35[1]; //Terminal Type + uint8_t tag_9F36[2]; //Application Transaction Counter (ATC) + uint8_t tag_9F37[4]; //Unpredictable Number + uint8_t tag_9F38_len; + uint8_t tag_9F38[255]; //PDOL + uint8_t tag_9F39[1]; //Point-of-Service (POS) Entry Mode + uint8_t tag_9F40[5]; //Additional Terminal Capabilities + uint8_t tag_9F41[4]; //Transaction Sequence Counter + uint8_t tag_9F42[2]; //Application Currency Code + uint8_t tag_9F43[4]; //Application Reference Currency Exponent + uint8_t tag_9F44[1]; //Application Currency Exponent + uint8_t tag_9F45[2]; //Data Authentication Code + uint8_t tag_9F46_len; + uint8_t tag_9F46[255]; //ICC Public Key Certificate + uint8_t tag_9F47_len; + uint8_t tag_9F47[3]; //ICC Public Key Exponent + uint8_t tag_9F48_len; + uint8_t tag_9F48[255]; //ICC Public Key Remainder + uint8_t tag_9F49_len; + uint8_t tag_9F49[252]; + uint8_t tag_9F4A[1]; //SDA Tag list + uint8_t tag_9F4B_len; + uint8_t tag_9F4B[255]; //Signed Dynamic Application Data + uint8_t tag_9F4C[8]; //ICC Dynamic Number + uint8_t tag_9F4D[2]; //Log Entry + uint8_t tag_9F4E[255]; //Merchant Name and Location + //9F50-9F7F are payment system specific + uint8_t tag_9F60[2]; //CVC3 track1 + uint8_t tag_9F61[2]; //CVC3 track2 + uint8_t tag_9F62[6]; //Track 1 Bit Map for CVC3 (PCVC3TRACK1) + uint8_t tag_9F63[6]; //Track 1 Bit Map for UN and ATC (PUNATCTRACK1) + uint8_t tag_9F64[1]; //Track 1 Number of ATC Digits (NATCTRACK1) + uint8_t tag_9F65[2]; //rack 2 Bit Map for CVC3 (PCVC3TRACK2) + uint8_t tag_9F66[2]; //Track 2 Bit Map for UN and ATC (PUNATCTRACK2), or VISA card type + uint8_t tag_9F67[1]; //Track 2 Number of ATC Digits (NATCTRACK2) + uint8_t tag_9F68_len; + uint8_t tag_9F68[252]; //Mag Stripe CVM List + uint8_t tag_9F69_len; + uint8_t tag_9F69[255]; //Unpredictable Number Data Object List (UDOL) + uint8_t tag_9F6A[8]; //Unpredictable Number (Numeric) + uint8_t tag_9F6B_len; + uint8_t tag_9F6B[19]; //track 2 data + uint8_t tag_9F6C[2]; //Mag Stripe Application Version Number(Card) + //template holders + uint8_t tag_61_len; + uint8_t tag_61[255]; //Application template + uint8_t tag_6F_len; + uint8_t tag_6F[255]; //6F template + uint8_t tag_A5_len; + uint8_t tag_A5[255]; //A5 template + uint8_t tag_DFNAME_len; + uint8_t tag_DFNAME[255]; //A5 template + uint8_t tag_70_len; + uint8_t tag_70[255]; //70 template + uint8_t tag_77_len; + uint8_t tag_77[255]; //77 template + uint8_t tag_80_len; + uint8_t tag_80[255]; //80 template + uint8_t tag_91_len; //Issuer Authentication Data + uint8_t tag_91[16]; + uint8_t tag_BF0C_len; + uint8_t tag_BF0C[222]; //File Control Information (FCI) Issuer Discretionary Data + uint8_t tag_DFName[16]; + uint8_t tag_DFName_len; +}emvtags; + +#endif //__EMVCARD_H diff --git a/armsrc/emvcmd.c b/armsrc/emvcmd.c new file mode 100644 index 00000000..3549d0e3 --- /dev/null +++ b/armsrc/emvcmd.c @@ -0,0 +1,740 @@ +//Peter Fillmore - 2014 +// +//-------------------------------------------------------------------------------- +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//-------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------- +//Routines to support EMV transactions +//-------------------------------------------------------------------------------- + +#include "mifare.h" +#include "iso14443a.h" +#include "emvutil.h" +#include "emvcmd.h" +#include "apps.h" +#include "emvdataels.h" + +static emvtags currentcard; //use to hold emv tags for the reader/card during communications +static tUart Uart; + +// The FPGA will report its internal sending delay in +uint16_t FpgaSendQueueDelay; +//variables used for timing purposes: +//these are in ssp_clk cycles: +//static uint32_t NextTransferTime; +static uint32_t LastTimeProxToAirStart; +//static uint32_t LastProxToAirDuration; + +//load individual tag into current card +void EMVloadvalue(uint32_t tag, uint8_t *datain){ + //Dbprintf("TAG=%i\n", tag); + //Dbprintf("DATA=%s\n", datain); + emv_settag(tag, datain, ¤tcard); +} + +void EMVReadRecord(uint8_t arg0, uint8_t arg1,emvtags *currentcard) +{ + uint8_t record = arg0; + uint8_t sfi = arg1 & 0x0F; //convert arg1 to number + uint8_t receivedAnswer[MAX_FRAME_SIZE]; + + //uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; + + //variables + tlvtag inputtag; //create the tag structure + //perform read + //write the result to the provided card + if(!emv_readrecord(record,sfi,receivedAnswer)) { + if(EMV_DBGLEVEL >= 1) Dbprintf("readrecord failed"); + } + if(*(receivedAnswer+1) == 0x70){ + decode_ber_tlv_item(receivedAnswer+1, &inputtag); + emv_decode_field(inputtag.value, inputtag.valuelength, currentcard); + } + else + { + if(EMV_DBGLEVEL >= 1) + Dbprintf("Record not found SFI=%i RECORD=%i", sfi, record); + } + return; +} + +void EMVSelectAID(uint8_t *AID, uint8_t AIDlen, emvtags* inputcard) +{ + uint8_t receivedAnswer[MAX_FRAME_SIZE]; + //uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; + + //variables + tlvtag inputtag; //create the tag structure + //perform select + if(!emv_select(AID, AIDlen, receivedAnswer)){ + if(EMV_DBGLEVEL >= 1) Dbprintf("AID Select failed"); + return; + } + //write the result to the provided card + if(*(receivedAnswer+1) == 0x6F){ + //decode the 6F template + decode_ber_tlv_item(receivedAnswer+1, &inputtag); + //store 84 and A5 tags + emv_decode_field(inputtag.value, inputtag.valuelength, ¤tcard); + //decode the A5 tag + if(currentcard.tag_A5_len > 0) + emv_decode_field(currentcard.tag_A5, currentcard.tag_A5_len, ¤tcard); + + //copy this result to the DFName + if(currentcard.tag_84_len == 0) + memcpy(currentcard.tag_DFName, currentcard.tag_84, currentcard.tag_84_len); + + //decode the BF0C result, assuming 1 directory entry for now + if(currentcard.tag_BF0C_len !=0){ + emv_decode_field(currentcard.tag_BF0C, currentcard.tag_BF0C_len, ¤tcard);} + //retrieve the AID, use the AID to decide what transaction flow to use + if(currentcard.tag_61_len !=0){ + emv_decode_field(currentcard.tag_61, currentcard.tag_61_len, ¤tcard);} + } + if(EMV_DBGLEVEL >= 2) + DbpString("SELECT AID COMPLETED"); +} + +int EMVGetProcessingOptions(uint8_t *PDOL, uint8_t PDOLlen, emvtags* inputcard) +{ + uint8_t receivedAnswer[MAX_FRAME_SIZE]; + //uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; + + //variables + tlvtag inputtag; //create the tag structure + //perform pdol + if(!emv_getprocessingoptions(PDOL, PDOLlen, receivedAnswer)){ + if(EMV_DBGLEVEL >= 1) Dbprintf("get processing options failed"); + return 0; + } + //write the result to the provided card + //FORMAT 1 received + if(receivedAnswer[1] == 0x80){ + //store AIP + //decode tag 80 + decode_ber_tlv_item(receivedAnswer+1, &inputtag); + memcpy(currentcard.tag_82, &inputtag.value, sizeof(currentcard.tag_82)); + memcpy(currentcard.tag_94, &inputtag.value[2], inputtag.valuelength - sizeof(currentcard.tag_82)); + currentcard.tag_94_len = inputtag.valuelength - sizeof(currentcard.tag_82); + } + else if(receivedAnswer[1] == 0x77){ + //decode the 77 template + decode_ber_tlv_item(receivedAnswer+1, &inputtag); + //store 82 and 94 tags (AIP, AFL) + emv_decode_field(inputtag.value, inputtag.valuelength, ¤tcard); + } + if(EMV_DBGLEVEL >= 2) + DbpString("GET PROCESSING OPTIONS COMPLETE"); + return 1; +} + +int EMVGetChallenge(emvtags* inputcard) +{ + uint8_t receivedAnswer[MAX_FRAME_SIZE]; + //uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; + //variables + //tlvtag inputtag; //create the tag structure + //perform select + if(!emv_getchallenge(receivedAnswer)){ + if(EMV_DBGLEVEL >= 1) Dbprintf("get processing options failed"); + return 1; + } + return 0; +} + +int EMVGenerateAC(uint8_t refcontrol, emvtags* inputcard) +{ + uint8_t receivedAnswer[MAX_FRAME_SIZE]; + uint8_t cdolcommand[MAX_FRAME_SIZE]; + uint8_t cdolcommandlen = 0; + tlvtag temptag; + + //uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; + if(currentcard.tag_8C_len > 0) { + emv_generateDOL(currentcard.tag_8C, currentcard.tag_8C_len, ¤tcard, cdolcommand, &cdolcommandlen); } + else{ + //cdolcommand = NULL; //cdol val is null + cdolcommandlen = 0; + } + //variables + //tlvtag inputtag; //create the tag structure + //perform select + if(!emv_generateAC(refcontrol, cdolcommand, cdolcommandlen,receivedAnswer)){ + if(EMV_DBGLEVEL >= 1) Dbprintf("get processing options failed"); + return 1; + } + if(receivedAnswer[2] == 0x77) //format 2 data field returned + { + decode_ber_tlv_item(&receivedAnswer[2], &temptag); + emv_decode_field(temptag.value, temptag.valuelength, ¤tcard); + } + + return 0; +} + +//function to perform paywave transaction +//takes in TTQ, amount authorised, unpredicable number and transaction currency code +int EMV_PaywaveTransaction() +{ + uint8_t cardMode = 0; + //determine mode of transaction from TTQ + if((currentcard.tag_9F66[0] & 0x40) == 0x40) { + cardMode = VISA_EMV; + } + else if((currentcard.tag_9F66[0] & 0x20) == 0x20) { + cardMode = VISA_FDDA; + } + else if((currentcard.tag_9F66[0] & 0x80) == 0x80) { + if((currentcard.tag_9F66[1] & 0x80) == 1) { //CVN17 + cardMode = VISA_CVN17; + } + else{ + cardMode = VISA_DCVV; + } + } + + EMVSelectAID(currentcard.tag_4F,currentcard.tag_4F_len, ¤tcard); //perform second AID command + + //get PDOL + uint8_t pdolcommand[20]; //20 byte buffer for pdol data + uint8_t pdolcommandlen = 0; + if(currentcard.tag_9F38_len > 0) { + emv_generateDOL(currentcard.tag_9F38, currentcard.tag_9F38_len, ¤tcard, pdolcommand, &pdolcommandlen); + } + Dbhexdump(pdolcommandlen, pdolcommand,false); + + if(!EMVGetProcessingOptions(pdolcommand,pdolcommandlen, ¤tcard)) { + if(EMV_DBGLEVEL >= 1) Dbprintf("PDOL failed"); + return 1; + } + + Dbprintf("AFL="); + Dbhexdump(currentcard.tag_94_len, currentcard.tag_94,false); + Dbprintf("AIP="); + Dbhexdump(2, currentcard.tag_82, false); + emv_decodeAIP(currentcard.tag_82); +// +// //decode the AFL list and read records + uint8_t i = 0; + uint8_t sfi = 0; + uint8_t recordstart = 0; + uint8_t recordend = 0; + if(currentcard.tag_94_len > 0){ + while( i < currentcard.tag_94_len){ + sfi = (currentcard.tag_94[i++] & 0xF8) >> 3; + recordstart = currentcard.tag_94[i++]; + recordend = currentcard.tag_94[i++]; + for(int j=recordstart; j<(recordend+1); j++){ + //read records + EMVReadRecord(j,sfi, ¤tcard); + //while(responsebuffer[0] == 0xF2) { + // EMVReadRecord(j,sfi, ¤tcard); + //} + } + i++; + } + } + else { + EMVReadRecord(1,1,¤tcard); + EMVReadRecord(1,2,¤tcard); + EMVReadRecord(1,3,¤tcard); + EMVReadRecord(2,1,¤tcard); + EMVReadRecord(2,2,¤tcard); + EMVReadRecord(2,3,¤tcard); + EMVReadRecord(3,1,¤tcard); + EMVReadRecord(3,3,¤tcard); + EMVReadRecord(4,2,¤tcard); + } + //EMVGetChallenge(¤tcard); + //memcpy(currentcard.tag_9F4C,&responsebuffer[1],8); // ICC UN + EMVGenerateAC(0x81,¤tcard); + + Dbprintf("CARDMODE=%i",cardMode); + return 0; +} + + +int EMV_PaypassTransaction() +{ + //uint8_t *responsebuffer = emv_get_bigbufptr(); + //tlvtag temptag; //buffer for decoded tags + //get the current block counter + //select the AID (Mastercard + EMVSelectAID(currentcard.tag_4F,currentcard.tag_4F_len, ¤tcard); + + //get PDOL + uint8_t pdolcommand[20]; //20 byte buffer for pdol data + uint8_t pdolcommandlen = 0; + if(currentcard.tag_9F38_len > 0) { + emv_generateDOL(currentcard.tag_9F38, currentcard.tag_9F38_len, ¤tcard, pdolcommand, &pdolcommandlen); + } + if(EMVGetProcessingOptions(pdolcommand,pdolcommandlen, ¤tcard)) { + if(EMV_DBGLEVEL >= 1) Dbprintf("PDOL failed"); + return 1; + } + + Dbprintf("AFL="); + Dbhexdump(currentcard.tag_94_len, currentcard.tag_94,false); + Dbprintf("AIP="); + Dbhexdump(2, currentcard.tag_82, false); + emv_decodeAIP(currentcard.tag_82); + + //decode the AFL list and read records + uint8_t i = 0; + uint8_t sfi = 0; + uint8_t recordstart = 0; + uint8_t recordend = 0; + + while( i< currentcard.tag_94_len){ + sfi = (currentcard.tag_94[i++] & 0xF8) >> 3; + recordstart = currentcard.tag_94[i++]; + recordend = currentcard.tag_94[i++]; + for(int j=recordstart; j<(recordend+1); j++){ + //read records + EMVReadRecord(j,sfi, ¤tcard); + //while(responsebuffer[0] == 0xF2) { + // EMVReadRecord(j,sfi, ¤tcard); + //} + } + i++; + } + /* get ICC dynamic data */ + if((currentcard.tag_82[0] & AIP_CDA_SUPPORTED) == AIP_CDA_SUPPORTED) + { + //DDA supported, so perform GENERATE AC + //generate the iCC UN + EMVGetChallenge(¤tcard); + //memcpy(currentcard.tag_9F4C,&responsebuffer[1],8); // ICC UN + EMVGenerateAC(0x80,¤tcard); + + + //generate AC2 + //if(currentcard.tag_8D_len > 0) { + // emv_generateDOL(currentcard.tag_8D, currentcard.tag_8D_len, ¤tcard, cdolcommand, &cdolcommandlen); } + //else{ + // //cdolcommand = NULL; //cdol val is null + // cdolcommandlen = 0; + //} + //emv_generateAC(0x80, cdolcommand,cdolcommandlen, ¤tcard); + + //if(responsebuffer[1] == 0x77) //format 2 data field returned + //{ + // decode_ber_tlv_item(&responsebuffer[1], &temptag); + // emv_decode_field(temptag.value, temptag.valuelength, ¤tcard); + //} + } + //generate cryptographic checksum + //uint8_t udol[4] = {0x00,0x00,0x00,0x00}; + //emv_computecryptogram(udol, sizeof(udol)); + //if(responsebuffer[1] == 0x77) //format 2 data field returned + //{ + // decode_ber_tlv_item(&responsebuffer[1], &temptag); + // emv_decode_field(temptag.value, temptag.valuelength, ¤tcard); + //} + return 0; +} + +void EMVTransaction() +{ + //params + uint8_t uid[10] = {0x00}; + uint32_t cuid = 0; + + //setup stuff + BigBuf_free(); BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(TRUE); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + while(true) { + if(!iso14443a_select_card(uid,NULL,&cuid)) { + if(EMV_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + } + //selectPPSE + EMVSelectAID((uint8_t *)DF_PSE, 14, ¤tcard); //hard coded len + //get response + if (!memcmp(currentcard.tag_4F, AID_MASTERCARD, sizeof(AID_MASTERCARD))){ + Dbprintf("Mastercard Paypass Card Detected"); + EMV_PaypassTransaction(); + } + else if (!memcmp(currentcard.tag_4F, AID_VISA, sizeof(AID_VISA))){ + Dbprintf("VISA Paywave Card Detected"); + EMV_PaywaveTransaction(); + } + //TODO: add other card schemes like AMEX, JCB, China Unionpay etc + break; + } + if (EMV_DBGLEVEL >= 2) DbpString("EMV TRANSACTION FINISHED"); + //finish up + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +void EMVdumpcard(void){ + dumpCard(¤tcard); +} + +//SIMULATOR CODE +//----------------------------------------------------------------------------- +// Main loop of simulated tag: receive commands from reader, decide what +// response to send, and send it. +//----------------------------------------------------------------------------- +void SimulateEMVcard() +{ + //uint8_t sak; //select ACKnowledge + uint16_t readerPacketLen = 64; //reader packet length - provided by RATS, default to 64 bytes if RATS not supported + + // The first response contains the ATQA (note: bytes are transmitted in reverse order). + //uint8_t atqapacket[2]; + + // The second response contains the (mandatory) first 24 bits of the UID + uint8_t uid0packet[5] = {0x00}; + memcpy(uid0packet, currentcard.UID, sizeof(uid0packet)); + // Check if the uid uses the (optional) part + uint8_t uid1packet[5] = {0x00}; + memcpy(uid1packet, currentcard.UID, sizeof(uid1packet)); + + // Calculate the BitCountCheck (BCC) for the first 4 bytes of the UID. + uid0packet[4] = uid0packet[0] ^ uid0packet[1] ^ uid0packet[2] ^ uid0packet[3]; + + // Prepare the mandatory SAK (for 4 and 7 byte UID) + uint8_t sak0packet[3] = {0x00}; + memcpy(sak0packet,¤tcard.SAK1,1); + ComputeCrc14443(CRC_14443_A, sak0packet, 1, &sak0packet[1], &sak0packet[2]); + uint8_t sak1packet[3] = {0x00}; + memcpy(sak1packet,¤tcard.SAK2,1); + // Prepare the optional second SAK (for 7 byte UID), drop the cascade bit + ComputeCrc14443(CRC_14443_A, sak1packet, 1, &sak1packet[1], &sak1packet[2]); + + uint8_t authanspacket[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce + //setup response to ATS + uint8_t ratspacket[currentcard.ATS_len]; + memcpy(ratspacket,currentcard.ATS, currentcard.ATS_len); + AppendCrc14443a(ratspacket,sizeof(ratspacket)-2); + + // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present, + // TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1 + // TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us) + // TC(1) = 0x02: CID supported, NAD not supported + //ComputeCrc14443(CRC_14443_A, response6, 4, &response6[4], &response6[5]); + + //Receive Acknowledge responses differ by PCB byte + uint8_t rack0packet[] = {0xa2,0x00,0x00}; + AppendCrc14443a(rack0packet,1); + uint8_t rack1packet[] = {0xa3,0x00,0x00}; + AppendCrc14443a(rack1packet,1); + //Negative Acknowledge + uint8_t rnak0packet[] = {0xb2,0x00,0x00}; + uint8_t rnak1packet[] = {0xb3,0x00,0x00}; + AppendCrc14443a(rnak0packet,1); + AppendCrc14443a(rnak1packet,1); + + //Protocol and parameter selection response, just say yes + uint8_t ppspacket[] = {0xd0,0x00,0x00}; + AppendCrc14443a(ppspacket,1); + + //hardcoded WTX packet - set to max time (49) + uint8_t wtxpacket[] ={0xf2,0x31,0x00,0x00}; + AppendCrc14443a(wtxpacket,2); + + //added additional responses for different readers, namely protocol parameter select and Receive acknowledments. - peter fillmore. + //added defininitions for predone responses to aid readability + #define ATR 0 + #define UID1 1 + #define UID2 2 + #define SELACK1 3 + #define SELACK2 4 + #define AUTH_ANS 5 + #define ATS 6 + #define RACK0 7 + #define RACK1 8 + #define RNAK0 9 + #define RNAK1 10 + #define PPSresponse 11 + #define WTX 12 + + #define TAG_RESPONSE_COUNT 13 + tag_response_info_t responses[TAG_RESPONSE_COUNT] = { + { .response = currentcard.ATQA, .response_n = sizeof(currentcard.ATQA) }, // Answer to request - respond with card type + { .response = uid0packet, .response_n = sizeof(uid0packet) }, // Anticollision cascade1 - respond with uid + { .response = uid1packet, .response_n = sizeof(uid1packet) }, // Anticollision cascade2 - respond with 2nd half of uid if asked + { .response = sak0packet, .response_n = sizeof(sak0packet) }, // Acknowledge select - cascade 1 + { .response = sak1packet, .response_n = sizeof(sak1packet) }, // Acknowledge select - cascade 2 + { .response = authanspacket, .response_n = sizeof(authanspacket) }, // Authentication answer (random nonce) + { .response = ratspacket, .response_n = sizeof(ratspacket) }, // dummy ATS (pseudo-ATR), answer to RATS + { .response = rack0packet, .response_n = sizeof(rack0packet) }, //R(ACK)0 + { .response = rack1packet, .response_n = sizeof(rack1packet) }, //R(ACK)0 + { .response = rnak0packet, .response_n = sizeof(rnak0packet) }, //R(NAK)0 + { .response = rnak1packet, .response_n = sizeof(rnak1packet) }, //R(NAK)1 + { .response = ppspacket, .response_n = sizeof(ppspacket)}, //PPS packet + { .response = wtxpacket, .response_n = sizeof(wtxpacket)}, //WTX packet +}; + + //calculated length of predone responses + uint16_t allocatedtaglen = 0; + for(int i=0;i 0) { + // Copy the CID from the reader query + //dynamic_response_info.response[1] = receivedCmd[1]; + + // Add CRC bytes, always used in ISO 14443A-4 compliant cards + AppendCrc14443a(dynamic_response_info.response,dynamic_response_info.response_n); + dynamic_response_info.response_n += 2; + if(dynamic_response_info.response_n > readerPacketLen){ //throw error if our reader doesn't support the send packet length + Dbprintf("Error: tag response is longer then what the reader supports, TODO:implement command chaining"); + LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); + break; + } + if (prepare_tag_modulation(&dynamic_response_info,DYNAMIC_MODULATION_BUFFER_SIZE) == false) { + Dbprintf("Error preparing tag response"); + LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); + break; + } + p_response = &dynamic_response_info; + } + } + + // Count number of wakeups received after a halt + if(order == HLTA && lastorder == PPS) { happened++; } + + // Count number of other messages after a halt + if(order != HLTA && lastorder == PPS) { happened2++; } + + if(cmdsRecvd > 999) { + DbpString("1000 commands later..."); + break; + } + cmdsRecvd++; + + if (p_response != NULL) { + EmSendCmd14443aRaw(p_response->modulation, p_response->modulation_n, receivedCmd[0] == 0x52); + // do the tracing for the previous reader request and this tag answer: + uint8_t par[MAX_PARITY_SIZE] = {0x00}; + GetParity(p_response->response, p_response->response_n, par); + + EmLogTrace(Uart.output, + Uart.len, + Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, + Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, + Uart.parity, + p_response->response, + p_response->response_n, + LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, + (LastTimeProxToAirStart + p_response->ProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, + par); + } + + if (!tracing) { + Dbprintf("Trace Full. Simulation stopped."); + break; + } + } + + Dbprintf("%x %x %x", happened, happened2, cmdsRecvd); + LED_A_OFF(); + BigBuf_free_keep_EM(); +} diff --git a/armsrc/emvcmd.h b/armsrc/emvcmd.h new file mode 100644 index 00000000..070eb586 --- /dev/null +++ b/armsrc/emvcmd.h @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// Peter Fillmore -2012 +// Based off MIFARECMD code +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// Routines to support EMV Transactions. +//----------------------------------------------------------------------------- + +#ifndef __EMVCMD_H +#define __EMVCMD_H + +#include "proxmark3.h" +#include "apps.h" +#include "util.h" +#include "string.h" + +#include "iso14443crc.h" +#include "iso14443a.h" +#include "common.h" +#include "emvutil.h" +#include "emvcard.h" + +#define VISA_DCVV 0 +#define VISA_CVN17 1 +#define VISA_FDDA 2 +#define VISA_EMV 3 + +#define MASTERCARD_MSR 0 +#define MASTERCARD_MCHIP 1 +#endif diff --git a/armsrc/emvdataels.c b/armsrc/emvdataels.c new file mode 100644 index 00000000..9958a27f --- /dev/null +++ b/armsrc/emvdataels.c @@ -0,0 +1,127 @@ +//Data elements for EMV transactions. +#include +#ifndef __EMVDATAELS_H +#define __EMVDATAELS_H +#include "emvdataels.h" +//Known AIDs + +typedef struct{ +uint8_t tag[2]; +char description[255]; +}tagdescription; + +const uint8_t AID_VISA[] = {0xa0,0x00,0x00,0x00,0x03}; +const uint8_t AID_VISA_DB[] = {0xa0,0x00,0x00,0x00,0x03,0x10,0x10}; +const uint8_t AID_VISA_C[] = {0xa0,0x00,0x00,0x00,0x03,0x10,0x10,0x01}; +const uint8_t AID_VISA_D[] = {0xa0,0x00,0x00,0x00,0x03,0x10,0x10,0x02}; +const uint8_t AID_VISA_E[] = {0xa0,0x00,0x00,0x00,0x03,0x20,0x10}; +const uint8_t AID_VISA_I[] = {0xa0,0x00,0x00,0x00,0x03,0x30,0x10}; +const uint8_t AID_VISA_P[] = {0xa0,0x00,0x00,0x00,0x03,0x80,0x10}; +const uint8_t AID_VISA_ATM[]= {0xa0,0x00,0x00,0x00,0x03,0x99,0x99,0x10}; +const uint8_t AID_MASTERCARD[]= {0xa0,0x00,0x00,0x00,0x04,0x10,0x10}; +const uint8_t AID_MAESTRO[] = {0xa0,0x00,0x00,0x00,0x04,0x30,0x60}; +const uint8_t AID_MAESTRO_UK[]= {0xa0,0x00,0x00,0x00,0x05,0x00,0x01}; +const uint8_t AID_MAESTRO_TEST[]={0xb0,0x12,0x34,0x56,0x78}; +const uint8_t AID_SELF_SERVICE[]={0xa0,0x00,0x00,0x00,0x24,0x01}; +const uint8_t AID_AMEX[] = {0xa0,0x00,0x00,0x00,0x25}; +const uint8_t AID_EXPRESSPAY[]= {0xa0,0x00,0x00,0x00,0x25,0x01,0x07,0x01}; +const uint8_t AID_LINK[] = {0xa0,0x00,0x00,0x00,0x29,0x10,0x10}; +const uint8_t AID_ALIAS[] = {0xa0,0x00,0x00,0x00,0x29,0x10,0x10}; + +//Master data file for PSE +//const uint8_t DF_PSE[] = {0x32, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31}; +const uint8_t DF_PSE[] = {0x32, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31}; + +//TAGS + +//SW1 return values +const uint8_t SW1_RESPONSE_BYTES[] = {0x61}; +const uint8_t SW1_WRONG_LENGTH[] = {0x6c}; +const uint8_t SW12_OK[] = {0x90,0x00}; +const uint8_t SW12_NOT_SUPPORTED[] = {0x6a,0x81}; +const uint8_t SW12_NOT_FOUND[] = {0x6a,0x82}; +const uint8_t SW12_COND_NOT_SAT[] = {0x69,0x83}; +const uint8_t PIN_BLOCKED[] = {0x69,0x84}; +const uint8_t PIN_BLOCKED2[] = {0x69,0x84}; +const uint8_t PIN_WRONG[] = {0x63}; + +const tagdescription EMV_TAG_LIST[] = { + {"\x4f\x00","Application Identifier (AID)"}, + {"\x50\x00","Application Label"}, + {"\x57\x00","Track 2 Equivalent Data"}, + {"\x5a\x00","Application Primary Account Number (PAN)"}, + {"\x6f\x00","File Control Information (FCI) Template"}, + {"\x70\x00","Record Template"}, + {"\x77\x00","response message template format 2"}, + {"\x80\x00","response message template format 1"}, + {"\x82\x00","application interchange profile"}, + {"\x83\x00","command template"}, + {"\x84\x00","df name"}, + {"\x86\x00","issuer script command"}, + {"\x87\x00","application priority indicator"}, + {"\x88\x00","short file identifier"}, + {"\x8a\x00","authorisation response code"}, + {"\x8c\x00","card risk management data object list 1 (cdol1)"}, + {"\x8d\x00","card risk management data object list 2 (cdol2)"}, + {"\x8e\x00","cardholder verification method (cvm) list"}, + {"\x8f\x00","certification authority public key index"}, + {"\x93\x00","signed static application data"}, + {"\x94\x00","application file locator"}, + {"\x95\x00","terminal verification results"}, + {"\x97\x00","transaction certificate data object list (tdol)",}, + {"\x9c\x00","transaction type"}, + {"\x9d\x00","directory definition file"}, + {"\xa5\x00","proprietary information"}, + {"\x5f\x20","cardholder name"}, + {"\x5f\x24","application expiration date yymmdd"}, + {"\x5f\x25","application effective date yymmdd"}, + {"\x5f\x28","issuer country code"}, + {"\x5f\x2a","transaction currency code"}, + {"\x5f\x2d","language preference"}, + {"\x5f\x30","service code"}, + {"\x5f\x34","application primary account number (pan) sequence number"}, + {"\x5f\x50","issuer url"}, + {"\x92\x00","issuer public key remainder"}, + {"\x9a\x00","transaction date"}, + {"\x9f\x02","amount, authorised (numeric)"}, + {"\x9f\x03","amount, other (numeric)"}, + {"\x9f\x04","amount, other (binary)"}, + {"\x9f\x05","application discretionary data"}, + {"\x9f\x07","application usage control"}, + {"\x9f\x08","application version number"}, + {"\x9f\x0d","issuer action code - default"}, + {"\x9f\x0e","issuer action code - denial"}, + {"\x9f\x0f","issuer action code - online"}, + {"\x9f\x11","issuer code table index"}, + {"\x9f\x12","application preferred name"}, + {"\x9f\x1a","terminal country code"}, + {"\x9f\x1f","track 1 discretionary data"}, + {"\x9f\x20","track 2 discretionary data"}, + {"\x9f\x26","application cryptogram"}, + {"\x9f\x32","issuer public key exponent"}, + {"\x9f\x36","application transaction counter"}, + {"\x9f\x37","unpredictable number"}, + {"\x9f\x38","processing options data object list (pdol)"}, + {"\x9f\x42","application currency code"}, + {"\x9f\x44","application currency exponent"}, + {"\x9f\x4a","static data authentication tag list"}, + {"\x9f\x4d","log entry"}, + {"\x9f\x66","card production life cycle"}, + {"\xbf\x0c","file control information (fci) issuer discretionary data"} +}; + +//AIP bitmasks details +#define AIP_CHIP_SUPPORTED 0x80 +#define AIP_MSR_SUPPORTED 0x40 + +#define AIP_SDA_SUPPORTED 0x40 +#define AIP_DDA_SUPPORTED 0x20 +#define AIP_CARDHOLDER_VERIFICATION 0x10 +#define AIP_TERMINAL_RISK 0x08 +#define AIP_ISSUER_AUTH 0x04 +#define AIP_CDA_SUPPORTED 0x01 + +//human readable error messages + + +#endif //__EMVDATAELS_H diff --git a/armsrc/emvdataels.h b/armsrc/emvdataels.h new file mode 100644 index 00000000..6f3b6fde --- /dev/null +++ b/armsrc/emvdataels.h @@ -0,0 +1,56 @@ +//Data elements for EMV transactions. +#include +#ifndef __EMVDATAELS_H +#define __EMVDATAELS_H +//Known AIDs +extern const uint8_t AID_VISA[5]; +extern const uint8_t AID_VISA_DB[7] ; +extern const uint8_t AID_VISA_C[8] ; +extern const uint8_t AID_VISA_D[8] ; +extern const uint8_t AID_VISA_E[7] ; +extern const uint8_t AID_VISA_I[7] ; +extern const uint8_t AID_VISA_P[7] ; +extern const uint8_t AID_VISA_ATM[8]; +extern const uint8_t AID_MASTERCARD[7]; +extern const uint8_t AID_MAESTRO[7]; +extern const uint8_t AID_MAESTRO_UK[7]; +extern const uint8_t AID_MAESTRO_TEST[5]; +extern const uint8_t AID_SELF_SERVICE[6]; +extern const uint8_t AID_AMEX[5]; +extern const uint8_t AID_EXPRESSPAY[]; +extern const uint8_t AID_LINK[7]; +extern const uint8_t AID_ALIAS[7]; + +//Master data file for PSE +extern const uint8_t DF_PSE[]; + +typedef struct{ + uint8_t tag[2]; + char description[255]; +}tagdescription; + +extern const tagdescription EMV_TAG_LIST[62]; //SW1 return values +extern const uint8_t SW1_RESPONSE_BYTES[]; +extern const uint8_t SW1_WRONG_LENGTH[] ; +extern const uint8_t SW12_OK[]; +extern const uint8_t SW12_NOT_SUPPORTED[] ; +extern const uint8_t SW12_NOT_FOUND[]; +extern const uint8_t SW12_COND_NOT_SAT[]; +extern const uint8_t PIN_BLOCKED[] ; +extern const uint8_t PIN_BLOCKED2[] ; +extern const uint8_t PIN_WRONG[] ; + +//AIP bitmasks details +#define AIP_CHIP_SUPPORTED 0x80 +#define AIP_MSR_SUPPORTED 0x40 + +#define AIP_SDA_SUPPORTED 0x40 +#define AIP_DDA_SUPPORTED 0x20 +#define AIP_CARDHOLDER_VERIFICATION 0x10 +#define AIP_TERMINAL_RISK 0x08 +#define AIP_ISSUER_AUTH 0x04 +#define AIP_CDA_SUPPORTED 0x01 + +//human readable error messages +//file structure, read from AFL +#endif //__EMVDATAELS_H diff --git a/armsrc/emvutil.c b/armsrc/emvutil.c new file mode 100644 index 00000000..e35cb1ef --- /dev/null +++ b/armsrc/emvutil.c @@ -0,0 +1,1837 @@ +//----------------------------------------------------------------------------- +// Peter Fillmore 2015 +// Many authors, whom made it possible +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// various EMV related functions. +//----------------------------------------------------------------------------- +#include +#include "proxmark3.h" +#include "apps.h" +#include "util.h" +#include "string.h" + +#include "BigBuf.h" + +#include "iso14443crc.h" +#include "iso14443a.h" +#include "emvutil.h" +#include "emvdataels.h" //EMV data elements +#include "emvtags.h" //EMV card structure + +#define DUMP(varname) Dbprintf("%s=", #varname); + +int EMV_DBGLEVEL = EMV_DBG_ALL; +//uint8_t PCB = 0x00; //track Protocol Control Byte externally + +//util functions +//print detected tag name over the serial link +int emv_printtag(uint8_t* selected_tag, emvtags* inputcard, uint8_t* outputstring, uint8_t* outputlen) +{ + //search tag list and print the match + //get the value of the tag + uint8_t tagvalue[255]; + uint8_t tagvaluelen; + emv_lookuptag(selected_tag, inputcard, tagvalue, &tagvaluelen); + //loop through selected tag, print the value found + for(int i=0; i<(sizeof(EMV_TAG_LIST)/sizeof(EMV_TAG_LIST[0])); i++){ + if(!memcmp(selected_tag, EMV_TAG_LIST[i].tag, 2)){ + memcpy(outputstring, EMV_TAG_LIST[i].description, strlen(EMV_TAG_LIST[i].description)); + memcpy(outputstring+(strlen(EMV_TAG_LIST[i].description)), "=", 1); + memcpy(outputstring+(strlen(EMV_TAG_LIST[i].description))+1, tagvalue, tagvaluelen); + *outputlen = strlen(EMV_TAG_LIST[i].description) + 1 + tagvaluelen; + break; + } + } + return 0; +} + +//returns the value of the emv tag in the supplied emvtags structure +int emv_lookuptag(uint8_t* tag, emvtags *currentcard, uint8_t* outputval, uint8_t* outputvallen) +{ + //loop through tag and return the appropriate value + uint8_t returnedtag[255]; + uint8_t returnedlength; + memset(returnedtag, 0x00, sizeof(returnedtag)); + if(!memcmp(tag, "\x4F\x00",2)){ + memcpy(&returnedtag, currentcard->tag_4F, currentcard->tag_4F_len); + returnedlength = currentcard->tag_4F_len; goto exitfunction;} + else if(!memcmp(tag, "\x50\x00",2)){ + memcpy(&returnedtag, currentcard->tag_50, currentcard->tag_50_len); + returnedlength = currentcard->tag_50_len; goto exitfunction;} + else if(!memcmp(tag, "\x56\x00",2)){ + memcpy(&returnedtag, currentcard->tag_56, currentcard->tag_56_len); + returnedlength = currentcard->tag_56_len; goto exitfunction;} + else if(!memcmp(tag, "\x57\x00",2)){ + memcpy(&returnedtag, currentcard->tag_57, currentcard->tag_57_len); + returnedlength = currentcard->tag_57_len; goto exitfunction;} + else if(!memcmp(tag, "\x5A\x00",2)){ + memcpy(&returnedtag, currentcard->tag_5A, currentcard->tag_5A_len); + returnedlength = currentcard->tag_5A_len; goto exitfunction;} + else if(!memcmp(tag, "\x82\x00",2)){ + memcpy(&returnedtag, currentcard->tag_82, sizeof(currentcard->tag_82)); + returnedlength = sizeof(currentcard->tag_82);goto exitfunction;} + else if(!memcmp(tag, "\x84\x00",2)){ + memcpy(&returnedtag, currentcard->tag_84, currentcard->tag_84_len); + returnedlength = currentcard->tag_84_len; goto exitfunction;} + else if(!memcmp(tag, "\x86\x00",2)){ + memcpy(&returnedtag, currentcard->tag_86, currentcard->tag_86_len); + returnedlength = currentcard->tag_86_len; goto exitfunction;} + else if(!memcmp(tag, "\x87\x00",2)){ + memcpy(&returnedtag, currentcard->tag_87, sizeof(currentcard->tag_87)); + returnedlength = sizeof(currentcard->tag_87);goto exitfunction;} + else if(!memcmp(tag, "\x88\x00",2)){ + memcpy(&returnedtag, currentcard->tag_88, currentcard->tag_50_len); + returnedlength = sizeof(currentcard->tag_88); goto exitfunction;} + else if(!memcmp(tag, "\x8A\x00",2)){ + memcpy(&returnedtag, currentcard->tag_8A, sizeof(currentcard->tag_8A)); + returnedlength = sizeof(currentcard->tag_8A);goto exitfunction;} + else if(!memcmp(tag, "\x8C\x00",2)){ + memcpy(&returnedtag, currentcard->tag_8C, currentcard->tag_8C_len); + returnedlength = currentcard->tag_8C_len; goto exitfunction;} + else if(!memcmp(tag, "\x8D\x00",2)){ + memcpy(&returnedtag, currentcard->tag_8D, currentcard->tag_8D_len); + returnedlength = currentcard->tag_8D_len; goto exitfunction;} + else if(!memcmp(tag, "\x8E\x00",2)){ + memcpy(&returnedtag, currentcard->tag_8E, currentcard->tag_8E_len); + returnedlength = currentcard->tag_8E_len; goto exitfunction;} + else if(!memcmp(tag, "\x8F\x00",2)){ + memcpy(&returnedtag, currentcard->tag_8F, sizeof(currentcard->tag_8F)); + returnedlength = sizeof(currentcard->tag_8F);goto exitfunction;} + else if(!memcmp(tag, "\x90\x00",2)){ + memcpy(&returnedtag, currentcard->tag_90, currentcard->tag_90_len); + returnedlength = currentcard->tag_90_len; goto exitfunction;} + else if(!memcmp(tag, "\x92\x00",2)){ + memcpy(&returnedtag, currentcard->tag_92, currentcard->tag_92_len); + returnedlength = currentcard->tag_92_len; goto exitfunction;} + else if(!memcmp(tag, "\x93\x00",2)){ + memcpy(&returnedtag, currentcard->tag_93, currentcard->tag_93_len); + returnedlength = currentcard->tag_93_len; goto exitfunction;} + else if(!memcmp(tag, "\x94\x00",2)){ + memcpy(&returnedtag, currentcard->tag_94, currentcard->tag_94_len); + returnedlength = currentcard->tag_94_len; goto exitfunction;} + else if(!memcmp(tag, "\x95\x00",2)){ + memcpy(&returnedtag, currentcard->tag_95, sizeof(currentcard->tag_95)); + returnedlength = sizeof(currentcard->tag_95);goto exitfunction;} + else if(!memcmp(tag, "\x97\x00",2)){ + memcpy(&returnedtag, currentcard->tag_97, currentcard->tag_97_len); + returnedlength = currentcard->tag_97_len; goto exitfunction;} + else if(!memcmp(tag, "\x98\x00",2)){ + memcpy(&returnedtag, currentcard->tag_98, sizeof(currentcard->tag_98)); + returnedlength = sizeof(currentcard->tag_98);goto exitfunction;} + else if(!memcmp(tag, "\x99\x00",2)){ + memcpy(&returnedtag, currentcard->tag_99, currentcard->tag_99_len); + returnedlength = currentcard->tag_99_len; goto exitfunction;} + else if(!memcmp(tag, "\x9A\x00",2)){ + memcpy(&returnedtag, currentcard->tag_9A, sizeof(currentcard->tag_9A)); + returnedlength = sizeof(currentcard->tag_9A);goto exitfunction;} + else if(!memcmp(tag, "\x9B\x00",2)){ + memcpy(&returnedtag, currentcard->tag_9B, sizeof(currentcard->tag_9B)); + returnedlength = sizeof(currentcard->tag_9B);goto exitfunction;} + else if(!memcmp(tag, "\x9C\x00",2)){ + memcpy(&returnedtag, currentcard->tag_9C, sizeof(currentcard->tag_9C)); + returnedlength = sizeof(currentcard->tag_9C);goto exitfunction;} + else if(!memcmp(tag, "\x9D\x00",2)){ + memcpy(&returnedtag, currentcard->tag_9D, currentcard->tag_9D_len); + returnedlength = currentcard->tag_9D_len; goto exitfunction;} + else if(!memcmp(tag, "\x9D\x00",2)){ + memcpy(&returnedtag, currentcard->tag_9D, currentcard->tag_9D_len); + returnedlength = currentcard->tag_9D_len; goto exitfunction;} + else if(!memcmp(tag, "\xCD\x00",2)){ + memcpy(&returnedtag, currentcard->tag_CD, sizeof(currentcard->tag_CD)); + returnedlength = sizeof(currentcard->tag_CD);goto exitfunction;} + else if(!memcmp(tag, "\xCE\x00",2)){ + memcpy(&returnedtag, currentcard->tag_CE, sizeof(currentcard->tag_CE)); + returnedlength = sizeof(currentcard->tag_CE);goto exitfunction;} + else if(!memcmp(tag, "\xCF\x00",2)){ + memcpy(&returnedtag, currentcard->tag_CF, sizeof(currentcard->tag_CF)); + returnedlength = sizeof(currentcard->tag_CF);goto exitfunction;} + else if(!memcmp(tag, "\xD7\x00",2)){ + memcpy(&returnedtag, currentcard->tag_D7, sizeof(currentcard->tag_D7)); + returnedlength = sizeof(currentcard->tag_D7);goto exitfunction;} + else if(!memcmp(tag, "\xD8\x00",2)){ + memcpy(&returnedtag, currentcard->tag_D8, sizeof(currentcard->tag_D8)); + returnedlength = sizeof(currentcard->tag_D8);goto exitfunction;} + else if(!memcmp(tag, "\xD9\x00",2)){ + memcpy(&returnedtag, currentcard->tag_D9, currentcard->tag_D9_len); + returnedlength = currentcard->tag_D9_len;goto exitfunction;} + else if(!memcmp(tag, "\xDA\x00",2)){ + memcpy(&returnedtag, currentcard->tag_DA, sizeof(currentcard->tag_DA)); + returnedlength = sizeof(currentcard->tag_DA);goto exitfunction;} + else if(!memcmp(tag, "\xDB\x00",2)){ + memcpy(&returnedtag, currentcard->tag_DB, sizeof(currentcard->tag_DB)); + returnedlength = sizeof(currentcard->tag_DB);goto exitfunction;} + else if(!memcmp(tag, "\xDC\x00",2)){ + memcpy(&returnedtag, currentcard->tag_DC, sizeof(currentcard->tag_DC)); + returnedlength = sizeof(currentcard->tag_DC);goto exitfunction;} + else if(!memcmp(tag, "\xDD\x00",2)){ + memcpy(&returnedtag, currentcard->tag_DD, sizeof(currentcard->tag_DD)); + returnedlength = sizeof(currentcard->tag_DD);goto exitfunction;} + else if(!memcmp(tag, "\xA5\x00",2)){ + memcpy(&returnedtag, currentcard->tag_A5, currentcard->tag_A5_len); + returnedlength = currentcard->tag_A5_len; goto exitfunction;} + else if(!memcmp(tag, "\xAF\x00",2)){ + memcpy(&returnedtag, currentcard->tag_AF, currentcard->tag_AF_len); + returnedlength = currentcard->tag_AF_len; goto exitfunction;} + if(*tag == 0x5F){ + if(*(tag+1) == 0x20){ + memcpy(&returnedtag, currentcard->tag_5F20, currentcard->tag_5F20_len); + returnedlength = currentcard->tag_5F20_len; goto exitfunction;} + else if(*(tag+1) == 0x24){ + memcpy(&returnedtag, currentcard->tag_5F24, sizeof(currentcard->tag_5F24)); + returnedlength = sizeof(currentcard->tag_5F24);goto exitfunction;} + else if(*(tag+1) == 0x25){ + memcpy(&returnedtag, currentcard->tag_5F25, sizeof(currentcard->tag_5F25)); + returnedlength = sizeof(currentcard->tag_5F25);goto exitfunction;} + else if(*(tag+1) == 0x28){ + memcpy(&returnedtag, currentcard->tag_5F28, sizeof(currentcard->tag_5F28)); + returnedlength = sizeof(currentcard->tag_5F28);goto exitfunction;} + else if(*(tag+1) == 0x2A){ + memcpy(&returnedtag, currentcard->tag_5F2A, sizeof(currentcard->tag_5F2A)); + returnedlength = sizeof(currentcard->tag_5F2A);goto exitfunction;} + else if(*(tag+1) == 0x2D){ + memcpy(&returnedtag, currentcard->tag_5F2D, currentcard->tag_5F2D_len); + returnedlength = currentcard->tag_5F2D_len; goto exitfunction;} + else if(*(tag+1) == 0x30){ + memcpy(&returnedtag, currentcard->tag_5F30, sizeof(currentcard->tag_5F30)); + returnedlength = sizeof(currentcard->tag_5F30);goto exitfunction;} + else if(*(tag+1) == 0x34){ + memcpy(&returnedtag, currentcard->tag_5F34, sizeof(currentcard->tag_5F34)); + returnedlength = sizeof(currentcard->tag_5F34);goto exitfunction;} + else if(*(tag+1) == 0x36){ + memcpy(&returnedtag, currentcard->tag_5F36, sizeof(currentcard->tag_5F36)); + returnedlength = sizeof(currentcard->tag_5F36);goto exitfunction;} + else if(*(tag+1) == 0x50){ + memcpy(&returnedtag, currentcard->tag_5F50, currentcard->tag_5F50_len); + returnedlength = currentcard->tag_5F50_len; goto exitfunction;} + else if(*(tag+1) == 0x54){ + memcpy(&returnedtag, currentcard->tag_5F54, currentcard->tag_5F54_len); + returnedlength = currentcard->tag_5F54_len; goto exitfunction;} + } + if(*tag == 0x9F) { + if(*(tag+1) == 0x01){ + memcpy(&returnedtag, currentcard->tag_9F01, sizeof(currentcard->tag_9F01)); + returnedlength = sizeof(currentcard->tag_9F01);goto exitfunction;} + else if(*(tag+1) == 0x02){ + memcpy(&returnedtag, currentcard->tag_9F02, sizeof(currentcard->tag_9F02)); + returnedlength = sizeof(currentcard->tag_9F02);goto exitfunction;} + else if(*(tag+1) == 0x03){ + returnedlength = sizeof(currentcard->tag_9F03);goto exitfunction;} + else if(*(tag+1) == 0x04){ + memcpy(&returnedtag, currentcard->tag_9F04, sizeof(currentcard->tag_9F04)); + returnedlength = sizeof(currentcard->tag_9F04);goto exitfunction;} + else if(*(tag+1) == 0x05){ + memcpy(&returnedtag, currentcard->tag_9F05, currentcard->tag_9F05_len); + returnedlength = currentcard->tag_9F05_len; goto exitfunction;} + else if(*(tag+1) == 0x06){ + memcpy(&returnedtag, currentcard->tag_9F06, currentcard->tag_9F06_len); + returnedlength = currentcard->tag_9F06_len; goto exitfunction;} + else if(*(tag+1) == 0x07){ + memcpy(&returnedtag, currentcard->tag_9F07, sizeof(currentcard->tag_9F07)); + returnedlength = sizeof(currentcard->tag_9F07);goto exitfunction;} + else if(*(tag+1) == 0x08){ + memcpy(&returnedtag, currentcard->tag_9F08, sizeof(currentcard->tag_9F08)); + returnedlength = sizeof(currentcard->tag_9F08);goto exitfunction;} + else if(*(tag+1) == 0x09){ + memcpy(&returnedtag, currentcard->tag_9F09, sizeof(currentcard->tag_9F09)); + returnedlength = sizeof(currentcard->tag_9F09);goto exitfunction;} + else if(*(tag+1) == 0x0B){ + memcpy(&returnedtag, currentcard->tag_9F0B, currentcard->tag_9F0B_len); + returnedlength = currentcard->tag_9F0B_len; goto exitfunction;} + else if(*(tag+1) == 0x0D){ + memcpy(&returnedtag, currentcard->tag_9F0D, sizeof(currentcard->tag_9F0D)); + returnedlength = sizeof(currentcard->tag_9F0D);goto exitfunction;} + else if(*(tag+1) == 0x0E){ + memcpy(&returnedtag, currentcard->tag_9F0E, sizeof(currentcard->tag_9F0E)); + returnedlength = sizeof(currentcard->tag_9F0E);goto exitfunction;} + else if(*(tag+1) == 0x0F){ + memcpy(&returnedtag, currentcard->tag_9F0F, sizeof(currentcard->tag_9F0F)); + returnedlength = sizeof(currentcard->tag_9F0F);goto exitfunction;} + else if(*(tag+1) == 0x10){ + memcpy(&returnedtag, currentcard->tag_9F10, currentcard->tag_9F10_len); + returnedlength = currentcard->tag_9F10_len;goto exitfunction;} + else if(*(tag+1) == 0x11){ + memcpy(&returnedtag, currentcard->tag_9F11, sizeof(currentcard->tag_9F11)); + returnedlength = sizeof(currentcard->tag_9F11);goto exitfunction;} + else if(*(tag+1) == 0x12){ + memcpy(&returnedtag, currentcard->tag_9F12, currentcard->tag_9F12_len); + returnedlength = currentcard->tag_9F12_len;goto exitfunction;} + else if(*(tag+1) == 0x1A){ + memcpy(&returnedtag, currentcard->tag_9F1A, sizeof(currentcard->tag_9F1A)); + goto exitfunction;} + else if(*(tag+1) == 0x1F){ + memcpy(&returnedtag, currentcard->tag_9F1F, currentcard->tag_9F1F_len); + returnedlength = currentcard->tag_9F1F_len; goto exitfunction;} + else if(*(tag+1) == 0x32){ + memcpy(&returnedtag, currentcard->tag_9F32, currentcard->tag_9F32_len); + returnedlength = currentcard->tag_9F32_len; goto exitfunction;} + else if(*(tag+1) == 0x34){ + memcpy(&returnedtag, currentcard->tag_9F34, sizeof(currentcard->tag_9F34)); + returnedlength = sizeof(currentcard->tag_9F34); goto exitfunction;} +else if(*(tag+1) == 0x35){ + memcpy(&returnedtag, currentcard->tag_9F35, sizeof(currentcard->tag_9F35)); + returnedlength = sizeof(currentcard->tag_9F35); goto exitfunction;} +else if(*(tag+1) == 0x37){ + memcpy(&returnedtag, currentcard->tag_9F37, sizeof(currentcard->tag_9F37)); + returnedlength = sizeof(currentcard->tag_9F37);goto exitfunction;} + else if(*(tag+1) == 0x38){ + memcpy(&returnedtag, currentcard->tag_9F38, currentcard->tag_9F38_len); + returnedlength = currentcard->tag_9F38_len; goto exitfunction;} + else if(*(tag+1) == 0x44){ + memcpy(&returnedtag, currentcard->tag_9F44, sizeof(currentcard->tag_9F44)); + returnedlength = sizeof(currentcard->tag_9F44);goto exitfunction;} + else if(*(tag+1) == 0x45){ + memcpy(&returnedtag, currentcard->tag_9F45, sizeof(currentcard->tag_9F45)); + returnedlength = sizeof(currentcard->tag_9F45);goto exitfunction;} + else if(*(tag+1) == 0x46){ + memcpy(&returnedtag, currentcard->tag_9F46, currentcard->tag_9F46_len); + returnedlength = currentcard->tag_9F46_len; goto exitfunction;} + else if(*(tag+1) == 0x47){ + memcpy(&returnedtag, currentcard->tag_9F47, currentcard->tag_9F47_len); + returnedlength = currentcard->tag_9F47_len; goto exitfunction;} + else if(*(tag+1) == 0x48){ + memcpy(&returnedtag, currentcard->tag_9F48, currentcard->tag_9F48_len); + returnedlength = currentcard->tag_9F48_len; goto exitfunction;} + else if(*(tag+1) == 0x49){ + memcpy(&returnedtag, currentcard->tag_9F49, currentcard->tag_9F49_len); + returnedlength = currentcard->tag_9F49_len; goto exitfunction;} + else if(*(tag+1) == 0x4A){ + memcpy(&returnedtag, currentcard->tag_9F4A, sizeof(currentcard->tag_9F4A)); + returnedlength = sizeof(currentcard->tag_9F4A);goto exitfunction;} + else if(*(tag+1) == 0x4B){ + memcpy(&returnedtag, currentcard->tag_9F4B, currentcard->tag_9F4B_len); + returnedlength = currentcard->tag_9F4B_len; goto exitfunction;} + else if(*(tag+1) == 0x4C){ + memcpy(&returnedtag, currentcard->tag_9F4C, sizeof(currentcard->tag_9F4C)); + returnedlength = sizeof(currentcard->tag_9F4C); goto exitfunction;} +else if(*(tag+1) == 0x60){ + memcpy(&returnedtag, currentcard->tag_9F60, sizeof(currentcard->tag_9F60)); + returnedlength = sizeof(currentcard->tag_9F60);goto exitfunction;} + else if(*(tag+1) == 0x61){ + memcpy(&returnedtag, currentcard->tag_9F61, sizeof(currentcard->tag_9F61)); + returnedlength = sizeof(currentcard->tag_9F61);goto exitfunction;} + else if(*(tag+1) == 0x62){ + memcpy(&returnedtag, currentcard->tag_9F62, sizeof(currentcard->tag_9F62)); + returnedlength = sizeof(currentcard->tag_9F62);goto exitfunction;} + else if(*(tag+1) == 0x63){ + memcpy(&returnedtag, currentcard->tag_9F63, sizeof(currentcard->tag_9F63)); + returnedlength = sizeof(currentcard->tag_9F63);goto exitfunction;} + else if(*(tag+1) == 0x64){ + memcpy(&returnedtag, currentcard->tag_9F64, sizeof(currentcard->tag_9F64)); + returnedlength = sizeof(currentcard->tag_9F64);goto exitfunction;} + else if(*(tag+1) == 0x65){ + memcpy(&returnedtag, currentcard->tag_9F65, sizeof(currentcard->tag_9F65)); + returnedlength = sizeof(currentcard->tag_9F65);goto exitfunction;} + else if(*(tag+1) == 0x66){ + memcpy(&returnedtag, currentcard->tag_9F66, sizeof(currentcard->tag_9F66)); + returnedlength = sizeof(currentcard->tag_9F66);goto exitfunction;} + else if(*(tag+1) == 0x67){ + memcpy(&returnedtag, currentcard->tag_9F67, sizeof(currentcard->tag_9F67)); + returnedlength = sizeof(currentcard->tag_9F67);goto exitfunction;} + else if(*(tag+1) == 0x68){ + memcpy(&returnedtag, currentcard->tag_9F68, currentcard->tag_9F68_len); + returnedlength = currentcard->tag_9F68_len;goto exitfunction;} + else if(*(tag+1) == 0x69){ + memcpy(&returnedtag, currentcard->tag_9F69, currentcard->tag_9F69_len); + returnedlength = currentcard->tag_9F69_len; goto exitfunction;} + else if(*(tag+1) == 0x6A){ + memcpy(&returnedtag, currentcard->tag_9F6A, sizeof(currentcard->tag_9F6A)); + returnedlength = sizeof(currentcard->tag_9F6A);goto exitfunction;} + else if(*(tag+1) == 0x6B){ + memcpy(&returnedtag, currentcard->tag_9F6B, currentcard->tag_9F6B_len); + returnedlength = currentcard->tag_9F6B_len; goto exitfunction;} + else if(*(tag+1) == 0x6C){ + memcpy(&returnedtag, currentcard->tag_9F6C, sizeof(currentcard->tag_9F6C)); + returnedlength = sizeof(currentcard->tag_9F6C);goto exitfunction;} + } + else { + if(!memcmp(tag, "\x61\x00",2)){ + memcpy(&returnedtag, currentcard->tag_61, currentcard->tag_61_len); + returnedlength = currentcard->tag_61_len; goto exitfunction;} + else if(!memcmp(tag, "\x6F\x00",2)){ + memcpy(&returnedtag, currentcard->tag_6F, currentcard->tag_6F_len); + returnedlength = currentcard->tag_6F_len; goto exitfunction;} + else if(!memcmp(tag, "\xAF\x00",2)){ + memcpy(&returnedtag, currentcard->tag_AF, currentcard->tag_AF_len); + returnedlength = currentcard->tag_AF_len; goto exitfunction;} + else if(!memcmp(tag, "\x70\x00",2)){ + memcpy(&returnedtag, currentcard->tag_70, currentcard->tag_70_len); + returnedlength = currentcard->tag_70_len; goto exitfunction;} + else if(!memcmp(tag, "\x77\x00",2)){ + memcpy(&returnedtag, currentcard->tag_77, currentcard->tag_77_len); + returnedlength = currentcard->tag_77_len; goto exitfunction;} + else if(!memcmp(tag, "\x80\x00",2)){ + memcpy(&returnedtag, currentcard->tag_80, currentcard->tag_80_len); + returnedlength = currentcard->tag_80_len; goto exitfunction;} + else if(!memcmp(tag, "\xBF\x0C",2)){ + memcpy(&returnedtag, currentcard->tag_BF0C, currentcard->tag_BF0C_len); + returnedlength = currentcard->tag_BF0C_len; goto exitfunction;} + else if(!memcmp(tag, "\xFF\x01",2)){ //special DF tag + memcpy(&returnedtag, currentcard->tag_DFName, currentcard->tag_DFName_len); + returnedlength = currentcard->tag_DFName_len; goto exitfunction;} + } +exitfunction: //goto label to exit search quickly once found + memcpy(outputval, &returnedtag, returnedlength); + *outputvallen = returnedlength; + return 0; +} + +//function to +int emv_settag(uint32_t tag, uint8_t *datain, emvtags *currentcard){ + char binarydata[255] = {0}; + //if((strlen((const char *)datain)%2) != 0){ //must be an even string + // return -1; + //} + //if(strlen((const char *)datain) > 255) { + // return -1; + //} + uint8_t datalen = strlen((const char *)datain) / 2; //length of datain + for(int i=0;iATQA); + Dbhexdump(sizeof(currentcard->ATQA), currentcard->ATQA, false); + DUMP(currentcard->UID); + Dbhexdump(currentcard->UID_len, currentcard->UID, false); + DUMP(currentcard->SAK1); + Dbhexdump(1, ¤tcard->SAK1, false); + DUMP(currentcard->SAK2); + Dbhexdump(1, ¤tcard->SAK2, false); + DUMP(currentcard->ATS); + Dbhexdump(currentcard->ATS_len, currentcard->ATS, false); + + DUMP(currentcard->tag_4F); + Dbhexdump(currentcard->tag_4F_len, currentcard->tag_4F, false); + DUMP(currentcard->tag_50); + Dbhexdump(currentcard->tag_50_len, currentcard->tag_50, false); + DUMP(currentcard->tag_56); + Dbhexdump(currentcard->tag_56_len, currentcard->tag_56, false); + DUMP(currentcard->tag_57); + Dbhexdump(currentcard->tag_57_len, currentcard->tag_57, false); + DUMP(currentcard->tag_5A); + Dbhexdump(currentcard->tag_5A_len, currentcard->tag_5A, false); + DUMP(currentcard->tag_82); + Dbhexdump(sizeof(currentcard->tag_82), currentcard->tag_82, false); + DUMP(currentcard->tag_84); + Dbhexdump(currentcard->tag_84_len, currentcard->tag_84, false); + DUMP(currentcard->tag_86); + Dbhexdump(currentcard->tag_86_len, currentcard->tag_86, false); + DUMP(currentcard->tag_87); + Dbhexdump(1, currentcard->tag_87, false); +DUMP(currentcard->tag_88); + Dbhexdump(1, currentcard->tag_88, false); +DUMP(currentcard->tag_8A); + Dbhexdump(2, currentcard->tag_8A, false); + DUMP(currentcard->tag_8C); + Dbhexdump(currentcard->tag_8C_len, currentcard->tag_8C, false); + DUMP(currentcard->tag_8D); + Dbhexdump(currentcard->tag_8D_len, currentcard->tag_8D, false); + DUMP(currentcard->tag_8E); + Dbhexdump(currentcard->tag_8E_len, currentcard->tag_8E, false); + DUMP(currentcard->tag_8F); + Dbhexdump(1, currentcard->tag_8F, false); + DUMP(currentcard->tag_90); + Dbhexdump(currentcard->tag_90_len, currentcard->tag_90, false); + DUMP(currentcard->tag_92); + Dbhexdump(currentcard->tag_92_len, currentcard->tag_92, false); + DUMP(currentcard->tag_93); + Dbhexdump(currentcard->tag_93_len, currentcard->tag_93, false); + DUMP(currentcard->tag_94); + Dbhexdump(currentcard->tag_94_len, currentcard->tag_94, false); + DUMP(currentcard->tag_95); + Dbhexdump(5, currentcard->tag_95, false); + DUMP(currentcard->tag_97); + Dbhexdump(currentcard->tag_97_len, currentcard->tag_97, false); + DUMP(currentcard->tag_98); + Dbhexdump(20, currentcard->tag_98, false); + DUMP(currentcard->tag_99); + Dbhexdump(currentcard->tag_99_len, currentcard->tag_99, false); + DUMP(currentcard->tag_9A); + Dbhexdump(3, currentcard->tag_9A, false); + DUMP(currentcard->tag_9B); + Dbhexdump(2, currentcard->tag_9B, false); + DUMP(currentcard->tag_9C); + Dbhexdump(1, currentcard->tag_9C, false); + DUMP(currentcard->tag_9D); + Dbhexdump(currentcard->tag_9D_len, currentcard->tag_9D, false); + DUMP(currentcard->tag_CD); + Dbhexdump(3, currentcard->tag_CD, false); + DUMP(currentcard->tag_CE); + Dbhexdump(3, currentcard->tag_CE, false); + DUMP(currentcard->tag_CF); + Dbhexdump(3, currentcard->tag_CF, false); + DUMP(currentcard->tag_D7); + Dbhexdump(3, currentcard->tag_D7, false); + DUMP(currentcard->tag_D8); + Dbhexdump(2, currentcard->tag_D8, false); + DUMP(currentcard->tag_D9); + Dbhexdump(currentcard->tag_D9_len, currentcard->tag_D9, false); + DUMP(currentcard->tag_DA); + Dbhexdump(2, currentcard->tag_DA, false); + DUMP(currentcard->tag_DB); + Dbhexdump(2, currentcard->tag_DB, false); + DUMP(currentcard->tag_DC); + Dbhexdump(2, currentcard->tag_DC, false); + DUMP(currentcard->tag_DD); + Dbhexdump(2, currentcard->tag_DD, false); + DUMP(currentcard->tag_AF); + Dbhexdump(currentcard->tag_AF_len, currentcard->tag_AF, false); + DUMP(currentcard->tag_5F20); + Dbhexdump(currentcard->tag_5F20_len, currentcard->tag_5F20, false); + DUMP(currentcard->tag_5F24); + Dbhexdump(3, currentcard->tag_5F24, false); + DUMP(currentcard->tag_5F25); + Dbhexdump(3, currentcard->tag_5F25, false); + DUMP(currentcard->tag_5F28); + Dbhexdump(2, currentcard->tag_5F28, false); + DUMP(currentcard->tag_5F2A); + Dbhexdump(2, currentcard->tag_5F2A, false); + DUMP(currentcard->tag_5F2D); + Dbhexdump(currentcard->tag_5F2D_len, currentcard->tag_5F2D, false); + DUMP(currentcard->tag_5F30); + Dbhexdump(3, currentcard->tag_5F30, false); + DUMP(currentcard->tag_5F34); + Dbhexdump(1, currentcard->tag_5F34, false); + DUMP(currentcard->tag_5F36); + Dbhexdump(2, currentcard->tag_5F36, false); + DUMP(currentcard->tag_5F50); + Dbhexdump(currentcard->tag_5F50_len, currentcard->tag_5F50, false); + DUMP(currentcard->tag_5F54); + Dbhexdump(currentcard->tag_5F54_len, currentcard->tag_5F54, false); + DUMP(currentcard->tag_9F01); + Dbhexdump(6, currentcard->tag_9F01, false); + DUMP(currentcard->tag_9F02); + Dbhexdump(6, currentcard->tag_9F02, false); + DUMP(currentcard->tag_9F03); + Dbhexdump(6, currentcard->tag_9F03, false); + DUMP(currentcard->tag_9F04); + Dbhexdump(4, currentcard->tag_9F04, false); + DUMP(currentcard->tag_9F05); + Dbhexdump(currentcard->tag_9F05_len, currentcard->tag_9F05, false); + DUMP(currentcard->tag_9F06); + Dbhexdump(currentcard->tag_9F06_len, currentcard->tag_9F06, false); + DUMP(currentcard->tag_9F07); + Dbhexdump(2, currentcard->tag_9F07, false); + DUMP(currentcard->tag_9F08); + Dbhexdump(2, currentcard->tag_9F08, false); + DUMP(currentcard->tag_9F09); + Dbhexdump(2, currentcard->tag_9F09, false); + DUMP(currentcard->tag_9F0B); + Dbhexdump(currentcard->tag_9F0B_len, currentcard->tag_9F0B, false); + DUMP(currentcard->tag_9F0D); + Dbhexdump(5, currentcard->tag_9F0D, false); + DUMP(currentcard->tag_9F0E); + Dbhexdump(5, currentcard->tag_9F0E, false); + DUMP(currentcard->tag_9F0F); + Dbhexdump(5, currentcard->tag_9F0F, false); + DUMP(currentcard->tag_9F10); + Dbhexdump(currentcard->tag_9F10_len, currentcard->tag_9F10, false); + DUMP(currentcard->tag_9F11); + Dbhexdump(1, currentcard->tag_9F11, false); + DUMP(currentcard->tag_9F12); + Dbhexdump(currentcard->tag_9F12_len, currentcard->tag_9F12, false); + DUMP(currentcard->tag_9F13); + Dbhexdump(2, currentcard->tag_9F13, false); + DUMP(currentcard->tag_9F14); + Dbhexdump(1, currentcard->tag_9F14, false); + DUMP(currentcard->tag_9F15); + Dbhexdump(2, currentcard->tag_9F15, false); + DUMP(currentcard->tag_9F16); + Dbhexdump(15, currentcard->tag_9F16, false); + DUMP(currentcard->tag_9F17); + Dbhexdump(1, currentcard->tag_9F17, false); + DUMP(currentcard->tag_9F18); + Dbhexdump(4, currentcard->tag_9F18, false); + DUMP(currentcard->tag_9F1A); + Dbhexdump(2, currentcard->tag_9F1A, false); + DUMP(currentcard->tag_9F1B); + Dbhexdump(4, currentcard->tag_9F1B, false); + DUMP(currentcard->tag_9F1C); + Dbhexdump(8, currentcard->tag_9F1C, false); + DUMP(currentcard->tag_9F1D); + Dbhexdump(currentcard->tag_9F1D_len, currentcard->tag_9F1D, false); + DUMP(currentcard->tag_9F1E); + Dbhexdump(8, currentcard->tag_9F1E, false); + DUMP(currentcard->tag_9F1F); + Dbhexdump(currentcard->tag_9F1F_len, currentcard->tag_9F1F, false); + DUMP(currentcard->tag_9F20); + Dbhexdump(currentcard->tag_9F20_len, currentcard->tag_9F20, false); + DUMP(currentcard->tag_9F21); + Dbhexdump(3, currentcard->tag_9F1E, false); + DUMP(currentcard->tag_9F22); + Dbhexdump(1, currentcard->tag_9F22, false); + DUMP(currentcard->tag_9F23); + Dbhexdump(1, currentcard->tag_9F23, false); + DUMP(currentcard->tag_9F26); + Dbhexdump(8, currentcard->tag_9F26, false); + DUMP(currentcard->tag_9F27); + Dbhexdump(1, currentcard->tag_9F27, false); + DUMP(currentcard->tag_9F2D); + Dbhexdump(currentcard->tag_9F2D_len, currentcard->tag_9F2D, false); + DUMP(currentcard->tag_9F2E); + Dbhexdump(3, currentcard->tag_9F2E, false); + DUMP(currentcard->tag_9F2F); + Dbhexdump(currentcard->tag_9F2F_len, currentcard->tag_9F2F, false); + DUMP(currentcard->tag_9F32); + Dbhexdump(currentcard->tag_9F32_len, currentcard->tag_9F32, false); + DUMP(currentcard->tag_9F33); + Dbhexdump(3, currentcard->tag_9F33, false); + DUMP(currentcard->tag_9F34); + Dbhexdump(3, currentcard->tag_9F34, false); + DUMP(currentcard->tag_9F35); + Dbhexdump(1, currentcard->tag_9F35, false); + DUMP(currentcard->tag_9F36); + Dbhexdump(2, currentcard->tag_9F36, false); + DUMP(currentcard->tag_9F37); + Dbhexdump(4, currentcard->tag_9F37, false); + DUMP(currentcard->tag_9F38); + Dbhexdump(currentcard->tag_9F38_len, currentcard->tag_9F38, false); + DUMP(currentcard->tag_9F39); + Dbhexdump(1, currentcard->tag_9F39, false); + DUMP(currentcard->tag_9F39); + Dbhexdump(1, currentcard->tag_9F39, false); + DUMP(currentcard->tag_9F40); + Dbhexdump(5, currentcard->tag_9F40, false); + DUMP(currentcard->tag_9F41); + Dbhexdump(4, currentcard->tag_9F41, false); + DUMP(currentcard->tag_9F42); + Dbhexdump(2, currentcard->tag_9F42, false); + DUMP(currentcard->tag_9F43); + Dbhexdump(4, currentcard->tag_9F43, false); + DUMP(currentcard->tag_9F44); + Dbhexdump(1, currentcard->tag_9F44, false); + DUMP(currentcard->tag_9F45); + Dbhexdump(2, currentcard->tag_9F45, false); + DUMP(currentcard->tag_9F46); + Dbhexdump(currentcard->tag_9F46_len, currentcard->tag_9F46, false); + DUMP(currentcard->tag_9F47); + Dbhexdump(currentcard->tag_9F47_len, currentcard->tag_9F47, false); + DUMP(currentcard->tag_9F48); + Dbhexdump(currentcard->tag_9F48_len, currentcard->tag_9F48, false); + DUMP(currentcard->tag_9F49); + Dbhexdump(currentcard->tag_9F49_len, currentcard->tag_9F49, false); + DUMP(currentcard->tag_9F4A); + Dbhexdump(1, currentcard->tag_9F4A, false); + DUMP(currentcard->tag_9F4B); + Dbhexdump(currentcard->tag_9F4B_len, currentcard->tag_9F4B, false); + DUMP(currentcard->tag_9F4C); + Dbhexdump(8, currentcard->tag_9F4C, false); + DUMP(currentcard->tag_9F4D); + Dbhexdump(2, currentcard->tag_9F4D, false); + DUMP(currentcard->tag_9F4E); + Dbhexdump(255, currentcard->tag_9F4E, false); + DUMP(currentcard->tag_9F60); + Dbhexdump(2, currentcard->tag_9F60, false); + DUMP(currentcard->tag_9F61); + Dbhexdump(2, currentcard->tag_9F61, false); + DUMP(currentcard->tag_9F62); + Dbhexdump(6, currentcard->tag_9F62, false); + DUMP(currentcard->tag_9F63); + Dbhexdump(6, currentcard->tag_9F63, false); + DUMP(currentcard->tag_9F64); + Dbhexdump(1, currentcard->tag_9F64, false); + DUMP(currentcard->tag_9F65); + Dbhexdump(2, currentcard->tag_9F65, false); + DUMP(currentcard->tag_9F66); + Dbhexdump(2, currentcard->tag_9F66, false); + DUMP(currentcard->tag_9F67); + Dbhexdump(1, currentcard->tag_9F67, false); + DUMP(currentcard->tag_9F68); + Dbhexdump(currentcard->tag_9F68_len, currentcard->tag_9F68, false); + DUMP(currentcard->tag_9F69); + Dbhexdump(currentcard->tag_9F69_len, currentcard->tag_9F69, false); + DUMP(currentcard->tag_9F6A); + Dbhexdump(8, currentcard->tag_9F6A, false); + DUMP(currentcard->tag_9F6B); + Dbhexdump(currentcard->tag_9F6B_len, currentcard->tag_9F6B, false); + DUMP(currentcard->tag_9F6C); + Dbhexdump(2, currentcard->tag_9F6C, false); + DUMP(currentcard->tag_61); + Dbhexdump(currentcard->tag_61_len, currentcard->tag_61, false); + DUMP(currentcard->tag_A5); + Dbhexdump(currentcard->tag_A5_len, currentcard->tag_A5, false); + DUMP(currentcard->tag_DFNAME); + Dbhexdump(currentcard->tag_DFNAME_len, currentcard->tag_DFNAME, false); + DUMP(currentcard->tag_70); + Dbhexdump(currentcard->tag_70_len, currentcard->tag_70, false); + DUMP(currentcard->tag_77); + Dbhexdump(currentcard->tag_77_len, currentcard->tag_77, false); + DUMP(currentcard->tag_80); + Dbhexdump(currentcard->tag_80_len, currentcard->tag_80, false); + DUMP(currentcard->tag_91); + Dbhexdump(currentcard->tag_91_len, currentcard->tag_91, false); + DUMP(currentcard->tag_BF0C); + Dbhexdump(currentcard->tag_BF0C_len, currentcard->tag_BF0C, false); + DUMP(currentcard->tag_DFName); + Dbhexdump(currentcard->tag_DFName_len, currentcard->tag_DFName, false); +} + + diff --git a/armsrc/emvutil.h b/armsrc/emvutil.h new file mode 100644 index 00000000..6fe748dd --- /dev/null +++ b/armsrc/emvutil.h @@ -0,0 +1,89 @@ +//----------------------------------------------------------------------------- +// Peter Fillmore 2014 +// code derived off merloks mifare code +// +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// code for work with EMV cards. +//----------------------------------------------------------------------------- +#ifndef __EMVUTIL_H +#define __EMVUTIL_H +#include +#include +#include "iso14443a.h" +#include "tlv.h" +#include "emvtags.h" +#include "emvdataels.h" +// mifare 4bit card answers +// reader voltage field detector +#define EMV_MINFIELDV 4000 + +// debug +// 0 - no debug messages 1 - error messages 2 - all messages 4 - extended debug mode +#define EMV_DBG_NONE 0 +#define EMV_DBG_ERROR 1 +#define EMV_DBG_ALL 2 +#define EMV_DBG_EXTENDED 4 + +extern int EMV_DBGLEVEL; + +//EMV emulator states need to update +#define EMVEMUL_NOFIELD 0 +#define EMVEMUL_IDLE 1 +#define EMVEMUL_SELECT1 2 +#define EMVEMUL_SELECT2 3 +#define EMVEMUL_SELECT3 4 +#define EMVEMUL_AUTH1 5 +#define EMVEMUL_AUTH2 6 +#define EMVEMUL_WORK 7 +#define EMVEMUL_HALTED 8 +#define EMVEMUL_ACK 9 +//#define cardSTATE_TO_IDLE() cardSTATE = EMVEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); +//grabbed from iso14443a.c +//static int EmGetCmd(uint8_t *received, int *len); +//int EmSendCmdEx(uint8_t *resp, size_t respLen, bool correctionNeeded);//tag types +//int EmSendCmd(uint8_t *resp, size_t respLen); +//#define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); +//extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data); + +//functions +//int emv_sendapdu( uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2, uint8_t lc, uint8_t* data, uint8_t le); +int emv_select(uint8_t* AID, uint8_t AID_len, void* data); +int emv_selectPPSE(); +int emv_readrecord(uint8_t recordnumber, uint8_t sfi, void* data); +int emv_getprocessingoptions(uint8_t* pdol, uint8_t pdol_len, void* data +); +int emv_computecryptogram(uint8_t* UDOL, uint8_t UDOL_len, void *data); +//return 8 8byte ICC random number. +int emv_getchallenge(void *data); +int emv_loopback(uint8_t* transData , uint8_t transData_len, void *data); +int emv_generateAC(uint8_t refcontrolparam, uint8_t* cdolinput, uint8_t cdolinputlen, void* data); +int emv_decodeAFL(uint8_t* AFL, uint8_t AFLlen); +int emv_decodeAIP(uint8_t* AIP); +int emv_decodeCVM(uint8_t* CVM, uint8_t CVMlen); +//memory management +//uint8_t* emv_get_bigbufptr(void); +//uint8_t* emv_get_bigbufptr_sendbuf(void); +//uint8_t* emv_get_bigbufptr_recbuf(void); + +//emulator +//void EMVsim(); + +//utils +int emv_printtag(uint8_t* selected_tag,emvtags* inputcard, uint8_t* outputstring, uint8_t* outputlen); +int emv_decode_field(uint8_t* inputfield,uint16_t inputlength, emvtags *result); +int emv_emvtags_decode_tag(tlvtag* inputtag, emvtags* currentcard); +//look up a tag in the current structure +int emv_lookuptag(uint8_t* tag, emvtags* currentcard, uint8_t* outputval, uint8_t* outputvallen); +//set a tag from external impurt +int emv_settag(uint32_t tag, uint8_t *datain, emvtags *currentcard) ; +void dumpCard(emvtags* currentcard); + +//generate a valid PDOL list from the returned card value, used in get processing options +int emv_generateDOL(uint8_t* DOL, uint8_t DOLlen,emvtags* currentcard, uint8_t* DOLoutput, uint8_t* DOLoutputlen); + +int emv_generatetemplate(uint8_t* templateval,emvtags* currentcard, uint8_t* returnedval, uint8_t* returnedlen, uint8_t numtags, ...); +#endif diff --git a/armsrc/tlv.c b/armsrc/tlv.c new file mode 100644 index 00000000..5f3bde2f --- /dev/null +++ b/armsrc/tlv.c @@ -0,0 +1,78 @@ +#include +#include + +int decode_ber_tlv_item(uint8_t* data, tlvtag* returnedtag) +{ + uint8_t tag[TAG_LENGTH] = {0x00,0x00}; + uint16_t length = 0; + //uint8_t value[VALUE_LENGTH]; + uint8_t lenlen = 0; + int i = 0; + int z = 0; + //decode tag + tag[0] = data[0]; + if((tag[0] & TLV_TAG_NUMBER_MASK) == TLV_TAG_NUMBER_MASK) { //see subsequent bytes + i++; + tag[i] = data[i]; + //assume tag is only two bytes long for now + /* + while((data[i] & TLV_TAG_MASK) == TLV_TAG_MASK){ + i++; + tag[i] = data[i]; + } + */ + } + i++; + //decode length + if((data[i] & TLV_LENGTH_MASK) == TLV_LENGTH_MASK) { + lenlen = data[i] ^ TLV_LENGTH_MASK; + i++; + length = (uint16_t)data[i]; + z = 1; + while(z < lenlen){ + i++; + z++; + length <<= 8; + length += (uint16_t)data[i]; + } + i++; + } + else { + length = (uint16_t)data[i]; + i++; + } + //copy results into the structure and return + memcpy(returnedtag->tag, tag, TAG_LENGTH); + (*returnedtag).valuelength = length; //return length of tag value + (*returnedtag).fieldlength = length + i + 1; //return length of total field + memcpy(returnedtag->value, &(data[i]), length); + return 0; +} + +//generate a TLV tag off input data +int encode_ber_tlv_item(uint8_t* tag, uint8_t taglen, uint8_t* data, uint32_t datalen, uint8_t* outputtag, uint32_t* outputtaglen) +{ + if(!tag || !data || !outputtag || !outputtaglen) //null pointer check + return 0; + + uint8_t datafieldlen = (datalen / 128) + 1; //field length of the tag + uint8_t tlvtotallen = taglen + datafieldlen + datalen; //total length of the tag + uint8_t returnedtag[tlvtotallen]; //buffer for the returned tag + uint8_t counter = 0; + memcpy(returnedtag, tag, taglen); //copy tag into buffer + counter += taglen; + if(datalen < 128){ // 1 byte length value + returnedtag[counter++] = datalen; + } + else{ + returnedtag[counter++] = datafieldlen | 0x80; //high bit set and number of length bytes + for(uint8_t i=datafieldlen; i !=0; i--){ + returnedtag[counter++] = (datalen >> (i * 8)) & 0xFF; //get current byte + } + } + memcpy(&returnedtag[counter], data, datalen); + *outputtaglen = tlvtotallen; + memcpy(outputtag, returnedtag,tlvtotallen); + return 0; +} + diff --git a/armsrc/tlv.h b/armsrc/tlv.h new file mode 100644 index 00000000..f1457aaa --- /dev/null +++ b/armsrc/tlv.h @@ -0,0 +1,34 @@ +#ifndef __TLV_H +#define __TLV_H + +#include +#include +#include +#include + +//structure buffer definitions +#define TAG_LENGTH 2 +#define VALUE_LENGTH 1024 + +//masks +//if TLV_TAG_NUMBER_MASK bits are set, refer to the next byte for the tag number +//otherwise its located in bits 1-5 +#define TLV_TAG_NUMBER_MASK 0x1f +//if TLV_DATA_MASK set then its a 'constructed data object' +//otherwise a 'primitive data object' +#define TLV_DATA_MASK 0x20 +#define TLV_TAG_MASK 0x80 +#define TLV_LENGTH_MASK 0x80 + +//tlv tag structure, tag can be max of 2 bytes, length up to 65535 and value 1024 bytes long +typedef struct { + uint8_t tag[TAG_LENGTH]; + uint16_t fieldlength; + uint16_t valuelength; + uint8_t value[VALUE_LENGTH]; +}tlvtag; + +//decode a BER TLV +extern int decode_ber_tlv_item(uint8_t* data, tlvtag* returnedtag); +extern int encode_ber_tlv_item(uint8_t* tag, uint8_t taglen, uint8_t*data, uint32_t datalen, uint8_t* outputtag, uint32_t* outputtaglen); +#endif //__TLV_H diff --git a/common/emvtags.h b/common/emvtags.h new file mode 100644 index 00000000..88cd42e8 --- /dev/null +++ b/common/emvtags.h @@ -0,0 +1,249 @@ +//----------------------------------------------------------------------------- +// Peter Fillmore 2014 +// code derived off merloks mifare code +// +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// structure to hold EMV card and terminal parameters +//----------------------------------------------------------------------------- +#ifndef __EMVCARD_H +#define __EMVCARD_H + +#include +#include + +//structure to hold received/set tag values +//variable data inputs have length specifiers +typedef struct { + //ISO14443-A card stuff + uint8_t ATQA[2]; //Answer to Request + uint8_t UID_len; + uint8_t UID[10]; + uint8_t SAK1; //SAK for UID 1 + uint8_t SAK2; //SAK for UID 2 + uint8_t ATS_len; //Answer to select + uint8_t ATS[256]; + //ATS + uint8_t TL; + uint8_t T0; + uint8_t TA1; + uint8_t TB1; + uint8_t TC1; + uint8_t* historicalbytes; + //PPS response + uint8_t PPSS; + //SFI 2 record 1 + uint8_t tag_4F_len; //length of AID + uint8_t tag_4F[16]; //Application Identifier (AID) + uint8_t tag_50_len; //length of application label + uint8_t tag_50[16]; //Application Label + uint8_t tag_56_len; //track1 length + uint8_t tag_56[76]; //Track 1 Data + uint8_t tag_57_len; //track2 equiv len + uint8_t tag_57[19]; //Track 2 Equivalent Data + uint8_t tag_5A_len; //PAN length + uint8_t tag_5A[10]; //Application Primary Account Number (PAN) + //uint8_t tag_6F[]; //File Control Information (FCI) Template + //uint8_t tag_70[255]; //Record Template + //uint8_t tag_77[]; //Response Message Template Format 2 + //uint8_t tag_80[]; //Response Message Template Format 1 + uint8_t tag_82[2]; //Application Interchange Profile AIP + //uint8_t tag_83[]; //Command Template + uint8_t tag_84_len; + uint8_t tag_84[16]; //DF Name + uint8_t tag_86_len; + uint8_t tag_86[261]; //Issuer Script Command + uint8_t tag_87[1]; //Application Priority Indicator + uint8_t tag_88[1]; //Short File Identifier + uint8_t tag_8A[2]; //Authorisation Response Code + uint8_t tag_8C_len; + uint8_t tag_8C[252]; //CDOL1 + uint8_t tag_8D_len; + uint8_t tag_8D[252]; //CDOL2 + uint8_t tag_8E_len; + uint8_t tag_8E[252]; //Cardholder Verification Method (CVM) List + uint8_t tag_8F[1]; //Certification Authority Public Key Index + uint8_t tag_90_len; + uint8_t tag_90[255]; //ssuer Public Key Certificate + uint8_t tag_92_len; + uint8_t tag_92[255]; //Issuer Public Key Remainder + uint8_t tag_93_len; + uint8_t tag_93[255]; //Signed Static Application Data + uint8_t tag_94_len; + uint8_t tag_94[252]; //Application File Locator AFL + uint8_t tag_95[5]; //Terminal Verification Results + uint8_t tag_97_len; + uint8_t tag_97[252]; //Transaction Certificate Data Object List (TDOL) + uint8_t tag_98[20]; //Transaction Certificate (TC) Hash Value + //assume 20 bytes, change after testing + uint8_t tag_99_len; + uint8_t tag_99[20]; //Transaction Personal Identification Number (PIN) Data + uint8_t tag_9A[3]; //Transaction Date + uint8_t tag_9B[2]; //Transaction Status Information + uint8_t tag_9C[1]; //Transaction Type + uint8_t tag_9D_len; + uint8_t tag_9D[16]; //Directory Definition File + + uint8_t tag_CD[3]; //Card Issuer Action Codes Paypass + uint8_t tag_CE[3]; + uint8_t tag_CF[3]; + + uint8_t tag_D7[3]; //Application Control (PayPass) + uint8_t tag_D8[2]; //Application Interchange Profile (PayPass) + uint8_t tag_D9_len; //Application File Locator (PayPass) + uint8_t tag_D9[16]; + uint8_t tag_DA[2]; //Static CVC3track1 + uint8_t tag_DB[2]; //Static CVC3track2 + uint8_t tag_DC[2]; //IVCVC3 CVC3track1 + uint8_t tag_DD[2]; //IVCVC3 CVC3track2 + + uint8_t tag_AF_len; + uint8_t tag_AF[255]; //Proprietary Information + + uint8_t tag_5F20_len; + uint8_t tag_5F20[26]; //Cardholder Name + uint8_t tag_5F24[3]; //Application Expiry Date + uint8_t tag_5F25[3]; //Application Effective Date YYMMDD + uint8_t tag_5F28[2]; //Issuer Country Code + uint8_t tag_5F2A[2]; //Transaction Currency Code + uint8_t tag_5F2D_len; + uint8_t tag_5F2D[8]; //Language Preference + uint8_t tag_5F30[2]; //Service Code + uint8_t tag_5F34[1]; //Application Primary Account Number (PAN) Sequence Number + uint8_t tag_5F36[2]; //ATC + uint8_t tag_5F50_len; + uint8_t tag_5F50[255]; //Issuer URL + uint8_t tag_5F54_len; + uint8_t tag_5F54[11]; //Bank Identifier Code (BIC) + uint8_t tag_9F01[6]; //Acquirer Identifier + uint8_t tag_9F02[6]; // Amount, Authorised (Numeric) + uint8_t tag_9F03[6]; //Amount, Other (Numeric) + uint8_t tag_9F04[4]; //Amount, Other (Binary) + uint8_t tag_9F05_len; + uint8_t tag_9F05[32]; //Application Discretionary Data + uint8_t tag_9F06_len; + uint8_t tag_9F06[16]; //AID terminal + uint8_t tag_9F07[2]; //Application Usage Control + uint8_t tag_9F08[2]; //Application Version Number + uint8_t tag_9F09[2]; //Application Version Number + //uint8_t tag_9F0A[2] + uint8_t tag_9F0B_len; + uint8_t tag_9F0B[45]; //Cardholder Name Extended + uint8_t tag_9F0D[5]; //Issuer Action Code - Default + uint8_t tag_9F0E[5]; //Issuer Action Code - Denial + uint8_t tag_9F0F[5]; //Issuer Action Code - Online + uint8_t tag_9F10_len; //Issuer Application Data + uint8_t tag_9F10[32]; + uint8_t tag_9F11[1]; //Issuer Code Table Index + uint8_t tag_9F12_len; + uint8_t tag_9F12[255]; //Application Preferred Name + uint8_t tag_9F13[2]; //Last Online Application Transaction Counter (ATC) Registerjk + uint8_t tag_9F14[1]; //Lower Consecutive Offline Limit + uint8_t tag_9F15[2]; //Merchant Category Code + uint8_t tag_9F16[15]; //Merchant Identifier + uint8_t tag_9F17[1]; //Personal Identification Number (PIN) Try Counter + uint8_t tag_9F18[4]; //Issuer Script Identifier + //uint8_t tag_9F19[] + uint8_t tag_9F1A[2]; //Terminal Country Code + uint8_t tag_9F1B[4]; //Terminal Floor Limit + uint8_t tag_9F1C[8]; //Terminal Identification + uint8_t tag_9F1D_len; + uint8_t tag_9F1D[8]; //Terminal Risk Management Data + uint8_t tag_9F1E[8]; //Interface Device (IFD) Serial Number + uint8_t tag_9F1F_len; + uint8_t tag_9F1F[255]; //Track 1 Discretionary Data + uint8_t tag_9F20_len; + uint8_t tag_9F20[255]; //Track 2 DD + uint8_t tag_9F21[3]; //Transaction Time + uint8_t tag_9F22[1]; //Certification Authority Public Key Index + uint8_t tag_9F23[1]; //Upper Consecutive Offline Limit + //uint8_t tag_9F24 + //uint8_t tag_9F25 + uint8_t tag_9F26[8]; //Application Cryptogram + uint8_t tag_9F27[1]; //Cryptogram Information Data + //uint8_t tag_9F28 + //uint8_t tag_9F29 + //uint8_t tag_9F2A + //uint8_t tag_9F2B + //uint8_t tag_9F2C + uint8_t tag_9F2D_len; + uint8_t tag_9F2D[255]; //Integrated Circuit Card (ICC) PIN Encipherment Public Key Certificate + uint8_t tag_9F2E[3]; //Integrated Circuit Card (ICC) PIN Encipherment Public Key Exponent + uint8_t tag_9F2F_len; + uint8_t tag_9F2F[255]; //Integrated Circuit Card (ICC) PIN Encipherment Public Key Remainder + //uint8_t tag_9F30 + //uint8_t tag_9F31 + uint8_t tag_9F32_len; + uint8_t tag_9F32[3]; //Issuer Public Key Exponent + uint8_t tag_9F33[3]; //Terminal Capabilities + uint8_t tag_9F34[3]; //Cardholder Verification Method (CVM) Results + uint8_t tag_9F35[1]; //Terminal Type + uint8_t tag_9F36[2]; //Application Transaction Counter (ATC) + uint8_t tag_9F37[4]; //Unpredictable Number + uint8_t tag_9F38_len; + uint8_t tag_9F38[255]; //PDOL + uint8_t tag_9F39[1]; //Point-of-Service (POS) Entry Mode + uint8_t tag_9F40[5]; //Additional Terminal Capabilities + uint8_t tag_9F41[4]; //Transaction Sequence Counter + uint8_t tag_9F42[2]; //Application Currency Code + uint8_t tag_9F43[4]; //Application Reference Currency Exponent + uint8_t tag_9F44[1]; //Application Currency Exponent + uint8_t tag_9F45[2]; //Data Authentication Code + uint8_t tag_9F46_len; + uint8_t tag_9F46[255]; //ICC Public Key Certificate + uint8_t tag_9F47_len; + uint8_t tag_9F47[3]; //ICC Public Key Exponent + uint8_t tag_9F48_len; + uint8_t tag_9F48[255]; //ICC Public Key Remainder + uint8_t tag_9F49_len; + uint8_t tag_9F49[252]; + uint8_t tag_9F4A[1]; //SDA Tag list + uint8_t tag_9F4B_len; + uint8_t tag_9F4B[255]; //Signed Dynamic Application Data + uint8_t tag_9F4C[8]; //ICC Dynamic Number + uint8_t tag_9F4D[2]; //Log Entry + uint8_t tag_9F4E[255]; //Merchant Name and Location + //9F50-9F7F are payment system specific + uint8_t tag_9F60[2]; //CVC3 track1 + uint8_t tag_9F61[2]; //CVC3 track2 + uint8_t tag_9F62[6]; //Track 1 Bit Map for CVC3 (PCVC3TRACK1) + uint8_t tag_9F63[6]; //Track 1 Bit Map for UN and ATC (PUNATCTRACK1) + uint8_t tag_9F64[1]; //Track 1 Number of ATC Digits (NATCTRACK1) + uint8_t tag_9F65[2]; //rack 2 Bit Map for CVC3 (PCVC3TRACK2) + uint8_t tag_9F66[2]; //Track 2 Bit Map for UN and ATC (PUNATCTRACK2), or VISA card type + uint8_t tag_9F67[1]; //Track 2 Number of ATC Digits (NATCTRACK2) + uint8_t tag_9F68_len; + uint8_t tag_9F68[252]; //Mag Stripe CVM List + uint8_t tag_9F69_len; + uint8_t tag_9F69[255]; //Unpredictable Number Data Object List (UDOL) + uint8_t tag_9F6A[8]; //Unpredictable Number (Numeric) + uint8_t tag_9F6B_len; + uint8_t tag_9F6B[19]; //track 2 data + uint8_t tag_9F6C[2]; //Mag Stripe Application Version Number(Card) + //template holders + uint8_t tag_61_len; + uint8_t tag_61[255]; //Application template + uint8_t tag_6F_len; + uint8_t tag_6F[255]; //6F template + uint8_t tag_A5_len; + uint8_t tag_A5[255]; //A5 template + uint8_t tag_DFNAME_len; + uint8_t tag_DFNAME[255]; //A5 template + uint8_t tag_70_len; + uint8_t tag_70[255]; //70 template + uint8_t tag_77_len; + uint8_t tag_77[255]; //77 template + uint8_t tag_80_len; + uint8_t tag_80[255]; //80 template + uint8_t tag_91_len; //Issuer Authentication Data + uint8_t tag_91[16]; + uint8_t tag_BF0C_len; + uint8_t tag_BF0C[222]; //File Control Information (FCI) Issuer Discretionary Data + uint8_t tag_DFName[16]; + uint8_t tag_DFName_len; +}emvtags; + +#endif //__EMVCARD_H diff --git a/traces/EMV/mastercardtags.txt b/traces/EMV/mastercardtags.txt new file mode 100644 index 00000000..a9548bbc --- /dev/null +++ b/traces/EMV/mastercardtags.txt @@ -0,0 +1,5 @@ +0x95:0000000000 +0x9F45:0000 +0x9F4C:0000000000000000 +0x9F35:12 +0x9F34:3F000000 diff --git a/traces/EMV/testcard.txt b/traces/EMV/testcard.txt new file mode 100644 index 00000000..961b01b4 --- /dev/null +++ b/traces/EMV/testcard.txt @@ -0,0 +1,4 @@ +ATQA:0400 +UID:8f2f27e166 +SAK1:28b4fc +RATS:0b788081024b4f4e4114118a76 diff --git a/traces/EMV/visaCVN17.txt b/traces/EMV/visaCVN17.txt new file mode 100644 index 00000000..505dff4b --- /dev/null +++ b/traces/EMV/visaCVN17.txt @@ -0,0 +1,9 @@ +0x9f02:000000000001 +0x9f03:000000000000 +0x9f1a:0826 +0x95:0000000000 +0x5f2a:0826 +0x9a:080401 +0x9c:01 +0x9f37:badf000d +0x9f66:80800000 diff --git a/traces/EMV/visaDCVV.txt b/traces/EMV/visaDCVV.txt new file mode 100644 index 00000000..5eedc12a --- /dev/null +++ b/traces/EMV/visaDCVV.txt @@ -0,0 +1,9 @@ +0x9f02:000000000100 +0x9f03:000000000000 +0x9f1a:0036 +0x95:0000000000 +0x5f2a:0036 +0x9a:080401 +0x9c:00 +0x9f37:badf000d +0x9f66:20800000 diff --git a/traces/EMV/visaEMV.txt b/traces/EMV/visaEMV.txt new file mode 100644 index 00000000..cb56efa3 --- /dev/null +++ b/traces/EMV/visaEMV.txt @@ -0,0 +1,9 @@ +0x9f02:000000000100 +0x9f03:000000000000 +0x9f1a:0036 +0x95:0000000000 +0x5f2a:0036 +0x9a:140101 +0x9c:00 +0x9f37:badf000d +0x9f66:18000000 diff --git a/traces/EMV/visaFDDA.txt b/traces/EMV/visaFDDA.txt new file mode 100644 index 00000000..c554eb02 --- /dev/null +++ b/traces/EMV/visaFDDA.txt @@ -0,0 +1,9 @@ +0x9f02:000000000100 +0x9f03:000000000000 +0x9f1a:0036 +0x95:0000000000 +0x5f2a:0036 +0x9a:140101 +0x9c:00 +0x9f37:badf000d +0x9f66:28000000 diff --git a/traces/EMV/visatags.txt b/traces/EMV/visatags.txt new file mode 100644 index 00000000..9efb5a9a --- /dev/null +++ b/traces/EMV/visatags.txt @@ -0,0 +1,9 @@ +0x9f02:000000000001 +0x9f03:000000000000 +0x9f1a:0826 +0x95:0000000000 +0x5f2a:0826 +0x9a:080401 +0x9c:01 +0x9f37:badf000d +0x9f66:d720c000 -- 2.39.2