From: merlokk <olegmsn@gmail.com>
Date: Sat, 25 Nov 2017 10:58:50 +0000 (+0200)
Subject: part of changes
X-Git-Tag: v3.1.0~112^2~3
X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/66efdc1f646eb4e8e0c0f50003cf9d469f4e54c1?hp=45eb1383e3029d887549161b4125f33550c23de6

part of changes
---

diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c
index 3c3c1f11..679c26ed 100644
--- a/client/emv/cmdemv.c
+++ b/client/emv/cmdemv.c
@@ -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
diff --git a/client/emv/emv_tags.c b/client/emv/emv_tags.c
index a7c11c3e..a69d7196 100644
--- a/client/emv/emv_tags.c
+++ b/client/emv/emv_tags.c
@@ -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;
diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h
index fdd3ab86..03d5c956 100644
--- a/client/emv/emvcore.h
+++ b/client/emv/emvcore.h
@@ -29,10 +29,34 @@
 #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
 
diff --git a/client/util.c b/client/util.c
index 92b0e7a6..b7f07bde 100644
--- a/client/util.c
+++ b/client/util.c
@@ -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;
 }
diff --git a/client/util.h b/client/util.h
index e9c48b03..fd7ceaff 100644
--- a/client/util.h
+++ b/client/util.h
@@ -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);