+ }
+
+ // copy Input list for Offline Data Authentication
+ if (ODAiListLen) {
+ struct tlvdb *oda = tlvdb_fixed(0x21, ODAiListLen, ODAiList); // not a standard tag
+ tlvdb_add(tlvRoot, oda);
+ PrintAndLogEx(NORMAL, "* Input list for Offline Data Authentication added to TLV. len=%d \n", ODAiListLen);
+ }
+
+ // get AIP
+ uint16_t AIP = 0;
+ const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL);
+ if (AIPtlv) {
+ AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100;
+ PrintAndLogEx(NORMAL, "* * AIP=%04x", AIP);
+ } else {
+ PrintAndLogEx(ERR, "Can't found AIP.");
+ }
+
+ // SDA
+ if (AIP & 0x0040) {
+ PrintAndLogEx(NORMAL, "\n* SDA");
+ trSDA(tlvRoot);
+ }
+
+ // DDA
+ if (AIP & 0x0020) {
+ PrintAndLogEx(NORMAL, "\n* DDA");
+ trDDA(channel, decodeTLV, tlvRoot);
+ }
+
+ // transaction check
+
+ // qVSDC
+ if (TrType == TT_QVSDCMCHIP|| TrType == TT_CDA){
+ // 9F26: Application Cryptogram
+ const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL);
+ if (AC) {
+ PrintAndLogEx(NORMAL, "\n--> qVSDC transaction.");
+ PrintAndLogEx(NORMAL, "* AC path");
+
+ // 9F36: Application Transaction Counter (ATC)
+ const struct tlv *ATC = tlvdb_get(tlvRoot, 0x9F36, NULL);
+ if (ATC) {
+
+ // 9F10: Issuer Application Data - optional
+ const struct tlv *IAD = tlvdb_get(tlvRoot, 0x9F10, NULL);
+
+ // print AC data
+ PrintAndLogEx(NORMAL, "ATC: %s", sprint_hex(ATC->value, ATC->len));
+ PrintAndLogEx(NORMAL, "AC: %s", sprint_hex(AC->value, AC->len));
+ if (IAD){
+ PrintAndLogEx(NORMAL, "IAD: %s", sprint_hex(IAD->value, IAD->len));
+
+ if (IAD->len >= IAD->value[0] + 1) {
+ PrintAndLogEx(NORMAL, "\tKey index: 0x%02x", IAD->value[1]);
+ PrintAndLogEx(NORMAL, "\tCrypto ver: 0x%02x(%03d)", IAD->value[2], IAD->value[2]);
+ PrintAndLogEx(NORMAL, "\tCVR:", sprint_hex(&IAD->value[3], IAD->value[0] - 2));
+ struct tlvdb * cvr = tlvdb_fixed(0x20, IAD->value[0] - 2, &IAD->value[3]);
+ TLVPrintFromTLVLev(cvr, 1);
+ }
+ } else {
+ PrintAndLogEx(WARNING, "IAD not found.");
+ }
+
+ } else {
+ PrintAndLogEx(ERR, "AC: Application Transaction Counter (ATC) not found.");
+ }
+ }
+ }
+
+ // 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
+ PrintAndLogEx(NORMAL, "\n--> Mastercard M/Chip transaction.");
+
+ PrintAndLogEx(NORMAL, "* * Generate challenge");
+ res = EMVGenerateChallenge(channel, true, buf, sizeof(buf), &len, &sw, tlvRoot);
+ if (res) {
+ PrintAndLogEx(WARNING, "GetChallenge. APDU error %4x", sw);
+ dreturn(6);
+ }
+ if (len < 4) {
+ PrintAndLogEx(WARNING, "GetChallenge. Wrong challenge length %d", len);
+ dreturn(6);
+ }
+
+ // ICC Dynamic Number
+ struct tlvdb * ICCDynN = tlvdb_fixed(0x9f4c, len, buf);
+ tlvdb_add(tlvRoot, ICCDynN);
+ if (decodeTLV){
+ PrintAndLogEx(NORMAL, "\n* * ICC Dynamic Number:");
+ TLVPrintFromTLV(ICCDynN);
+ }
+
+ 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);
+ }
+
+ if (decodeTLV)
+ TLVPrintFromBuffer(buf, len);
+
+ // CDA
+ PrintAndLogEx(NORMAL, "\n* CDA:");
+ struct tlvdb *ac_tlv = tlvdb_parse_multi(buf, len);
+ res = trCDA(tlvRoot, ac_tlv, pdol_data_tlv, cdol_data_tlv);
+ if (res) {
+ PrintAndLogEx(NORMAL, "CDA error (%d)", res);
+ }
+ free(ac_tlv);
+ free(cdol_data_tlv);
+
+ PrintAndLogEx(NORMAL, "\n* 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);
+ PrintAndLogEx(NORMAL, "------------------------------");
+ if (CID->len > 0) {
+ switch(CID->value[0] & EMVAC_AC_MASK){
+ case EMVAC_AAC:
+ PrintAndLogEx(NORMAL, "Transaction DECLINED.");
+ break;
+ case EMVAC_TC:
+ PrintAndLogEx(NORMAL, "Transaction approved OFFLINE.");
+ break;
+ case EMVAC_ARQC:
+ PrintAndLogEx(NORMAL, "Transaction approved ONLINE.");
+ break;
+ default:
+ PrintAndLogEx(WARNING, "Error: CID transaction code error %2x", CID->value[0] & EMVAC_AC_MASK);
+ break;
+ }
+ } else {
+ PrintAndLogEx(WARNING, "Wrong CID length %d", CID->len);
+ }
+ } else {
+ PrintAndLogEx(WARNING, "CID(9F27) not found.");
+ }
+
+ }
+ }
+
+ // MSD
+ if (AIP & 0x8000 && TrType == TT_MSD) {
+ PrintAndLogEx(NORMAL, "\n--> MSD transaction.");
+
+ PrintAndLogEx(NORMAL, "* MSD dCVV path. Check dCVV");
+
+ const struct tlv *track2 = tlvdb_get(tlvRoot, 0x57, NULL);
+ if (track2) {
+ PrintAndLogEx(NORMAL, "Track2: %s", sprint_hex(track2->value, track2->len));
+
+ struct tlvdb *dCVV = GetdCVVRawFromTrack2(track2);
+ PrintAndLogEx(NORMAL, "dCVV raw data:");
+ TLVPrintFromTLV(dCVV);
+
+ if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) {
+ PrintAndLogEx(NORMAL, "\n* Mastercard calculate UDOL");
+
+ // UDOL (9F69)
+ const struct tlv *UDOL = tlvdb_get(tlvRoot, 0x9F69, NULL);
+ // UDOL(9F69) default: 9F6A (Unpredictable number) 4 bytes
+ const struct tlv defUDOL = {
+ .tag = 0x01,
+ .len = 3,
+ .value = (uint8_t *)"\x9f\x6a\x04",
+ };
+ if (!UDOL)
+ PrintAndLogEx(NORMAL, "Use default UDOL.");
+
+ struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag
+ if (!udol_data_tlv){
+ PrintAndLogEx(WARNING, "can't create UDOL TLV.");
+ dreturn(8);
+ }
+
+ PrintAndLogEx(NORMAL, "UDOL data[%d]: %s", udol_data_tlv->len, sprint_hex(udol_data_tlv->value, udol_data_tlv->len));
+
+ PrintAndLogEx(NORMAL, "\n* Mastercard compute cryptographic checksum(UDOL)");
+
+ res = MSCComputeCryptoChecksum(channel, true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
+ if (res) {
+ PrintAndLogEx(WARNING, "Compute Crypto Checksum. APDU error %4x", sw);
+ free(udol_data_tlv);
+ dreturn(9);
+ }
+
+ // Mastercard compute cryptographic checksum result
+ TLVPrintFromBuffer(buf, len);
+ PrintAndLogEx(NORMAL, "");
+
+ free(udol_data_tlv);
+
+ }
+ } else {
+ PrintAndLogEx(WARNING, "MSD: Track2 data not found.");
+ }
+ }
+
+ // 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 );
+