diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 75f1de60..fb5a560b 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -287,6 +287,7 @@ int UsageCmdHFEMVExec(void) { PrintAndLog(" -v : transaction type - qVSDC or M/Chip.\n"); PrintAndLog(" -c : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n"); PrintAndLog(" -x : transaction type - VSDC. For test only. Not a standart behavior.\n"); + PrintAndLog(" -g : VISA. generate AC from GPO\n"); PrintAndLog("By default : transaction type - MSD.\n"); PrintAndLog("Samples:"); PrintAndLog(" hf emv pse -s -> select card"); @@ -302,6 +303,7 @@ int CmdHFEMVExec(const char *cmd) { bool decodeTLV = false; bool forceSearch = false; enum TransactionType TrType = TT_MSD; + bool GenACGPO = false; uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; @@ -355,6 +357,10 @@ int CmdHFEMVExec(const char *cmd) { case 'C': TrType = TT_CDA; break; + case 'g': + case 'G': + GenACGPO = true; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp)); return 1; @@ -425,6 +431,10 @@ int CmdHFEMVExec(const char *cmd) { PrintAndLog("\n* Init transaction parameters."); //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4 + char *qVSDC = "\x26\x00\x00\x00"; + if (GenACGPO) { + qVSDC = "\x26\x80\x00\x00"; + } switch(TrType) { case TT_MSD: TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD @@ -434,15 +444,16 @@ int CmdHFEMVExec(const char *cmd) { TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC break; case TT_QVSDCMCHIP: - TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC + TLV_ADD(0x9F66, qVSDC); // qVSDC break; case TT_CDA: - TLV_ADD(0x9F66, "\x26\x80\x00\x00"); // CDA + TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled) break; default: TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC break; } + //9F02:(Amount, Authorised (Numeric)) len:6 TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00"); //9F1A:(Terminal Country Code) len:2 @@ -480,7 +491,7 @@ int CmdHFEMVExec(const char *cmd) { res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); free(pdol_data_tlv_data); - //free(pdol_data_tlv); + //free(pdol_data_tlv); --- free on exit. if (res) { PrintAndLog("GPO error(%d): %4x. Exit...", res, sw); @@ -695,8 +706,6 @@ int CmdHFEMVExec(const char *cmd) { // EMVAC_TC + EMVAC_CDAREQ --- to get SDAD res = EMVAC(true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); - //free(cdol_data_tlv); - if (res) { PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw); return 5; @@ -713,6 +722,7 @@ int CmdHFEMVExec(const char *cmd) { PrintAndLog("CDA error (%d)", res); } free(ac_tlv); + free(cdol_data_tlv); PrintAndLog("\n* M/Chip transaction result:"); // 9F27: Cryptogram Information Data (CID) @@ -804,6 +814,7 @@ int CmdHFEMVExec(const char *cmd) { DropField(); // Destroy TLV's + free(pdol_data_tlv); tlvdb_free(tlvSelect); tlvdb_free(tlvRoot); diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index a31aa336..7803060e 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -367,6 +367,44 @@ struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct t return idn_db; } +struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData) +{ + size_t data_len; + unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len, + tlvdb_get(db, 0x9f4b, NULL), + tlvdb_get(db, 0x9f37, NULL), + tlvdb_get(db, 0x9f02, NULL), + tlvdb_get(db, 0x5f2a, NULL), + tlvdb_get(db, 0x9f69, NULL), + NULL); + + if (!data || data_len < 3) + return NULL; + + if (data[3] < 2 || data[3] > data_len - 3) { + free(data); + return NULL; + } + + if (showData){ + printf("Recovered data:\n"); + dump_buffer(data, data_len, stdout, 0); + } + + size_t idn_len = data[4]; + if (idn_len > data[3] - 1) { + free(data); + return NULL; + } + + // 9f36 Application Transaction Counter (ATC) + struct tlvdb *atc_db = tlvdb_fixed(0x9f36, idn_len, data + 5); + + free(data); + + return atc_db; +} + static bool tlv_hash(void *data, const struct tlv *tlv, int level, bool is_leaf) { struct crypto_hash *ch = data; diff --git a/client/emv/emv_pki.h b/client/emv/emv_pki.h index ffa63946..e37e3c7d 100644 --- a/client/emv/emv_pki.h +++ b/client/emv/emv_pki.h @@ -29,6 +29,7 @@ struct tlvdb *emv_pki_recover_dac(const struct emv_pk *pk, const struct tlvdb *d struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData); 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_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, 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 710431ac..59027bbc 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -532,14 +532,6 @@ 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; @@ -608,7 +600,6 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) { ); } - 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); @@ -616,17 +607,30 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) { // 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..."); - 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; + const struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true); + free(ddol_data_tlv); + if (!atc_db) { + PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)"); + return 8; } - PrintAndLog("fDDA hash data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); - + // 9f36 Application Transaction Counter (ATC) + const struct tlv *atc_tlv = tlvdb_get(atc_db, 0x9f36, NULL); + if(atc_tlv) { + PrintAndLog("\nATC (Application Transaction Counter) [%zu] %s", atc_tlv->len, sprint_hex_inrow(atc_tlv->value, atc_tlv->len)); + + const struct tlv *core_atc_tlv = tlvdb_get(tlv, 0x9f36, NULL); + if(tlv_equal(core_atc_tlv, atc_tlv)) { + PrintAndLog("ATC check OK."); + PrintAndLog("fDDA (fast DDA) verified OK."); + } else { + PrintAndLog("ERROR: fDDA verified, but ATC in the certificate and ATC in the record not the same."); + } + } else { + PrintAndLog("\nERROR: fDDA (fast DDA) verify error"); + return 9; + } } else { struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); if (dac_db) { @@ -660,6 +664,7 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) { return 6; } + struct tlvdb *dda_db = NULL; if (buf[0] == 0x80) { if (len < 3 ) { PrintAndLog("ERROR: Internal Authenticate format1 parsing error. length=%d", len); @@ -683,37 +688,28 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) { if (decodeTLV) TLVPrintFromTLV(dda_db); } - } - - 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)"); - tlvdb_free(dda_db); - return 8; - } - tlvdb_free(dda_db); - // 9f4c ICC Dynamic Number - const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL); - if(idn_tlv) { - if(sdad_tlv) { // fDDA - PrintAndLog("\nATC (Application Transaction Counter) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len)); - PrintAndLog("fDDA (fast DDA) verified OK."); - } else { // DDA + 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)"); + tlvdb_free(dda_db); + return 8; + } + tlvdb_free(dda_db); + + // 9f4c ICC Dynamic Number + const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL); + if(idn_tlv) { 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 { - if(sdad_tlv) { // fDDA - PrintAndLog("\nERROR: fDDA (fast DDA) verify error"); - } else { // DDA + tlvdb_add(tlv, idn_db); + tlvdb_free(idn_db); + } else { PrintAndLog("\nERROR: DDA verify error"); + tlvdb_free(idn_db); + return 9; } - tlvdb_free(idn_db); - return 9; } return 0;