]> cvs.zerfleddert.de Git - proxmark3-svn/blobdiff - client/emv/cmdemv.c
Merge pull request #524 from Proxmark/iceman1001-patch-1
[proxmark3-svn] / client / emv / cmdemv.c
index 679c26edeb321705d546c3078d0379d263ac86e1..92ae01f944c88a2fabcec2d35c361941e1d7fe04 100644 (file)
@@ -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("  -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");
        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;
        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;
 
        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':
                        switch (param_getchar_indx(cmd, 1, cmdp)) {
                                case 'h':
                                case 'H':
-                                       UsageCmdHFEMVPPSE();
+                                       UsageCmdHFEMVExec();
                                        return 0;
                                case 's':
                                case 'S':
                                        return 0;
                                case 's':
                                case 'S':
@@ -335,6 +340,18 @@ int CmdHFEMVExec(const char *cmd) {
                                case 'F':
                                        forceSearch = true;
                                        break;
                                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;
                                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
        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
     //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);
        
        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) {      
        free(pdol_data_tlv);
        
        if (res) {      
@@ -544,13 +577,27 @@ int CmdHFEMVExec(const char *cmd) {
                break;
        }       
        
                break;
        }       
        
-       // transaction check
+       // get AIP
        const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL);      
        uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100;
        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
        // qVSDC
-       {
+       if (TrType == TT_QVSDCMCHIP|| TrType == TT_CDA){
                // 9F26: Application Cryptogram
                const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL);
                if (AC) {
                // 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
                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
                
                }
        }
                
        // MSD
-       if (AIP & 0x8000) {
+       if (AIP & 0x8000 && TrType == TT_MSD) { 
                PrintAndLog("\n--> MSD transaction.");
                
                PrintAndLog("\n--> MSD transaction.");
                
-               
                PrintAndLog("* MSD dCVV path. Check dCVV");
 
                const struct tlv *track2 = tlvdb_get(tlvRoot, 0x57, NULL);
                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.");
 
                                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;
                                }
                                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)");
                                
                                
                                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;
                                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();
        
        // DropField
        DropField();
        
Impressum, Datenschutz