part of changes
authormerlokk <olegmsn@gmail.com>
Sat, 25 Nov 2017 10:58:50 +0000 (12:58 +0200)
committermerlokk <olegmsn@gmail.com>
Sat, 25 Nov 2017 10:58:50 +0000 (12:58 +0200)
client/emv/cmdemv.c
client/emv/emv_tags.c
client/emv/emvcore.h
client/util.c
client/util.h

index 3c3c1f1129b86509c89c877398b22e737e9c451a..679c26edeb321705d546c3078d0379d263ac86e1 100644 (file)
@@ -402,12 +402,12 @@ int CmdHFEMVExec(const char *cmd) {
                TLVPrintFromBuffer(buf, len);
        PrintAndLog("* Selected.");
        
-PrintAndLog("-----BREAK.");
-return 0;
        PrintAndLog("\n* Init transaction parameters.");
 
     //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
-       TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // E6
+//     TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
+       TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
+//     TLV_ADD(0x9F66, "\x8e\x00\x00\x00"); // CDA
     //9F02:(Amount, Authorised (Numeric)) len:6
        TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
     //9F1A:(Terminal Country Code) len:2
@@ -421,8 +421,10 @@ return 0;
        TLV_ADD(0x9C,   "\x00");
        // 9F37 Unpredictable Number len:4
        TLV_ADD(0x9F37, "\x01\x02\x03\x04");
+       // 9F6A Unpredictable Number (MSD for UDOL) len:4
+       TLV_ADD(0x9F6A, "\x01\x02\x03\x04");
 
-       TLVPrintFromTLV(tlvRoot);
+       TLVPrintFromTLV(tlvRoot); // TODO delete!!!
        
        PrintAndLog("\n* Calc PDOL.");
        struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
@@ -439,8 +441,6 @@ return 0;
        }
        PrintAndLog("PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
 
-//PrintAndLog("-----BREAK.");
-//return 0;
        PrintAndLog("\n* GPO.");
        res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
        
@@ -453,21 +453,49 @@ return 0;
 
        // process response template format 1 [id:80  2b AIP + x4b AFL] and format 2 [id:77 TLV]
        if (buf[0] == 0x80) {
-               
-               
-               
                if (decodeTLV){
                        PrintAndLog("GPO response format1:");
                        TLVPrintFromBuffer(buf, len);
                }
-       } else {
-               
-               
                
+               if (len < 4 || (len - 4) % 4) {
+                       PrintAndLog("ERROR: GPO response format1 parsing error. length=%d", len);
+               } else {
+                       // AIP
+                       struct tlvdb * f1AIP = tlvdb_fixed(0x82, 2, buf + 2);
+                       tlvdb_add(tlvRoot, f1AIP);
+                       if (decodeTLV){
+                               PrintAndLog("\n* * Decode response format 1 (0x80) AIP and AFL:");
+                               TLVPrintFromTLV(f1AIP);
+                       }
+
+                       // AFL
+                       struct tlvdb * f1AFL = tlvdb_fixed(0x94, len - 4, buf + 2 + 2);
+                       tlvdb_add(tlvRoot, f1AFL);
+                       if (decodeTLV)
+                               TLVPrintFromTLV(f1AFL);
+               }               
+       } else {
                if (decodeTLV)
                        TLVPrintFromBuffer(buf, len);
        }
        
+       // extract PAN from track2
+       {
+               const struct tlv *track2 = tlvdb_get(tlvRoot, 0x57, NULL);
+               if (!tlvdb_get(tlvRoot, 0x5a, NULL) && track2 && track2->len >= 8) {
+                       struct tlvdb *pan = GetPANFromTrack2(track2);
+                       if (pan) {
+                               tlvdb_add(tlvRoot, pan); 
+                               
+                               const struct tlv *pantlv = tlvdb_get(tlvRoot, 0x5a, NULL);      
+                               PrintAndLog("\n* * Extracted PAN from track2: %s", sprint_hex(pantlv->value, pantlv->len));
+                       } else {
+                               PrintAndLog("\n* * WARNING: Can't extract PAN from track2.");
+                       }
+               }
+       }
+       
        PrintAndLog("\n* Read records from AFL.");
        const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL);
        if (!AFL || !AFL->len) {
@@ -516,7 +544,125 @@ return 0;
                break;
        }       
        
-       // additional contacless EMV commands (fDDA, CDA, external authenticate)
+       // transaction check
+       const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL);      
+       uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100;
+       PrintAndLog("* * AIP=%x", AIP);
+
+       // qVSDC
+       {
+               // 9F26: Application Cryptogram
+               const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL);
+               if (AC) {
+                       PrintAndLog("\n--> qVSDC transaction.");
+                       PrintAndLog("* 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
+                               PrintAndLog("ATC: %s", sprint_hex(ATC->value, ATC->len));
+                               PrintAndLog("AC: %s", sprint_hex(AC->value, AC->len));
+                               if (IAD){
+                                       PrintAndLog("IAD: %s", sprint_hex(IAD->value, IAD->len));
+                                       
+                                       if (IAD->len >= IAD->value[0] + 1) {
+                                               PrintAndLog("\tKey index:  0x%02x", IAD->value[1]);
+                                               PrintAndLog("\tCrypto ver: 0x%02x(%03d)", IAD->value[2], IAD->value[2]);
+                                               PrintAndLog("\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 {
+                                       PrintAndLog("WARNING: IAD not found.");
+                               }
+                               
+                       } else {
+                               PrintAndLog("ERROR AC: Application Transaction Counter (ATC) not found.");
+                       }
+               }
+       }
+       
+       // TODO: Mastercard M/CHIP
+       {
+               const struct tlv *CDOL1 = tlvdb_get(tlvRoot, 0x8c, NULL);
+               if (CDOL1 && GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) { // and m/chip transaction flag
+               
+               }
+       }
+               
+       // MSD
+       if (AIP & 0x8000) {
+               PrintAndLog("\n--> MSD transaction.");
+               
+               
+               PrintAndLog("* MSD dCVV path. Check dCVV");
+
+               const struct tlv *track2 = tlvdb_get(tlvRoot, 0x57, NULL);
+               if (track2) {
+                       PrintAndLog("Track2: %s", sprint_hex(track2->value, track2->len));
+
+                       struct tlvdb *dCVV = GetdCVVRawFromTrack2(track2);
+                       PrintAndLog("dCVV raw data:");
+                       TLVPrintFromTLV(dCVV);
+                       
+                       if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) {
+                               PrintAndLog("\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)
+                                       PrintAndLog("Use default UDOL.");
+
+                               struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - fake 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("\n* Mastercard compute cryptographic checksum(UDOL)");
+                               
+                               res = MSCComputeCryptoChecksum(true, udol_data_tlv_data, udol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
+                               if (res) {
+                                       PrintAndLog("ERROR Compute Crypto Checksum. APDU error %4x", sw);
+                                       return 5;
+                               }
+                               
+                               if (decodeTLV) {
+                                       TLVPrintFromBuffer(buf, len);
+                                       PrintAndLog("");
+                               }
+
+                       }
+               } else {
+                       PrintAndLog("ERROR MSD: Track2 data not found.");
+               }
+       }
+       
+       // additional contacless EMV commands (fDDA, external authenticate)
        
        
        // DropField
index a7c11c3e768d3d98a35d23f04063882a3f8400b4..a69d7196011d11dd8130937c692651e1c1dd8758 100644 (file)
@@ -21,6 +21,7 @@
 #include "emv_tags.h"
 
 #include <stdlib.h>
+#include <string.h>
 
 #define PRINT_INDENT(level)    {for (int i = 0; i < (level); i++) fprintf(f, "\t");}
 
@@ -33,6 +34,7 @@ enum emv_tag_t {
        EMV_TAG_STRING,
        EMV_TAG_NUMERIC,
        EMV_TAG_YYMMDD,
+       EMV_TAG_CVR,
 };
 
 struct emv_tag {
@@ -144,12 +146,38 @@ static const struct emv_tag_bit EMV_TTQ[] = {
        EMV_BIT_FINISH,
 };
 
+static const struct emv_tag_bit EMV_CVR[] = {
+       // mask 0F 0F F0 0F
+       { EMV_BIT(1, 4), "CDA Performed" },
+       { EMV_BIT(1, 3), "Offline DDA Performed" },
+       { EMV_BIT(1, 2), "Issuer Authentication Not Performed" },
+       { EMV_BIT(1, 1), "Issuer Authentication performed and Failed" },
+       { EMV_BIT(2, 4), "Offline PIN Verification Performed" },
+       { EMV_BIT(2, 3), "Offline PIN Verification Performed and PIN Not Successfully Verified" },
+       { EMV_BIT(2, 2), "PIN Try Limit Exceeded" },
+       { EMV_BIT(2, 1), "Last Online Transaction Not Completed" },
+       { EMV_BIT(3, 8), "Lower Offline Transaction Count Limit Exceeded" },
+       { EMV_BIT(3, 7), "Upper Offline Transaction Count Limit Exceeded" },
+       { EMV_BIT(3, 6), "Lower Cumulative Offline Amount Limit Exceeded" },
+       { EMV_BIT(3, 5), "Upper Cumulative Offline Amount Limit Exceeded" },
+       { EMV_BIT(4, 4), "Issuer script processing failed on last transaction" },
+       { EMV_BIT(4, 3), "Offline data authentication failed on previous transaction and transaction declined offline" },
+       { EMV_BIT(4, 2), "Go Online on Next Transaction Was Set" },
+       { EMV_BIT(4, 1), "Unable to go Online" },
+       EMV_BIT_FINISH,
+};
+
 // All Data Elements by Tags used in TLV structure (according to the EMV 4.2 Standard )
 // https://www.eftlab.co.uk/index.php/site-map/knowledge-base/145-emv-nfc-tags
 // http://dexterous-programmer.blogspot.in/2012/05/emv-tags.html
 static const struct emv_tag emv_tags[] = {
+       // internal
        { 0x00  , "Unknown ???" },
        { 0x01  , "", EMV_TAG_STRING }, // string for headers
+       { 0x02  , "Raw data", }, // data
+       { 0x20  , "Cardholder Verification Results (CVR)", EMV_TAG_CVR }, // not standard!
+
+       // EMV
        { 0x41  , "Country code and national data" },
        { 0x42  , "Issuer Identification Number (IIN)" },
        { 0x4f  , "Application Dedicated File (ADF) Name" },
@@ -228,6 +256,8 @@ static const struct emv_tag emv_tags[] = {
        { 0x9f4c, "ICC Dynamic Number" },
        { 0x9f4d, "Log Entry" },
        { 0x9f4f, "Log Format", EMV_TAG_DOL },
+       { 0x9f60, "CVC3 (Track1)" },
+       { 0x9f61, "CVC3 (Track2)" },
        { 0x9f62, "PCVC3(Track1)" },
        { 0x9f63, "PUNATC(Track1)" },
        { 0x9f64, "NATC(Track1)" },
@@ -375,6 +405,72 @@ static uint32_t emv_get_binary(const unsigned char *S)
        return (S[0] << 24) | (S[1] << 16) | (S[2] << 8) | (S[3] << 0);
 }
 
+// https://github.com/binaryfoo/emv-bertlv/blob/master/src/main/resources/fields/visa-cvr.txt
+static void emv_tag_dump_cvr(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
+       if (!tlv || tlv->len < 1) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tINVALID!\n");
+               return;
+       }
+       
+       if (tlv->len != tlv->value[0] + 1) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tINVALID length!\n");
+               return;
+       }
+       
+       if (tlv->len >= 2) {
+               // AC1
+               PRINT_INDENT(level);
+               if ((tlv->value[1] & 0xC0) == 0x00)     fprintf(f, "\tAC1: AAC (Transaction declined)\n");
+               if ((tlv->value[1] & 0xC0) == 0x40)     fprintf(f, "\tAC1: TC (Transaction approved)\n");
+               if ((tlv->value[1] & 0xC0) == 0x80)     fprintf(f, "\tAC1: ARQC (Online authorisation requested)\n");
+               if ((tlv->value[1] & 0xC0) == 0xC0)     fprintf(f, "\tAC1: RFU\n");
+               // AC2
+               PRINT_INDENT(level);
+               if ((tlv->value[1] & 0x30) == 0x00)     fprintf(f, "\tAC2: AAC (Transaction declined)\n");
+               if ((tlv->value[1] & 0x30) == 0x10)     fprintf(f, "\tAC2: TC (Transaction approved)\n");
+               if ((tlv->value[1] & 0x30) == 0x20)     fprintf(f, "\tAC2: not requested (ARQC)\n");
+               if ((tlv->value[1] & 0x30) == 0x30)     fprintf(f, "\tAC2: RFU\n");
+       }
+       if (tlv->len >= 3 && (tlv->value[2] >> 4)) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tPIN try: %x\n", tlv->value[2] >> 4);
+       }
+       if (tlv->len >= 4 && (tlv->value[3] & 0x0F)) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tIssuer discretionary bits: %x\n", tlv->value[3] & 0x0F);
+       }
+       if (tlv->len >= 5 && (tlv->value[4] >> 4)) {
+               PRINT_INDENT(level);
+               fprintf(f, "\tSuccessfully processed issuer script commands: %x\n", tlv->value[4] >> 4);
+       }
+       
+       // mask 0F 0F F0 0F
+       uint8_t data[20] = {0};
+       memcpy(data, &tlv->value[1], tlv->len - 1);
+       data[0] &= 0x0F;
+       data[1] &= 0x0F;
+       data[2] &= 0xF0;
+       data[3] &= 0x0F;
+       const struct tlv bit_tlv = {
+               .tag = tlv->tag,
+               .len = tlv->len - 1,
+               .value = data,
+       };
+       const struct emv_tag bit_tag = {
+               .tag = tag->tag,
+               .name = tag->name,
+               .type = EMV_TAG_BITMASK,
+               .data = EMV_CVR,
+       };
+       
+       if (data[0] || data[1] || data[2] || data[3])
+               emv_tag_dump_bitmask(&bit_tlv, &bit_tag, f, level);
+       
+       return;
+}
+
 static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
 {
        uint32_t X, Y;
@@ -528,6 +624,10 @@ bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level)
        case EMV_TAG_YYMMDD:
                emv_tag_dump_yymmdd(tlv, tag, f, level);
                break;
+       case EMV_TAG_CVR:
+               fprintf(f, "\n");
+               emv_tag_dump_cvr(tlv, tag, f, level);
+               break;
        };
 
        return true;
index fdd3ab868762ae9148d524a4053921376cf6a6c2..03d5c956c232fbaae1ff54e7861320e4c0c643f9 100644 (file)
 #define APDU_RES_LEN 260
 #define APDU_AID_LEN 50
 
+typedef struct {
+       uint8_t CLA;
+       uint8_t INS;
+       uint8_t P1;
+       uint8_t P2;
+       uint8_t Lc;
+       uint8_t *data;
+} sAPDU;
+
+enum CardPSVendor {
+       CV_NA,
+       CV_VISA,
+       CV_MASTERCARD,
+       CV_AMERICANEXPRESS,
+       CV_JCB,
+       CV_CB,
+       CV_OTHER,
+};
+extern enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen);
+
 extern void TLVPrintFromBuffer(uint8_t *data, int datalen);
 extern void TLVPrintFromTLV(struct tlvdb *tlv);
+extern void TLVPrintFromTLVLev(struct tlvdb *tlv, int level);
 extern void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv);
 
+extern struct tlvdb *GetPANFromTrack2(const struct tlv *track2);
+extern struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2);
+
 extern void SetAPDULogging(bool logging);
 
 // search application
@@ -45,6 +69,8 @@ extern int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen)
 // Get Processing Options
 extern int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
 extern int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
+// Mastercard
+int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
 
 #endif
 
index 92b0e7a6ab22dadd8160252f6364734b8c7a870d..b7f07bde056ec5b79834088a77de8d466b08a358 100644 (file)
@@ -111,6 +111,31 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount)
        sprintf(fnameptr, "%s", ext); 
 }
 
+void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len, 
+       const size_t min_str_len, const size_t spaces_between, bool uppercase) {
+               
+       char *tmp = (char *)buf;
+       size_t i;
+
+       int maxLen = ( hex_len > hex_max_len) ? hex_max_len : hex_len;
+
+       for (i = 0; i < maxLen; ++i, tmp += 2 + spaces_between) {
+               sprintf(tmp, (uppercase) ? "%02X" : "%02x", (unsigned int) hex_data[i]); 
+               
+               for (int j = 0; j < spaces_between; j++)
+                       sprintf(tmp + 2 + j, " ");
+       }
+       
+       i *= (2 + spaces_between);
+       int minStrLen = min_str_len > i ? min_str_len : 0;
+       if (minStrLen > hex_max_len)
+               minStrLen = hex_max_len;
+       for(; i < minStrLen; i++, tmp += 1) 
+               sprintf(tmp, " ");
+
+       return;
+}
+
 // printing and converting functions
 
 void print_hex(const uint8_t * data, const size_t len)
@@ -141,33 +166,17 @@ void print_hex_break(const uint8_t *data, const size_t len, uint8_t breaks) {
 }
 
 char *sprint_hex(const uint8_t *data, const size_t len) {
+       static char buf[1025] = {0};
        
-       int maxLen = ( len > 1024/3) ? 1024/3 : len;
-       static char buf[1024];
-       memset(buf, 0x00, 1024);
-       char *tmp = buf;
-       size_t i;
-
-       for (i=0; i < maxLen; ++i, tmp += 3)
-               sprintf(tmp, "%02x ", (unsigned int) data[i]);
+       hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, 0, 1, false);
 
        return buf;
 }
 
 char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const size_t min_str_len) {
-       
-       int maxLen = ( len > 1024/2) ? 1024/2 : len;
-       static char buf[1024] = {0};
-       char *tmp = buf;
-       size_t i;
+       static char buf[1025] = {0};
 
-       for (i = 0; i < maxLen; ++i, tmp += 2)
-               sprintf(tmp, "%02x", (unsigned int) data[i]);
-       
-       i *= 2;
-       int minStrLen = min_str_len > i ? min_str_len : 0;
-       for(; i < minStrLen; i++, tmp += 1) 
-               sprintf(tmp, " ");
+       hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, min_str_len, 0, false);
 
        return buf;
 }
index e9c48b0353bbc27e3c7f0cccaf38fd81f7d9228d..fd7ceafffb6de7685328405fa479cc2163810c16 100644 (file)
@@ -12,6 +12,7 @@
 #define UTIL_H__
 
 #include <stdint.h>
+#include <stdbool.h>
 #include <stddef.h>
 
 #ifndef ROTR
@@ -35,6 +36,9 @@ extern void AddLogUint64(char *fileName, char *extData, const uint64_t data);
 extern void AddLogCurrentDT(char *fileName);
 extern void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount);
 
+extern void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, 
+       const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase);
+
 extern void print_hex(const uint8_t * data, const size_t len);
 extern char *sprint_hex(const uint8_t * data, const size_t len);
 extern char *sprint_hex_inrow(const uint8_t *data, const size_t len);
Impressum, Datenschutz