#include "cmdemv.h"
#include <ctype.h>
+#include <string.h>
#include "proxmark3.h"
#include "cmdparser.h"
+#include "ui.h"
+#include "util.h"
#include "mifare.h"
#include "emvjson.h"
#include "emv_pki.h"
#include "cliparser/cliparser.h"
#include "jansson.h"
#include "emv_roca.h"
-
+#include "pcsc.h"
+#include "apduinfo.h"
+#include "dol.h"
+#include "emv_tags.h"
+#include "cmdhf14a.h"
#define TLV_ADD(tag, value)( tlvdb_change_or_add_node(tlvRoot, tag, sizeof(value) - 1, (const unsigned char *)value) )
void ParamLoadDefaults(struct tlvdb *tlvRoot) {
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, using %s", getAlternativeSmartcardReader());
+ 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);
return 0;
}
-#define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;}
+#define dreturn(n) {free(pdol_data_tlv); tlvdb_free(tlvSelect); tlvdb_free(tlvRoot); DropFieldEx( channel ); return n;}
void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum TransactionType TrType, bool GenACGPO) {
}
}
+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--;
}
}
}
}
}
- if (channel == ECC_CONTACTLESS) {
- DropField();
+ // 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);
+
+
}
+ DropFieldEx( channel );
+
// Destroy TLV's
free(pdol_data_tlv);
tlvdb_free(tlvSelect);
#else
CLIGetStrWithReturn(11, relfname, &relfnamelen);
#endif
+ PrintChannel(channel);
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
CLIParserFree();
}
// drop field at start
- if (channel == ECC_CONTACTLESS) {
- DropField();
- }
+ DropFieldEx( channel );
// iso 14443 select
PrintAndLogEx(NORMAL, "--> GET UID, ATS.");
if (EMVSearch(channel, false, true, decodeTLV, tlvSelect)) {
PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit...");
tlvdb_free(tlvSelect);
- DropField();
+ DropFieldEx( channel );
return 3;
}
if (!AIDlen) {
PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit...");
- if (channel == ECC_CONTACTLESS) {
- DropField();
- }
+ DropFieldEx( channel );
return 4;
}
if (res) {
PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res);
tlvdb_free(tlvRoot);
- DropField();
+ DropFieldEx( channel );
return 5;
}
if (!pdol_data_tlv){
PrintAndLogEx(ERR, "Can't create PDOL TLV.");
tlvdb_free(tlvRoot);
- if (channel == ECC_CONTACTLESS) {
- DropField();
- }
+ DropFieldEx( channel );
return 6;
}
if (!pdol_data_tlv_data) {
PrintAndLogEx(ERR, "Can't create PDOL data.");
tlvdb_free(tlvRoot);
- DropField();
+ DropFieldEx( channel );
return 6;
}
PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
if (res) {
PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw);
tlvdb_free(tlvRoot);
- if (channel == ECC_CONTACTLESS) {
- DropField();
- }
+ DropFieldEx( channel );
return 7;
}
ProcessGPOResponseFormat1(tlvRoot, buf, len, decodeTLV);
// free tlv object
tlvdb_free(tlvRoot);
- if (channel == ECC_CONTACTLESS) {
- DropField();
- }
+ DropFieldEx( channel );
res = json_dump_file(root, fname, JSON_INDENT(2));
if (res) {
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();
+ DropFieldEx( channel );
return 3;
}
if (!AIDlen) {
PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit...");
- if (channel == ECC_CONTACTLESS) {
- DropField();
- }
+ DropFieldEx( channel );
return 4;
}
if (res) {
PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res);
tlvdb_free(tlvRoot);
- if (channel == ECC_CONTACTLESS) {
- DropField();
- }
+ DropFieldEx( channel );
return 5;
}
if (!pdol_data_tlv){
PrintAndLogEx(ERR, "Can't create PDOL TLV.");
tlvdb_free(tlvRoot);
- if (channel == ECC_CONTACTLESS) {
- DropField();
- }
+ DropFieldEx( channel );
return 6;
}
if (!pdol_data_tlv_data) {
PrintAndLogEx(ERR, "Can't create PDOL data.");
tlvdb_free(tlvRoot);
- DropField();
+ DropFieldEx( channel );
return 6;
}
PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
if (res) {
PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw);
tlvdb_free(tlvRoot);
- if (channel == ECC_CONTACTLESS) {
- DropField();
- }
+ DropFieldEx( channel );
return 7;
}
ProcessGPOResponseFormat1(tlvRoot, buf, len, false);
struct emv_pk *pk = get_ca_pk(tlvRoot);
if (!pk) {
- PrintAndLogEx(ERR, "ERROR: Key not found. Exit.");
+ PrintAndLogEx(ERR, "CA Public Key not found. Exit.");
goto out;
}
goto out;
}
+ char RID[15] = {0};
+ memcpy(RID, sprint_hex(issuer_pk->rid, 5), 14);
PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %s IDX %02hhx CSN %s",
- sprint_hex(issuer_pk->rid, 5),
+ RID,
issuer_pk->index,
sprint_hex(issuer_pk->serial, 3)
);
PrintAndLogEx(WARNING, "WARNING: ICC certificate not found. Exit.");
goto out;
}
+
+ memcpy(RID, sprint_hex(icc_pk->rid, 5), 14);
PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %s IDX %02hhx CSN %s\n",
- sprint_hex(icc_pk->rid, 5),
+ RID,
icc_pk->index,
sprint_hex(icc_pk->serial, 3)
);
// free tlv object
tlvdb_free(tlvRoot);
- if (channel == ECC_CONTACTLESS) {
- DropField();
- }
-
+ DropFieldEx( channel );
return 0;
}