X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/314a9b9cdd3d0e45bef3158e0a40de8568edf236..cd028159be9a6a3d7b158d2076cc94bf2b4f1143:/client/emv/emv_pki.c?ds=sidebyside

diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c
index 7803060e..4e14483f 100644
--- a/client/emv/emv_pki.c
+++ b/client/emv/emv_pki.c
@@ -18,14 +18,19 @@
 #endif
 
 #include "emv_pki.h"
-#include "crypto.h"
-#include "dump.h"
-#include "util.h"
 
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
+#include "crypto.h"
+#include "dump.h"
+#include "util.h"
+#include "ui.h"
+
+static bool strictExecution = true;
+void PKISetStrictExecution(bool se) {
+	strictExecution = se;
+}
 
 static const unsigned char empty_tlv_value[] = {};
 static const struct tlv empty_tlv = {.tag = 0x0, .len = 0, .value = empty_tlv_value};
@@ -36,7 +41,8 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
 		uint8_t msgtype,
 		size_t *len,
 		const struct tlv *cert_tlv,
-		... /* A list of tlv pointers, end with NULL */
+		int tlv_count,
+		... /* A list of tlv pointers */
 		)
 {
 	struct crypto_pk *kcp;
@@ -48,12 +54,12 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
 		return NULL;
 
 	if (!cert_tlv) {
-		printf("ERROR: Can't find certificate\n");
+		PrintAndLogEx(ERR, "Can't find certificate\n");
 		return NULL;
 	}
 
 	if (cert_tlv->len != enc_pk->mlen) {
-		printf("ERROR: Certificate length (%d) not equal key length (%d)\n", cert_tlv->len, enc_pk->mlen);
+		PrintAndLogEx(ERR, "Certificate length (%zd) not equal key length (%zd)\n", cert_tlv->len, enc_pk->mlen);
 		return NULL;
 	}
 	kcp = crypto_pk_open(enc_pk->pk_algo,
@@ -65,20 +71,20 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
 	data = crypto_pk_encrypt(kcp, cert_tlv->value, cert_tlv->len, &data_len);
 	crypto_pk_close(kcp);
 
-/*	if (true){
-		printf("Recovered data:\n");
+	/*if (true){
+		PrintAndLogEx(INFO, "Recovered data:\n");
 		dump_buffer(data, data_len, stdout, 0);
 	}*/
-	
+
 	if (data[data_len-1] != 0xbc || data[0] != 0x6a || data[1] != msgtype) {
-		printf("ERROR: Certificate format\n");
+		PrintAndLogEx(ERR, "Certificate format\n");
 		free(data);
 		return NULL;
 	}
 
 	size_t hash_pos = emv_pki_hash_psn[msgtype];
 	if (hash_pos == 0 || hash_pos > data_len){
-		printf("ERROR: Cant get hash position in the certificate\n");
+		PrintAndLogEx(ERR, "Can't get hash position in the certificate\n");
 		free(data);
 		return NULL;
 	}
@@ -86,7 +92,7 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
 	struct crypto_hash *ch;
 	ch = crypto_hash_open(data[hash_pos]);
 	if (!ch) {
-		printf("ERROR: Cant do hash\n");
+		PrintAndLogEx(ERR, "Can't do hash\n");
 		free(data);
 		return NULL;
 	}
@@ -94,23 +100,29 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
 	size_t hash_len = crypto_hash_get_size(ch);
 	crypto_hash_write(ch, data + 1, data_len - 2 - hash_len);
 
-	va_start(vl, cert_tlv);
-	while (true) {
+	va_start(vl, tlv_count);
+	for (int i = 0; i < tlv_count; i++) {
 		const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
 		if (!add_tlv)
-			break;
+			continue;
 
 		crypto_hash_write(ch, add_tlv->value, add_tlv->len);
 	}
 	va_end(vl);
 
-	if (memcmp(data + data_len - 1 - hash_len, crypto_hash_read(ch), hash_len)) {
-		printf("ERROR: Calculated wrong hash\n");
-		printf("decoded:    %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len));
-		printf("calculated: %s\n",sprint_hex(crypto_hash_read(ch), hash_len));
-		crypto_hash_close(ch);
-		free(data);
-		return NULL;
+	uint8_t hash[hash_len];
+	memset(hash, 0, hash_len);
+	memcpy(hash, crypto_hash_read(ch), hash_len);
+	if (memcmp(data + data_len - 1 - hash_len, hash, hash_len)) {
+		PrintAndLogEx(ERR, "Calculated wrong hash\n");
+		PrintAndLogEx(INFO, "decoded:    %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len));
+		PrintAndLogEx(INFO, "calculated: %s\n",sprint_hex(hash, hash_len));
+		
+		if (strictExecution) {
+			crypto_hash_close(ch);
+			free(data);
+			return NULL;
+		}
 	}
 
 	crypto_hash_close(ch);
@@ -157,6 +169,7 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
 		const struct tlv *exp_tlv,
 		const struct tlv *rem_tlv,
 		const struct tlv *add_tlv,
+		const struct tlv *sdatl_tlv,
 		bool showData
 		)
 {
@@ -176,23 +189,25 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
 	else if (msgtype == 4)
 		pan_length = 10;
 	else {
-		printf("ERROR: Message type must be 2 or 4\n");
+		PrintAndLogEx(ERR, "Message type must be 2 or 4\n");
 		return NULL;
 	}
 
 	data = emv_pki_decode_message(enc_pk, msgtype, &data_len,
 			cert_tlv,
+			5,
 			rem_tlv,
 			exp_tlv,
 			add_tlv,
+			sdatl_tlv,
 			NULL);
 	if (!data || data_len < 11 + pan_length) {
-		printf("ERROR: Can't decode message\n");
+		PrintAndLogEx(ERR, "Can't decode message\n");
 		return NULL;
 	}
 
 	if (showData){ 
-		printf("Recovered data:\n");
+		PrintAndLogEx(INFO, "Recovered data:\n");
 		dump_buffer(data, data_len, stdout, 0);
 	}
 
@@ -208,7 +223,7 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
 
 	if (((msgtype == 2) && (pan2_len < 4 || pan2_len > pan_len)) ||
 	    ((msgtype == 4) && (pan2_len != pan_len))) {
-		printf("ERROR: Invalid PAN lengths\n");
+		PrintAndLogEx(ERR, "Invalid PAN lengths\n");
 		free(data);
 
 		return NULL;
@@ -217,9 +232,9 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
 	unsigned i;
 	for (i = 0; i < pan2_len; i++)
 		if (emv_cn_get(pan_tlv, i) != emv_cn_get(&pan2_tlv, i)) {
-			printf("ERROR: PAN data mismatch\n");
-			printf("tlv  pan=%s\n", sprint_hex(pan_tlv->value, pan_tlv->len));
-			printf("cert pan=%s\n", sprint_hex(pan2_tlv.value, pan2_tlv.len));
+			PrintAndLogEx(ERR, "PAN data mismatch\n");
+			PrintAndLogEx(INFO, "tlv  pan=%s\n", sprint_hex(pan_tlv->value, pan_tlv->len));
+			PrintAndLogEx(INFO, "cert pan=%s\n", sprint_hex(pan2_tlv.value, pan2_tlv.len));
 			free(data);
 
 			return NULL;
@@ -227,7 +242,7 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
 
 	pk_len = data[9 + pan_length];
 	if (pk_len > data_len - 11 - pan_length + rem_tlv->len) {
-		printf("ERROR: Invalid pk length\n");
+		PrintAndLogEx(ERR, "Invalid pk length\n");
 		free(data);
 		return NULL;
 	}
@@ -267,9 +282,10 @@ static struct emv_pk *emv_pki_decode_key(const struct emv_pk *enc_pk,
 		const struct tlv *cert_tlv,
 		const struct tlv *exp_tlv,
 		const struct tlv *rem_tlv,
-		const struct tlv *add_tlv
+		const struct tlv *add_tlv,
+		const struct tlv *sdatl_tlv
 		) {
-	return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, false);
+	return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, sdatl_tlv, false);
 }
 
 struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db)
@@ -279,17 +295,30 @@ struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb
 			tlvdb_get(db, 0x90, NULL),
 			tlvdb_get(db, 0x9f32, NULL),
 			tlvdb_get(db, 0x92, NULL),
+			NULL,
 			NULL);
 }
 
 struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv)
 {
-	return emv_pki_decode_key(pk, 4,
+	size_t sdatl_len;
+	unsigned char *sdatl = emv_pki_sdatl_fill(db, &sdatl_len);
+	struct tlv sda_tdata = {
+		.tag = 0x00,        // dummy tag
+		.len = sdatl_len,
+		.value = sdatl
+	};
+	
+	struct emv_pk *res = emv_pki_decode_key(pk, 4,
 			tlvdb_get(db, 0x5a, NULL),
 			tlvdb_get(db, 0x9f46, NULL),
 			tlvdb_get(db, 0x9f47, NULL),
 			tlvdb_get(db, 0x9f48, NULL),
-			sda_tlv);
+			sda_tlv,
+			&sda_tdata);
+			
+	free(sdatl); // malloc here: emv_pki_sdatl_fill
+	return res;
 }
 
 struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db)
@@ -299,22 +328,67 @@ struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb
 			tlvdb_get(db, 0x9f2d, NULL),
 			tlvdb_get(db, 0x9f2e, NULL),
 			tlvdb_get(db, 0x9f2f, NULL),
+			NULL,
 			NULL);
 }
 
+unsigned char *emv_pki_sdatl_fill(const struct tlvdb *db, size_t *sdatl_len) {
+	uint8_t buf[2048] = {0};
+	size_t len = 0;
+	
+	*sdatl_len = 0;
+	
+	const struct tlv *sda_tl = tlvdb_get(db, 0x9f4a, NULL);
+	if (!sda_tl || sda_tl->len <= 0)
+		return NULL;
+
+	for (int i = 0; i < sda_tl->len; i++) {
+		uint32_t tag = sda_tl->value[i]; // here may be multibyte, but now not
+		const struct tlv *elm = tlvdb_get(db, tag, NULL);
+		if (elm) {
+			memcpy(&buf[len], elm->value, elm->len);
+			len += elm->len;
+		}		
+	}
+	
+	if (len) {
+		*sdatl_len = len;
+		unsigned char *value = malloc(len);
+		memcpy(value, buf, len);
+		return value;
+	}
+	
+	return NULL;
+}
+
+
 struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData)
 {
 	size_t data_len;
+	
+	// Static Data Authentication Tag List
+	size_t sdatl_len;
+	unsigned char *sdatl = emv_pki_sdatl_fill(db, &sdatl_len);
+	struct tlv sda_tdata = {
+		.tag = 0x00,        // dummy tag
+		.len = sdatl_len,
+		.value = sdatl
+	};
+
 	unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len,
 			tlvdb_get(db, 0x93, NULL),
+			3,
 			sda_tlv,
+			&sda_tdata,
 			NULL);
 
+	free(sdatl); // malloc here: emv_pki_sdatl_fill
+	
 	if (!data || data_len < 5)
 		return NULL;
 
 	if (showData){
-		printf("Recovered data:\n");
+		PrintAndLogEx(INFO, "Recovered data:\n");
 		dump_buffer(data, data_len, stdout, 0);
 	}
 
@@ -324,6 +398,7 @@ struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct t
 
 	return dac_db;
 }
+
 struct tlvdb *emv_pki_recover_dac(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv) {
 	return emv_pki_recover_dac_ex(enc_pk, db, sda_tlv, false);
 }
@@ -337,6 +412,7 @@ struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct t
 	size_t data_len;
 	unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
 			tlvdb_get(db, 0x9f4b, NULL),
+			2,
 			dyn_tlv,
 			NULL);
 
@@ -349,7 +425,7 @@ struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct t
 	}
 
 	if (showData){
-		printf("Recovered data:\n");
+		PrintAndLogEx(INFO, "Recovered data:\n");
 		dump_buffer(data, data_len, stdout, 0);
 	}
 
@@ -372,6 +448,7 @@ struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct t
 	size_t data_len;
 	unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
 			tlvdb_get(db, 0x9f4b, NULL),
+			5,
 			tlvdb_get(db, 0x9f37, NULL),
 			tlvdb_get(db, 0x9f02, NULL),
 			tlvdb_get(db, 0x5f2a, NULL),
@@ -387,7 +464,7 @@ struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct t
 	}
 
 	if (showData){
-		printf("Recovered data:\n");
+		PrintAndLogEx(INFO, "Recovered data:\n");
 		dump_buffer(data, data_len, stdout, 0);
 	}
 
@@ -448,26 +525,27 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t
 	size_t data_len = 0;
 	unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
 			tlvdb_get(this_db, 0x9f4b, NULL),
+			2,
 			un_tlv,
 			NULL);
 	if (!data || data_len < 3) {
-		printf("ERROR: can't decode message. len %d\n", data_len);
+		PrintAndLogEx(ERR, "can't decode message. len %zd\n", data_len);
 		return NULL;
 	}
 
 	if (showData){
-		printf("Recovered data:\n");
+		PrintAndLogEx(INFO, "Recovered data:\n");
 		dump_buffer(data, data_len, stdout, 0);
 	}
 
 	if (data[3] < 30 || data[3] > data_len - 4) {
-		printf("ERROR: Invalid data length\n");
+		PrintAndLogEx(ERR, "Invalid data length\n");
 		free(data);
 		return NULL;
 	}
 
 	if (!cid_tlv || cid_tlv->len != 1 || cid_tlv->value[0] != data[5 + data[4]]) {
-		printf("ERROR: CID mismatch\n");
+		PrintAndLogEx(ERR, "CID mismatch\n");
 		free(data);
 		return NULL;
 	}
@@ -475,7 +553,7 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t
 	struct crypto_hash *ch;
 	ch = crypto_hash_open(enc_pk->hash_algo);
 	if (!ch) {
-		printf("ERROR: can't create hash\n");
+		PrintAndLogEx(ERR, "Can't create hash\n");
 		free(data);
 		return NULL;
 	}
@@ -490,7 +568,7 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t
 	tlvdb_visit(this_db, tlv_hash, ch, 0);
 
 	if (memcmp(data + 5 + data[4] + 1 + 8, crypto_hash_read(ch), 20)) {
-		printf("ERROR: calculated hash error\n");
+		PrintAndLogEx(ERR, "Calculated hash error\n");
 		crypto_hash_close(ch);
 		free(data);
 		return NULL;
@@ -499,7 +577,7 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t
 
 	size_t idn_len = data[4];
 	if (idn_len > data[3] - 1) {
-		printf("ERROR: Invalid IDN length\n");
+		PrintAndLogEx(ERR, "Invalid IDN length\n");
 		free(data);
 		return NULL;
 	}