X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/66efdc1f646eb4e8e0c0f50003cf9d469f4e54c1..fa85b08504eda7045b4b7d50fee1b75c4f5e5dd2:/client/emv/cmdemv.c diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 679c26ed..92ae01f9 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -283,6 +283,10 @@ int UsageCmdHFEMVExec(void) { 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"); @@ -296,6 +300,7 @@ int CmdHFEMVExec(const char *cmd) { 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; @@ -317,7 +322,7 @@ int CmdHFEMVExec(const char *cmd) { switch (param_getchar_indx(cmd, 1, cmdp)) { case 'h': case 'H': - UsageCmdHFEMVPPSE(); + UsageCmdHFEMVExec(); return 0; case 's': case 'S': @@ -335,6 +340,18 @@ int CmdHFEMVExec(const char *cmd) { 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; @@ -405,9 +422,24 @@ int CmdHFEMVExec(const char *cmd) { 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 @@ -444,6 +476,7 @@ int CmdHFEMVExec(const char *cmd) { 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) { @@ -544,13 +577,27 @@ int CmdHFEMVExec(const char *cmd) { 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) { @@ -587,19 +634,88 @@ int CmdHFEMVExec(const char *cmd) { } } - // 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); @@ -624,28 +740,17 @@ int CmdHFEMVExec(const char *cmd) { 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; } - - size_t udol_data_tlv_data_len; - unsigned char *udol_data_tlv_data = tlv_encode(udol_data_tlv, &udol_data_tlv_data_len); - if (!udol_data_tlv_data) { - PrintAndLog("ERROR: can't create UDOL data."); - return 4; - } - // eliminate fake tag - udol_data_tlv_data_len -= 2; - udol_data_tlv_data += 2; - - PrintAndLog("UDOL data[%d]: %s", udol_data_tlv_data_len, sprint_hex(udol_data_tlv_data, udol_data_tlv_data_len)); + PrintAndLog("UDOL data[%d]: %s", udol_data_tlv->len, sprint_hex(udol_data_tlv->value, udol_data_tlv->len)); PrintAndLog("\n* Mastercard compute cryptographic checksum(UDOL)"); - res = MSCComputeCryptoChecksum(true, udol_data_tlv_data, udol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); + res = MSCComputeCryptoChecksum(true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLog("ERROR Compute Crypto Checksum. APDU error %4x", sw); return 5; @@ -662,9 +767,6 @@ int CmdHFEMVExec(const char *cmd) { } } - // additional contacless EMV commands (fDDA, external authenticate) - - // DropField DropField();