//-----------------------------------------------------------------------------
-// Copyright (C) 2017 Merlok
+// Copyright (C) 2017, 2018 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
return 0;
}
+#define TLV_ADD(tag, value)( tlvdb_add(tlvRoot, tlvdb_fixed(tag, sizeof(value) - 1, (const unsigned char *)value)) )
+
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");
+ "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 -st 01020304 -> execute GPO with 4-byte PDOL data, show result in TLV\n");
+ // here need to add load params from file and gen pdol
void* argtable[] = {
arg_param_begin,
// calc PDOL
struct tlv *pdol_data_tlv = NULL;
struct tlv data_tlv = {
- .tag = 0x83, //was 01
+ .tag = 0x01,
.len = datalen,
.value = (uint8_t *)data,
};
if (dataMakeFromPDOL) {
// TODO
PrintAndLog("Make PDOL data not implemented!");
+
+ //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");
+ //5F2A:(Transaction Currency Code) len:2
+ // USD 840, EUR 978, RUR 810, RUB 643, RUR 810(old), UAH 980, AZN 031, n/a 999
+ TLV_ADD(0x5F2A, "\x09\x80");
+ //9A:(Transaction Date) len:3
+ TLV_ADD(0x9A, "\x00\x00\x00");
+ //9C:(Transaction Type) len:1 | 00 => Goods and service #01 => Cash
+ TLV_ADD(0x9C, "\x00");
+ // 9F37 Unpredictable Number len:4
+ TLV_ADD(0x9F37, "\x01\x02\x03\x04");
+ // 9F6A Unpredictable Number (MSD for UDOL) len:4
+ TLV_ADD(0x9F6A, "\x01\x02\x03\x04");
+ //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
+ TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
+
if (paramsLoadFromFile) {
};
/* pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
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");
+ "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");
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_str1(NULL, NULL, "<SFI 1byte HEX><SFIrec 1byte HEX>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
}
int CmdHFEMVAC(const char *cmd) {
+ uint8_t data[APDU_RES_LEN] = {0};
+ int datalen = 0;
- return 0;
+ CLIParserInit("hf 14a 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 -> execute GPO with 2-byte CDOLdata and keep field ON after command\n"
+ "\thf emv genac -t 01020304 -> execute GPO with 4-byte CDOL data, show result in TLV\n");
+
+ void* argtable[] = {
+ arg_param_begin,
+ arg_lit0("kK", "keep", "keep field ON for next command"),
+ arg_lit0("cC", "cda", "executes CDA transaction. Needs to get SDAD in results."),
+ arg_lit0("aA", "apdu", "show APDU reqests and responses"),
+ arg_lit0("tT", "tlv", "TLV decode results of selected applets"),
+ arg_str1(NULL, NULL, "<HEX CDOLdata>", NULL),
+ arg_param_end
+ };
+ CLIExecWithReturn(cmd, argtable, false);
+
+ bool leaveSignalON = arg_get_lit(1);
+ bool trTypeCDA = arg_get_lit(2);
+ bool APDULogging = arg_get_lit(3);
+ bool decodeTLV = arg_get_lit(4);
+ CLIGetStrWithReturn(5, 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 CDOL
+ struct tlv *cdol_data_tlv = NULL;
+// struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
+ struct tlv data_tlv = {
+ .tag = 0x01,
+ .len = datalen,
+ .value = (uint8_t *)data,
+ };
+ cdol_data_tlv = &data_tlv;
+ PrintAndLog("CDOL data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
+
+ // exec
+ uint8_t buf[APDU_RES_LEN] = {0};
+ size_t len = 0;
+ uint16_t sw = 0;
+ int res = EMVAC(leaveSignalON, (trTypeCDA) ? 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);
+ 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 CmdHFEMVGenerateChallenge(const char *cmd) {
+ CLIParserInit("hf 14a challenge",
+ "Executes Generate Challenge command. It returns 4 or 8-byte random number from card:\n",
+ "Usage:\n\thf emv challenge -> get challenge\n\thf emv challenge -k -> get challenge, keep fileld ON\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_param_end
+ };
+ CLIExecWithReturn(cmd, argtable, true);
+
+ bool leaveSignalON = arg_get_lit(1);
+ bool APDULogging = arg_get_lit(2);
+ CLIParserFree();
+
+ SetAPDULogging(APDULogging);
+
+ // exec
+ 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);
+
+ if (sw)
+ PrintAndLog("APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
+
+ if (res)
+ return res;
+
+ PrintAndLog("Challenge: %s", sprint_hex(buf, len));
+
+ if (len != 4 && len != 8)
+ PrintAndLog("WARNING: length of challenge must be 4 or 8, but it %d", len);
+
return 0;
}
int CmdHFEMVInternalAuthenticate(const char *cmd) {
+ uint8_t data[APDU_RES_LEN] = {0};
+ int datalen = 0;
- return 0;
+ CLIParserInit("hf 14a 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");
+
+ 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_str1(NULL, NULL, "<HEX DDOLdata>", NULL),
+ arg_param_end
+ };
+ CLIExecWithReturn(cmd, argtable, false);
+
+ bool leaveSignalON = arg_get_lit(1);
+ bool APDULogging = arg_get_lit(2);
+ bool decodeTLV = arg_get_lit(3);
+ CLIGetStrWithReturn(4, data, &datalen);
+ CLIParserFree();
+
+ SetAPDULogging(APDULogging);
+
+ // DDOL
+ PrintAndLog("DDOL data[%d]: %s", datalen, sprint_hex(data, datalen));
+
+ // exec
+ 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);
+
+ 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 UsageCmdHFEMVExec(void) {
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) {
{"genac", CmdHFEMVAC, 0, "Generate ApplicationCryptogram."},
{"challenge", CmdHFEMVGenerateChallenge, 0, "Generate challenge."},
{"intauth", CmdHFEMVInternalAuthenticate, 0, "Internal authentication."},
- {"test", CmdHFEMVTest, 0, "Crypto logic test."},
+ {"test", CmdHFEMVTest, 0, "Crypto logic test."},
{NULL, NULL, 0, NULL}
};