diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index 0ffc4a5a..eafadb6d 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -19,6 +19,7 @@ #include "emv_pki.h" #include "crypto.h" +#include "dump.h" #include #include @@ -49,7 +50,7 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, return NULL; if (cert_tlv->len != enc_pk->mlen) { - printf("Certificate length (%d) not equal key length (%d)", cert_tlv->len, enc_pk->mlen); + printf("ERROR: Certificate length (%d) not equal key length (%d)\n", cert_tlv->len, enc_pk->mlen); return NULL; } kcp = crypto_pk_open(enc_pk->pk_algo, @@ -62,12 +63,14 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, crypto_pk_close(kcp); if (data[data_len-1] != 0xbc || data[0] != 0x6a || data[1] != msgtype) { + printf("ERROR: 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"); free(data); return NULL; } @@ -75,6 +78,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"); free(data); return NULL; } @@ -93,6 +97,7 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, va_end(vl); if (memcmp(data + data_len - 1 - hash_len, crypto_hash_read(ch), hash_len)) { + printf("ERROR: Calculated wrong hash\n"); crypto_hash_close(ch); free(data); return NULL; @@ -279,7 +284,11 @@ struct tlvdb *emv_pki_recover_dac(const struct emv_pk *enc_pk, const struct tlvd return dac_db; } -struct tlvdb *emv_pki_recover_idn(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv) +struct tlvdb *emv_pki_recover_idn(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv) { + return emv_pki_recover_idn_ex(enc_pk, db, dyn_tlv, false); +} + +struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData) { size_t data_len; unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len, @@ -303,6 +312,12 @@ struct tlvdb *emv_pki_recover_idn(const struct emv_pk *enc_pk, const struct tlvd // 9f4c ICC Dynamic Number struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5); + + if (showData){ + printf("Recovered data:\n"); + dump_buffer(data, data_len, stdout, 0); + } + free(data); return idn_db; diff --git a/client/emv/emv_pki.h b/client/emv/emv_pki.h index 72d84cc4..83e02a35 100644 --- a/client/emv/emv_pki.h +++ b/client/emv/emv_pki.h @@ -27,6 +27,7 @@ struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb struct tlvdb *emv_pki_recover_dac(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *sda_tlv); struct tlvdb *emv_pki_recover_idn(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv); +struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData); struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlvdb *this_db, const struct tlv *pdol_data_tlv, diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 682effc9..88e87dda 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -532,6 +532,14 @@ int trSDA(struct tlvdb *tlv) { static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04}; static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value }; +static const unsigned char default_fdda_ddol_value[] = + {0x9f, 0x37, 0x04, + 0x9f, 0x02, 0x06, + 0x5f, 0x2A, 0x02, + 0x9f, 0x69, 0x07, // 9f69[07] Card Authentication Related Data + }; +static struct tlv default_fdda_ddol_tlv = {.tag = 0x9f49, .len = 12, .value = default_fdda_ddol_value }; + int trDDA(bool decodeTLV, struct tlvdb *tlv) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; @@ -600,40 +608,51 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) { ); } - struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); - if (dac_db) { - const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); - printf("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); - tlvdb_add(tlv, dac_db); - } else { - PrintAndLog("ERROR: SSAD verify error"); - return 4; - } - - PrintAndLog("\n* Calc DDOL"); - const struct tlv *ddol_tlv = tlvdb_get(tlv, 0x9f49, NULL); - if (!ddol_tlv) { - ddol_tlv = &default_ddol_tlv; - PrintAndLog("DDOL [9f49] not found. Using default DDOL"); - } - - struct tlv *ddol_data_tlv = dol_process(ddol_tlv, tlv, 0); - if (!ddol_data_tlv) { - PrintAndLog("ERROR: Can't create DDOL TLV"); - return 5; - } - - PrintAndLog("DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); - struct tlvdb *dda_db = NULL; + struct tlv *ddol_data_tlv = NULL; // 9F4B: Signed Dynamic Application Data const struct tlv *sdad_tlv = tlvdb_get(tlv, 0x9f4b, NULL); // DDA with internal authenticate OR fDDA with filled 0x9F4B tag (GPO result) // EMV kernel3 v2.4, contactless book C-3, C.1., page 147 if (sdad_tlv) { - PrintAndLog("\n* * * * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA..."); + PrintAndLog("\n* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA..."); dda_db = tlv; + + PrintAndLog("\n* Calc fDDA hash"); + ddol_data_tlv = dol_process(&default_fdda_ddol_tlv, tlv, 0); + if (!ddol_data_tlv) { + PrintAndLog("ERROR: Can't create fDDA hash TLV"); + return 5; + } + + PrintAndLog("fDDA hash data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); + } else { + struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); + if (dac_db) { + const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); + printf("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); + tlvdb_add(tlv, dac_db); + } else { + PrintAndLog("ERROR: SSAD verify error"); + return 4; + } + + PrintAndLog("\n* Calc DDOL"); + const struct tlv *ddol_tlv = tlvdb_get(tlv, 0x9f49, NULL); + if (!ddol_tlv) { + ddol_tlv = &default_ddol_tlv; + PrintAndLog("DDOL [9f49] not found. Using default DDOL"); + } + + ddol_data_tlv = dol_process(ddol_tlv, tlv, 0); + if (!ddol_data_tlv) { + PrintAndLog("ERROR: Can't create DDOL TLV"); + return 5; + } + + PrintAndLog("DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); + PrintAndLog("\n* Internal Authenticate"); int res = EMVInternalAuthenticate(true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL); if (res) { @@ -666,7 +685,7 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) { } } - struct tlvdb *idn_db = emv_pki_recover_idn(icc_pk, dda_db, ddol_data_tlv); + struct tlvdb *idn_db = emv_pki_recover_idn_ex(icc_pk, dda_db, ddol_data_tlv, true); free(ddol_data_tlv); if (!idn_db) { PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)"); @@ -678,7 +697,8 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) { // 9f4c ICC Dynamic Number const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL); if(idn_tlv) { - PrintAndLog("\nDDA verified OK. IDN (ICC Dynamic Number) %zu bytes long\n", idn_tlv->len); + PrintAndLog("\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len)); + PrintAndLog("DDA verified OK."); tlvdb_add(tlv, idn_db); tlvdb_free(idn_db); } else {