--- /dev/null
+//Peter Fillmore - 2014
+//
+//--------------------------------------------------------------------------------
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//--------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------
+//Routines to support EMV transactions
+//--------------------------------------------------------------------------------
+
+#include "mifare.h"
+#include "iso14443a.h"
+#include "emvutil.h"
+#include "emvcmd.h"
+#include "apps.h"
+#include "emvdataels.h"
+
+static emvtags currentcard; //use to hold emv tags for the reader/card during communications
+static tUart Uart;
+
+// The FPGA will report its internal sending delay in
+uint16_t FpgaSendQueueDelay;
+//variables used for timing purposes:
+//these are in ssp_clk cycles:
+//static uint32_t NextTransferTime;
+static uint32_t LastTimeProxToAirStart;
+//static uint32_t LastProxToAirDuration;
+
+//load individual tag into current card
+void EMVloadvalue(uint32_t tag, uint8_t *datain){
+ //Dbprintf("TAG=%i\n", tag);
+ //Dbprintf("DATA=%s\n", datain);
+ emv_settag(tag, datain, ¤tcard);
+}
+
+void EMVReadRecord(uint8_t arg0, uint8_t arg1,emvtags *currentcard)
+{
+ uint8_t record = arg0;
+ uint8_t sfi = arg1 & 0x0F; //convert arg1 to number
+ uint8_t receivedAnswer[MAX_FRAME_SIZE];
+
+ //uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
+
+ //variables
+ tlvtag inputtag; //create the tag structure
+ //perform read
+ //write the result to the provided card
+ if(!emv_readrecord(record,sfi,receivedAnswer)) {
+ if(EMV_DBGLEVEL >= 1) Dbprintf("readrecord failed");
+ }
+ if(*(receivedAnswer+1) == 0x70){
+ decode_ber_tlv_item(receivedAnswer+1, &inputtag);
+ emv_decode_field(inputtag.value, inputtag.valuelength, currentcard);
+ }
+ else
+ {
+ if(EMV_DBGLEVEL >= 1)
+ Dbprintf("Record not found SFI=%i RECORD=%i", sfi, record);
+ }
+ return;
+}
+
+void EMVSelectAID(uint8_t *AID, uint8_t AIDlen, emvtags* inputcard)
+{
+ uint8_t receivedAnswer[MAX_FRAME_SIZE];
+ //uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
+
+ //variables
+ tlvtag inputtag; //create the tag structure
+ //perform select
+ if(!emv_select(AID, AIDlen, receivedAnswer)){
+ if(EMV_DBGLEVEL >= 1) Dbprintf("AID Select failed");
+ return;
+ }
+ //write the result to the provided card
+ if(*(receivedAnswer+1) == 0x6F){
+ //decode the 6F template
+ decode_ber_tlv_item(receivedAnswer+1, &inputtag);
+ //store 84 and A5 tags
+ emv_decode_field(inputtag.value, inputtag.valuelength, ¤tcard);
+ //decode the A5 tag
+ if(currentcard.tag_A5_len > 0)
+ emv_decode_field(currentcard.tag_A5, currentcard.tag_A5_len, ¤tcard);
+
+ //copy this result to the DFName
+ if(currentcard.tag_84_len == 0)
+ memcpy(currentcard.tag_DFName, currentcard.tag_84, currentcard.tag_84_len);
+
+ //decode the BF0C result, assuming 1 directory entry for now
+ if(currentcard.tag_BF0C_len !=0){
+ emv_decode_field(currentcard.tag_BF0C, currentcard.tag_BF0C_len, ¤tcard);}
+ //retrieve the AID, use the AID to decide what transaction flow to use
+ if(currentcard.tag_61_len !=0){
+ emv_decode_field(currentcard.tag_61, currentcard.tag_61_len, ¤tcard);}
+ }
+ if(EMV_DBGLEVEL >= 2)
+ DbpString("SELECT AID COMPLETED");
+}
+
+int EMVGetProcessingOptions(uint8_t *PDOL, uint8_t PDOLlen, emvtags* inputcard)
+{
+ uint8_t receivedAnswer[MAX_FRAME_SIZE];
+ //uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
+
+ //variables
+ tlvtag inputtag; //create the tag structure
+ //perform pdol
+ if(!emv_getprocessingoptions(PDOL, PDOLlen, receivedAnswer)){
+ if(EMV_DBGLEVEL >= 1) Dbprintf("get processing options failed");
+ return 0;
+ }
+ //write the result to the provided card
+ //FORMAT 1 received
+ if(receivedAnswer[1] == 0x80){
+ //store AIP
+ //decode tag 80
+ decode_ber_tlv_item(receivedAnswer+1, &inputtag);
+ memcpy(currentcard.tag_82, &inputtag.value, sizeof(currentcard.tag_82));
+ memcpy(currentcard.tag_94, &inputtag.value[2], inputtag.valuelength - sizeof(currentcard.tag_82));
+ currentcard.tag_94_len = inputtag.valuelength - sizeof(currentcard.tag_82);
+ }
+ else if(receivedAnswer[1] == 0x77){
+ //decode the 77 template
+ decode_ber_tlv_item(receivedAnswer+1, &inputtag);
+ //store 82 and 94 tags (AIP, AFL)
+ emv_decode_field(inputtag.value, inputtag.valuelength, ¤tcard);
+ }
+ if(EMV_DBGLEVEL >= 2)
+ DbpString("GET PROCESSING OPTIONS COMPLETE");
+ return 1;
+}
+
+int EMVGetChallenge(emvtags* inputcard)
+{
+ uint8_t receivedAnswer[MAX_FRAME_SIZE];
+ //uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
+ //variables
+ //tlvtag inputtag; //create the tag structure
+ //perform select
+ if(!emv_getchallenge(receivedAnswer)){
+ if(EMV_DBGLEVEL >= 1) Dbprintf("get processing options failed");
+ return 1;
+ }
+ return 0;
+}
+
+int EMVGenerateAC(uint8_t refcontrol, emvtags* inputcard)
+{
+ uint8_t receivedAnswer[MAX_FRAME_SIZE];
+ uint8_t cdolcommand[MAX_FRAME_SIZE];
+ uint8_t cdolcommandlen = 0;
+ tlvtag temptag;
+
+ //uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
+ if(currentcard.tag_8C_len > 0) {
+ emv_generateDOL(currentcard.tag_8C, currentcard.tag_8C_len, ¤tcard, cdolcommand, &cdolcommandlen); }
+ else{
+ //cdolcommand = NULL; //cdol val is null
+ cdolcommandlen = 0;
+ }
+ //variables
+ //tlvtag inputtag; //create the tag structure
+ //perform select
+ if(!emv_generateAC(refcontrol, cdolcommand, cdolcommandlen,receivedAnswer)){
+ if(EMV_DBGLEVEL >= 1) Dbprintf("get processing options failed");
+ return 1;
+ }
+ if(receivedAnswer[2] == 0x77) //format 2 data field returned
+ {
+ decode_ber_tlv_item(&receivedAnswer[2], &temptag);
+ emv_decode_field(temptag.value, temptag.valuelength, ¤tcard);
+ }
+
+ return 0;
+}
+
+//function to perform paywave transaction
+//takes in TTQ, amount authorised, unpredicable number and transaction currency code
+int EMV_PaywaveTransaction()
+{
+ uint8_t cardMode = 0;
+ //determine mode of transaction from TTQ
+ if((currentcard.tag_9F66[0] & 0x40) == 0x40) {
+ cardMode = VISA_EMV;
+ }
+ else if((currentcard.tag_9F66[0] & 0x20) == 0x20) {
+ cardMode = VISA_FDDA;
+ }
+ else if((currentcard.tag_9F66[0] & 0x80) == 0x80) {
+ if((currentcard.tag_9F66[1] & 0x80) == 1) { //CVN17
+ cardMode = VISA_CVN17;
+ }
+ else{
+ cardMode = VISA_DCVV;
+ }
+ }
+
+ EMVSelectAID(currentcard.tag_4F,currentcard.tag_4F_len, ¤tcard); //perform second AID command
+
+ //get PDOL
+ uint8_t pdolcommand[20]; //20 byte buffer for pdol data
+ uint8_t pdolcommandlen = 0;
+ if(currentcard.tag_9F38_len > 0) {
+ emv_generateDOL(currentcard.tag_9F38, currentcard.tag_9F38_len, ¤tcard, pdolcommand, &pdolcommandlen);
+ }
+ Dbhexdump(pdolcommandlen, pdolcommand,false);
+
+ if(!EMVGetProcessingOptions(pdolcommand,pdolcommandlen, ¤tcard)) {
+ if(EMV_DBGLEVEL >= 1) Dbprintf("PDOL failed");
+ return 1;
+ }
+
+ Dbprintf("AFL=");
+ Dbhexdump(currentcard.tag_94_len, currentcard.tag_94,false);
+ Dbprintf("AIP=");
+ Dbhexdump(2, currentcard.tag_82, false);
+ emv_decodeAIP(currentcard.tag_82);
+//
+// //decode the AFL list and read records
+ uint8_t i = 0;
+ uint8_t sfi = 0;
+ uint8_t recordstart = 0;
+ uint8_t recordend = 0;
+ if(currentcard.tag_94_len > 0){
+ while( i < currentcard.tag_94_len){
+ sfi = (currentcard.tag_94[i++] & 0xF8) >> 3;
+ recordstart = currentcard.tag_94[i++];
+ recordend = currentcard.tag_94[i++];
+ for(int j=recordstart; j<(recordend+1); j++){
+ //read records
+ EMVReadRecord(j,sfi, ¤tcard);
+ //while(responsebuffer[0] == 0xF2) {
+ // EMVReadRecord(j,sfi, ¤tcard);
+ //}
+ }
+ i++;
+ }
+ }
+ else {
+ EMVReadRecord(1,1,¤tcard);
+ EMVReadRecord(1,2,¤tcard);
+ EMVReadRecord(1,3,¤tcard);
+ EMVReadRecord(2,1,¤tcard);
+ EMVReadRecord(2,2,¤tcard);
+ EMVReadRecord(2,3,¤tcard);
+ EMVReadRecord(3,1,¤tcard);
+ EMVReadRecord(3,3,¤tcard);
+ EMVReadRecord(4,2,¤tcard);
+ }
+ //EMVGetChallenge(¤tcard);
+ //memcpy(currentcard.tag_9F4C,&responsebuffer[1],8); // ICC UN
+ EMVGenerateAC(0x81,¤tcard);
+
+ Dbprintf("CARDMODE=%i",cardMode);
+ return 0;
+}
+
+
+int EMV_PaypassTransaction()
+{
+ //uint8_t *responsebuffer = emv_get_bigbufptr();
+ //tlvtag temptag; //buffer for decoded tags
+ //get the current block counter
+ //select the AID (Mastercard
+ EMVSelectAID(currentcard.tag_4F,currentcard.tag_4F_len, ¤tcard);
+
+ //get PDOL
+ uint8_t pdolcommand[20]; //20 byte buffer for pdol data
+ uint8_t pdolcommandlen = 0;
+ if(currentcard.tag_9F38_len > 0) {
+ emv_generateDOL(currentcard.tag_9F38, currentcard.tag_9F38_len, ¤tcard, pdolcommand, &pdolcommandlen);
+ }
+ if(EMVGetProcessingOptions(pdolcommand,pdolcommandlen, ¤tcard)) {
+ if(EMV_DBGLEVEL >= 1) Dbprintf("PDOL failed");
+ return 1;
+ }
+
+ Dbprintf("AFL=");
+ Dbhexdump(currentcard.tag_94_len, currentcard.tag_94,false);
+ Dbprintf("AIP=");
+ Dbhexdump(2, currentcard.tag_82, false);
+ emv_decodeAIP(currentcard.tag_82);
+
+ //decode the AFL list and read records
+ uint8_t i = 0;
+ uint8_t sfi = 0;
+ uint8_t recordstart = 0;
+ uint8_t recordend = 0;
+
+ while( i< currentcard.tag_94_len){
+ sfi = (currentcard.tag_94[i++] & 0xF8) >> 3;
+ recordstart = currentcard.tag_94[i++];
+ recordend = currentcard.tag_94[i++];
+ for(int j=recordstart; j<(recordend+1); j++){
+ //read records
+ EMVReadRecord(j,sfi, ¤tcard);
+ //while(responsebuffer[0] == 0xF2) {
+ // EMVReadRecord(j,sfi, ¤tcard);
+ //}
+ }
+ i++;
+ }
+ /* get ICC dynamic data */
+ if((currentcard.tag_82[0] & AIP_CDA_SUPPORTED) == AIP_CDA_SUPPORTED)
+ {
+ //DDA supported, so perform GENERATE AC
+ //generate the iCC UN
+ EMVGetChallenge(¤tcard);
+ //memcpy(currentcard.tag_9F4C,&responsebuffer[1],8); // ICC UN
+ EMVGenerateAC(0x80,¤tcard);
+
+
+ //generate AC2
+ //if(currentcard.tag_8D_len > 0) {
+ // emv_generateDOL(currentcard.tag_8D, currentcard.tag_8D_len, ¤tcard, cdolcommand, &cdolcommandlen); }
+ //else{
+ // //cdolcommand = NULL; //cdol val is null
+ // cdolcommandlen = 0;
+ //}
+ //emv_generateAC(0x80, cdolcommand,cdolcommandlen, ¤tcard);
+
+ //if(responsebuffer[1] == 0x77) //format 2 data field returned
+ //{
+ // decode_ber_tlv_item(&responsebuffer[1], &temptag);
+ // emv_decode_field(temptag.value, temptag.valuelength, ¤tcard);
+ //}
+ }
+ //generate cryptographic checksum
+ //uint8_t udol[4] = {0x00,0x00,0x00,0x00};
+ //emv_computecryptogram(udol, sizeof(udol));
+ //if(responsebuffer[1] == 0x77) //format 2 data field returned
+ //{
+ // decode_ber_tlv_item(&responsebuffer[1], &temptag);
+ // emv_decode_field(temptag.value, temptag.valuelength, ¤tcard);
+ //}
+ return 0;
+}
+
+void EMVTransaction()
+{
+ //params
+ uint8_t uid[10] = {0x00};
+ uint32_t cuid = 0;
+
+ //setup stuff
+ BigBuf_free(); BigBuf_Clear_ext(false);
+ clear_trace();
+ set_tracing(TRUE);
+
+ LED_A_ON();
+ LED_B_OFF();
+ LED_C_OFF();
+
+ iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
+ while(true) {
+ if(!iso14443a_select_card(uid,NULL,&cuid)) {
+ if(EMV_DBGLEVEL >= 1) Dbprintf("Can't select card");
+ break;
+ }
+ //selectPPSE
+ EMVSelectAID((uint8_t *)DF_PSE, 14, ¤tcard); //hard coded len
+ //get response
+ if (!memcmp(currentcard.tag_4F, AID_MASTERCARD, sizeof(AID_MASTERCARD))){
+ Dbprintf("Mastercard Paypass Card Detected");
+ EMV_PaypassTransaction();
+ }
+ else if (!memcmp(currentcard.tag_4F, AID_VISA, sizeof(AID_VISA))){
+ Dbprintf("VISA Paywave Card Detected");
+ EMV_PaywaveTransaction();
+ }
+ //TODO: add other card schemes like AMEX, JCB, China Unionpay etc
+ break;
+ }
+ if (EMV_DBGLEVEL >= 2) DbpString("EMV TRANSACTION FINISHED");
+ //finish up
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ LEDsoff();
+}
+
+void EMVdumpcard(void){
+ dumpCard(¤tcard);
+}
+
+//SIMULATOR CODE
+//-----------------------------------------------------------------------------
+// Main loop of simulated tag: receive commands from reader, decide what
+// response to send, and send it.
+//-----------------------------------------------------------------------------
+void SimulateEMVcard()
+{
+ //uint8_t sak; //select ACKnowledge
+ uint16_t readerPacketLen = 64; //reader packet length - provided by RATS, default to 64 bytes if RATS not supported
+
+ // The first response contains the ATQA (note: bytes are transmitted in reverse order).
+ //uint8_t atqapacket[2];
+
+ // The second response contains the (mandatory) first 24 bits of the UID
+ uint8_t uid0packet[5] = {0x00};
+ memcpy(uid0packet, currentcard.UID, sizeof(uid0packet));
+ // Check if the uid uses the (optional) part
+ uint8_t uid1packet[5] = {0x00};
+ memcpy(uid1packet, currentcard.UID, sizeof(uid1packet));
+
+ // Calculate the BitCountCheck (BCC) for the first 4 bytes of the UID.
+ uid0packet[4] = uid0packet[0] ^ uid0packet[1] ^ uid0packet[2] ^ uid0packet[3];
+
+ // Prepare the mandatory SAK (for 4 and 7 byte UID)
+ uint8_t sak0packet[3] = {0x00};
+ memcpy(sak0packet,¤tcard.SAK1,1);
+ ComputeCrc14443(CRC_14443_A, sak0packet, 1, &sak0packet[1], &sak0packet[2]);
+ uint8_t sak1packet[3] = {0x00};
+ memcpy(sak1packet,¤tcard.SAK2,1);
+ // Prepare the optional second SAK (for 7 byte UID), drop the cascade bit
+ ComputeCrc14443(CRC_14443_A, sak1packet, 1, &sak1packet[1], &sak1packet[2]);
+
+ uint8_t authanspacket[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce
+ //setup response to ATS
+ uint8_t ratspacket[currentcard.ATS_len];
+ memcpy(ratspacket,currentcard.ATS, currentcard.ATS_len);
+ AppendCrc14443a(ratspacket,sizeof(ratspacket)-2);
+
+ // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present,
+ // TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1
+ // TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us)
+ // TC(1) = 0x02: CID supported, NAD not supported
+ //ComputeCrc14443(CRC_14443_A, response6, 4, &response6[4], &response6[5]);
+
+ //Receive Acknowledge responses differ by PCB byte
+ uint8_t rack0packet[] = {0xa2,0x00,0x00};
+ AppendCrc14443a(rack0packet,1);
+ uint8_t rack1packet[] = {0xa3,0x00,0x00};
+ AppendCrc14443a(rack1packet,1);
+ //Negative Acknowledge
+ uint8_t rnak0packet[] = {0xb2,0x00,0x00};
+ uint8_t rnak1packet[] = {0xb3,0x00,0x00};
+ AppendCrc14443a(rnak0packet,1);
+ AppendCrc14443a(rnak1packet,1);
+
+ //Protocol and parameter selection response, just say yes
+ uint8_t ppspacket[] = {0xd0,0x00,0x00};
+ AppendCrc14443a(ppspacket,1);
+
+ //hardcoded WTX packet - set to max time (49)
+ uint8_t wtxpacket[] ={0xf2,0x31,0x00,0x00};
+ AppendCrc14443a(wtxpacket,2);
+
+ //added additional responses for different readers, namely protocol parameter select and Receive acknowledments. - peter fillmore.
+ //added defininitions for predone responses to aid readability
+ #define ATR 0
+ #define UID1 1
+ #define UID2 2
+ #define SELACK1 3
+ #define SELACK2 4
+ #define AUTH_ANS 5
+ #define ATS 6
+ #define RACK0 7
+ #define RACK1 8
+ #define RNAK0 9
+ #define RNAK1 10
+ #define PPSresponse 11
+ #define WTX 12
+
+ #define TAG_RESPONSE_COUNT 13
+ tag_response_info_t responses[TAG_RESPONSE_COUNT] = {
+ { .response = currentcard.ATQA, .response_n = sizeof(currentcard.ATQA) }, // Answer to request - respond with card type
+ { .response = uid0packet, .response_n = sizeof(uid0packet) }, // Anticollision cascade1 - respond with uid
+ { .response = uid1packet, .response_n = sizeof(uid1packet) }, // Anticollision cascade2 - respond with 2nd half of uid if asked
+ { .response = sak0packet, .response_n = sizeof(sak0packet) }, // Acknowledge select - cascade 1
+ { .response = sak1packet, .response_n = sizeof(sak1packet) }, // Acknowledge select - cascade 2
+ { .response = authanspacket, .response_n = sizeof(authanspacket) }, // Authentication answer (random nonce)
+ { .response = ratspacket, .response_n = sizeof(ratspacket) }, // dummy ATS (pseudo-ATR), answer to RATS
+ { .response = rack0packet, .response_n = sizeof(rack0packet) }, //R(ACK)0
+ { .response = rack1packet, .response_n = sizeof(rack1packet) }, //R(ACK)0
+ { .response = rnak0packet, .response_n = sizeof(rnak0packet) }, //R(NAK)0
+ { .response = rnak1packet, .response_n = sizeof(rnak1packet) }, //R(NAK)1
+ { .response = ppspacket, .response_n = sizeof(ppspacket)}, //PPS packet
+ { .response = wtxpacket, .response_n = sizeof(wtxpacket)}, //WTX packet
+};
+
+ //calculated length of predone responses
+ uint16_t allocatedtaglen = 0;
+ for(int i=0;i<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();
+}
--- /dev/null
+//-----------------------------------------------------------------------------
+// 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, ¤tcard->SAK1, false);
+ DUMP(currentcard->SAK2);
+ Dbhexdump(1, ¤tcard->SAK2, false);
+ DUMP(currentcard->ATS);
+ Dbhexdump(currentcard->ATS_len, currentcard->ATS, false);
+
+ DUMP(currentcard->tag_4F);
+ Dbhexdump(currentcard->tag_4F_len, currentcard->tag_4F, false);
+ DUMP(currentcard->tag_50);
+ Dbhexdump(currentcard->tag_50_len, currentcard->tag_50, false);
+ DUMP(currentcard->tag_56);
+ Dbhexdump(currentcard->tag_56_len, currentcard->tag_56, false);
+ DUMP(currentcard->tag_57);
+ Dbhexdump(currentcard->tag_57_len, currentcard->tag_57, false);
+ DUMP(currentcard->tag_5A);
+ Dbhexdump(currentcard->tag_5A_len, currentcard->tag_5A, false);
+ DUMP(currentcard->tag_82);
+ Dbhexdump(sizeof(currentcard->tag_82), currentcard->tag_82, false);
+ DUMP(currentcard->tag_84);
+ Dbhexdump(currentcard->tag_84_len, currentcard->tag_84, false);
+ DUMP(currentcard->tag_86);
+ Dbhexdump(currentcard->tag_86_len, currentcard->tag_86, false);
+ DUMP(currentcard->tag_87);
+ Dbhexdump(1, currentcard->tag_87, false);
+DUMP(currentcard->tag_88);
+ Dbhexdump(1, currentcard->tag_88, false);
+DUMP(currentcard->tag_8A);
+ Dbhexdump(2, currentcard->tag_8A, false);
+ DUMP(currentcard->tag_8C);
+ Dbhexdump(currentcard->tag_8C_len, currentcard->tag_8C, false);
+ DUMP(currentcard->tag_8D);
+ Dbhexdump(currentcard->tag_8D_len, currentcard->tag_8D, false);
+ DUMP(currentcard->tag_8E);
+ Dbhexdump(currentcard->tag_8E_len, currentcard->tag_8E, false);
+ DUMP(currentcard->tag_8F);
+ Dbhexdump(1, currentcard->tag_8F, false);
+ DUMP(currentcard->tag_90);
+ Dbhexdump(currentcard->tag_90_len, currentcard->tag_90, false);
+ DUMP(currentcard->tag_92);
+ Dbhexdump(currentcard->tag_92_len, currentcard->tag_92, false);
+ DUMP(currentcard->tag_93);
+ Dbhexdump(currentcard->tag_93_len, currentcard->tag_93, false);
+ DUMP(currentcard->tag_94);
+ Dbhexdump(currentcard->tag_94_len, currentcard->tag_94, false);
+ DUMP(currentcard->tag_95);
+ Dbhexdump(5, currentcard->tag_95, false);
+ DUMP(currentcard->tag_97);
+ Dbhexdump(currentcard->tag_97_len, currentcard->tag_97, false);
+ DUMP(currentcard->tag_98);
+ Dbhexdump(20, currentcard->tag_98, false);
+ DUMP(currentcard->tag_99);
+ Dbhexdump(currentcard->tag_99_len, currentcard->tag_99, false);
+ DUMP(currentcard->tag_9A);
+ Dbhexdump(3, currentcard->tag_9A, false);
+ DUMP(currentcard->tag_9B);
+ Dbhexdump(2, currentcard->tag_9B, false);
+ DUMP(currentcard->tag_9C);
+ Dbhexdump(1, currentcard->tag_9C, false);
+ DUMP(currentcard->tag_9D);
+ Dbhexdump(currentcard->tag_9D_len, currentcard->tag_9D, false);
+ DUMP(currentcard->tag_CD);
+ Dbhexdump(3, currentcard->tag_CD, false);
+ DUMP(currentcard->tag_CE);
+ Dbhexdump(3, currentcard->tag_CE, false);
+ DUMP(currentcard->tag_CF);
+ Dbhexdump(3, currentcard->tag_CF, false);
+ DUMP(currentcard->tag_D7);
+ Dbhexdump(3, currentcard->tag_D7, false);
+ DUMP(currentcard->tag_D8);
+ Dbhexdump(2, currentcard->tag_D8, false);
+ DUMP(currentcard->tag_D9);
+ Dbhexdump(currentcard->tag_D9_len, currentcard->tag_D9, false);
+ DUMP(currentcard->tag_DA);
+ Dbhexdump(2, currentcard->tag_DA, false);
+ DUMP(currentcard->tag_DB);
+ Dbhexdump(2, currentcard->tag_DB, false);
+ DUMP(currentcard->tag_DC);
+ Dbhexdump(2, currentcard->tag_DC, false);
+ DUMP(currentcard->tag_DD);
+ Dbhexdump(2, currentcard->tag_DD, false);
+ DUMP(currentcard->tag_AF);
+ Dbhexdump(currentcard->tag_AF_len, currentcard->tag_AF, false);
+ DUMP(currentcard->tag_5F20);
+ Dbhexdump(currentcard->tag_5F20_len, currentcard->tag_5F20, false);
+ DUMP(currentcard->tag_5F24);
+ Dbhexdump(3, currentcard->tag_5F24, false);
+ DUMP(currentcard->tag_5F25);
+ Dbhexdump(3, currentcard->tag_5F25, false);
+ DUMP(currentcard->tag_5F28);
+ Dbhexdump(2, currentcard->tag_5F28, false);
+ DUMP(currentcard->tag_5F2A);
+ Dbhexdump(2, currentcard->tag_5F2A, false);
+ DUMP(currentcard->tag_5F2D);
+ Dbhexdump(currentcard->tag_5F2D_len, currentcard->tag_5F2D, false);
+ DUMP(currentcard->tag_5F30);
+ Dbhexdump(3, currentcard->tag_5F30, false);
+ DUMP(currentcard->tag_5F34);
+ Dbhexdump(1, currentcard->tag_5F34, false);
+ DUMP(currentcard->tag_5F36);
+ Dbhexdump(2, currentcard->tag_5F36, false);
+ DUMP(currentcard->tag_5F50);
+ Dbhexdump(currentcard->tag_5F50_len, currentcard->tag_5F50, false);
+ DUMP(currentcard->tag_5F54);
+ Dbhexdump(currentcard->tag_5F54_len, currentcard->tag_5F54, false);
+ DUMP(currentcard->tag_9F01);
+ Dbhexdump(6, currentcard->tag_9F01, false);
+ DUMP(currentcard->tag_9F02);
+ Dbhexdump(6, currentcard->tag_9F02, false);
+ DUMP(currentcard->tag_9F03);
+ Dbhexdump(6, currentcard->tag_9F03, false);
+ DUMP(currentcard->tag_9F04);
+ Dbhexdump(4, currentcard->tag_9F04, false);
+ DUMP(currentcard->tag_9F05);
+ Dbhexdump(currentcard->tag_9F05_len, currentcard->tag_9F05, false);
+ DUMP(currentcard->tag_9F06);
+ Dbhexdump(currentcard->tag_9F06_len, currentcard->tag_9F06, false);
+ DUMP(currentcard->tag_9F07);
+ Dbhexdump(2, currentcard->tag_9F07, false);
+ DUMP(currentcard->tag_9F08);
+ Dbhexdump(2, currentcard->tag_9F08, false);
+ DUMP(currentcard->tag_9F09);
+ Dbhexdump(2, currentcard->tag_9F09, false);
+ DUMP(currentcard->tag_9F0B);
+ Dbhexdump(currentcard->tag_9F0B_len, currentcard->tag_9F0B, false);
+ DUMP(currentcard->tag_9F0D);
+ Dbhexdump(5, currentcard->tag_9F0D, false);
+ DUMP(currentcard->tag_9F0E);
+ Dbhexdump(5, currentcard->tag_9F0E, false);
+ DUMP(currentcard->tag_9F0F);
+ Dbhexdump(5, currentcard->tag_9F0F, false);
+ DUMP(currentcard->tag_9F10);
+ Dbhexdump(currentcard->tag_9F10_len, currentcard->tag_9F10, false);
+ DUMP(currentcard->tag_9F11);
+ Dbhexdump(1, currentcard->tag_9F11, false);
+ DUMP(currentcard->tag_9F12);
+ Dbhexdump(currentcard->tag_9F12_len, currentcard->tag_9F12, false);
+ DUMP(currentcard->tag_9F13);
+ Dbhexdump(2, currentcard->tag_9F13, false);
+ DUMP(currentcard->tag_9F14);
+ Dbhexdump(1, currentcard->tag_9F14, false);
+ DUMP(currentcard->tag_9F15);
+ Dbhexdump(2, currentcard->tag_9F15, false);
+ DUMP(currentcard->tag_9F16);
+ Dbhexdump(15, currentcard->tag_9F16, false);
+ DUMP(currentcard->tag_9F17);
+ Dbhexdump(1, currentcard->tag_9F17, false);
+ DUMP(currentcard->tag_9F18);
+ Dbhexdump(4, currentcard->tag_9F18, false);
+ DUMP(currentcard->tag_9F1A);
+ Dbhexdump(2, currentcard->tag_9F1A, false);
+ DUMP(currentcard->tag_9F1B);
+ Dbhexdump(4, currentcard->tag_9F1B, false);
+ DUMP(currentcard->tag_9F1C);
+ Dbhexdump(8, currentcard->tag_9F1C, false);
+ DUMP(currentcard->tag_9F1D);
+ Dbhexdump(currentcard->tag_9F1D_len, currentcard->tag_9F1D, false);
+ DUMP(currentcard->tag_9F1E);
+ Dbhexdump(8, currentcard->tag_9F1E, false);
+ DUMP(currentcard->tag_9F1F);
+ Dbhexdump(currentcard->tag_9F1F_len, currentcard->tag_9F1F, false);
+ DUMP(currentcard->tag_9F20);
+ Dbhexdump(currentcard->tag_9F20_len, currentcard->tag_9F20, false);
+ DUMP(currentcard->tag_9F21);
+ Dbhexdump(3, currentcard->tag_9F1E, false);
+ DUMP(currentcard->tag_9F22);
+ Dbhexdump(1, currentcard->tag_9F22, false);
+ DUMP(currentcard->tag_9F23);
+ Dbhexdump(1, currentcard->tag_9F23, false);
+ DUMP(currentcard->tag_9F26);
+ Dbhexdump(8, currentcard->tag_9F26, false);
+ DUMP(currentcard->tag_9F27);
+ Dbhexdump(1, currentcard->tag_9F27, false);
+ DUMP(currentcard->tag_9F2D);
+ Dbhexdump(currentcard->tag_9F2D_len, currentcard->tag_9F2D, false);
+ DUMP(currentcard->tag_9F2E);
+ Dbhexdump(3, currentcard->tag_9F2E, false);
+ DUMP(currentcard->tag_9F2F);
+ Dbhexdump(currentcard->tag_9F2F_len, currentcard->tag_9F2F, false);
+ DUMP(currentcard->tag_9F32);
+ Dbhexdump(currentcard->tag_9F32_len, currentcard->tag_9F32, false);
+ DUMP(currentcard->tag_9F33);
+ Dbhexdump(3, currentcard->tag_9F33, false);
+ DUMP(currentcard->tag_9F34);
+ Dbhexdump(3, currentcard->tag_9F34, false);
+ DUMP(currentcard->tag_9F35);
+ Dbhexdump(1, currentcard->tag_9F35, false);
+ DUMP(currentcard->tag_9F36);
+ Dbhexdump(2, currentcard->tag_9F36, false);
+ DUMP(currentcard->tag_9F37);
+ Dbhexdump(4, currentcard->tag_9F37, false);
+ DUMP(currentcard->tag_9F38);
+ Dbhexdump(currentcard->tag_9F38_len, currentcard->tag_9F38, false);
+ DUMP(currentcard->tag_9F39);
+ Dbhexdump(1, currentcard->tag_9F39, false);
+ DUMP(currentcard->tag_9F39);
+ Dbhexdump(1, currentcard->tag_9F39, false);
+ DUMP(currentcard->tag_9F40);
+ Dbhexdump(5, currentcard->tag_9F40, false);
+ DUMP(currentcard->tag_9F41);
+ Dbhexdump(4, currentcard->tag_9F41, false);
+ DUMP(currentcard->tag_9F42);
+ Dbhexdump(2, currentcard->tag_9F42, false);
+ DUMP(currentcard->tag_9F43);
+ Dbhexdump(4, currentcard->tag_9F43, false);
+ DUMP(currentcard->tag_9F44);
+ Dbhexdump(1, currentcard->tag_9F44, false);
+ DUMP(currentcard->tag_9F45);
+ Dbhexdump(2, currentcard->tag_9F45, false);
+ DUMP(currentcard->tag_9F46);
+ Dbhexdump(currentcard->tag_9F46_len, currentcard->tag_9F46, false);
+ DUMP(currentcard->tag_9F47);
+ Dbhexdump(currentcard->tag_9F47_len, currentcard->tag_9F47, false);
+ DUMP(currentcard->tag_9F48);
+ Dbhexdump(currentcard->tag_9F48_len, currentcard->tag_9F48, false);
+ DUMP(currentcard->tag_9F49);
+ Dbhexdump(currentcard->tag_9F49_len, currentcard->tag_9F49, false);
+ DUMP(currentcard->tag_9F4A);
+ Dbhexdump(1, currentcard->tag_9F4A, false);
+ DUMP(currentcard->tag_9F4B);
+ Dbhexdump(currentcard->tag_9F4B_len, currentcard->tag_9F4B, false);
+ DUMP(currentcard->tag_9F4C);
+ Dbhexdump(8, currentcard->tag_9F4C, false);
+ DUMP(currentcard->tag_9F4D);
+ Dbhexdump(2, currentcard->tag_9F4D, false);
+ DUMP(currentcard->tag_9F4E);
+ Dbhexdump(255, currentcard->tag_9F4E, false);
+ DUMP(currentcard->tag_9F60);
+ Dbhexdump(2, currentcard->tag_9F60, false);
+ DUMP(currentcard->tag_9F61);
+ Dbhexdump(2, currentcard->tag_9F61, false);
+ DUMP(currentcard->tag_9F62);
+ Dbhexdump(6, currentcard->tag_9F62, false);
+ DUMP(currentcard->tag_9F63);
+ Dbhexdump(6, currentcard->tag_9F63, false);
+ DUMP(currentcard->tag_9F64);
+ Dbhexdump(1, currentcard->tag_9F64, false);
+ DUMP(currentcard->tag_9F65);
+ Dbhexdump(2, currentcard->tag_9F65, false);
+ DUMP(currentcard->tag_9F66);
+ Dbhexdump(2, currentcard->tag_9F66, false);
+ DUMP(currentcard->tag_9F67);
+ Dbhexdump(1, currentcard->tag_9F67, false);
+ DUMP(currentcard->tag_9F68);
+ Dbhexdump(currentcard->tag_9F68_len, currentcard->tag_9F68, false);
+ DUMP(currentcard->tag_9F69);
+ Dbhexdump(currentcard->tag_9F69_len, currentcard->tag_9F69, false);
+ DUMP(currentcard->tag_9F6A);
+ Dbhexdump(8, currentcard->tag_9F6A, false);
+ DUMP(currentcard->tag_9F6B);
+ Dbhexdump(currentcard->tag_9F6B_len, currentcard->tag_9F6B, false);
+ DUMP(currentcard->tag_9F6C);
+ Dbhexdump(2, currentcard->tag_9F6C, false);
+ DUMP(currentcard->tag_61);
+ Dbhexdump(currentcard->tag_61_len, currentcard->tag_61, false);
+ DUMP(currentcard->tag_A5);
+ Dbhexdump(currentcard->tag_A5_len, currentcard->tag_A5, false);
+ DUMP(currentcard->tag_DFNAME);
+ Dbhexdump(currentcard->tag_DFNAME_len, currentcard->tag_DFNAME, false);
+ DUMP(currentcard->tag_70);
+ Dbhexdump(currentcard->tag_70_len, currentcard->tag_70, false);
+ DUMP(currentcard->tag_77);
+ Dbhexdump(currentcard->tag_77_len, currentcard->tag_77, false);
+ DUMP(currentcard->tag_80);
+ Dbhexdump(currentcard->tag_80_len, currentcard->tag_80, false);
+ DUMP(currentcard->tag_91);
+ Dbhexdump(currentcard->tag_91_len, currentcard->tag_91, false);
+ DUMP(currentcard->tag_BF0C);
+ Dbhexdump(currentcard->tag_BF0C_len, currentcard->tag_BF0C, false);
+ DUMP(currentcard->tag_DFName);
+ Dbhexdump(currentcard->tag_DFName_len, currentcard->tag_DFName, false);
+}
+
+