TLV_ADD(0x9F6A, "\x01\x02\x03\x04");
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
+ //95:(Terminal Verification Results) len:5
+ // all OK TVR
+ TLV_ADD(0x95, "\x00\x00\x00\x00\x00");
+}
+
+void PrintChannel(EMVCommandChannel channel) {
+ switch(channel) {
+ case ECC_CONTACTLESS:
+ PrintAndLogEx(INFO, "Channel: CONTACTLESS");
+ break;
+ case ECC_CONTACT:
+ PrintAndLogEx(INFO, "Channel: CONTACT");
+ break;
+ }
}
int CmdEMVSelect(const char *cmd) {
#ifdef WITH_SMARTCARD
if (arg_get_lit(5))
channel = ECC_CONTACT;
+ PrintChannel(channel);
CLIGetHexWithReturn(6, data, &datalen);
#else
CLIGetHexWithReturn(5, data, &datalen);
if (arg_get_lit(5))
channel = ECC_CONTACT;
#endif
+ PrintChannel(channel);
CLIParserFree();
SetAPDULogging(APDULogging);
if (arg_get_lit(7))
channel = ECC_CONTACT;
#endif
+ PrintChannel(channel);
CLIParserFree();
SetAPDULogging(APDULogging);
#else
CLIGetHexWithReturn(6, data, &datalen);
#endif
+ PrintChannel(channel);
CLIParserFree();
SetAPDULogging(APDULogging);
#else
CLIGetHexWithReturn(4, data, &datalen);
#endif
+ PrintChannel(channel);
CLIParserFree();
if (datalen != 2) {
#else
CLIGetHexWithReturn(8, data, &datalen);
#endif
+ PrintChannel(channel);
CLIParserFree();
SetAPDULogging(APDULogging);
if (arg_get_lit(3))
channel = ECC_CONTACT;
#endif
+ PrintChannel(channel);
CLIParserFree();
SetAPDULogging(APDULogging);
#else
CLIGetHexWithReturn(6, data, &datalen);
#endif
+ PrintChannel(channel);
CLIParserFree();
SetAPDULogging(APDULogging);
}
}
+void ProcessACResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV) {
+ if (buf[0] == 0x80) {
+ if (decodeTLV){
+ PrintAndLog("GPO response format1:");
+ TLVPrintFromBuffer(buf, len);
+ }
+
+ uint8_t elmlen = len - 2; // wo 0x80XX
+
+ if (len < 4 + 2 || (elmlen - 2) % 4 || elmlen != buf[1]) {
+ PrintAndLogEx(ERR, "GPO response format1 parsing error. length=%d", len);
+ } else {
+ struct tlvdb *tlvElm = NULL;
+ if (decodeTLV)
+ PrintAndLog("\n------------ Format1 decoded ------------");
+
+ // CID (Cryptogram Information Data)
+ tlvdb_change_or_add_node_ex(tlvRoot, 0x9f27, 1, &buf[2], &tlvElm);
+ if (decodeTLV)
+ TLVPrintFromTLV(tlvElm);
+
+ // ATC (Application Transaction Counter)
+ tlvdb_change_or_add_node_ex(tlvRoot, 0x9f36, 2, &buf[3], &tlvElm);
+ if (decodeTLV)
+ TLVPrintFromTLV(tlvElm);
+
+ // AC (Application Cryptogram)
+ tlvdb_change_or_add_node_ex(tlvRoot, 0x9f26, MIN(8, elmlen - 3), &buf[5], &tlvElm);
+ if (decodeTLV)
+ TLVPrintFromTLV(tlvElm);
+
+ // IAD (Issuer Application Data) - optional
+ if (len > 11 + 2) {
+ tlvdb_change_or_add_node_ex(tlvRoot, 0x9f10, elmlen - 11, &buf[13], &tlvElm);
+ if (decodeTLV)
+ TLVPrintFromTLV(tlvElm);
+ }
+ }
+ } else {
+ if (decodeTLV)
+ TLVPrintFromBuffer(buf, len);
+ }
+}
+
int CmdEMVExec(const char *cmd) {
uint8_t buf[APDU_RESPONSE_LEN] = {0};
size_t len = 0;
if (arg_get_lit(11))
channel = ECC_CONTACT;
#endif
+ PrintChannel(channel);
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
char *PSE_or_PPSE = psenum == 1 ? "PSE" : "PPSE";
uint8_t SFIend = AFL->value[i * 4 + 2];
uint8_t SFIoffline = AFL->value[i * 4 + 3];
- PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline);
+ PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline count:%02x", SFI, SFIstart, SFIend, SFIoffline);
if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) {
PrintAndLogEx(NORMAL, "SFI ERROR! Skipped...");
continue;
// Build Input list for Offline Data Authentication
// EMV 4.3 book3 10.3, page 96
- if (SFIoffline) {
+ if (SFIoffline > 0) {
if (SFI < 11) {
const unsigned char *abuf = buf;
size_t elmlen = len;
memcpy(&ODAiList[ODAiListLen], buf, len);
ODAiListLen += len;
}
+
+ SFIoffline--;
}
}
}
}
}
+ // VSDC
+ if (GetCardPSVendor(AID, AIDlen) == CV_VISA && (TrType == TT_VSDC || TrType == TT_CDA)){
+ PrintAndLogEx(NORMAL, "\n--> VSDC transaction.");
+
+ PrintAndLogEx(NORMAL, "* * Calc CDOL1");
+ struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
+ if (!cdol_data_tlv) {
+ PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV.");
+ dreturn(6);
+ }
+
+ PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
+
+ PrintAndLogEx(NORMAL, "* * AC1");
+ // EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
+ 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);
+ dreturn(7);
+ }
+
+ // process Format1 (0x80) and print Format2 (0x77)
+ ProcessACResponseFormat1(tlvRoot, buf, len, decodeTLV);
+
+ PrintAndLogEx(NORMAL, "\n* * Processing online request\n");
+
+ // authorization response code from acquirer
+ const char HostResponse[] = "00"; //0 x3030
+ PrintAndLogEx(NORMAL, "* * Host Response: `%s`", HostResponse);
+ tlvdb_change_or_add_node(tlvRoot, 0x8a, sizeof(HostResponse) - 1, (const unsigned char *)HostResponse);
+
+ }
+
if (channel == ECC_CONTACTLESS) {
DropField();
}
#else
CLIGetStrWithReturn(11, relfname, &relfnamelen);
#endif
+ PrintChannel(channel);
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
CLIParserFree();
CLIParserInit("emv roca",
"Tries to extract public keys and run the ROCA test against them.\n",
"Usage:\n"
- "\temv roca -w -> select CONTACT card and run test\n\temv roca -> select CONTACTLESS card and run test\n");
+ "\temv roca -w -> select --CONTACT-- card and run test\n"
+ "\temv roca -> select --CONTACTLESS-- card and run test\n"
+ );
void* argtable[] = {
arg_param_begin,
+ arg_lit0("tT", "selftest", "self test"),
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
arg_param_end
};
EMVCommandChannel channel = ECC_CONTACTLESS;
if (arg_get_lit(1))
+ return roca_self_test();
+#ifdef WITH_SMARTCARD
+ if (arg_get_lit(2))
channel = ECC_CONTACT;
+#endif
+ PrintChannel(channel);
// select card
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
+ char *PSE_or_PPSE = psenum == 1 ? "PSE" : "PPSE";
SetAPDULogging(false);
const char *al = "Applets list";
struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al);
- // EMV PPSE
- PrintAndLogEx(NORMAL, "--> PPSE.");
- res = EMVSearchPSE(channel, false, true, psenum, false, tlvSelect);
+ // EMV PSE/PPSE
+ PrintAndLogEx(NORMAL, "--> %s.", PSE_or_PPSE);
+ res = EMVSearchPSE(channel, true, true, psenum, false, tlvSelect);
- // check PPSE and select application id
+ // check PSE/PPSE and select application id
if (!res) {
TLVPrintAIDlistFromSelectTLV(tlvSelect);
} else {
// EMV SEARCH with AID list
PrintAndLogEx(NORMAL, "--> AID search.");
if (EMVSearch(channel, false, true, false, tlvSelect)) {
- PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit...");
+ PrintAndLogEx(ERR, "Couldn't find any known EMV AID. Exit...");
tlvdb_free(tlvSelect);
DropField();
return 3;
}
// EMV SELECT application
- SetAPDULogging(false);
+ SetAPDULogging(true);
EMVSelectApplication(tlvSelect, AID, &AIDlen);
tlvdb_free(tlvSelect);