]> git.zerfleddert.de Git - proxmark3-svn/commitdiff
ADD: copied all EMV files from peter filmoores fork. Have not started with making...
authoriceman1001 <iceman@iuse.se>
Sun, 20 Mar 2016 18:37:29 +0000 (19:37 +0100)
committericeman1001 <iceman@iuse.se>
Sun, 20 Mar 2016 18:37:29 +0000 (19:37 +0100)
17 files changed:
armsrc/emvcard.h [new file with mode: 0644]
armsrc/emvcmd.c [new file with mode: 0644]
armsrc/emvcmd.h [new file with mode: 0644]
armsrc/emvdataels.c [new file with mode: 0644]
armsrc/emvdataels.h [new file with mode: 0644]
armsrc/emvutil.c [new file with mode: 0644]
armsrc/emvutil.h [new file with mode: 0644]
armsrc/tlv.c [new file with mode: 0644]
armsrc/tlv.h [new file with mode: 0644]
common/emvtags.h [new file with mode: 0644]
traces/EMV/mastercardtags.txt [new file with mode: 0644]
traces/EMV/testcard.txt [new file with mode: 0644]
traces/EMV/visaCVN17.txt [new file with mode: 0644]
traces/EMV/visaDCVV.txt [new file with mode: 0644]
traces/EMV/visaEMV.txt [new file with mode: 0644]
traces/EMV/visaFDDA.txt [new file with mode: 0644]
traces/EMV/visatags.txt [new file with mode: 0644]

diff --git a/armsrc/emvcard.h b/armsrc/emvcard.h
new file mode 100644 (file)
index 0000000..7757949
--- /dev/null
@@ -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 (file)
index 0000000..3549d0e
--- /dev/null
@@ -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, &currentcard);
+}
+
+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, &currentcard); 
+        //decode the A5 tag 
+        if(currentcard.tag_A5_len > 0) 
+            emv_decode_field(currentcard.tag_A5, currentcard.tag_A5_len, &currentcard);
+        
+        //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, &currentcard);}
+         //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, &currentcard);}
+    }
+    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, &currentcard); 
+    } 
+    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, &currentcard, 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, &currentcard); 
+    } 
+    
+    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, &currentcard); //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, &currentcard, pdolcommand, &pdolcommandlen); 
+    }
+    Dbhexdump(pdolcommandlen, pdolcommand,false);
+
+    if(!EMVGetProcessingOptions(pdolcommand,pdolcommandlen, &currentcard)) {
+        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, &currentcard);
+                //while(responsebuffer[0] == 0xF2) {
+                //    EMVReadRecord(j,sfi, &currentcard);
+                //}
+            }  
+            i++;
+        }
+    }
+    else {
+        EMVReadRecord(1,1,&currentcard);
+        EMVReadRecord(1,2,&currentcard);
+        EMVReadRecord(1,3,&currentcard);
+        EMVReadRecord(2,1,&currentcard);
+        EMVReadRecord(2,2,&currentcard);
+        EMVReadRecord(2,3,&currentcard);
+        EMVReadRecord(3,1,&currentcard);
+        EMVReadRecord(3,3,&currentcard);
+        EMVReadRecord(4,2,&currentcard);
+    }
+    //EMVGetChallenge(&currentcard);
+        //memcpy(currentcard.tag_9F4C,&responsebuffer[1],8); // ICC UN 
+    EMVGenerateAC(0x81,&currentcard);
+
+    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, &currentcard);  
+    
+    //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, &currentcard, pdolcommand, &pdolcommandlen); 
+    }
+    if(EMVGetProcessingOptions(pdolcommand,pdolcommandlen, &currentcard)) {
+        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, &currentcard);
+            //while(responsebuffer[0] == 0xF2) {
+            //    EMVReadRecord(j,sfi, &currentcard);
+            //}
+        }  
+        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(&currentcard);
+        //memcpy(currentcard.tag_9F4C,&responsebuffer[1],8); // ICC UN 
+        EMVGenerateAC(0x80,&currentcard);
+        
+        //generate AC2  
+        //if(currentcard.tag_8D_len > 0) { 
+        //    emv_generateDOL(currentcard.tag_8D, currentcard.tag_8D_len, &currentcard, cdolcommand, &cdolcommandlen); }
+        //else{
+        //    //cdolcommand = NULL; //cdol val is null
+        //    cdolcommandlen = 0;
+        //}
+        //emv_generateAC(0x80, cdolcommand,cdolcommandlen, &currentcard);
+        
+        //if(responsebuffer[1] == 0x77) //format 2 data field returned
+        //{
+        //    decode_ber_tlv_item(&responsebuffer[1], &temptag);
+        //    emv_decode_field(temptag.value, temptag.valuelength, &currentcard); 
+        //}
+    } 
+    //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, &currentcard); 
+    //} 
+    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, &currentcard); //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(&currentcard);
+} 
+
+//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,&currentcard.SAK1,1);
+       ComputeCrc14443(CRC_14443_A, sak0packet, 1, &sak0packet[1], &sak0packet[2]);
+       uint8_t sak1packet[3]  = {0x00};
+    memcpy(sak1packet,&currentcard.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<TAG_RESPONSE_COUNT;i++){
+        allocatedtaglen += responses[i].response_n;
+    }
+       //uint8_t selectOrder = 0; 
+       BigBuf_free_keep_EM();
+    // Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
+       // Such a response is less time critical, so we can prepare them on the fly
+       
+    #define DYNAMIC_RESPONSE_BUFFER_SIZE 256 //max frame size 
+       #define DYNAMIC_MODULATION_BUFFER_SIZE 2 + 9*DYNAMIC_RESPONSE_BUFFER_SIZE //(start and stop bit, 8 bit packet with 1 bit parity
+       
+    //uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE];
+       //uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE];
+    uint8_t *dynamic_response_buffer = BigBuf_malloc(DYNAMIC_RESPONSE_BUFFER_SIZE);
+    uint8_t *dynamic_modulation_buffer = BigBuf_malloc(DYNAMIC_MODULATION_BUFFER_SIZE);
+    
+    tag_response_info_t dynamic_response_info = {
+               .response = dynamic_response_buffer,
+               .response_n = 0,
+               .modulation = dynamic_modulation_buffer,
+               .modulation_n = 0
+       };
+       // allocate buffers from BigBuf (so we're not in the stack)
+       uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
+       uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE);
+    //uint8_t* free_buffer_pointer;
+    //free_buffer_pointer = BigBuf_malloc((allocatedtaglen*8) +(allocatedtaglen) + (TAG_RESPONSE_COUNT * 3));
+    BigBuf_malloc((allocatedtaglen*8) +(allocatedtaglen) + (TAG_RESPONSE_COUNT * 3));
+    // clear trace
+       clear_trace();
+       set_tracing(TRUE);
+
+       // Prepare the responses of the anticollision phase
+       // there will be not enough time to do this at the moment the reader sends it REQA
+       for (size_t i=0; i<TAG_RESPONSE_COUNT; i++)
+               prepare_allocated_tag_modulation(&responses[i]);
+
+       int len = 0;
+
+       // To control where we are in the protocol
+       int order = 0;
+       int lastorder;
+    int currentblock = 1; //init to 1 
+    int previousblock = 0; //used to store previous block counter 
+
+       // Just to allow some checks
+       int happened = 0;
+       int happened2 = 0;
+       int cmdsRecvd = 0;
+
+       // We need to listen to the high-frequency, peak-detected path.
+       iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
+
+       cmdsRecvd = 0;
+       tag_response_info_t* p_response;
+
+       LED_A_ON();
+       for(;;) {
+               // Clean receive command buffer
+               
+               if(!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) {
+                       DbpString("Button press");
+                       break;
+               }
+
+               p_response = NULL;
+               
+               // Okay, look at the command now.
+           previousblock = currentblock; //get previous block  
+        lastorder = order;
+           currentblock = receivedCmd[0] & 0x01;       
+        
+        if(receivedCmd[0] == 0x26) { // Received a REQUEST
+                       p_response = &responses[ATR]; order = REQA;
+               } else if(receivedCmd[0] == 0x52) { // Received a WAKEUP
+                       p_response = &responses[ATR]; order = WUPA;
+               } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x93) {   // Received request for UID (cascade 1)
+                       p_response = &responses[UID1]; order = SELUID1;
+               } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x95) {   // Received request for UID (cascade 2)
+                       p_response = &responses[UID2]; order = SELUID2;
+               } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x93) {   // Received a SELECT (cascade 1)
+                       p_response = &responses[SELACK1]; order = SEL1;
+               } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x95) {   // Received a SELECT (cascade 2)
+                       p_response = &responses[SELACK2]; order = SEL2;
+               } else if((receivedCmd[0] & 0xA2) == 0xA2){ //R-Block received 
+            if(previousblock == currentblock){ //rule 11, retransmit last block
+                       p_response = &dynamic_response_info;
+            } else {
+                if((receivedCmd[0] & 0xB2) == 0xB2){ //RNAK, rule 12
+                    if(currentblock == 0)
+                        p_response = &responses[RACK0];
+                    else
+                        p_response = &responses[RACK1];
+                               } else {
+                    //rule 13
+                    //TODO: implement chaining 
+                }
+            }
+        }
+        else if(receivedCmd[0] == 0xD0){ //Protocol and parameter selection response
+            p_response = &responses[PPSresponse];
+                       order = PPS;
+        }
+        else if(receivedCmd[0] == 0x30) {      // Received a (plain) READ
+                   //we're an EMV card - so no read commands   
+            p_response = NULL;
+               } else if(receivedCmd[0] == 0x50) {     // Received a HALT
+                       LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE);
+                       p_response = NULL;
+                       order = HLTA;
+               } else if(receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61) {   // Received an authentication request
+                       p_response = &responses[AUTH_ANS];
+                       order = AUTH;
+               } else if(receivedCmd[0] == 0xE0) {     // Received a RATS request
+                   readerPacketLen = GetReaderLength(receivedCmd); //get length of supported packet    
+                       p_response = &responses[ATS];
+                       order = RATS;
+               } else if (order == AUTH && len == 8) { // Received {nr] and {ar} (part of authentication)
+                       LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE);
+                       uint32_t nr = bytes_to_num(receivedCmd,4);
+                       uint32_t ar = bytes_to_num(receivedCmd+4,4);
+                       Dbprintf("Auth attempt {nr}{ar}: %08x %08x",nr,ar);
+               } else {
+                       // Check for ISO 14443A-4 compliant commands, look at left nibble
+                       switch (receivedCmd[0]) {
+                               case 0x0B:
+                               case 0x0A: // IBlock (command)
+                case 0x02:
+                case 0x03: {
+                                   dynamic_response_info.response_n = 0; 
+                    dynamic_response_info.response[0] = receivedCmd[0]; // copy PCB 
+                    //dynamic_response_info.response[1] = receivedCmd[1]; // copy PCB 
+                    dynamic_response_info.response_n++ ; 
+                    switch(receivedCmd[1]) {
+                        case 0x00: 
+                            switch(receivedCmd[2]){
+                                case 0xA4: //select
+                                    if(receivedCmd[5] == 0x0E){ 
+                                    }
+                                    else if(receivedCmd[5] == 0x07){
+                                            //selectOrder = 0;
+                                    }
+                                    else{ //send not supported msg
+                                        memcpy(dynamic_response_info.response+1, "\x6a\x82", 2);
+                                        dynamic_response_info.response_n += 2;
+                                    }
+                                    break;
+                                case 0xB2: //read record
+                                    if(receivedCmd[3] == 0x01 && receivedCmd[4] == 0x0C){
+                                        dynamic_response_info.response_n += 2;
+                                        Dbprintf("READ RECORD 1 1"); 
+                                    }
+                                    break;
+                                }
+                                                               break;
+                        case 0x80: 
+                            switch(receivedCmd[2]){
+                                case 0xA8: //get processing options
+                                    break;
+                                           }
+                        } 
+                    }break;
+                           case 0x1A:
+                           case 0x1B: { // Chaining command
+                                     dynamic_response_info.response[0] = 0xaa | ((receivedCmd[0]) & 1);
+                                     dynamic_response_info.response_n = 2;
+                                   } break;
+
+                               case 0xaa:
+                               case 0xbb: {
+                                 dynamic_response_info.response[0] = receivedCmd[0] ^ 0x11;
+                                 dynamic_response_info.response_n = 2;
+                               } break;
+                                 
+                               case 0xBA: { //
+                                 memcpy(dynamic_response_info.response,"\xAB\x00",2);
+                                 dynamic_response_info.response_n = 2;
+                               } break;
+
+                               case 0xCA:
+                case 0xC2: { // Readers sends deselect command
+                                 //we send the command back - this is what tags do in android implemenation i believe - peterfillmore 
+                   memcpy(dynamic_response_info.response,receivedCmd,1);
+                                  dynamic_response_info.response_n = 1;  
+                               } break;
+                
+                               default: {
+                                       // Never seen this command before
+                                       LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE);
+                                       Dbprintf("Received unknown command (len=%d):",len);
+                                       Dbhexdump(len,receivedCmd,false);
+                                       // Do not respond
+                                       dynamic_response_info.response_n = 0;
+                               } break;
+                       }
+      
+                       if (dynamic_response_info.response_n > 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 (file)
index 0000000..070eb58
--- /dev/null
@@ -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 (file)
index 0000000..9958a27
--- /dev/null
@@ -0,0 +1,127 @@
+//Data elements for EMV transactions.
+#include <stdint.h>
+#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 (file)
index 0000000..6f3b6fd
--- /dev/null
@@ -0,0 +1,56 @@
+//Data elements for EMV transactions.
+#include <stdint.h>
+#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 (file)
index 0000000..e35cb1e
--- /dev/null
@@ -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 <stdarg.h>
+#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;i<strlen((const char *)datain);i+=2){
+        binarydata[i/2] |= (char)hex2int(datain[i]) << 4;
+        binarydata[i/2] |= (char)hex2int(datain[i+1]);
+    } 
+    Dbprintf("BINARYDATA="); 
+    Dbhexdump(datalen,(uint8_t *)binarydata,false);
+    switch(tag){
+        case 0x4F:
+            memcpy(currentcard->tag_4F, binarydata, datalen);
+            currentcard->tag_4F_len = datalen;
+            break; 
+        case 0x50:
+            memcpy(currentcard->tag_50, binarydata, datalen);
+            currentcard->tag_50_len = datalen;
+            break;
+        case 0x56:
+            memcpy(currentcard->tag_56, binarydata, datalen);
+            currentcard->tag_56_len = datalen;
+            break;
+        case 0x57:
+            memcpy(currentcard->tag_57, binarydata, datalen);
+            currentcard->tag_57_len = datalen;
+            break;
+        case 0x5a:
+            memcpy(currentcard->tag_5A, binarydata, datalen);
+            currentcard->tag_5A_len = datalen;
+            break;
+        case 0x61:
+            memcpy(currentcard->tag_61, binarydata, datalen);
+            currentcard->tag_61_len = datalen;
+            break;
+        case 0x6f:
+            memcpy(currentcard->tag_6F, binarydata, datalen);
+            currentcard->tag_6F_len = datalen;
+            break;
+        case 0x70:
+            memcpy(currentcard->tag_70, binarydata, datalen);
+            currentcard->tag_70_len = datalen;
+            break;
+        case 0x77:
+            memcpy(currentcard->tag_77, binarydata, datalen);
+            currentcard->tag_77_len = datalen;
+            break;
+        case 0x80:
+            memcpy(currentcard->tag_80, binarydata, datalen);
+            currentcard->tag_80_len = datalen;
+            break;
+        case 0x82:
+            memcpy(currentcard->tag_82, binarydata, sizeof(currentcard->tag_82));
+            break; 
+        case 0x84:
+            memcpy(currentcard->tag_84, binarydata, datalen);
+            currentcard->tag_84_len = datalen;
+            break;
+        case 0x86:
+            memcpy(currentcard->tag_86, binarydata, datalen);
+            currentcard->tag_86_len = datalen;
+            break;
+        case 0x87:
+            memcpy(currentcard->tag_87, binarydata, sizeof(currentcard->tag_87));
+            break;
+        case 0x88:
+            memcpy(currentcard->tag_88, binarydata, sizeof(currentcard->tag_88));
+            break;
+        case 0x8a:
+            memcpy(currentcard->tag_8A, binarydata, sizeof(currentcard->tag_8A));
+            break;
+        case 0x8c:
+            memcpy(currentcard->tag_8C, binarydata, datalen);
+            currentcard->tag_8C_len = datalen;
+            break;
+        case 0x8d:
+            memcpy(currentcard->tag_8D, binarydata, datalen);
+            currentcard->tag_8D_len = datalen;
+            break;
+        case 0x8e:
+            memcpy(currentcard->tag_8E, binarydata, datalen);
+            currentcard->tag_8E_len = datalen;
+            break;
+        case 0x8f:
+            memcpy(currentcard->tag_8F, binarydata, sizeof(currentcard->tag_8F));
+            break;
+        case 0x90:
+            memcpy(currentcard->tag_90, binarydata, datalen);
+            currentcard->tag_90_len = datalen;
+            break;
+        case 0x91:
+            memcpy(currentcard->tag_91, binarydata, datalen);
+            currentcard->tag_91_len = datalen;
+            break;
+        case 0x92:
+            memcpy(currentcard->tag_92, binarydata, datalen);
+            currentcard->tag_92_len = datalen;
+            break;
+        case 0x93:
+            memcpy(currentcard->tag_93, binarydata, datalen);
+            currentcard->tag_93_len = datalen;           
+            break;
+        case 0x94:
+            memcpy(currentcard->tag_94, binarydata, datalen);
+            currentcard->tag_94_len = datalen;           
+            break;
+        case 0x95:
+            memcpy(currentcard->tag_95, binarydata, sizeof(currentcard->tag_95));
+            break;
+        case 0x97:
+            memcpy(currentcard->tag_97, binarydata, datalen);
+            currentcard->tag_97_len = datalen;           
+            break;
+        case 0x98:
+            memcpy(currentcard->tag_98, binarydata, sizeof(currentcard->tag_98));
+            break;
+        case 0x99:
+            memcpy(currentcard->tag_99, binarydata, datalen);
+            currentcard->tag_99_len = datalen;           
+            break;
+        case 0x9a:
+            memcpy(currentcard->tag_9A, binarydata, sizeof(currentcard->tag_9A));
+            break;
+        case 0x9b:
+            memcpy(currentcard->tag_9B, binarydata, sizeof(currentcard->tag_9B));
+            break;
+        case 0x9c:
+            memcpy(currentcard->tag_9C, binarydata, sizeof(currentcard->tag_9C));
+            break;
+        case 0x9d:
+            memcpy(currentcard->tag_9D, binarydata, datalen);
+            currentcard->tag_9D_len = datalen;           
+            break;
+        case 0xa5:
+            memcpy(currentcard->tag_A5, binarydata, datalen);
+            currentcard->tag_A5_len = datalen;           
+            break; 
+        case 0xaf:
+            memcpy(currentcard->tag_AF, binarydata, datalen);
+            currentcard->tag_AF_len = datalen;           
+            break; 
+        case 0xcd:
+            memcpy(currentcard->tag_CD, binarydata, sizeof(currentcard->tag_CD));
+            break;
+        case 0xce:
+            memcpy(currentcard->tag_CE, binarydata, sizeof(currentcard->tag_CE));
+            break;
+        case 0xcf:
+            memcpy(currentcard->tag_CF, binarydata, sizeof(currentcard->tag_CF));
+            break;
+        case 0xd7:
+            memcpy(currentcard->tag_CF, binarydata, sizeof(currentcard->tag_CF));
+            break;
+        case 0xd8:
+            memcpy(currentcard->tag_CF, binarydata, sizeof(currentcard->tag_CF));
+            break;
+        case 0xd9:
+            break;
+        case 0xda:
+            memcpy(currentcard->tag_DA, binarydata, sizeof(currentcard->tag_DA));
+            break;
+        case 0xdb:
+            memcpy(currentcard->tag_DB, binarydata, sizeof(currentcard->tag_DB));
+            break;
+        case 0xdc:
+            memcpy(currentcard->tag_DB, binarydata, sizeof(currentcard->tag_DB));
+            break;
+        case 0xdd:
+            memcpy(currentcard->tag_DD, binarydata, sizeof(currentcard->tag_DD));
+            break;
+        case 0x5f20:
+            break;
+        case 0x5f24:
+            memcpy(currentcard->tag_5F24, binarydata, sizeof(currentcard->tag_5F24));
+            break;
+        case 0x5f25:
+            memcpy(currentcard->tag_5F25, binarydata, sizeof(currentcard->tag_5F25));
+            break;
+        case 0x5f28:
+            memcpy(currentcard->tag_5F28, binarydata, sizeof(currentcard->tag_5F28));
+            break;
+        case 0x5f2a:
+            memcpy(currentcard->tag_5F2A, binarydata, sizeof(currentcard->tag_5F2A));
+            break;
+        case 0x5f2d:
+            break;
+        case 0x5f30:
+            memcpy(currentcard->tag_5F30, binarydata, sizeof(currentcard->tag_5F30));
+            break;
+        case 0x5f34:
+            memcpy(currentcard->tag_5F34, binarydata, sizeof(currentcard->tag_5F34));
+            break;
+        case 0x5f36:
+            memcpy(currentcard->tag_5F36, binarydata, sizeof(currentcard->tag_5F36));
+            break;
+        case 0x5f50:
+            break;
+        case 0x5f54:
+            memcpy(currentcard->tag_5F54, binarydata, sizeof(currentcard->tag_5F54));
+            break;
+        case 0x9f01:
+            memcpy(currentcard->tag_9F01, binarydata, sizeof(currentcard->tag_9F01));
+            break;
+        case 0x9f02:
+            memcpy(currentcard->tag_9F02, binarydata, sizeof(currentcard->tag_9F02));
+            break;
+        case 0x9f03:
+            memcpy(currentcard->tag_9F03, binarydata, sizeof(currentcard->tag_9F03));
+            break;
+        case 0x9f04:
+            memcpy(currentcard->tag_9F04, binarydata, sizeof(currentcard->tag_9F04));
+            break;
+        case 0x9f05:
+            memcpy(currentcard->tag_9F05, binarydata, datalen);
+            currentcard->tag_9F05_len = datalen;
+            break;
+        case 0x9f06:
+            memcpy(currentcard->tag_9F06, binarydata, datalen);
+            currentcard->tag_9F06_len = datalen;
+            break;
+        case 0x9f07:
+            memcpy(currentcard->tag_9F07, binarydata, sizeof(currentcard->tag_9F07));
+            break;
+        case 0x9f08:
+            memcpy(currentcard->tag_9F08, binarydata, sizeof(currentcard->tag_9F08));
+            break;
+        case 0x9f09:
+            memcpy(currentcard->tag_9F09, binarydata, sizeof(currentcard->tag_9F09));
+            break;
+        case 0x9f0b:
+            memcpy(currentcard->tag_9F0B, binarydata, sizeof(currentcard->tag_9F0B));
+            break;
+        case 0x9f0d:
+            memcpy(currentcard->tag_9F0D, binarydata, sizeof(currentcard->tag_9F0D));
+            break;
+        case 0x9f0e:
+            memcpy(currentcard->tag_9F0E, binarydata, sizeof(currentcard->tag_9F0E));
+            break;
+        case 0x9f0f:
+            memcpy(currentcard->tag_9F0F, binarydata, sizeof(currentcard->tag_9F0F));
+            break;
+        case 0x9f10:
+            memcpy(currentcard->tag_9F10, binarydata, datalen);
+            currentcard->tag_9F10_len = datalen;break;
+        case 0x9f11:
+            memcpy(currentcard->tag_9F11, binarydata, sizeof(currentcard->tag_9F11));
+            break;
+        case 0x9f12:
+            memcpy(currentcard->tag_9F12, binarydata, datalen);
+            currentcard->tag_9F12_len = datalen;break;
+        case 0x9f13:
+            memcpy(currentcard->tag_9F13, binarydata, sizeof(currentcard->tag_9F13));
+            break;
+        case 0x9f14:
+            memcpy(currentcard->tag_9F14, binarydata, sizeof(currentcard->tag_9F14));
+            break;
+        case 0x9f15:
+            memcpy(currentcard->tag_9F15, binarydata, sizeof(currentcard->tag_9F15));
+            break;
+        case 0x9f16:
+            memcpy(currentcard->tag_9F16, binarydata, sizeof(currentcard->tag_9F16));
+            break;
+        case 0x9f17:
+            memcpy(currentcard->tag_9F17, binarydata, sizeof(currentcard->tag_9F17));
+            break;
+        case 0x9f18:
+            memcpy(currentcard->tag_9F18, binarydata, sizeof(currentcard->tag_9F18));
+            break;
+        case 0x9f1a:
+            memcpy(currentcard->tag_9F1A, binarydata, sizeof(currentcard->tag_9F1A));
+            break;
+        case 0x9f1b:
+            memcpy(currentcard->tag_9F1B, binarydata, sizeof(currentcard->tag_9F1B));
+            break;
+        case 0x9f1c:
+            memcpy(currentcard->tag_9F1C, binarydata, sizeof(currentcard->tag_9F1C));
+            break;
+        case 0x9f1d:
+            memcpy(currentcard->tag_9F1D, binarydata, datalen);
+            currentcard->tag_9F1D_len = datalen;break;
+        case 0x9f1e:
+            memcpy(currentcard->tag_9F1E, binarydata, sizeof(currentcard->tag_9F1E));
+            break;
+        case 0x9f1f:
+            memcpy(currentcard->tag_9F1F, binarydata, datalen);
+            currentcard->tag_9F1F_len = datalen;break;
+        case 0x9f20:
+            memcpy(currentcard->tag_9F20, binarydata, datalen);
+            currentcard->tag_9F20_len = datalen;break;
+        case 0x9f21:
+            memcpy(currentcard->tag_9F21, binarydata, sizeof(currentcard->tag_9F21));
+            break;
+        case 0x9f22:
+            memcpy(currentcard->tag_9F22, binarydata, sizeof(currentcard->tag_9F22));
+            break;
+        case 0x9f23:
+            memcpy(currentcard->tag_9F23, binarydata, sizeof(currentcard->tag_9F23));
+            break;
+        case 0x9f26:
+            memcpy(currentcard->tag_9F26, binarydata, sizeof(currentcard->tag_9F26));
+            break;
+        case 0x9f27:
+            memcpy(currentcard->tag_9F27, binarydata, sizeof(currentcard->tag_9F27));
+            break;
+        case 0x9f2d:
+            memcpy(currentcard->tag_9F2D, binarydata, datalen);
+            currentcard->tag_9F2D_len = datalen;break;
+        case 0x9f2e:
+            memcpy(currentcard->tag_9F2E, binarydata, sizeof(currentcard->tag_9F2E));
+            break;
+        case 0x9f2f:
+            memcpy(currentcard->tag_9F2F, binarydata, datalen);
+            currentcard->tag_9F2F_len = datalen;break;
+        case 0x9f32:
+            memcpy(currentcard->tag_9F32, binarydata, datalen);
+            currentcard->tag_9F32_len = datalen;break;
+        case 0x9f33:
+            memcpy(currentcard->tag_9F33, binarydata, sizeof(currentcard->tag_9F33));
+            break;
+        case 0x9f34:
+            memcpy(currentcard->tag_9F34, binarydata, sizeof(currentcard->tag_9F34));
+            break;
+        case 0x9f35:
+            memcpy(currentcard->tag_9F35, binarydata, sizeof(currentcard->tag_9F35));
+            break;
+        case 0x9f36:
+            memcpy(currentcard->tag_9F36, binarydata, sizeof(currentcard->tag_9F36));
+            break;
+        case 0x9f37:
+            memcpy(currentcard->tag_9F37, binarydata, sizeof(currentcard->tag_9F37));
+            break;
+        case 0x9f38:
+            break;
+        case 0x9f39:
+            memcpy(currentcard->tag_9F39, binarydata, sizeof(currentcard->tag_9F39));
+            break;
+        case 0x9f40:
+            memcpy(currentcard->tag_9F40, binarydata, sizeof(currentcard->tag_9F40));
+            break;
+        case 0x9f41:
+            memcpy(currentcard->tag_9F41, binarydata, sizeof(currentcard->tag_9F41));
+            break;
+        case 0x9f42:
+            memcpy(currentcard->tag_9F42, binarydata, sizeof(currentcard->tag_9F42));
+            break;
+        case 0x9f43:
+            memcpy(currentcard->tag_9F43, binarydata, sizeof(currentcard->tag_9F43));
+            break;
+        case 0x9f44:
+            memcpy(currentcard->tag_9F44, binarydata, sizeof(currentcard->tag_9F44));
+            break;
+        case 0x9f45:
+            memcpy(currentcard->tag_9F45, binarydata, sizeof(currentcard->tag_9F45));
+            break;
+        case 0x9f46:
+            memcpy(currentcard->tag_9F46, binarydata, datalen);
+            currentcard->tag_9F46_len = datalen;break;
+        case 0x9f47:
+            memcpy(currentcard->tag_9F47, binarydata, datalen);
+            currentcard->tag_9F47_len = datalen;break;
+        case 0x9f48:
+            memcpy(currentcard->tag_9F48, binarydata, datalen);
+            currentcard->tag_9F48_len = datalen;break;
+        case 0x9f49:
+            memcpy(currentcard->tag_9F49, binarydata, datalen);
+            currentcard->tag_9F49_len = datalen;break;
+        case 0x9f4a:
+            memcpy(currentcard->tag_9F4A, binarydata, sizeof(currentcard->tag_9F4A));
+            break;
+        case 0x9f4b:
+            memcpy(currentcard->tag_9F4B, binarydata, datalen);
+            currentcard->tag_9F4B_len = datalen;break;
+        case 0x9f4c:
+            memcpy(currentcard->tag_9F4C, binarydata, sizeof(currentcard->tag_9F4C));
+            break;
+        case 0x9f4d:
+            memcpy(currentcard->tag_9F4D, binarydata, sizeof(currentcard->tag_9F4D));
+            break;
+        case 0x9f4e:
+            memcpy(currentcard->tag_9F4E, binarydata, sizeof(currentcard->tag_9F4E));
+            break;
+        case 0x9f60:
+            memcpy(currentcard->tag_9F60, binarydata, sizeof(currentcard->tag_9F60));
+            break;
+        case 0x9f61:
+            memcpy(currentcard->tag_9F61, binarydata, sizeof(currentcard->tag_9F61));
+            break;
+        case 0x9f62:
+            memcpy(currentcard->tag_9F62, binarydata, sizeof(currentcard->tag_9F62));
+            break;
+        case 0x9f63:
+            memcpy(currentcard->tag_9F63, binarydata, sizeof(currentcard->tag_9F63));
+            break;
+        case 0x9f64:
+            memcpy(currentcard->tag_9F64, binarydata, sizeof(currentcard->tag_9F64));
+            break;
+        case 0x9f65:
+            memcpy(currentcard->tag_9F65, binarydata, sizeof(currentcard->tag_9F65));
+            break;
+        case 0x9f66:
+            memcpy(currentcard->tag_9F66, binarydata, sizeof(currentcard->tag_9F66));
+            break;
+        case 0x9f67:
+            memcpy(currentcard->tag_9F67, binarydata, sizeof(currentcard->tag_9F67));
+            break;
+        case 0x9f68:
+            memcpy(currentcard->tag_9F68, binarydata, datalen);
+            currentcard->tag_9F68_len = datalen;break;
+        case 0x9f69:
+            memcpy(currentcard->tag_9F69, binarydata, datalen);
+            currentcard->tag_9F69_len = datalen;break;
+        case 0x9f6a:
+            memcpy(currentcard->tag_9F6A, binarydata, sizeof(currentcard->tag_9F6A));
+            break;
+        case 0x9f6b:
+            memcpy(currentcard->tag_9F6B, binarydata, sizeof(currentcard->tag_9F6B));
+            break;
+        case 0x9f6c:
+            memcpy(currentcard->tag_9F6C, binarydata, sizeof(currentcard->tag_9F6C));
+            break;
+        case 0xbf0c:
+            memcpy(currentcard->tag_BF0C, binarydata, datalen);
+            currentcard->tag_BF0C_len = datalen;break;
+        default:
+            break;
+        }
+    return 0; 
+}
+
+/* generates an emv template based off tag values supplied */ 
+int emv_generatetemplate(uint8_t* templateval,emvtags* currentcard, uint8_t* returnedval, uint8_t* returnedlen,uint8_t numtags, ...)
+{
+    va_list arguments;
+    uint8_t* currenttag; //value of the current tag
+    uint8_t tagval[255]; //buffer to hold the extracted tag value 
+    uint8_t taglen = 0; //extracted tag length 
+    uint8_t bufferval[255]; 
+    uint8_t counter = 0; 
+    uint32_t encodedlen = 0; 
+    va_start(arguments, numtags);
+    for(int x=0; x<numtags; x++){
+        currenttag = va_arg(arguments, uint8_t*);     
+        emv_lookuptag(currenttag, currentcard, tagval, &taglen);
+        encode_ber_tlv_item(currenttag, (uint8_t)strlen((const char*)currenttag), tagval, (uint32_t)taglen, bufferval+counter, &encodedlen);
+        counter +=encodedlen; 
+    } 
+    encode_ber_tlv_item(templateval, strlen((const char*) templateval), bufferval, counter, returnedval, &encodedlen);   
+    *returnedlen = encodedlen; 
+    return 0;
+}
+
+//generate a valid pdol list
+int emv_generateDOL(uint8_t* DOL, uint8_t DOLlen,emvtags* currentcard,uint8_t* DOLoutput, uint8_t* DOLoutputlen)
+{
+    if(!DOL || !currentcard || !DOLoutput) // null pointer checks
+        return 1; 
+    //scan through the DOL list and construct the result.
+    uint8_t i = 0;
+    uint8_t DOLcounter = 0; //points to the current DOL buffer location 
+    uint8_t scannedtaglen = 0; //length of a scanned tag
+    uint8_t scannedtag[2] = {0x00,0x00}; //buffer for the scanned tag
+    uint8_t DOLoutputbuffer[255]; 
+    uint8_t retrievedtagvallen; 
+    
+    memset(DOLoutputbuffer,0x00, 255); //clear the output buffer
+    while(i < DOLlen)
+    {
+        //length of DOL tag 
+        if((*(DOL+i) & 0x1F) == 0x1F)
+            { scannedtaglen = 2;}
+        else
+            {scannedtaglen=1;}
+        memcpy(scannedtag, DOL+i,scannedtaglen);
+        //look up tag value and copy
+        //Dbhexdump(2,scannedtag,false); 
+        emv_lookuptag(scannedtag,currentcard,&(DOLoutputbuffer[DOLcounter]),&retrievedtagvallen);
+        DOLcounter += (uint8_t)DOL[i+scannedtaglen];
+        i += scannedtaglen + 1; 
+        memset(scannedtag, 0x00, 2); //clear current tag 
+         
+    }
+    memcpy(DOLoutput, DOLoutputbuffer, DOLcounter);
+    *DOLoutputlen = DOLcounter; 
+    return 0; 
+}
+
+
+//decode the tag inputted and fill in the supplied structure. clean up the cleanup_passpass function
+int emv_emvtags_decode_tag(tlvtag* inputtag, emvtags* currentcard)
+{
+    if(!inputtag || !currentcard) {
+        return 1;
+    } 
+    //scan decoded tag 
+    if(*(inputtag->tag) == 0x5F) {
+        if(*(inputtag->tag+1) == 0x20){
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_5F20)))
+            return 1; 
+            memcpy(currentcard->tag_5F20, inputtag->value, inputtag->valuelength);
+            currentcard->tag_5F20_len = inputtag->valuelength;
+        }
+        if(*(inputtag->tag+1) == 0x24){
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_5F24)))
+                return 1; 
+            memcpy(currentcard->tag_5F24, inputtag->value, sizeof(currentcard->tag_5F24));}
+        if(*(inputtag->tag+1) == 0x25){
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_5F25)))
+                return 1; 
+            memcpy(currentcard->tag_5F25, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x28){
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_5F28)))
+                return 1; 
+            memcpy(currentcard->tag_5F28, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x2A){
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_5F2A)))
+                return 1; 
+            memcpy(currentcard->tag_5F2A, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x2D){
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_5F2D)))
+                return 1; 
+            memcpy(currentcard->tag_5F2D, inputtag->value, inputtag->valuelength);
+            currentcard->tag_5F2D_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x30){
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_5F30)))
+                return 1; 
+            memcpy(currentcard->tag_5F30, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x34){
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_5F34)))
+                return 1; 
+            memcpy(currentcard->tag_5F34, inputtag->value, sizeof(currentcard->tag_5F34));}
+        if(*(inputtag->tag+1) == 0x36){
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_5F36)))
+                return 1; 
+            memcpy(currentcard->tag_5F36, inputtag->value, sizeof(currentcard->tag_5F36));}
+        if(*(inputtag->tag+1) == 0x50){
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_5F50)))
+                return 1; 
+            memcpy(currentcard->tag_5F50, inputtag->value, inputtag->valuelength);
+            currentcard->tag_5F50_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x54){
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_5F54)))
+                return 1; 
+            memcpy(currentcard->tag_5F54, inputtag->value, inputtag->valuelength);
+            currentcard->tag_5F54_len = inputtag->valuelength;}
+    }
+    if(*(inputtag->tag) == 0x9F){
+        if(*(inputtag->tag+1) == 0x01){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F01)))
+            return 1; 
+        memcpy(currentcard->tag_9F01, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x02){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F02)))
+            return 1; 
+        memcpy(currentcard->tag_9F02, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x03){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F03)))
+            return 1; 
+        memcpy(currentcard->tag_9F03, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x04){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F04)))
+            return 1; 
+        memcpy(currentcard->tag_9F04, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x05){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F05)))
+            return 1; 
+        memcpy(currentcard->tag_9F05, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F05_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x06){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F06)))
+            return 1; 
+        memcpy(currentcard->tag_9F06, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F06_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x07){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F07)))
+            return 1; 
+        memcpy(currentcard->tag_9F07, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x08){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F08)))
+            return 1; 
+        memcpy(currentcard->tag_9F08, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x09){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F09)))
+            return 1; 
+        memcpy(currentcard->tag_9F09, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x0B){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F0B)))
+            return 1; 
+        memcpy(currentcard->tag_9F0B, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F0B_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x0D){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F0D)))
+            return 1; 
+        memcpy(currentcard->tag_9F0D, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x0E){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F0E)))
+            return 1; 
+        memcpy(currentcard->tag_9F0E, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x0F){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F0F)))
+            return 1; 
+        memcpy(currentcard->tag_9F0F, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x11){ 
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F11)))
+                return 1; 
+            memcpy(currentcard->tag_9F11, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x12){ 
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F12)))
+                return 1; 
+            memcpy(currentcard->tag_9F12, inputtag->value, inputtag->valuelength);
+            currentcard->tag_9F12_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x13){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F13)))
+            return 1; 
+        memcpy(currentcard->tag_9F13, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x14){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F14)))
+            return 1; 
+        memcpy(currentcard->tag_9F14, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x15){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F15)))
+            return 1; 
+        memcpy(currentcard->tag_9F15, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x16){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F16)))
+            return 1; 
+        memcpy(currentcard->tag_9F16, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x17){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F17)))
+            return 1; 
+        memcpy(currentcard->tag_9F17, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x18){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F18)))
+            return 1; 
+        memcpy(currentcard->tag_9F18, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x1A){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F1A)))
+            return 1; 
+        memcpy(currentcard->tag_9F1A, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x1B){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F1B)))
+            return 1; 
+        memcpy(currentcard->tag_9F1B, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x1C){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F1C)))
+            return 1; 
+        memcpy(currentcard->tag_9F1C, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x1D){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F1D)))
+            return 1; 
+        memcpy(currentcard->tag_9F1D, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F1D_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x1E){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F1E)))
+            return 1; 
+        memcpy(currentcard->tag_9F1E, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x1F){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F1F)))
+            return 1; 
+        memcpy(currentcard->tag_9F1F, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F1F_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x32){ 
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F32)))
+                return 1; 
+            currentcard->tag_9F32_len = inputtag->valuelength; 
+            memcpy(currentcard->tag_9F32, inputtag->value, inputtag->valuelength);
+        }
+        if(*(inputtag->tag+1) == 0x34){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F34)))
+            return 1; 
+        memcpy(currentcard->tag_9F34, inputtag->value, inputtag->valuelength);}
+if(*(inputtag->tag+1) == 0x35){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F35)))
+            return 1; 
+        memcpy(currentcard->tag_9F35, inputtag->value, inputtag->valuelength);}
+if(*(inputtag->tag+1) == 0x37){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F37)))
+            return 1; 
+        memcpy(currentcard->tag_9F37, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x38){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F38)))
+            return 1; 
+        memcpy(currentcard->tag_9F38, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F38_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x44){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F44)))
+            return 1; 
+        memcpy(currentcard->tag_9F44, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x45){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F45)))
+            return 1; 
+        memcpy(currentcard->tag_9F45, inputtag->value, inputtag->valuelength);}
+if(*(inputtag->tag+1) == 0x46){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F46)))
+            return 1; 
+        memcpy(currentcard->tag_9F46, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F46_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x47){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F47)))
+            return 1; 
+        memcpy(currentcard->tag_9F47, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F47_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x48){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F48)))
+            return 1; 
+        memcpy(currentcard->tag_9F48, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F48_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x49){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F49)))
+            return 1; 
+        memcpy(currentcard->tag_9F49, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F49_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x4A){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F4A)))
+            return 1; 
+        memcpy(currentcard->tag_9F4A, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x4B){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F4B)))
+            return 1; 
+        memcpy(currentcard->tag_9F4B, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F4B_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x4C){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F4C)))
+            return 1; 
+        memcpy(currentcard->tag_9F4C, inputtag->value, inputtag->valuelength);}
+if(*(inputtag->tag+1) == 0x60){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F60)))
+            return 1; 
+        memcpy(currentcard->tag_9F60, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x61){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F61)))
+            return 1; 
+        memcpy(currentcard->tag_9F61, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x62){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F62)))
+            return 1; 
+        memcpy(currentcard->tag_9F62, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x63){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F63)))
+            return 1; 
+        memcpy(currentcard->tag_9F63, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x64){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F64)))
+            return 1; 
+        memcpy(currentcard->tag_9F64, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x65){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F65)))
+            return 1; 
+        memcpy(currentcard->tag_9F65, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x66){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F66)))
+            return 1; 
+        memcpy(currentcard->tag_9F66, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x67){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F67)))
+            return 1; 
+        memcpy(currentcard->tag_9F67, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x68){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F68)))
+            return 1; 
+        memcpy(currentcard->tag_9F68, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F68_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x69){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F69)))
+            return 1; 
+        memcpy(currentcard->tag_9F69, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F69_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x6A){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F6A)))
+            return 1; 
+        memcpy(currentcard->tag_9F6A, inputtag->value, inputtag->valuelength);}
+        if(*(inputtag->tag+1) == 0x6B){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F6B)))
+            return 1; 
+        memcpy(currentcard->tag_9F6B, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9F6B_len = inputtag->valuelength;}
+        if(*(inputtag->tag+1) == 0x6C){ 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9F6C)))
+            return 1; 
+        memcpy(currentcard->tag_9F6C, inputtag->value, inputtag->valuelength);}
+}
+else 
+{ 
+    if(*(inputtag->tag) == 0xBF){ //BF0C 
+        if(*(inputtag->tag+1) == 0x0C){ 
+            if(!(inputtag->valuelength <= sizeof(currentcard->tag_BF0C)))
+                return 1; 
+            memcpy(currentcard->tag_BF0C, inputtag->value, inputtag->valuelength);
+            currentcard->tag_BF0C_len = inputtag->valuelength;}
+    }
+    else if(*(inputtag->tag) == 0x4F){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_4F)))
+            return 1; 
+        memcpy(currentcard->tag_4F, inputtag->value, inputtag->valuelength);
+        currentcard->tag_4F_len = inputtag->valuelength;}
+    else if(*(inputtag->tag) == 0x50){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_50)))
+            return 1; 
+        memcpy(currentcard->tag_50, inputtag->value, inputtag->valuelength);
+        currentcard->tag_50_len = inputtag->valuelength;
+    } 
+    else if(*(inputtag->tag) == 0x56){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_56)))
+            return 1; 
+        memcpy(currentcard->tag_56, inputtag->value, inputtag->valuelength);
+        currentcard->tag_56_len = inputtag->valuelength;
+    }
+    else if(*(inputtag->tag) == 0x57){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_57)))
+            return 1; 
+        memcpy(currentcard->tag_57, inputtag->value, inputtag->valuelength);
+        currentcard->tag_57_len = inputtag->valuelength;
+    }
+    else if(*(inputtag->tag) == 0x5A){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_5A)))
+            return 1; 
+        memcpy(currentcard->tag_5A, inputtag->value, inputtag->valuelength);
+        currentcard->tag_5A_len = inputtag->valuelength;} 
+    else if(*(inputtag->tag) == 0x61){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_61)))
+            return 1; 
+        memcpy(currentcard->tag_61, inputtag->value, inputtag->valuelength);
+        currentcard->tag_61_len = inputtag->valuelength;
+    }
+    else if(*(inputtag->tag) == 0x6F){ //BF0C 
+        memcpy(currentcard->tag_6F,inputtag->value,inputtag->valuelength);}
+    
+    else if(*(inputtag->tag) == 0x70){ //BF0C 
+        memcpy(currentcard->tag_70,inputtag->value,inputtag->valuelength);}
+    else if(*(inputtag->tag) == 0x77){ //BF0C 
+        memcpy(currentcard->tag_77,inputtag->value,inputtag->valuelength);}
+    else if(*(inputtag->tag) == 0x80){ //BF0C 
+        memcpy(currentcard->tag_80,inputtag->value,inputtag->valuelength);}
+    else if(*(inputtag->tag) == 0x82){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_82)))
+            return 1; 
+        memcpy(currentcard->tag_82, inputtag->value, inputtag->valuelength);}
+    else if(*(inputtag->tag) == 0x84){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_84)))
+            return 1; 
+        memcpy(currentcard->tag_84, inputtag->value, inputtag->valuelength);
+        currentcard->tag_84_len = inputtag->valuelength;
+    }
+    else if(*(inputtag->tag) == 0x86){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_86)))
+            return 1; 
+        memcpy(currentcard->tag_86, inputtag->value, inputtag->valuelength);
+        currentcard->tag_86_len = inputtag->valuelength;
+    }
+    else if(*(inputtag->tag) == 0x87){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_87)))
+            return 1; 
+        memcpy(currentcard->tag_87, inputtag->value, inputtag->valuelength);}
+    else if(*(inputtag->tag) == 0x88){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_88)))
+            return 1; 
+        memcpy(currentcard->tag_88, inputtag->value, inputtag->valuelength);}
+    else if(*(inputtag->tag) == 0x8A){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_8A)))
+            return 1; 
+        memcpy(currentcard->tag_8A, inputtag->value, inputtag->valuelength);}
+    else if(*(inputtag->tag) == 0x8C){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_8C)))
+            return 1; 
+        memcpy(currentcard->tag_8C, inputtag->value, inputtag->valuelength);
+        currentcard->tag_8C_len = inputtag->valuelength;
+    }    
+    else if(*(inputtag->tag) == 0x8D){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_8D)))
+            return 1; 
+        memcpy(currentcard->tag_8D, inputtag->value, inputtag->valuelength);
+        currentcard->tag_8D_len = inputtag->valuelength;
+    }
+    else if(*(inputtag->tag) == 0x8E){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_8E)))
+            return 1; 
+        memcpy(currentcard->tag_8E, inputtag->value, inputtag->valuelength);
+        currentcard->tag_8E_len = inputtag->valuelength;
+    }
+    else if(*(inputtag->tag) == 0x8F){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_8F)))
+            return 1; 
+        memcpy(currentcard->tag_8F,inputtag->value,sizeof(currentcard->tag_8F));}
+    else if(*(inputtag->tag) == 0x90){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_90)))
+            return 1; 
+        memcpy(currentcard->tag_90, inputtag->value, inputtag->valuelength);
+        currentcard->tag_90_len = inputtag->valuelength;}
+    else if(*(inputtag->tag) == 0x92){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_92)))
+            return 1; 
+        memcpy(currentcard->tag_92, inputtag->value, inputtag->valuelength);
+        currentcard->tag_92_len = inputtag->valuelength;} 
+    else if(*(inputtag->tag) == 0x93){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_93)))
+            return 1; 
+        memcpy(currentcard->tag_93, inputtag->value, inputtag->valuelength);
+        currentcard->tag_93_len = inputtag->valuelength;} 
+    else if(*(inputtag->tag) == 0x94){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_94)))
+            return 1; 
+        memcpy(currentcard->tag_94, inputtag->value, inputtag->valuelength);
+        currentcard->tag_94_len = inputtag->valuelength;} 
+    else if(*(inputtag->tag) == 0x95){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_95)))
+            return 1; 
+        memcpy(currentcard->tag_95, inputtag->value, inputtag->valuelength);} 
+    else if(*(inputtag->tag) == 0x97){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_97)))
+            return 1; 
+        memcpy(currentcard->tag_97, inputtag->value, inputtag->valuelength);
+        currentcard->tag_97_len = inputtag->valuelength;} 
+    else if(*(inputtag->tag) == 0x98){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_98)))
+            return 1; 
+        memcpy(currentcard->tag_98, inputtag->value, inputtag->valuelength);}
+    else if(*(inputtag->tag) == 0x99){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_99)))
+            return 1; 
+        memcpy(currentcard->tag_99, inputtag->value, inputtag->valuelength);
+        currentcard->tag_99_len = inputtag->valuelength;} 
+    else if(*(inputtag->tag) == 0x9A){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9A)))
+            return 1; 
+        memcpy(currentcard->tag_9A, inputtag->value, inputtag->valuelength);}
+    else if(*(inputtag->tag) == 0x9B){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9B)))
+            return 1; 
+        memcpy(currentcard->tag_9B, inputtag->value, inputtag->valuelength);}
+    else if(*(inputtag->tag) == 0x9C){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9C)))
+            return 1; 
+        memcpy(currentcard->tag_9C, inputtag->value, inputtag->valuelength);}
+    else if(*(inputtag->tag) == 0x9D){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_9D)))
+            return 1; 
+        memcpy(currentcard->tag_9D, inputtag->value, inputtag->valuelength);
+        currentcard->tag_9D_len = inputtag->valuelength;} 
+    else if(*(inputtag->tag) == 0xA5){ //BF0C 
+        if(!(inputtag->valuelength <= sizeof(currentcard->tag_A5)))
+            return 1; 
+        memcpy(currentcard->tag_A5, inputtag->value, inputtag->valuelength);
+        currentcard->tag_A5_len = inputtag->valuelength;}
+   } 
+   return 0;
+}
+
+int emv_decode_field(uint8_t* inputfield,uint16_t inputlength, emvtags *result)
+{
+    uint16_t lengthcounter=0; 
+    tlvtag newtag; 
+    //copy result to the testtag
+    if(!result){
+        return 1;
+    } 
+    //loop through and decode template 
+    while(lengthcounter < inputlength)
+    {
+        //decode the tlv tag 
+        decode_ber_tlv_item((inputfield+lengthcounter),&newtag);
+        //write the emvtags strucutre 
+        emv_emvtags_decode_tag(&newtag,result); 
+        //move to next value and decode 
+        lengthcounter += newtag.fieldlength-1; 
+    }
+    return 0;
+}
+
+int emv_select(uint8_t* AID, uint8_t AID_len, void* data)
+{
+    uint16_t selectCmd_len = 4 + 1 + AID_len + 1; 
+    uint8_t selectCmd[selectCmd_len];
+    
+    selectCmd[0] = 0x00;
+    selectCmd[1] = 0xA4;
+    selectCmd[2] = 0x04;
+    selectCmd[3] = 0x00;
+    selectCmd[4] = AID_len;
+    memcpy(&(selectCmd[5]), AID, AID_len);
+    selectCmd[selectCmd_len-1] = 0x00;
+    return iso14_apdu(selectCmd,selectCmd_len,false, 0,data);
+}
+
+//perform READ RECORD
+int emv_readrecord(uint8_t recordnumber, uint8_t sfi, void* data)
+{
+    uint16_t readRecordCmd_len = 5; 
+    uint8_t readRecordCmd[readRecordCmd_len];
+    
+    readRecordCmd[0] = 0x00;
+    readRecordCmd[1] = 0xB2;
+    readRecordCmd[2] = recordnumber;
+    readRecordCmd[3] = ((sfi << 3) | 0x04);
+    readRecordCmd[4] = 0x00;
+    return iso14_apdu(readRecordCmd,readRecordCmd_len,false,0,data); 
+}
+
+int emv_getprocessingoptions(uint8_t* pdol, uint8_t pdol_len, void* data)
+{
+    uint16_t processingCmd_len = 4 + 1 + 2 + pdol_len + 1; 
+    uint8_t processingCmd[processingCmd_len];
+    
+    processingCmd[0] = 0x80;
+    processingCmd[1] = 0xA8;
+    processingCmd[2] = 0x00;
+    processingCmd[3] = 0x00; 
+    processingCmd[4] = pdol_len + 2; 
+    processingCmd[5] = 0x83; //template
+    processingCmd[6] = pdol_len;
+    if(pdol_len > 0){ 
+        memcpy(&(processingCmd[7]), pdol, pdol_len);}
+    processingCmd[processingCmd_len] = 0x00; 
+    //Dbhexdump(processingCmd_len, processingCmd, false); 
+    return iso14_apdu(processingCmd,processingCmd_len,false, 0, data);
+}
+
+int emv_computecryptogram(uint8_t* UDOL, uint8_t UDOL_len, void *data)
+{
+    uint16_t cryptogramCmd_len = 4 + 1 + UDOL_len + 1; 
+    uint8_t cryptogramCmd[cryptogramCmd_len];
+    
+    cryptogramCmd[0] = 0x80;
+    cryptogramCmd[1] = 0x2A;
+    cryptogramCmd[2] = 0x8E;
+    cryptogramCmd[3] = 0x80; 
+    cryptogramCmd[4] = UDOL_len;
+    memcpy(&(cryptogramCmd[5]), UDOL, UDOL_len);
+    cryptogramCmd[cryptogramCmd_len-1] = 0x00;
+    return iso14_apdu(cryptogramCmd,cryptogramCmd_len,false, 0,data);
+}
+
+int emv_getchallenge(void *data)
+{
+    uint16_t challengeCmd_len = 5; 
+    uint8_t challengeCmd[challengeCmd_len];
+    
+    challengeCmd[0] = 0x00;
+    challengeCmd[1] = 0x84;
+    challengeCmd[2] = 0x00;
+    challengeCmd[3] = 0x00; 
+    challengeCmd[4] = 0x00;
+     
+    return iso14_apdu(challengeCmd,challengeCmd_len,false, 0,data);
+}
+
+int emv_loopback(uint8_t* transData , uint8_t transData_len, void *data)
+{
+    uint16_t loopbackCmd_len = 4 + 1 + transData_len + 1; 
+    uint8_t loopbackCmd[loopbackCmd_len];
+    
+    loopbackCmd[0] = 0x00;
+    loopbackCmd[1] = 0xEE;
+    loopbackCmd[2] = 0x00;
+    loopbackCmd[3] = 0x00; 
+    loopbackCmd[4] = loopbackCmd_len;
+    memcpy(&(loopbackCmd[5]), transData, transData_len);  
+    return iso14_apdu(loopbackCmd,loopbackCmd_len,false, 0,data);
+}
+
+//generateAC
+int emv_generateAC(uint8_t refcontrolparam, uint8_t* cdolinput, uint8_t cdolinputlen, void* data)
+{
+    uint16_t acCmd_len = 4 + 1 + cdolinputlen + 1; 
+    uint8_t acCmd[acCmd_len];
+    
+    acCmd[0] = 0x80;
+    acCmd[1] = 0xAE;
+    acCmd[2] = refcontrolparam;
+    acCmd[3] = 0x00; 
+    acCmd[4] = cdolinputlen;
+    memcpy(&(acCmd[5]), cdolinput, cdolinputlen);  
+    acCmd[acCmd_len-1] = 0x00;
+    Dbhexdump(acCmd_len, acCmd,false); 
+    return iso14_apdu(acCmd,acCmd_len,false,0,data);
+}
+
+int emv_decodeAFL(uint8_t* AFL, uint8_t AFLlen )
+{
+
+    return 0;
+}
+
+//Print out AIP Bit meanings
+int emv_decodeAIP(uint8_t* AIP)
+{
+    if((AIP[0] & AIP_SDA_SUPPORTED) == AIP_SDA_SUPPORTED)
+        Dbprintf("SDA supported");
+    if((AIP[0] & AIP_DDA_SUPPORTED) == AIP_DDA_SUPPORTED)
+        Dbprintf("DDA supported");  
+    if((AIP[0] & AIP_CARDHOLDER_VERIFICATION)==AIP_CARDHOLDER_VERIFICATION)
+        Dbprintf("Cardholder verification is supported");  
+    if((AIP[0] & AIP_TERMINAL_RISK) == AIP_TERMINAL_RISK)
+        Dbprintf("Terminal risk management is to be performed");  
+    if((AIP[0] & AIP_ISSUER_AUTH) == AIP_ISSUER_AUTH)
+        Dbprintf("Issuer authentication is supported ");  
+    if((AIP[0] & AIP_CDA_SUPPORTED) == AIP_CDA_SUPPORTED)
+        Dbprintf("CDA supported");  
+    if((AIP[1] & AIP_CHIP_SUPPORTED) == AIP_CHIP_SUPPORTED)
+        Dbprintf("Chip supported");
+    if((AIP[1] & AIP_MSR_SUPPORTED) == AIP_MSR_SUPPORTED)
+        Dbprintf("MSR supported"); 
+    return 0;
+}
+
+int emv_decodeCVM(uint8_t* CVM, uint8_t CVMlen)
+{
+    uint8_t counter = 0;
+    uint32_t amountX = 0;
+    uint32_t amountY = 0; 
+    amountX = bytes_to_num(CVM, 4);
+    amountY = bytes_to_num(CVM+4, 4); 
+    counter +=8;
+    while(counter < CVMlen)
+    {
+        if((CVM[counter] & 0x40) == 0x40){
+            if((CVM[counter] & 0x3F)== 0x00){
+                Dbprintf("Fail CVM processing");
+            }
+            if((CVM[counter] & 0x3F) == 0x01){
+                Dbprintf("Plaintext PIN verification performed by ICC");
+            }
+            if((CVM[counter] & 0x3F) == 0x02){
+                Dbprintf("Enciphered PIN verified online");
+            }
+            if((CVM[counter] & 0x3F) == 0x03){
+                Dbprintf("Plaintext PIN verification performed by ICC and signature (paper)");
+            }
+            if((CVM[counter] & 0x3F) == 0x04){
+                Dbprintf("Enciphered PIN verification performed by ICC");
+            }  
+            if((CVM[counter] & 0x3F) == 0x05){
+                Dbprintf("Enciphered PIN verification performed by ICC and signature (paper)");
+            }  
+            if((CVM[counter] & 0x3F) == 0x30){
+                Dbprintf("Signature (paper)");
+            }  
+            if((CVM[counter] & 0x3F) == 0x40){
+                Dbprintf("No CVM required");
+            }
+            counter +=2; 
+        }
+        else{
+            Dbprintf("Fail cardholder verification if this CVM is unsuccessful"); 
+            counter +=2; 
+        }
+        if(CVM[counter+1] == 0x00){
+            Dbprintf("Always");}
+        if(CVM[counter+1] == 0x01){
+            Dbprintf("If unattended cash");}
+        if(CVM[counter+1] == 0x02){
+            Dbprintf("If not unattended cash and not manual cash and not purchase with cashback");}
+        if(CVM[counter+1] == 0x03){
+            Dbprintf("If terminal supports the CVM");}
+        if(CVM[counter+1] == 0x04){
+            Dbprintf("If manual cash");}
+        if(CVM[counter+1] == 0x05){
+            Dbprintf("If purchase with cashback");}
+        if(CVM[counter+1] == 0x06){
+            Dbprintf("If transaction is in the application currency and is under %lu value", amountX);}
+         if(CVM[counter+1] == 0x07){
+            Dbprintf("If transaction is in the application currency and is over %lu value", amountX);}
+         if(CVM[counter+1] == 0x08){
+            Dbprintf("If transaction is in the application currency and is under %lu value", amountY);}
+         if(CVM[counter+1] == 0x09){
+            Dbprintf("If transaction is in the application currency and is over %lu value", amountY);}
+     }
+    return 0;
+}
+
+//dump the current card to the console
+void dumpCard(emvtags* currentcard){
+    DUMP(currentcard->ATQA);
+    Dbhexdump(sizeof(currentcard->ATQA), currentcard->ATQA, false);
+    DUMP(currentcard->UID);
+    Dbhexdump(currentcard->UID_len,  currentcard->UID, false);
+    DUMP(currentcard->SAK1);
+    Dbhexdump(1,  &currentcard->SAK1, false);
+    DUMP(currentcard->SAK2);
+    Dbhexdump(1,  &currentcard->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 (file)
index 0000000..6fe748d
--- /dev/null
@@ -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 <stdarg.h>
+#include <stdint.h>
+#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 (file)
index 0000000..5f3bde2
--- /dev/null
@@ -0,0 +1,78 @@
+#include <tlv.h>
+#include <stddef.h>
+
+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 (file)
index 0000000..f1457aa
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __TLV_H
+#define __TLV_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+//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 (file)
index 0000000..88cd42e
--- /dev/null
@@ -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 <stdint.h>
+#include <stddef.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 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 (file)
index 0000000..a9548bb
--- /dev/null
@@ -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 (file)
index 0000000..961b01b
--- /dev/null
@@ -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 (file)
index 0000000..505dff4
--- /dev/null
@@ -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 (file)
index 0000000..5eedc12
--- /dev/null
@@ -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 (file)
index 0000000..cb56efa
--- /dev/null
@@ -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 (file)
index 0000000..c554eb0
--- /dev/null
@@ -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 (file)
index 0000000..9efb5a9
--- /dev/null
@@ -0,0 +1,9 @@
+0x9f02:000000000001
+0x9f03:000000000000
+0x9f1a:0826
+0x95:0000000000
+0x5f2a:0826
+0x9a:080401
+0x9c:01
+0x9f37:badf000d
+0x9f66:d720c000
Impressum, Datenschutz