From 47d954c79ff91cb0f9efa5d9f20400640636dd05 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 3 Dec 2018 18:16:25 +0200 Subject: [PATCH 01/11] move emv commands to root --- client/cmdhf.c | 1 - client/cmdhf.h | 1 - client/cmdmain.c | 1 + client/cmdmain.h | 1 + client/emv/cmdemv.c | 64 ++++++++++++++++++++++----------------------- client/emv/cmdemv.h | 16 ++++++------ 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/client/cmdhf.c b/client/cmdhf.c index 65b6bd33d..cb4e424da 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -112,7 +112,6 @@ static command_t CommandTable[] = { {"14b", CmdHF14B, 1, "{ ISO14443B RFIDs... }"}, {"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"}, {"epa", CmdHFEPA, 1, "{ German Identification Card... }"}, - {"emv", CmdHFEMV, 1, "{ EMV RFIDs... }"}, {"felica", CmdHFFelica, 1, "{ ISO18092 / Felica RFIDs... }"}, {"legic", CmdHFLegic, 1, "{ LEGIC RFIDs... }"}, {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, diff --git a/client/cmdhf.h b/client/cmdhf.h index bd191ead5..b2dcc10f1 100644 --- a/client/cmdhf.h +++ b/client/cmdhf.h @@ -30,7 +30,6 @@ #include "cmdhfmfdes.h" // DESFIRE #include "cmdhftopaz.h" // TOPAZ #include "cmdhffelica.h" // ISO18092 / FeliCa -#include "emv/cmdemv.h" // EMV #include "cmdhffido.h" // FIDO authenticators #include "cmdtrace.h" // trace list diff --git a/client/cmdmain.c b/client/cmdmain.c index 85d7f19c3..5b147e76a 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -22,6 +22,7 @@ static command_t CommandTable[] = { {"hf", CmdHF, 1, "{ High Frequency commands... }"}, {"hw", CmdHW, 1, "{ Hardware commands... }"}, {"lf", CmdLF, 1, "{ Low Frequency commands... }"}, + {"emv", CmdEMV, 1, "{ EMV iso14443 and iso7816... }"}, {"rem", CmdRem, 1, "{ Add text to row in log file }"}, {"reveng", CmdRev, 1, "{ Crc calculations from the software reveng 1.53... }"}, {"script", CmdScript, 1, "{ Scripting commands }"}, diff --git a/client/cmdmain.h b/client/cmdmain.h index 74804300d..629cd98af 100644 --- a/client/cmdmain.h +++ b/client/cmdmain.h @@ -31,6 +31,7 @@ #include "cmdscript.h" #include "cmdcrc.h" #include "cmdanalyse.h" +#include "emv/cmdemv.h" // EMV #ifdef WITH_FLASH #include "cmdflashmem.h" // rdv40 flashmem commands diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 5a64892c4..fef34a863 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -40,7 +40,7 @@ void ParamLoadDefaults(struct tlvdb *tlvRoot) { TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC } -int CmdHFEMVSelect(const char *cmd) { +int CmdEMVSelect(const char *cmd) { uint8_t data[APDU_AID_LEN] = {0}; int datalen = 0; @@ -86,7 +86,7 @@ int CmdHFEMVSelect(const char *cmd) { return 0; } -int CmdHFEMVSearch(const char *cmd) { +int CmdEMVSearch(const char *cmd) { CLIParserInit("hf emv search", "Tries to select all applets from applet list:\n", @@ -131,7 +131,7 @@ int CmdHFEMVSearch(const char *cmd) { return 0; } -int CmdHFEMVPPSE(const char *cmd) { +int CmdEMVPPSE(const char *cmd) { CLIParserInit("hf emv pse", "Executes PSE/PPSE select command. It returns list of applet on the card:\n", @@ -181,7 +181,7 @@ int CmdHFEMVPPSE(const char *cmd) { return 0; } -int CmdHFEMVGPO(const char *cmd) { +int CmdEMVGPO(const char *cmd) { uint8_t data[APDU_RES_LEN] = {0}; int datalen = 0; @@ -276,7 +276,7 @@ int CmdHFEMVGPO(const char *cmd) { return 0; } -int CmdHFEMVReadRecord(const char *cmd) { +int CmdEMVReadRecord(const char *cmd) { uint8_t data[APDU_RES_LEN] = {0}; int datalen = 0; @@ -326,7 +326,7 @@ int CmdHFEMVReadRecord(const char *cmd) { return 0; } -int CmdHFEMVAC(const char *cmd) { +int CmdEMVAC(const char *cmd) { uint8_t data[APDU_RES_LEN] = {0}; int datalen = 0; @@ -437,7 +437,7 @@ int CmdHFEMVAC(const char *cmd) { return 0; } -int CmdHFEMVGenerateChallenge(const char *cmd) { +int CmdEMVGenerateChallenge(const char *cmd) { CLIParserInit("hf emv challenge", "Executes Generate Challenge command. It returns 4 or 8-byte random number from card.\nNeeds a EMV applet to be selected and GPO to be executed.", @@ -477,7 +477,7 @@ int CmdHFEMVGenerateChallenge(const char *cmd) { return 0; } -int CmdHFEMVInternalAuthenticate(const char *cmd) { +int CmdEMVInternalAuthenticate(const char *cmd) { uint8_t data[APDU_RES_LEN] = {0}; int datalen = 0; @@ -631,7 +631,7 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, } } -int CmdHFEMVExec(const char *cmd) { +int CmdEMVExec(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; @@ -1071,7 +1071,7 @@ int CmdHFEMVExec(const char *cmd) { return 0; } -int CmdHFEMVScan(const char *cmd) { +int CmdEMVScan(const char *cmd) { uint8_t AID[APDU_AID_LEN] = {0}; size_t AIDlen = 0; uint8_t buf[APDU_RES_LEN] = {0}; @@ -1409,46 +1409,46 @@ int usage_emv_getrnd(void){ } //retrieve the UN number from a terminal -int CmdHfEMVGetrng(const char *Cmd) { +int CmdEMVGetrng(const char *Cmd) { char cmdp = param_getchar(Cmd, 0); if ( cmdp == 'h' || cmdp == 'H') return usage_emv_getrnd(); return 0; } -int CmdHfEMVList(const char *Cmd) { +int CmdEMVList(const char *Cmd) { return CmdTraceList("7816"); } -int CmdHFEMVTest(const char *cmd) { +int CmdEMVTest(const char *cmd) { return ExecuteCryptoTests(true); } 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."}, - {"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."}, - {"scan", CmdHFEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."}, - {"test", CmdHFEMVTest, 0, "Crypto logic test."}, + {"help", CmdHelp, 1, "This help"}, + {"exec", CmdEMVExec, 0, "Executes EMV contactless transaction."}, + {"pse", CmdEMVPPSE, 0, "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."}, + {"search", CmdEMVSearch, 0, "Try to select all applets from applets list and print installed applets."}, + {"select", CmdEMVSelect, 0, "Select applet."}, + {"gpo", CmdEMVGPO, 0, "Execute GetProcessingOptions."}, + {"readrec", CmdEMVReadRecord, 0, "Read files from card."}, + {"genac", CmdEMVAC, 0, "Generate ApplicationCryptogram."}, + {"challenge", CmdEMVGenerateChallenge, 0, "Generate challenge."}, + {"intauth", CmdEMVInternalAuthenticate, 0, "Internal authentication."}, + {"scan", CmdEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."}, + {"test", CmdEMVTest, 0, "Crypto logic test."}, /* - {"getrng", CmdHfEMVGetrng, 0, "get random number from terminal"}, - {"eload", CmdHfEmvELoad, 0, "load EMV tag into device"}, - {"dump", CmdHfEmvDump, 0, "dump EMV tag values"}, - {"sim", CmdHfEmvSim, 0, "simulate EMV tag"}, - {"clone", CmdHfEmvClone, 0, "clone an EMV tag"}, + {"getrng", CmdEMVGetrng, 0, "get random number from terminal"}, + {"eload", CmdEmvELoad, 0, "load EMV tag into device"}, + {"dump", CmdEmvDump, 0, "dump EMV tag values"}, + {"sim", CmdEmvSim, 0, "simulate EMV tag"}, + {"clone", CmdEmvClone, 0, "clone an EMV tag"}, */ - {"list", CmdHfEMVList, 0, "[Deprecated] List ISO7816 history"}, + {"list", CmdEMVList, 0, "[Deprecated] List ISO7816 history"}, {NULL, NULL, 0, NULL} }; -int CmdHFEMV(const char *Cmd) { +int CmdEMV(const char *Cmd) { clearCommandBuffer(); CmdsParse(CommandTable, Cmd); return 0; diff --git a/client/emv/cmdemv.h b/client/emv/cmdemv.h index 76fb89c4b..b4397fd15 100644 --- a/client/emv/cmdemv.h +++ b/client/emv/cmdemv.h @@ -26,13 +26,13 @@ #include "emvcore.h" #include "apduinfo.h" -int CmdHFEMV(const char *Cmd); +int CmdEMV(const char *Cmd); -extern int CmdHFEMVSelect(const char *cmd); -extern int CmdHFEMVSearch(const char *cmd); -extern int CmdHFEMVPPSE(const char *cmd); -extern int CmdHFEMVExec(const char *cmd); -extern int CmdHfEMVGetrng(const char *Cmd); -extern int CmdHfEMVList(const char *Cmd); +extern int CmdEMVSelect(const char *cmd); +extern int CmdEMVSearch(const char *cmd); +extern int CmdEMVPPSE(const char *cmd); +extern int CmdEMVExec(const char *cmd); +extern int CmdEMVGetrng(const char *Cmd); +extern int CmdEMVList(const char *Cmd); -#endif \ No newline at end of file +#endif From 7fd3536b295cbd220fc478f8028bb85db1bb292a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 3 Dec 2018 18:16:39 +0200 Subject: [PATCH 02/11] fix appveyor --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index a38ff647b..1ebbfea5c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -304,7 +304,7 @@ test_script: #proxmark crypto tests - ExecTest "hf emv test" "hf emv test" {bash -lc "cd ~/client;./proxmark3 comx -c 'hf emv test'"} "Tests ?OK" + ExecTest "emv test" "emv test" {bash -lc "cd ~/client;./proxmark3 comx -c 'emv test'"} "Tests ?OK" if ($global:TestsPassed) { From e8671e6c18f270b9aa5c494827c85a338db0b489 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 3 Dec 2018 18:21:05 +0200 Subject: [PATCH 03/11] fix emv command's help --- client/emv/cmdemv.c | 64 ++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index fef34a863..29f26b7a7 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -44,9 +44,9 @@ int CmdEMVSelect(const char *cmd) { uint8_t data[APDU_AID_LEN] = {0}; int datalen = 0; - CLIParserInit("hf emv select", + CLIParserInit("emv 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"); + "Usage:\n\temv select -s a00000000101 -> select card, select applet\n\temv select -st a00000000101 -> select card, select applet, show result in TLV\n"); void* argtable[] = { arg_param_begin, @@ -88,9 +88,9 @@ int CmdEMVSelect(const char *cmd) { int CmdEMVSearch(const char *cmd) { - CLIParserInit("hf emv search", + CLIParserInit("emv search", "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"); + "Usage:\n\temv search -s -> select card and search\n\temv search -st -> select card, search and show result in TLV\n"); void* argtable[] = { arg_param_begin, @@ -133,9 +133,9 @@ int CmdEMVSearch(const char *cmd) { int CmdEMVPPSE(const char *cmd) { - CLIParserInit("hf emv pse", + CLIParserInit("emv 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"); + "Usage:\n\temv pse -s1 -> select, get pse\n\temv pse -st2 -> select, get ppse, show result in TLV\n"); void* argtable[] = { arg_param_begin, @@ -185,11 +185,11 @@ int CmdEMVGPO(const char *cmd) { uint8_t data[APDU_RES_LEN] = {0}; int datalen = 0; - CLIParserInit("hf emv gpo", + CLIParserInit("emv gpo", "Executes Get Processing Options command. It returns data in TLV format (0x77 - format2) or plain format (0x80 - format1).\nNeeds a EMV applet to be selected.", - "Usage:\n\thf emv gpo -k -> execute GPO\n" - "\thf emv gpo -t 01020304 -> execute GPO with 4-byte PDOL data, show result in TLV\n" - "\thf emv gpo -pmt 9F 37 04 -> load params from file, make PDOL data from PDOL, execute GPO with PDOL, show result in TLV\n"); + "Usage:\n\temv gpo -k -> execute GPO\n" + "\temv gpo -t 01020304 -> execute GPO with 4-byte PDOL data, show result in TLV\n" + "\temv gpo -pmt 9F 37 04 -> load params from file, make PDOL data from PDOL, execute GPO with PDOL, show result in TLV\n"); void* argtable[] = { arg_param_begin, @@ -280,9 +280,9 @@ int CmdEMVReadRecord(const char *cmd) { uint8_t data[APDU_RES_LEN] = {0}; int datalen = 0; - CLIParserInit("hf emv readrec", + CLIParserInit("emv 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.", - "Usage:\n\thf emv readrec -k 0101 -> read file SFI=01, SFIrec=01\n\thf emv readrec -kt 0201-> read file 0201 and show result in TLV\n"); + "Usage:\n\temv readrec -k 0101 -> read file SFI=01, SFIrec=01\n\temv readrec -kt 0201-> read file 0201 and show result in TLV\n"); void* argtable[] = { arg_param_begin, @@ -330,12 +330,12 @@ int CmdEMVAC(const char *cmd) { uint8_t data[APDU_RES_LEN] = {0}; int datalen = 0; - CLIParserInit("hf emv genac", + CLIParserInit("emv genac", "Generate Application Cryptogram command. It returns data in TLV format .\nNeeds a EMV applet to be selected and GPO to be executed.", - "Usage:\n\thf emv genac -k 0102 -> generate AC with 2-byte CDOLdata and keep field ON after command\n" - "\thf emv genac -t 01020304 -> generate AC with 4-byte CDOL data, show result in TLV\n" - "\thf emv genac -Daac 01020304 -> generate AC with 4-byte CDOL data and terminal decision 'declined'\n" - "\thf emv genac -pmt 9F 37 04 -> load params from file, make CDOL data from CDOL, generate AC with CDOL, show result in TLV"); + "Usage:\n\temv genac -k 0102 -> generate AC with 2-byte CDOLdata and keep field ON after command\n" + "\temv genac -t 01020304 -> generate AC with 4-byte CDOL data, show result in TLV\n" + "\temv genac -Daac 01020304 -> generate AC with 4-byte CDOL data and terminal decision 'declined'\n" + "\temv genac -pmt 9F 37 04 -> load params from file, make CDOL data from CDOL, generate AC with CDOL, show result in TLV"); void* argtable[] = { arg_param_begin, @@ -439,9 +439,9 @@ int CmdEMVAC(const char *cmd) { int CmdEMVGenerateChallenge(const char *cmd) { - CLIParserInit("hf emv challenge", + CLIParserInit("emv challenge", "Executes Generate Challenge command. It returns 4 or 8-byte random number from card.\nNeeds a EMV applet to be selected and GPO to be executed.", - "Usage:\n\thf emv challenge -> get challenge\n\thf emv challenge -k -> get challenge, keep fileld ON\n"); + "Usage:\n\temv challenge -> get challenge\n\temv challenge -k -> get challenge, keep fileld ON\n"); void* argtable[] = { arg_param_begin, @@ -481,11 +481,11 @@ int CmdEMVInternalAuthenticate(const char *cmd) { uint8_t data[APDU_RES_LEN] = {0}; int datalen = 0; - CLIParserInit("hf emv intauth", + CLIParserInit("emv intauth", "Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\nNeeds a EMV applet to be selected and GPO to be executed.", - "Usage:\n\thf emv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n" - "\thf emv intauth -t 01020304 -> execute Internal Authenticate with 4-byte DDOL data, show result in TLV\n" - "\thf emv intauth -pmt 9F 37 04 -> load params from file, make DDOL data from DDOL, Internal Authenticate with DDOL, show result in TLV"); + "Usage:\n\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n" + "\temv intauth -t 01020304 -> execute Internal Authenticate with 4-byte DDOL data, show result in TLV\n" + "\temv intauth -pmt 9F 37 04 -> load params from file, make DDOL data from DDOL, Internal Authenticate with DDOL, show result in TLV"); void* argtable[] = { arg_param_begin, @@ -646,10 +646,10 @@ int CmdEMVExec(const char *cmd) { struct tlvdb *tlvRoot = NULL; struct tlv *pdol_data_tlv = NULL; - CLIParserInit("hf emv exec", + CLIParserInit("emv exec", "Executes EMV contactless transaction", - "Usage:\n\thf emv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n" - "\thf emv exec -satc -> select card, execute CDA transaction, show APDU and TLV\n"); + "Usage:\n\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n" + "\temv exec -satc -> select card, execute CDA transaction, show APDU and TLV\n"); void* argtable[] = { arg_param_begin, @@ -1081,11 +1081,11 @@ int CmdEMVScan(const char *cmd) { json_t *root; json_error_t error; - CLIParserInit("hf emv scan", + CLIParserInit("emv scan", "Scan EMV card and save it contents to a file.", "It executes EMV contactless transaction and saves result to a file which can be used for emulation\n" - "Usage:\n\thf emv scan -at -> scan MSD transaction mode and show APDU and TLV\n" - "\thf emv scan -c -> scan CDA transaction mode\n"); + "Usage:\n\temv scan -at -> scan MSD transaction mode and show APDU and TLV\n" + "\temv scan -c -> scan CDA transaction mode\n"); void* argtable[] = { arg_param_begin, @@ -1160,7 +1160,7 @@ int CmdEMVScan(const char *cmd) { return 2; } - JsonSaveStr(root, "$.File.Created", "proxmark3 `hf emv scan`"); + JsonSaveStr(root, "$.File.Created", "proxmark3 `emv scan`"); JsonSaveStr(root, "$.Card.Communication", "iso14443-4a"); JsonSaveBufAsHex(root, "$.Card.UID", (uint8_t *)&card.uid, card.uidlen); @@ -1399,12 +1399,12 @@ int CmdEMVScan(const char *cmd) { int usage_emv_getrnd(void){ PrintAndLogEx(NORMAL, "retrieve the UN number from a terminal"); - PrintAndLogEx(NORMAL, "Usage: hf emv getrnd [h]"); + PrintAndLogEx(NORMAL, "Usage: emv getrnd [h]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv getrnd"); + PrintAndLogEx(NORMAL, " emv getrnd"); return 0; } From 2245673262aea9d9d8935bae2a0ac6985b31d628 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 3 Dec 2018 18:46:11 +0200 Subject: [PATCH 04/11] fix search big loop --- client/emv/emvcore.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index f2acda25c..b0a474fc7 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -260,6 +260,10 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool Includ if (APDULogging) PrintAndLogEx(NORMAL, "<<<< %s", sprint_hex(Result, *ResultLen)); + if (*ResultLen < 2) { + return 200; + } + *ResultLen -= 2; isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1]; if (sw) @@ -400,8 +404,8 @@ int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvd if (++retrycnt < 3){ i--; } else { - // card select error, proxmark error - if (res == 1) { + // (1) - card select error, proxmark error OR (200) - result length = 0 + if (res == 1 || res == 200) { PrintAndLogEx(WARNING, "Exit..."); return 1; } From 01a10bade75b75afd0385ef96cb34a1531013bb6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 3 Dec 2018 18:49:54 +0200 Subject: [PATCH 05/11] Mastercard compute cryptographic checksum result will print anyway --- client/emv/cmdemv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 29f26b7a7..7308b8335 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -1048,10 +1048,10 @@ int CmdEMVExec(const char *cmd) { dreturn(9); } - if (decodeTLV) { - TLVPrintFromBuffer(buf, len); - PrintAndLogEx(NORMAL, ""); - } + // Mastercard compute cryptographic checksum result + TLVPrintFromBuffer(buf, len); + PrintAndLogEx(NORMAL, ""); + free(udol_data_tlv); } From 4c7e5757f3b3b656be9682bf6d9984ca47655890 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Mon, 3 Dec 2018 19:29:31 +0200 Subject: [PATCH 06/11] added channel parameter --- client/emv/cmdemv.c | 98 +++++++++++++++++++++++++++++------------- client/emv/emvcore.c | 72 +++++++++++++++++-------------- client/emv/emvcore.h | 29 +++++++------ client/fido/fidocore.c | 6 +-- 4 files changed, 128 insertions(+), 77 deletions(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 7308b8335..4ab8a8a56 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -54,6 +54,7 @@ int CmdEMVSelect(const char *cmd) { 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_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), arg_strx0(NULL, NULL, "", NULL), arg_param_end }; @@ -63,7 +64,10 @@ int CmdEMVSelect(const char *cmd) { bool leaveSignalON = arg_get_lit(2); bool APDULogging = arg_get_lit(3); bool decodeTLV = arg_get_lit(4); - CLIGetHexWithReturn(5, data, &datalen); + EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(5)) + channel = ECC_CONTACT; + CLIGetHexWithReturn(6, data, &datalen); CLIParserFree(); SetAPDULogging(APDULogging); @@ -72,7 +76,7 @@ int CmdEMVSelect(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - int res = EMVSelect(activateField, leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); + int res = EMVSelect(channel, activateField, leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); if (sw) PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); @@ -98,6 +102,7 @@ int CmdEMVSearch(const char *cmd) { 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_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -106,6 +111,9 @@ int CmdEMVSearch(const char *cmd) { bool leaveSignalON = arg_get_lit(2); bool APDULogging = arg_get_lit(3); bool decodeTLV = arg_get_lit(4); + EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(5)) + channel = ECC_CONTACT; CLIParserFree(); SetAPDULogging(APDULogging); @@ -114,7 +122,7 @@ int CmdEMVSearch(const char *cmd) { const char *al = "Applets list"; t = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); - if (EMVSearch(activateField, leaveSignalON, decodeTLV, t)) { + if (EMVSearch(channel, activateField, leaveSignalON, decodeTLV, t)) { tlvdb_free(t); return 2; } @@ -145,6 +153,7 @@ int CmdEMVPPSE(const char *cmd) { 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_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -158,6 +167,9 @@ int CmdEMVPPSE(const char *cmd) { PSENum = 2; bool APDULogging = arg_get_lit(5); bool decodeTLV = arg_get_lit(6); + EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(7)) + channel = ECC_CONTACT; CLIParserFree(); SetAPDULogging(APDULogging); @@ -166,7 +178,7 @@ int CmdEMVPPSE(const char *cmd) { 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 = EMVSelectPSE(channel, activateField, leaveSignalON, PSENum, buf, sizeof(buf), &len, &sw); if (sw) PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); @@ -198,6 +210,7 @@ int CmdEMVGPO(const char *cmd) { arg_lit0("mM", "make", "make PDOLdata from PDOL (tag 9F38) and parameters (by default uses default parameters)"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("tT", "tlv", "TLV decode results of selected applets"), + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), arg_strx0(NULL, NULL, "", NULL), arg_param_end }; @@ -208,7 +221,10 @@ int CmdEMVGPO(const char *cmd) { bool dataMakeFromPDOL = arg_get_lit(3); bool APDULogging = arg_get_lit(4); bool decodeTLV = arg_get_lit(5); - CLIGetHexWithReturn(6, data, &datalen); + EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(6)) + channel = ECC_CONTACT; + CLIGetHexWithReturn(7, data, &datalen); CLIParserFree(); SetAPDULogging(APDULogging); @@ -258,7 +274,7 @@ int CmdEMVGPO(const char *cmd) { 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); + int res = EMVGPO(channel, leaveSignalON, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); if (pdol_data_tlv != &data_tlv) free(pdol_data_tlv); @@ -289,6 +305,7 @@ int CmdEMVReadRecord(const char *cmd) { 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_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), arg_strx1(NULL, NULL, "", NULL), arg_param_end }; @@ -297,7 +314,10 @@ int CmdEMVReadRecord(const char *cmd) { bool leaveSignalON = arg_get_lit(1); bool APDULogging = arg_get_lit(2); bool decodeTLV = arg_get_lit(3); - CLIGetHexWithReturn(4, data, &datalen); + EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(4)) + channel = ECC_CONTACT; + CLIGetHexWithReturn(5, data, &datalen); CLIParserFree(); if (datalen != 2) { @@ -311,7 +331,7 @@ int CmdEMVReadRecord(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - int res = EMVReadRecord(leaveSignalON, data[0], data[1], buf, sizeof(buf), &len, &sw, NULL); + int res = EMVReadRecord(channel, leaveSignalON, data[0], data[1], buf, sizeof(buf), &len, &sw, NULL); if (sw) PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); @@ -346,6 +366,7 @@ int CmdEMVAC(const char *cmd) { arg_lit0("mM", "make", "make CDOLdata from CDOL (tag 8C and 8D) and parameters (by default uses default parameters)"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("tT", "tlv", "TLV decode results of selected applets"), + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), arg_strx1(NULL, NULL, "", NULL), arg_param_end }; @@ -375,7 +396,10 @@ int CmdEMVAC(const char *cmd) { bool dataMakeFromCDOL = arg_get_lit(5); bool APDULogging = arg_get_lit(6); bool decodeTLV = arg_get_lit(7); - CLIGetHexWithReturn(8, data, &datalen); + EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(8)) + channel = ECC_CONTACT; + CLIGetHexWithReturn(9, data, &datalen); CLIParserFree(); SetAPDULogging(APDULogging); @@ -419,7 +443,7 @@ int CmdEMVAC(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - int res = EMVAC(leaveSignalON, termDecision, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); + int res = EMVAC(channel, leaveSignalON, termDecision, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); if (cdol_data_tlv != &data_tlv) free(cdol_data_tlv); @@ -447,12 +471,16 @@ int CmdEMVGenerateChallenge(const char *cmd) { arg_param_begin, arg_lit0("kK", "keep", "keep field ON for next command"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); bool leaveSignalON = arg_get_lit(1); bool APDULogging = arg_get_lit(2); + EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(3)) + channel = ECC_CONTACT; CLIParserFree(); SetAPDULogging(APDULogging); @@ -461,7 +489,7 @@ int CmdEMVGenerateChallenge(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - int res = EMVGenerateChallenge(leaveSignalON, buf, sizeof(buf), &len, &sw, NULL); + int res = EMVGenerateChallenge(channel, leaveSignalON, buf, sizeof(buf), &len, &sw, NULL); if (sw) PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); @@ -494,6 +522,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) { arg_lit0("mM", "make", "make DDOLdata from DDOL (tag 9F49) and parameters (by default uses default parameters)"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("tT", "tlv", "TLV decode results of selected applets"), + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), arg_strx1(NULL, NULL, "", NULL), arg_param_end }; @@ -504,7 +533,10 @@ int CmdEMVInternalAuthenticate(const char *cmd) { bool dataMakeFromDDOL = arg_get_lit(3); bool APDULogging = arg_get_lit(4); bool decodeTLV = arg_get_lit(5); - CLIGetHexWithReturn(6, data, &datalen); + EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(6)) + channel = ECC_CONTACT; + CLIGetHexWithReturn(7, data, &datalen); CLIParserFree(); SetAPDULogging(APDULogging); @@ -548,7 +580,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - int res = EMVInternalAuthenticate(leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); + int res = EMVInternalAuthenticate(channel, leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); if (ddol_data_tlv != &data_tlv) free(ddol_data_tlv); @@ -663,6 +695,7 @@ int CmdEMVExec(const char *cmd) { arg_lit0("cC", "qvsdccda", "Transaction type - qVSDC or M/Chip plus CDA (SDAD generation)."), arg_lit0("xX", "vsdc", "Transaction type - VSDC. For test only. Not a standart behavior."), arg_lit0("gG", "acgpo", "VISA. generate AC from GPO."), + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -682,6 +715,9 @@ int CmdEMVExec(const char *cmd) { TrType = TT_VSDC; bool GenACGPO = arg_get_lit(9); + EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(10)) + channel = ECC_CONTACT; CLIParserFree(); SetAPDULogging(showAPDU); @@ -696,7 +732,7 @@ int CmdEMVExec(const char *cmd) { // PPSE PrintAndLogEx(NORMAL, "\n* PPSE."); SetAPDULogging(showAPDU); - res = EMVSearchPSE(activateField, true, decodeTLV, tlvSelect); + res = EMVSearchPSE(channel, activateField, true, decodeTLV, tlvSelect); // check PPSE and select application id if (!res) { @@ -709,7 +745,7 @@ int CmdEMVExec(const char *cmd) { if (!AIDlen) { PrintAndLogEx(NORMAL, "\n* Search AID in list."); SetAPDULogging(false); - if (EMVSearch(activateField, true, decodeTLV, tlvSelect)) { + if (EMVSearch(channel, activateField, true, decodeTLV, tlvSelect)) { dreturn(2); } @@ -731,7 +767,7 @@ int CmdEMVExec(const char *cmd) { // Select PrintAndLogEx(NORMAL, "\n* Selecting AID:%s", sprint_hex_inrow(AID, AIDlen)); SetAPDULogging(showAPDU); - res = EMVSelect(false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); + res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLogEx(WARNING, "Can't select AID (%d). Exit...", res); @@ -762,7 +798,7 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(NORMAL, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); PrintAndLogEx(NORMAL, "\n* GPO."); - res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); + res = EMVGPO(channel, 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 on exit. @@ -818,7 +854,7 @@ int CmdEMVExec(const char *cmd) { for (int n = SFIstart; n <= SFIend; n++) { PrintAndLogEx(NORMAL, "* * * SFI[%02x] %d", SFI, n); - res = EMVReadRecord(true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); + res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLogEx(WARNING, "Error SFI[%02x]. APDU error %4x", SFI, sw); continue; @@ -874,7 +910,7 @@ int CmdEMVExec(const char *cmd) { // DDA if (AIP & 0x0020) { PrintAndLogEx(NORMAL, "\n* DDA"); - trDDA(decodeTLV, tlvRoot); + trDDA(channel, decodeTLV, tlvRoot); } // transaction check @@ -924,7 +960,7 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(NORMAL, "\n--> Mastercard M/Chip transaction."); PrintAndLogEx(NORMAL, "* * Generate challenge"); - res = EMVGenerateChallenge(true, buf, sizeof(buf), &len, &sw, tlvRoot); + res = EMVGenerateChallenge(channel, true, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLogEx(WARNING, "Error GetChallenge. APDU error %4x", sw); dreturn(6); @@ -952,7 +988,7 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(NORMAL, "* * AC1"); // 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); + res = EMVAC(channel, 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); if (res) { PrintAndLogEx(NORMAL, "AC1 error(%d): %4x. Exit...", res, sw); @@ -1041,7 +1077,7 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(NORMAL, "\n* Mastercard compute cryptographic checksum(UDOL)"); - res = MSCComputeCryptoChecksum(true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); + res = MSCComputeCryptoChecksum(channel, true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLogEx(WARNING, "Error Compute Crypto Checksum. APDU error %4x", sw); free(udol_data_tlv); @@ -1099,6 +1135,7 @@ int CmdEMVScan(const char *cmd) { arg_lit0("xX", "vsdc", "Transaction type - VSDC. For test only. Not a standart behavior."), arg_lit0("gG", "acgpo", "VISA. generate AC from GPO."), arg_lit0("mM", "merge", "Merge output file with card's data. (warning: the file may be corrupted!)"), + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), arg_str1(NULL, NULL, "output.json", "JSON output file name"), arg_param_end }; @@ -1119,10 +1156,13 @@ int CmdEMVScan(const char *cmd) { bool GenACGPO = arg_get_lit(9); bool MergeJSON = arg_get_lit(10); + EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(11)) + channel = ECC_CONTACT; uint8_t relfname[250] ={0}; char *crelfname = (char *)relfname; int relfnamelen = 0; - CLIGetStrWithReturn(11, relfname, &relfnamelen); + CLIGetStrWithReturn(12, relfname, &relfnamelen); CLIParserFree(); SetAPDULogging(showAPDU); @@ -1174,7 +1214,7 @@ int CmdEMVScan(const char *cmd) { // EMV PPSE PrintAndLogEx(NORMAL, "--> PPSE."); - res = EMVSelectPSE(true, true, 2, buf, sizeof(buf), &len, &sw); + res = EMVSelectPSE(channel, true, true, 2, buf, sizeof(buf), &len, &sw); if (!res && sw == 0x9000){ if (decodeTLV) @@ -1191,7 +1231,7 @@ int CmdEMVScan(const char *cmd) { tlvdb_free(fci); } - res = EMVSearchPSE(false, true, decodeTLV, tlvSelect); + res = EMVSearchPSE(channel, false, true, decodeTLV, tlvSelect); // check PPSE and select application id if (!res) { @@ -1200,7 +1240,7 @@ int CmdEMVScan(const char *cmd) { // EMV SEARCH with AID list SetAPDULogging(false); PrintAndLogEx(NORMAL, "--> AID search."); - if (EMVSearch(false, true, decodeTLV, tlvSelect)) { + if (EMVSearch(channel, false, true, decodeTLV, tlvSelect)) { PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit..."); tlvdb_free(tlvSelect); DropField(); @@ -1233,7 +1273,7 @@ int CmdEMVScan(const char *cmd) { PrintAndLogEx(NORMAL, "\n-->Selecting AID:%s.", sprint_hex_inrow(AID, AIDlen)); SetAPDULogging(showAPDU); - res = EMVSelect(false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); + res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res); @@ -1281,7 +1321,7 @@ int CmdEMVScan(const char *cmd) { PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); PrintAndLogEx(INFO, "-->GPO."); - res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); + res = EMVGPO(channel, 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); @@ -1340,7 +1380,7 @@ int CmdEMVScan(const char *cmd) { for(int n = SFIstart; n <= SFIend; n++) { PrintAndLogEx(INFO, "---->SFI[%02x] %d", SFI, n); - res = EMVReadRecord(true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); + res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLogEx(ERR, "SFI[%02x]. APDU error %4x", SFI, sw); continue; diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index b0a474fc7..aa68b6cdf 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -230,12 +230,13 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) { return tlvdb_fixed(0x02, dCVVlen, dCVV); } -int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { +int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { uint8_t data[APDU_RES_LEN] = {0}; *ResultLen = 0; if (sw) *sw = 0; uint16_t isw = 0; + int res = 0; if (ActivateField) { DropField(); @@ -250,11 +251,16 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool Includ if (APDULogging) PrintAndLogEx(NORMAL, ">>>> %s", sprint_hex(data, (IncludeLe?6:5) + apdu.Lc)); - // 6 byes + data = INS + CLA + P1 + P2 + Lc + + Le(?IncludeLe) - int res = ExchangeAPDU14a(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); - - if (res) { - return res; + switch(channel) { + case ECC_CONTACTLESS: + // 6 byes + data = INS + CLA + P1 + P2 + Lc + + Le(?IncludeLe) + res = ExchangeAPDU14a(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + if (res) { + return res; + } + break; + case ECC_CONTACT: + break; } if (APDULogging) @@ -289,15 +295,15 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool Includ return 0; } -int EMVExchange(bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(false, LeaveFieldON, apdu, true, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + return EMVExchangeEx(channel, false, LeaveFieldON, apdu, true, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVSelect(bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, true, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + return EMVExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, true, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVSelectPSE(bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { +int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t buf[APDU_AID_LEN] = {0}; *ResultLen = 0; int len = 0; @@ -314,19 +320,19 @@ int EMVSelectPSE(bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t } // select - res = EMVSelect(ActivateField, LeaveFieldON, buf, len, Result, MaxResultLen, ResultLen, sw, NULL); + res = EMVSelect(channel, ActivateField, LeaveFieldON, buf, len, Result, MaxResultLen, ResultLen, sw, NULL); return res; } -int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { +int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { uint8_t data[APDU_RES_LEN] = {0}; size_t datalen = 0; uint16_t sw = 0; int res; // select PPSE - res = EMVSelectPSE(ActivateField, true, 2, data, sizeof(data), &datalen, &sw); + res = EMVSelectPSE(channel, ActivateField, true, 2, data, sizeof(data), &datalen, &sw); if (!res){ struct tlvdb *t = NULL; @@ -340,7 +346,7 @@ int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct t while (ttmp) { const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x4f, NULL); if (tgAID) { - res = EMVSelect(false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv); + res = EMVSelect(channel, false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv); // retry if error and not returned sw error if (res && res != 5) { @@ -387,7 +393,7 @@ int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct t return res; } -int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { +int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { uint8_t aidbuf[APDU_AID_LEN] = {0}; int aidlen = 0; uint8_t data[APDU_RES_LEN] = {0}; @@ -398,7 +404,7 @@ int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvd int retrycnt = 0; for(int i = 0; i < AIDlistLen; i ++) { param_gethex_to_eol(AIDlist[i].aid, 0, aidbuf, sizeof(aidbuf), &aidlen); - res = EMVSelect((i == 0) ? ActivateField : false, (i == AIDlistLen - 1) ? LeaveFieldON : true, aidbuf, aidlen, data, sizeof(data), &datalen, &sw, tlv); + res = EMVSelect(channel, (i == 0) ? ActivateField : false, (i == AIDlistLen - 1) ? LeaveFieldON : true, aidbuf, aidlen, data, sizeof(data), &datalen, &sw, tlv); // retry if error and not returned sw error if (res && res != 5) { if (++retrycnt < 3){ @@ -468,38 +474,38 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) { return 0; } -int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - int res = EMVExchange(LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + int res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); if (*sw == 0x6700) { PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); - res = EMVExchangeEx(false, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); + res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); } return res; } -int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0xae, RefControl, 0x00, CDOLLen, CDOL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0xae, RefControl, 0x00, CDOLLen, CDOL}, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - int res = EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + int res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); if (*sw == 0x6700) { PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); - res = EMVExchangeEx(false, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); + res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); } return res; } -int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + return EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv); } -int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv); +int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv); } // Authentication @@ -569,7 +575,7 @@ int trSDA(struct tlvdb *tlv) { static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04}; static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value }; -int trDDA(bool decodeTLV, struct tlvdb *tlv) { +int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; @@ -709,7 +715,7 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) { PrintAndLogEx(NORMAL, "DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); PrintAndLogEx(NORMAL, "\n* Internal Authenticate"); - int res = EMVInternalAuthenticate(true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL); + int res = EMVInternalAuthenticate(channel, true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL); if (res) { PrintAndLogEx(WARNING, "Internal Authenticate error(%d): %4x. Exit...", res, sw); free(ddol_data_tlv); diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index 5fb6f202c..c2b1746e1 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -32,6 +32,11 @@ #define APDU_RES_LEN 260 #define APDU_AID_LEN 50 +typedef enum { + ECC_CONTACTLESS, + ECC_CONTACT +} EMVCommandChannel; + enum TransactionType { TT_MSD, TT_VSDC, // not standart for contactless!!!! @@ -71,28 +76,28 @@ extern struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2); extern void SetAPDULogging(bool logging); // exchange -extern int EMVExchange(bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // search application -extern int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); -extern int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); -extern int EMVSelectPSE(bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); -extern int EMVSelect(bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); +extern int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); +extern int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +extern int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // select application extern int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen); // Get Processing Options -extern int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); -extern int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // AC -extern int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); -extern int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // DDA -extern int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // Mastercard -int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // Auth extern int trSDA(struct tlvdb *tlv); -extern int trDDA(bool decodeTLV, struct tlvdb *tlv); +extern int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv); extern int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv); extern int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root); diff --git a/client/fido/fidocore.c b/client/fido/fidocore.c index 39c2052f9..ee39fbbe9 100644 --- a/client/fido/fidocore.c +++ b/client/fido/fidocore.c @@ -170,17 +170,17 @@ char *fido2GetCmdMemberDescription(uint8_t cmdCode, bool isResponse, int memberN int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t data[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01}; - return EMVSelect(ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); + return EMVSelect(ECC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); } int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - int res = EMVExchange(true, apdu, Result, MaxResultLen, ResultLen, sw, NULL); + int res = EMVExchange(ECC_CONTACTLESS, true, apdu, Result, MaxResultLen, ResultLen, sw, NULL); if (res == 5) // apdu result (sw) not a 0x9000 res = 0; // software chaining while (!res && (*sw >> 8) == 0x61) { size_t oldlen = *ResultLen; - res = EMVExchange(true, (sAPDU){0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL); + res = EMVExchange(ECC_CONTACTLESS, true, (sAPDU){0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL); if (res == 5) // apdu result (sw) not a 0x9000 res = 0; From 312ec79e481b9e71e90f144730e630576fa44ab6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 5 Dec 2018 17:27:28 +0200 Subject: [PATCH 07/11] added sketch sc apdu --- client/cmdsmartcard.c | 6 ++++++ client/cmdsmartcard.h | 2 ++ client/emv/emvcore.c | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index 59172b9c8..0173e0ca2 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -244,6 +244,12 @@ int CmdSmartRaw(const char *Cmd) { return 0; } +int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + + return 0; +} + + int CmdSmartUpgrade(const char *Cmd) { PrintAndLogEx(WARNING, "WARNING - Smartcard socket firmware upgrade."); diff --git a/client/cmdsmartcard.h b/client/cmdsmartcard.h index 5ba453e30..8cc0ae851 100644 --- a/client/cmdsmartcard.h +++ b/client/cmdsmartcard.h @@ -32,6 +32,8 @@ extern int CmdSmartUpgrade(const char* cmd); extern int CmdSmartInfo(const char* cmd); extern int CmdSmartReader(const char *Cmd); +extern int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); + extern int usage_sm_raw(void); extern int usage_sm_reader(void); extern int usage_sm_info(void); diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index aa68b6cdf..7df706e8e 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -260,6 +260,11 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField } break; case ECC_CONTACT: + //int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); + res = ExchangeAPDU14a(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + if (res) { + return res; + } break; } From ec3acc7d8af7b833aab655ce4ae2935a652edc6a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 5 Dec 2018 19:23:13 +0200 Subject: [PATCH 08/11] some of emv commands works in test mode --- client/cmdsmartcard.c | 33 +++++++++++++++++++++++++++++++-- client/emv/emvcore.c | 2 +- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index 0173e0ca2..d02e93477 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -87,6 +87,14 @@ static bool smart_select(bool silent) { if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); return false; } + + if (!silent) { + smart_card_atr_t card; + memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); + + PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); + } + return true; } @@ -124,8 +132,8 @@ static int smart_response(uint8_t *data) { goto out; } - PrintAndLogEx(INFO, "Requesting response"); - uint8_t getstatus[] = {0x00, ISO7816_GETSTATUS, 0x00, 0x00, len }; + PrintAndLogEx(INFO, "Requesting response. len=0x%x", len); + uint8_t getstatus[] = {ISO7816_GETSTATUS, 0x00, 0x00, len}; UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}}; memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) ); clearCommandBuffer(); @@ -245,6 +253,27 @@ int CmdSmartRaw(const char *Cmd) { } int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + *dataoutlen = 0; + + if (activateCard) + smart_select(false); + printf("* APDU SC\n"); + + UsbCommand c = {CMD_SMART_RAW, {SC_RAW | SC_CONNECT, datainlen, 0}}; + if (activateCard) { + c.arg[0] |= SC_SELECT; + } + memcpy(c.d.asBytes, datain, datainlen); + clearCommandBuffer(); + SendCommand(&c); + + int len = smart_response(dataout); + + if ( len < 0 ) { + return 2; + } + + *dataoutlen = len; return 0; } diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 7df706e8e..fcf0bf81f 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -261,7 +261,7 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField break; case ECC_CONTACT: //int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); - res = ExchangeAPDU14a(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + res = ExchangeAPDUSC(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); if (res) { return res; } From 34b53a5b48ff342fe7ed9c6060467c57c145edcd Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 6 Dec 2018 14:44:55 +0200 Subject: [PATCH 09/11] exchange works --- client/cmdsmartcard.c | 86 ++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 21 deletions(-) diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index d02e93477..db3c69f0e 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -119,29 +119,56 @@ static int smart_wait(uint8_t *data) { return len; } -static int smart_response(uint8_t *data) { +static int smart_response(uint8_t apduINS, uint8_t *data) { - int len = -1; int datalen = smart_wait(data); + bool needGetData = false; - if ( data[datalen - 2] == 0x61 || data[datalen - 2] == 0x9F ) { - len = data[datalen - 1]; - } - - if (len == -1 ) { + if (datalen < 2 ) { goto out; } - PrintAndLogEx(INFO, "Requesting response. len=0x%x", len); - uint8_t getstatus[] = {ISO7816_GETSTATUS, 0x00, 0x00, len}; - UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}}; - memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) ); - clearCommandBuffer(); - SendCommand(&cStatus); - - datalen = smart_wait(data); -out: + if (datalen > 2 && data[0] != apduINS) { + PrintAndLogEx(ERR, "Card ACK error. len=0x%x data[0]=%02x", datalen, data[0]); + datalen = 0; + goto out; + } + if ( data[datalen - 2] == 0x61 || data[datalen - 2] == 0x9F ) { + needGetData = true; + } + + if (needGetData) { + int len = data[datalen - 1]; + PrintAndLogEx(INFO, "Requesting response. len=0x%x", len); + uint8_t getstatus[] = {ISO7816_GETSTATUS, 0x00, 0x00, len}; + UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}}; + memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) ); + clearCommandBuffer(); + SendCommand(&cStatus); + + datalen = smart_wait(data); + + if (datalen < 2 ) { + goto out; + } + + if (datalen > 2 && data[0] != ISO7816_GETSTATUS) { + PrintAndLogEx(ERR, "GetResponse ACK error. len=0x%x data[0]=%02x", len, data[0]); + datalen = 0; + goto out; + } + + if (datalen != len + 2 + 1) { // 2 - response, 1 - ACK + PrintAndLogEx(WARNING, "GetResponse wrong length. Must be: 0x%02x but: 0x%02x", len, datalen - 3); + } + } + + if (datalen > 2) { + datalen--; + memmove(data, &data[1], datalen); + } +out: return datalen; } @@ -227,7 +254,7 @@ int CmdSmartRaw(const char *Cmd) { if ( !buf ) return 1; - int len = smart_response(buf); + int len = smart_response(data[1], buf); if ( len < 0 ) { free(buf); return 2; @@ -239,7 +266,7 @@ int CmdSmartRaw(const char *Cmd) { memcpy(c.d.asBytes, data, sizeof(data) ); clearCommandBuffer(); SendCommand(&c); - len = smart_response(buf); + len = smart_response(data[1], buf); data[4] = 0; } @@ -267,12 +294,29 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave clearCommandBuffer(); SendCommand(&c); - int len = smart_response(dataout); + int len = smart_response(datain[1], dataout); if ( len < 0 ) { return 2; } + // retry + if (len > 1 && dataout[len - 2] == 0x6c && datainlen > 4) { + UsbCommand c2 = {CMD_SMART_RAW, {SC_RAW, datainlen, 0}}; + memcpy(c2.d.asBytes, datain, datainlen); + + int vlen = 5 + datain[4]; + if (datainlen == vlen) + datainlen++; + + c2.d.asBytes[vlen] = dataout[len - 1]; + + clearCommandBuffer(); + SendCommand(&c2); + + len = smart_response(datain[1], dataout); + } + *dataoutlen = len; return 0; @@ -569,7 +613,7 @@ int CmdSmartBruteforceSFI(const char *Cmd) { clearCommandBuffer(); SendCommand(&c); - smart_response(buf); + smart_response(data[1], buf); // if 0x6C if ( buf[0] == 0x6C ) { @@ -578,7 +622,7 @@ int CmdSmartBruteforceSFI(const char *Cmd) { memcpy(c.d.asBytes, data, sizeof(data) ); clearCommandBuffer(); SendCommand(&c); - uint8_t len = smart_response(buf); + uint8_t len = smart_response(data[1], buf); // TLV decoder if (len > 4) From 17d0194aeaea402ca09464e0537db99c384bf4d5 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 6 Dec 2018 19:47:57 +0200 Subject: [PATCH 10/11] small fix and block scan command --- client/emv/cmdemv.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 4ab8a8a56..0ddf4e035 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -707,16 +707,16 @@ int CmdEMVExec(const char *cmd) { bool forceSearch = arg_get_lit(5); enum TransactionType TrType = TT_MSD; - if (arg_get_lit(6)) - TrType = TT_QVSDCMCHIP; if (arg_get_lit(7)) - TrType = TT_CDA; + TrType = TT_QVSDCMCHIP; if (arg_get_lit(8)) + TrType = TT_CDA; + if (arg_get_lit(9)) TrType = TT_VSDC; - bool GenACGPO = arg_get_lit(9); + bool GenACGPO = arg_get_lit(10); EMVCommandChannel channel = ECC_CONTACTLESS; - if (arg_get_lit(10)) + if (arg_get_lit(11)) channel = ECC_CONTACT; CLIParserFree(); @@ -1167,6 +1167,12 @@ int CmdEMVScan(const char *cmd) { SetAPDULogging(showAPDU); + // TODO + if (channel == ECC_CONTACT) { + PrintAndLogEx(ERR, "Do not use contact interface. Exit."); + return 1; + } + // current path + file name if (!strstr(crelfname, ".json")) strcat(crelfname, ".json"); From 80d07bcaac284a936ab50b583d3f594761d53792 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 6 Dec 2018 20:04:28 +0200 Subject: [PATCH 11/11] added code if AIP not found --- client/emv/cmdemv.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 0ddf4e035..647123faf 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -895,11 +895,16 @@ int CmdEMVExec(const char *cmd) { tlvdb_add(tlvRoot, oda); PrintAndLogEx(NORMAL, "* Input list for Offline Data Authentication added to TLV. len=%d \n", ODAiListLen); } - + // get AIP + uint16_t AIP = 0; const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL); - uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100; - PrintAndLogEx(NORMAL, "* * AIP=%04x", AIP); + if (AIPtlv) { + AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100; + PrintAndLogEx(NORMAL, "* * AIP=%04x", AIP); + } else { + PrintAndLogEx(ERR, "Can't found AIP."); + } // SDA if (AIP & 0x0040) {