PrintAndLog(" -a : show APDU reqests and responses\n");
PrintAndLog(" -t : TLV decode results\n");
PrintAndLog(" -f : force search AID. Search AID instead of execute PPSE.\n");
+ PrintAndLog(" -v : transaction type - qVSDC or M/Chip.\n");
+ PrintAndLog(" -c : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n");
+ PrintAndLog(" -x : transaction type - VSDC. For test only. Not a standart behavior.\n");
+ PrintAndLog("By default : transaction type - MSD.\n");
PrintAndLog("Samples:");
PrintAndLog(" hf emv pse -s -> select card");
PrintAndLog(" hf emv pse -s -t -a -> select card, show responses in TLV, show APDU");
bool showAPDU = false;
bool decodeTLV = false;
bool forceSearch = false;
+ enum TransactionType TrType = TT_MSD;
uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0;
switch (param_getchar_indx(cmd, 1, cmdp)) {
case 'h':
case 'H':
- UsageCmdHFEMVPPSE();
+ UsageCmdHFEMVExec();
return 0;
case 's':
case 'S':
case 'F':
forceSearch = true;
break;
+ case 'x':
+ case 'X':
+ TrType = TT_VSDC;
+ break;
+ case 'v':
+ case 'V':
+ TrType = TT_QVSDCMCHIP;
+ break;
+ case 'c':
+ case 'C':
+ TrType = TT_CDA;
+ break;
default:
PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
return 1;
PrintAndLog("\n* Init transaction parameters.");
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
- TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
-// TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
-// TLV_ADD(0x9F66, "\x8e\x00\x00\x00"); // CDA
+ switch(TrType) {
+ case TT_MSD:
+ TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
+ break;
+ // not standart for contactless. just for test.
+ case TT_VSDC:
+ TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC
+ break;
+ case TT_QVSDCMCHIP:
+ TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
+ break;
+ case TT_CDA:
+ TLV_ADD(0x9F66, "\x86\x80\x00\x00"); // CDA
+ break;
+ default:
+ TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
+ break;
+ }
//9F02:(Amount, Authorised (Numeric)) len:6
TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
//9F1A:(Terminal Country Code) len:2
PrintAndLog("\n* GPO.");
res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
+ free(pdol_data_tlv_data);
free(pdol_data_tlv);
if (res) {
break;
}
- // transaction check
+ // get AIP
const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL);
uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100;
- PrintAndLog("* * AIP=%x", AIP);
+ PrintAndLog("* * AIP=%04x", AIP);
+ // SDA
+ if (AIP & 0x0040) {
+ PrintAndLog("\n* SDA");
+ trSDA(AID, AIDlen, tlvRoot);
+ }
+
+ // DDA
+ if (AIP & 0x0020) {
+ PrintAndLog("\n* DDA");
+
+ }
+
+ // transaction check
+
// qVSDC
- {
+ if (TrType == TT_QVSDCMCHIP|| TrType == TT_CDA){
// 9F26: Application Cryptogram
const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL);
if (AC) {
}
}
- // TODO: Mastercard M/CHIP
- {
+ // Mastercard M/CHIP
+ if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD && (TrType == TT_QVSDCMCHIP || TrType == TT_CDA)){
const struct tlv *CDOL1 = tlvdb_get(tlvRoot, 0x8c, NULL);
if (CDOL1 && GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) { // and m/chip transaction flag
+ PrintAndLog("\n--> Mastercard M/Chip transaction.");
+
+ PrintAndLog("* * Generate challenge");
+ res = EMVGenerateChallenge(true, buf, sizeof(buf), &len, &sw, tlvRoot);
+ if (res) {
+ PrintAndLog("ERROR GetChallenge. APDU error %4x", sw);
+ return 5;
+ }
+ if (len < 4) {
+ PrintAndLog("ERROR GetChallenge. Wrong challenge length %d", len);
+ return 5;
+ }
+
+ // ICC Dynamic Number
+ struct tlvdb * ICCDynN = tlvdb_fixed(0x9f4c, len, buf);
+ tlvdb_add(tlvRoot, ICCDynN);
+ if (decodeTLV){
+ PrintAndLog("\n* * ICC Dynamic Number:");
+ TLVPrintFromTLV(ICCDynN);
+ }
+
+ PrintAndLog("* * Calc CDOL1");
+ struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
+ if (!cdol_data_tlv){
+ PrintAndLog("ERROR: can't create CDOL1 TLV.");
+ return 4;
+ }
+ PrintAndLog("CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
+
+ PrintAndLog("* * 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);
+
+ free(cdol_data_tlv);
+
+ if (res) {
+ PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw);
+ return 5;
+ }
+
+ if (decodeTLV)
+ TLVPrintFromBuffer(buf, len);
+
+ PrintAndLog("* M/Chip transaction result:");
+ // 9F27: Cryptogram Information Data (CID)
+ const struct tlv *CID = tlvdb_get(tlvRoot, 0x9F27, NULL);
+ if (CID) {
+ emv_tag_dump(CID, stdout, 0);
+ PrintAndLog("------------------------------");
+ if (CID->len > 0) {
+ switch(CID->value[0] & EMVAC_AC_MASK){
+ case EMVAC_AAC:
+ PrintAndLog("Transaction DECLINED.");
+ break;
+ case EMVAC_TC:
+ PrintAndLog("Transaction approved OFFLINE.");
+ break;
+ case EMVAC_ARQC:
+ PrintAndLog("Transaction approved ONLINE.");
+ break;
+ default:
+ PrintAndLog("ERROR: CID transaction code error %2x", CID->value[0] & EMVAC_AC_MASK);
+ break;
+ }
+ } else {
+ PrintAndLog("ERROR: Wrong CID length %d", CID->len);
+ }
+ } else {
+ PrintAndLog("ERROR: CID(9F27) not found.");
+ }
}
}
// MSD
- if (AIP & 0x8000) {
+ if (AIP & 0x8000 && TrType == TT_MSD) {
PrintAndLog("\n--> MSD transaction.");
-
PrintAndLog("* MSD dCVV path. Check dCVV");
const struct tlv *track2 = tlvdb_get(tlvRoot, 0x57, NULL);
if (!UDOL)
PrintAndLog("Use default UDOL.");
- struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - fake tag!
+ struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag
if (!udol_data_tlv){
PrintAndLog("ERROR: can't create UDOL TLV.");
return 4;
}
}
- // additional contacless EMV commands (fDDA, external authenticate)
-
-
// DropField
DropField();