]> cvs.zerfleddert.de Git - proxmark3-svn/blobdiff - client/emv/cmdemv.c
`hf emv gpo` works
[proxmark3-svn] / client / emv / cmdemv.c
index 92ae01f944c88a2fabcec2d35c361941e1d7fe04..496b3cb8b11238847a18af9f4a8ef082a0063672 100644 (file)
@@ -8,86 +8,39 @@
 // EMV commands
 //-----------------------------------------------------------------------------
 
+#include <ctype.h>
 #include "cmdemv.h"
-
-int UsageCmdHFEMVSelect(void) {
-       PrintAndLog("HELP :  Executes select applet command:\n");
-       PrintAndLog("Usage:  hf emv select [-s][-k][-a][-t] <HEX applet AID>\n");
-       PrintAndLog("  Options:");
-       PrintAndLog("  -s       : select card");
-       PrintAndLog("  -k       : keep field for next command");
-       PrintAndLog("  -a       : show APDU reqests and responses\n");
-       PrintAndLog("  -t       : TLV decode results\n");
-       PrintAndLog("Samples:");
-       PrintAndLog(" hf emv select -s a00000000101 -> select card, select applet");
-       PrintAndLog(" hf emv select -s -t a00000000101 -> select card, select applet, show result in TLV");
-       return 0;
-}
+#include "test/cryptotest.h"
+#include "cliparser/cliparser.h"
 
 int CmdHFEMVSelect(const char *cmd) {
        uint8_t data[APDU_AID_LEN] = {0};
        int datalen = 0;
-       bool activateField = false;
-       bool leaveSignalON = false;
-       bool decodeTLV = false;
-
-       if (strlen(cmd) < 1) {
-               UsageCmdHFEMVSelect();
-               return 0;
-       }
-       
-       SetAPDULogging(false);
-       
-       int cmdp = 0;
-       while(param_getchar(cmd, cmdp) != 0x00) {
-               char c = param_getchar(cmd, cmdp);
-               if ((c == '-') && (param_getlength(cmd, cmdp) == 2))
-                       switch (param_getchar_indx(cmd, 1, cmdp)) {
-                               case 'h':
-                               case 'H':
-                                       UsageCmdHFEMVSelect();
-                                       return 0;
-                               case 's':
-                               case 'S':
-                                       activateField = true;
-                                       break;
-                               case 'k':
-                               case 'K':
-                                       leaveSignalON = true;
-                                       break;
-                               case 'a':
-                               case 'A':
-                                       SetAPDULogging(true);
-                                       break;
-                               case 't':
-                               case 'T':
-                                       decodeTLV = true;
-                                       break;
-                               default:
-                                       PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
-                                       return 1;
-               }
 
-               if (isxdigit(c)) {
-                       switch(param_gethex_to_eol(cmd, cmdp, data, sizeof(data), &datalen)) {
-                       case 1:
-                               PrintAndLog("Invalid HEX value.");
-                               return 1;
-                       case 2:
-                               PrintAndLog("AID too large.");
-                               return 1;
-                       case 3:
-                               PrintAndLog("Hex must have even number of digits.");
-                               return 1;
-                       }
-                       
-                       // we get all the hex to end of line with spaces
-                       break;
-               }
 
+       CLIParserInit("hf 14a select", 
+               "Executes select applet command", 
+               "Usage:\n\thf emv select -s a00000000101 -> select card, select applet\n\thf emv select -st a00000000101 -> select card, select applet, show result in TLV\n");
 
-               cmdp++;
-       }
+       void* argtable[] = {
+               arg_param_begin,
+               arg_lit0("sS",  "select",  "activate field and select card"),
+               arg_lit0("kK",  "keep",    "keep field for next command"),
+               arg_lit0("aA",  "apdu",    "show APDU reqests and responses"),
+               arg_lit0("tT",  "tlv",     "TLV decode results"),
+               arg_str0(NULL,  NULL,      "<HEX applet AID>", NULL),
+               arg_param_end
+       };
+       CLIExecWithReturn(cmd, argtable, true);
+       
+       bool activateField = arg_get_lit(1);
+       bool leaveSignalON = arg_get_lit(2);
+       bool APDULogging = arg_get_lit(3);
+       bool decodeTLV = arg_get_lit(4);
+       CLIGetStrWithReturn(5, data, &datalen);
+       CLIParserFree();
+       
+       SetAPDULogging(APDULogging);
        
        // exec
        uint8_t buf[APDU_RES_LEN] = {0};
@@ -107,65 +60,30 @@ int CmdHFEMVSelect(const char *cmd) {
        return 0;
 }
 
-int UsageCmdHFEMVSearch(void) {
-       PrintAndLog("HELP :  Tries to select all applets from applet list:\n");
-       PrintAndLog("Usage:  hf emv search [-s][-k][-a][-t]\n");
-       PrintAndLog("  Options:");
-       PrintAndLog("  -s       : select card");
-       PrintAndLog("  -k       : keep field for next command");
-       PrintAndLog("  -a       : show APDU reqests and responses\n");
-       PrintAndLog("  -t       : TLV decode results of selected applets\n");
-       PrintAndLog("Samples:");
-       PrintAndLog(" hf emv search -s -> select card and search");
-       PrintAndLog(" hf emv search -s -t -> select card, search and show result in TLV");
-       return 0;
-}
-
 int CmdHFEMVSearch(const char *cmd) {
 
-       bool activateField = false;
-       bool leaveSignalON = false;
-       bool decodeTLV = false;
+       CLIParserInit("hf 14a select", 
+               "Tries to select all applets from applet list:\n", 
+               "Usage:\n\thf emv search -s -> select card and search\n\thf emv search -st -> select card, search and show result in TLV\n");
 
-       if (strlen(cmd) < 1) {
-               UsageCmdHFEMVSearch();
-               return 0;
-       }
+       void* argtable[] = {
+               arg_param_begin,
+               arg_lit0("sS",  "select",  "activate field and select card"),
+               arg_lit0("kK",  "keep",    "keep field ON for next command"),
+               arg_lit0("aA",  "apdu",    "show APDU reqests and responses"),
+               arg_lit0("tT",  "tlv",     "TLV decode results of selected applets"),
+               arg_param_end
+       };
+       CLIExecWithReturn(cmd, argtable, true);
        
-       SetAPDULogging(false);
+       bool activateField = arg_get_lit(1);
+       bool leaveSignalON = arg_get_lit(2);
+       bool APDULogging = arg_get_lit(3);
+       bool decodeTLV = arg_get_lit(4);
+       CLIParserFree();
+       
+       SetAPDULogging(APDULogging);
        
-       int cmdp = 0;
-       while(param_getchar(cmd, cmdp) != 0x00) {
-               char c = param_getchar(cmd, cmdp);
-               if ((c == '-') && (param_getlength(cmd, cmdp) == 2))
-                       switch (param_getchar_indx(cmd, 1, cmdp)) {
-                               case 'h':
-                               case 'H':
-                                       UsageCmdHFEMVSearch();
-                                       return 0;
-                               case 's':
-                               case 'S':
-                                       activateField = true;
-                                       break;
-                               case 'k':
-                               case 'K':
-                                       leaveSignalON = true;
-                                       break;
-                               case 'a':
-                               case 'A':
-                                       SetAPDULogging(true);
-                                       break;
-                               case 't':
-                               case 'T':
-                                       decodeTLV = true;
-                                       break;
-                               default:
-                                       PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
-                                       return 1;
-               }
-               cmdp++;
-       }
-
        struct tlvdb *t = NULL;
        const char *al = "Applets list";
        t = tlvdb_fixed(1, strlen(al), (const unsigned char *)al);
@@ -187,80 +105,179 @@ int CmdHFEMVSearch(const char *cmd) {
        return 0;
 }
 
-int UsageCmdHFEMVPPSE(void) {
-       PrintAndLog("HELP :  Executes PSE/PPSE select command. It returns list of applet on the card:\n");
-       PrintAndLog("Usage:  hf emv pse [-s][-k][-1][-2][-a][-t]\n");
-       PrintAndLog("  Options:");
-       PrintAndLog("  -s       : select card");
-       PrintAndLog("  -k       : keep field for next command");
-       PrintAndLog("  -1       : ppse (1PAY.SYS.DDF01)");
-       PrintAndLog("  -2       : pse (2PAY.SYS.DDF01)");
-       PrintAndLog("  -a       : show APDU reqests and responses\n");
-       PrintAndLog("  -t       : TLV decode results\n");
-       PrintAndLog("Samples:");
-       PrintAndLog(" hf emv pse -s -1 -> select, get pse");
-       PrintAndLog(" hf emv pse -s -k -2 -> select, get ppse, keep field");
-       PrintAndLog(" hf emv pse -s -t -2 -> select, get ppse, show result in TLV");
-       return 0;
-}
-
 int CmdHFEMVPPSE(const char *cmd) {
        
+       CLIParserInit("hf 14a pse", 
+               "Executes PSE/PPSE select command. It returns list of applet on the card:\n", 
+               "Usage:\n\thf emv pse -s1 -> select, get pse\n\thf emv pse -st2 -> select, get ppse, show result in TLV\n");
+
+       void* argtable[] = {
+               arg_param_begin,
+               arg_lit0("sS",  "select",  "activate field and select card"),
+               arg_lit0("kK",  "keep",    "keep field ON for next command"),
+               arg_lit0("1",   "pse",     "pse (1PAY.SYS.DDF01) mode"),
+               arg_lit0("2",   "ppse",    "ppse (2PAY.SYS.DDF01) mode (default mode)"),
+               arg_lit0("aA",  "apdu",    "show APDU reqests and responses"),
+               arg_lit0("tT",  "tlv",     "TLV decode results of selected applets"),
+               arg_param_end
+       };
+       CLIExecWithReturn(cmd, argtable, true);
+       
+       bool activateField = arg_get_lit(1);
+       bool leaveSignalON = arg_get_lit(2);
        uint8_t PSENum = 2;
-       bool activateField = false;
-       bool leaveSignalON = false;
-       bool decodeTLV = false;
+       if (arg_get_lit(3))
+               PSENum = 1;
+       if (arg_get_lit(4))
+               PSENum = 2;
+       bool APDULogging = arg_get_lit(5);
+       bool decodeTLV = arg_get_lit(6);
+       CLIParserFree();        
+       
+       SetAPDULogging(APDULogging);
+       
+       // exec
+       uint8_t buf[APDU_RES_LEN] = {0};
+       size_t len = 0;
+       uint16_t sw = 0;
+       int res = EMVSelectPSE(activateField, leaveSignalON, PSENum, buf, sizeof(buf), &len, &sw);
+       
+       if (sw)
+               PrintAndLog("APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); 
 
-       if (strlen(cmd) < 1) {
-               UsageCmdHFEMVPPSE();
+       if (res)
+               return res;
+       
+       
+       if (decodeTLV)
+               TLVPrintFromBuffer(buf, len);
+
+       return 0;
+}
+
+int CmdHFEMVGPO(const char *cmd) {
+       uint8_t data[APDU_RES_LEN] = {0};
+       int datalen = 0;
+
+       CLIParserInit("hf 14a gpo", 
+               "Executes Get Processing Options command. It returns data in TLV format (0x77 - format2) or plain (0x80 - format1) formats.\nNeeds a bank applet to be selected.\n", 
+               "Usage:\n\thf emv gpo -k -> select, execute GPO\n\thf emv gpo -st 01020304 -> select, execute GPO with 4-byte PDOL data, show result in TLV\n");
+
+       void* argtable[] = {
+               arg_param_begin,
+               arg_lit0("kK",  "keep",    "keep field ON for next command"),
+               arg_lit0("pP",  "params",  "load parameters for PDOL making from `emv/defparams.json` file (by default uses default parameters) (NOT WORK!!!)"),
+               arg_lit0("mM",  "make",    "make PDOLdata from PDOL (tag 9F38) and parameters (NOT WORK!!!)"),
+               arg_lit0("aA",  "apdu",    "show APDU reqests and responses"),
+               arg_lit0("tT",  "tlv",     "TLV decode results of selected applets"),
+               arg_str0(NULL,  NULL,      "<HEX PDOLdata/PDOL>", NULL),
+               arg_param_end
+       };
+       CLIExecWithReturn(cmd, argtable, true);
+       
+       bool leaveSignalON = arg_get_lit(1);
+       bool paramsLoadFromFile = arg_get_lit(2);
+       bool dataMakeFromPDOL = arg_get_lit(3);
+       bool APDULogging = arg_get_lit(4);
+       bool decodeTLV = arg_get_lit(5);
+       CLIGetStrWithReturn(6, data, &datalen);
+       CLIParserFree();        
+       
+       SetAPDULogging(APDULogging);
+       
+       // Init TLV tree
+       const char *alr = "Root terminal TLV tree";
+       struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr);
+       
+       // calc PDOL
+       struct tlv *pdol_data_tlv = NULL;
+       struct tlv data_tlv = {
+               .tag = 0x83,  //was 01
+               .len = datalen,
+               .value = (uint8_t *)data,
+       };
+       if (dataMakeFromPDOL) {
+               // TODO
+               PrintAndLog("Make PDOL data not implemented!");
+               if (paramsLoadFromFile) {
+               };
+/*             pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
+               if (!pdol_data_tlv){
+                       PrintAndLog("ERROR: can't create PDOL TLV.");
+                       tlvdb_free(tlvRoot);
+                       return 4;
+               }*/
                return 0;
+       } else {
+               pdol_data_tlv = &data_tlv;
        }
 
-       SetAPDULogging(false);
+       size_t pdol_data_tlv_data_len = 0;
+       unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len);
+       if (!pdol_data_tlv_data) {
+               PrintAndLog("ERROR: can't create PDOL data.");
+               tlvdb_free(tlvRoot);
+               return 4;
+       }
+       PrintAndLog("PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
        
-       int cmdp = 0;
-       while(param_getchar(cmd, cmdp) != 0x00) {
-               char c = param_getchar(cmd, cmdp);
-               if ((c == '-') && (param_getlength(cmd, cmdp) == 2))
-                       switch (param_getchar_indx(cmd, 1, cmdp)) {
-                               case 'h':
-                               case 'H':
-                                       UsageCmdHFEMVPPSE();
-                                       return 0;
-                               case 's':
-                               case 'S':
-                                       activateField = true;
-                                       break;
-                               case 'k':
-                               case 'K':
-                                       leaveSignalON = true;
-                                       break;
-                               case 'a':
-                               case 'A':
-                                       SetAPDULogging(true);
-                                       break;
-                               case 't':
-                               case 'T':
-                                       decodeTLV = true;
-                                       break;
-                               case '1':
-                                       PSENum = 1;
-                                       break;
-                               case '2':
-                                       PSENum = 2;
-                                       break;
-                               default:
-                                       PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
-                                       return 1;
-               }
-               cmdp++;
+       // exec
+       uint8_t buf[APDU_RES_LEN] = {0};
+       size_t len = 0;
+       uint16_t sw = 0;
+       int res = EMVGPO(leaveSignalON, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
+       
+       free(pdol_data_tlv_data);
+       tlvdb_free(tlvRoot);
+       
+       if (sw)
+               PrintAndLog("APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); 
+
+       if (res)
+               return res;
+       
+       if (decodeTLV)
+               TLVPrintFromBuffer(buf, len);
+
+       return 0;
+}
+
+int CmdHFEMVReadRecord(const char *cmd) {
+       uint8_t data[APDU_RES_LEN] = {0};
+       int datalen = 0;
+
+       CLIParserInit("hf 14a readrec", 
+               "Executes Read Record command. It returns data in TLV format.\nNeeds a bank applet to be selected and sometimes needs GPO to be executed.\n", 
+               "Usage:\n\thf emv readrec -k -> select, get pse\n\thf emv readrec -st2 -> select, get ppse, show result in TLV\n");
+
+       void* argtable[] = {
+               arg_param_begin,
+               arg_lit0("kK",  "keep",    "keep field ON for next command"),
+               arg_lit0("aA",  "apdu",    "show APDU reqests and responses"),
+               arg_lit0("tT",  "tlv",     "TLV decode results of selected applets"),
+               arg_str0(NULL,  NULL,      "<SFI 1byte HEX><SFIrec 1byte HEX>", NULL),
+               arg_param_end
+       };
+       CLIExecWithReturn(cmd, argtable, true);
+       
+       bool leaveSignalON = arg_get_lit(1);
+       bool APDULogging = arg_get_lit(2);
+       bool decodeTLV = arg_get_lit(3);
+       CLIGetStrWithReturn(4, data, &datalen);
+       CLIParserFree();
+       
+       if (datalen != 2) {
+               PrintAndLog("ERROR: Command needs to have 2 bytes of data");
+               return 1;
        }
        
+       SetAPDULogging(APDULogging);
+               
        // exec
        uint8_t buf[APDU_RES_LEN] = {0};
        size_t len = 0;
        uint16_t sw = 0;
-       int res = EMVSelectPSE(activateField, leaveSignalON, PSENum, buf, sizeof(buf), &len, &sw);
+       int res = EMVReadRecord(leaveSignalON, data[0], data[1], buf, sizeof(buf), &len, &sw, NULL);
        
        if (sw)
                PrintAndLog("APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); 
@@ -275,9 +292,24 @@ int CmdHFEMVPPSE(const char *cmd) {
        return 0;
 }
 
+int CmdHFEMVAC(const char *cmd) {
+
+       return 0;
+}
+
+int CmdHFEMVGenerateChallenge(const char *cmd) {
+
+       return 0;
+}
+
+int CmdHFEMVInternalAuthenticate(const char *cmd) {
+
+       return 0;
+}
+
 int UsageCmdHFEMVExec(void) {
        PrintAndLog("HELP :  Executes EMV contactless transaction:\n");
-       PrintAndLog("Usage:  hf emv exec [-s][-a][-t]\n");
+       PrintAndLog("Usage:  hf emv exec [-s][-a][-t][-f][-v][-c][-x][-g]\n");
        PrintAndLog("  Options:");
        PrintAndLog("  -s       : select card");
        PrintAndLog("  -a       : show APDU reqests and responses\n");
@@ -286,14 +318,16 @@ int UsageCmdHFEMVExec(void) {
        PrintAndLog("  -v       : transaction type - qVSDC or M/Chip.\n");
        PrintAndLog("  -c       : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n");
        PrintAndLog("  -x       : transaction type - VSDC. For test only. Not a standart behavior.\n");
+       PrintAndLog("  -g       : VISA. generate AC from GPO\n");
        PrintAndLog("By default : transaction type - MSD.\n");
        PrintAndLog("Samples:");
-       PrintAndLog(" hf emv pse -s -> select card");
-       PrintAndLog(" hf emv pse -s -t -a -> select card, show responses in TLV, show APDU");
+       PrintAndLog(" hf emv exec -s -a -t -> execute MSD transaction");
+       PrintAndLog(" hf emv exec -s -a -t -c -> execute CDA transaction");
        return 0;
 }
 
 #define TLV_ADD(tag, value)( tlvdb_add(tlvRoot, tlvdb_fixed(tag, sizeof(value) - 1, (const unsigned char *)value)) )
+#define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;}
 
 int CmdHFEMVExec(const char *cmd) {
        bool activateField = false;
@@ -301,15 +335,22 @@ int CmdHFEMVExec(const char *cmd) {
        bool decodeTLV = false;
        bool forceSearch = false;
        enum TransactionType TrType = TT_MSD;
+       bool GenACGPO = false;
 
        uint8_t buf[APDU_RES_LEN] = {0};
        size_t len = 0;
        uint16_t sw = 0;
        uint8_t AID[APDU_AID_LEN] = {0};
        size_t AIDlen = 0;
+       uint8_t ODAiList[4096];
+       size_t ODAiListLen = 0;
        
        int res;
        
+       struct tlvdb *tlvSelect = NULL;
+       struct tlvdb *tlvRoot = NULL;
+       struct tlv *pdol_data_tlv = NULL;
+
        if (strlen(cmd) < 1) {
                UsageCmdHFEMVExec();
                return 0;
@@ -352,6 +393,10 @@ int CmdHFEMVExec(const char *cmd) {
                                case 'C':
                                        TrType = TT_CDA;
                                        break;
+                               case 'g':
+                               case 'G':
+                                       GenACGPO = true;
+                                       break;
                                default:
                                        PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
                                        return 1;
@@ -361,7 +406,6 @@ int CmdHFEMVExec(const char *cmd) {
 
        
        // init applets list tree
-       struct tlvdb *tlvSelect = NULL;
        const char *al = "Applets list";
        tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al);
 
@@ -385,8 +429,7 @@ int CmdHFEMVExec(const char *cmd) {
                PrintAndLog("\n* Search AID in list.");
                SetAPDULogging(false);
                if (EMVSearch(activateField, true, decodeTLV, tlvSelect)) {
-                       tlvdb_free(tlvSelect);
-                       return 2;
+                       dreturn(2);
                }
 
                // check search and select application id
@@ -395,14 +438,13 @@ int CmdHFEMVExec(const char *cmd) {
        }
        
        // Init TLV tree
-       struct tlvdb *tlvRoot = NULL;
        const char *alr = "Root terminal TLV tree";
        tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr);
        
        // check if we found EMV application on card
        if (!AIDlen) {
                PrintAndLog("Can't select AID. EMV AID not found");
-               return 2;
+               dreturn(2);
        }
        
        // Select
@@ -412,7 +454,7 @@ int CmdHFEMVExec(const char *cmd) {
        
        if (res) {      
                PrintAndLog("Can't select AID (%d). Exit...", res);
-               return 3;
+               dreturn(3);
        }
        
        if (decodeTLV)
@@ -422,25 +464,30 @@ int CmdHFEMVExec(const char *cmd) {
        PrintAndLog("\n* Init transaction parameters.");
 
     //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
+       char *qVSDC = "\x26\x00\x00\x00";
+       if (GenACGPO) {
+               qVSDC = "\x26\x80\x00\x00";
+       }
        switch(TrType) {
                case TT_MSD:
                        TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
                        break;
-               // not standart for contactless. just for test.
+               // not standard for contactless. just for test.
                case TT_VSDC:  
                        TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC
                        break;
                case TT_QVSDCMCHIP:
-                       TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
+                       TLV_ADD(0x9F66, qVSDC); // qVSDC
                        break;
                case TT_CDA:
-                       TLV_ADD(0x9F66, "\x86\x80\x00\x00"); // CDA
+                       TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled)
                        break;
                default:
                        TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
                        break;
        }
-    //9F02:(Amount, Authorised (Numeric)) len:6
+       
+    //9F02:(Amount, authorized (Numeric)) len:6
        TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
     //9F1A:(Terminal Country Code) len:2
        TLV_ADD(0x9F1A, "ru");
@@ -459,17 +506,17 @@ int CmdHFEMVExec(const char *cmd) {
        TLVPrintFromTLV(tlvRoot); // TODO delete!!!
        
        PrintAndLog("\n* Calc PDOL.");
-       struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
+       pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
        if (!pdol_data_tlv){
                PrintAndLog("ERROR: can't create PDOL TLV.");
-               return 4;
+               dreturn(4);
        }
        
        size_t pdol_data_tlv_data_len;
        unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len);
        if (!pdol_data_tlv_data) {
                PrintAndLog("ERROR: can't create PDOL data.");
-               return 4;
+               dreturn(4);
        }
        PrintAndLog("PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
 
@@ -477,11 +524,11 @@ int CmdHFEMVExec(const char *cmd) {
        res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
        
        free(pdol_data_tlv_data);
-       free(pdol_data_tlv);
+       //free(pdol_data_tlv); --- free on exit.
        
        if (res) {      
                PrintAndLog("GPO error(%d): %4x. Exit...", res, sw);
-               return 5;
+               dreturn(5);
        }
 
        // process response template format 1 [id:80  2b AIP + x4b AFL] and format 2 [id:77 TLV]
@@ -567,9 +614,23 @@ int CmdHFEMVExec(const char *cmd) {
                                        PrintAndLog("");
                                }
                                
+                               // Build Input list for Offline Data Authentication
+                               // EMV 4.3 book3 10.3, page 96
                                if (SFIoffline) {
-                                       // here will be offline records storing...
-                                       // dont foget: if (sfi < 11)
+                                       if (SFI < 11) {
+                                               const unsigned char *abuf = buf;
+                                               size_t elmlen = len;
+                                               struct tlv e;
+                                               if (tlv_parse_tl(&abuf, &elmlen, &e)) {
+                                                       memcpy(&ODAiList[ODAiListLen], &buf[len - elmlen], elmlen);
+                                                       ODAiListLen += elmlen;
+                                               } else {
+                                                       PrintAndLog("ERROR SFI[%02x]. Creating input list for Offline Data Authentication error.", SFI);
+                                               }
+                                       } else {
+                                               memcpy(&ODAiList[ODAiListLen], buf, len);
+                                               ODAiListLen += len;
+                                       }
                                }
                        }
                }
@@ -577,6 +638,13 @@ int CmdHFEMVExec(const char *cmd) {
                break;
        }       
        
+       // copy Input list for Offline Data Authentication
+       if (ODAiListLen) {
+               struct tlvdb *oda = tlvdb_fixed(0x21, ODAiListLen, ODAiList); // not a standard tag
+               tlvdb_add(tlvRoot, oda); 
+               PrintAndLog("* Input list for Offline Data Authentication added to TLV. len=%d \n", ODAiListLen);
+       }
+       
        // get AIP
        const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL);      
        uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100;
@@ -585,13 +653,13 @@ int CmdHFEMVExec(const char *cmd) {
        // SDA
        if (AIP & 0x0040) {
                PrintAndLog("\n* SDA");
-               trSDA(AID, AIDlen, tlvRoot);
+               trSDA(tlvRoot);
        }
 
        // DDA
        if (AIP & 0x0020) {
                PrintAndLog("\n* DDA");
-               
+               trDDA(decodeTLV, tlvRoot);
        }       
        
        // transaction check
@@ -644,11 +712,11 @@ int CmdHFEMVExec(const char *cmd) {
                        res = EMVGenerateChallenge(true, buf, sizeof(buf), &len, &sw, tlvRoot);
                        if (res) {
                                PrintAndLog("ERROR GetChallenge. APDU error %4x", sw);
-                               return 5;
+                               dreturn(6);
                        }
                        if (len < 4) {
                                PrintAndLog("ERROR GetChallenge. Wrong challenge length %d", len);
-                               return 5;
+                               dreturn(6);
                        }
                        
                        // ICC Dynamic Number
@@ -663,7 +731,7 @@ int CmdHFEMVExec(const char *cmd) {
                        struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
                        if (!cdol_data_tlv){
                                PrintAndLog("ERROR: can't create CDOL1 TLV.");
-                               return 4;
+                               dreturn(6);
                        }
                        PrintAndLog("CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
                        
@@ -671,17 +739,25 @@ int CmdHFEMVExec(const char *cmd) {
                        // EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
                        res = EMVAC(true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
                        
-                       free(cdol_data_tlv);
-                       
                        if (res) {      
                                PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw);
-                               return 5;
+                               dreturn(7);
                        }
                        
                        if (decodeTLV)
                                TLVPrintFromBuffer(buf, len);
                        
-                       PrintAndLog("* M/Chip transaction result:");
+                       // CDA
+                       PrintAndLog("\n* CDA:");
+                       struct tlvdb *ac_tlv = tlvdb_parse_multi(buf, len);
+                       res = trCDA(tlvRoot, ac_tlv, pdol_data_tlv, cdol_data_tlv);
+                       if (res) {      
+                               PrintAndLog("CDA error (%d)", res);
+                       }
+                       free(ac_tlv);
+                       free(cdol_data_tlv);
+                       
+                       PrintAndLog("\n* M/Chip transaction result:");
                        // 9F27: Cryptogram Information Data (CID)
                        const struct tlv *CID = tlvdb_get(tlvRoot, 0x9F27, NULL);
                        if (CID) {
@@ -743,7 +819,7 @@ int CmdHFEMVExec(const char *cmd) {
                                struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag
                                if (!udol_data_tlv){
                                        PrintAndLog("ERROR: can't create UDOL TLV.");
-                                       return 4;
+                                       dreturn(8);
                                }
 
                                PrintAndLog("UDOL data[%d]: %s", udol_data_tlv->len, sprint_hex(udol_data_tlv->value, udol_data_tlv->len));
@@ -753,24 +829,27 @@ int CmdHFEMVExec(const char *cmd) {
                                res = MSCComputeCryptoChecksum(true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
                                if (res) {
                                        PrintAndLog("ERROR Compute Crypto Checksum. APDU error %4x", sw);
-                                       return 5;
+                                       free(udol_data_tlv);
+                                       dreturn(9);
                                }
                                
                                if (decodeTLV) {
                                        TLVPrintFromBuffer(buf, len);
                                        PrintAndLog("");
                                }
+                               free(udol_data_tlv);
 
                        }
                } else {
                        PrintAndLog("ERROR MSD: Track2 data not found.");
                }
        }
-       
+
        // DropField
        DropField();
        
        // Destroy TLV's
+       free(pdol_data_tlv);
        tlvdb_free(tlvSelect);
        tlvdb_free(tlvRoot);
 
@@ -779,13 +858,23 @@ int CmdHFEMVExec(const char *cmd) {
        return 0;
 }
 
+int CmdHFEMVTest(const char *cmd) {
+       return ExecuteCryptoTests(true);
+}
+
 int CmdHelp(const char *Cmd);
 static command_t CommandTable[] =  {
-       {"help",        CmdHelp,                1,      "This help"},
-       {"exec",        CmdHFEMVExec,   0,      "Executes EMV contactless transaction."},
-       {"pse",         CmdHFEMVPPSE,   0,      "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."},
-       {"search",      CmdHFEMVSearch, 0,      "Try to select all applets from applets list and print installed applets."},
-       {"select",      CmdHFEMVSelect, 0,      "Select applet."},
+       {"help",                CmdHelp,                                                1,      "This help"},
+       {"exec",                CmdHFEMVExec,                                   0,      "Executes EMV contactless transaction."},
+       {"pse",                 CmdHFEMVPPSE,                                   0,      "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."},
+       {"search",              CmdHFEMVSearch,                                 0,      "Try to select all applets from applets list and print installed applets."},
+       {"select",              CmdHFEMVSelect,                                 0,      "Select applet."},
+       {"gpo",                 CmdHFEMVGPO,                                    0,      "Execute GetProcessingOptions."},
+       {"readrec",             CmdHFEMVReadRecord,                             0,      "Read files from card."},
+       {"genac",               CmdHFEMVAC,                                             0,      "Generate ApplicationCryptogram."},
+       {"challenge",   CmdHFEMVGenerateChallenge,              0,      "Generate challenge."},
+       {"intauth",             CmdHFEMVInternalAuthenticate,   0,      "Internal authentication."},
+       {"test",                CmdHFEMVTest,   0,      "Crypto logic test."},
        {NULL, NULL, 0, NULL}
 };
 
Impressum, Datenschutz