X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/95b697f017a4e9af954fdc766e614f67b8e290d1..1963cc9fe0ab7d6ddd04c5f8b4f27af836e98335:/client/emv/emv_pki.c diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index da102291..4e14483f 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -18,14 +18,14 @@ #endif #include "emv_pki.h" -#include "crypto.h" -#include "dump.h" -#include "util.h" -#include #include #include #include +#include "crypto.h" +#include "dump.h" +#include "util.h" +#include "ui.h" static bool strictExecution = true; void PKISetStrictExecution(bool se) { @@ -41,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; @@ -53,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 (%zd) not equal key length (%zd)\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, @@ -70,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; } @@ -91,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; } @@ -99,20 +100,23 @@ 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)); + 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); @@ -165,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 ) { @@ -184,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); } @@ -216,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; @@ -225,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; @@ -235,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; } @@ -275,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) @@ -287,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) @@ -307,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); } @@ -332,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); } @@ -345,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); @@ -357,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); } @@ -380,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), @@ -395,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); } @@ -456,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 %zd\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; } @@ -483,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; } @@ -498,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; @@ -507,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; }