From f1da47336e178078a74c879d30479254898661fe Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 29 May 2020 12:42:52 +0200 Subject: [PATCH] fix: 'emv scan -w' - calculats hash correct --- client/src/emv/cmdemv.c | 80 +++++++++++++++++++++++++++------------- client/src/emv/emvcore.c | 56 +++++++++++++--------------- 2 files changed, 81 insertions(+), 55 deletions(-) diff --git a/client/src/emv/cmdemv.c b/client/src/emv/cmdemv.c index 474b4224b..347c7916a 100644 --- a/client/src/emv/cmdemv.c +++ b/client/src/emv/cmdemv.c @@ -1368,6 +1368,8 @@ static int CmdEMVScan(const char *Cmd) { size_t AIDlen = 0; uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; + uint8_t ODAI_list[4096]; + size_t ODAI_listlen = 0; uint16_t sw = 0; int res; json_t *root; @@ -1425,7 +1427,7 @@ static int CmdEMVScan(const char *Cmd) { if (!IfPm3Smartcard()) { if (channel == ECC_CONTACT) { - PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support. Exiting."); + PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support, exiting"); return PM3_EDEVNOTSUPP; } } @@ -1435,6 +1437,7 @@ static int CmdEMVScan(const char *Cmd) { // current path + file name if (!strstr(crelfname, ".json")) strcat(crelfname, ".json"); + char fname[strlen(get_my_executable_directory()) + strlen(crelfname) + 1]; strcpy(fname, get_my_executable_directory()); strcat(fname, crelfname); @@ -1447,7 +1450,7 @@ static int CmdEMVScan(const char *Cmd) { } if (!json_is_object(root)) { - PrintAndLogEx(ERR, "Invalid json format. root must be an object."); + PrintAndLogEx(ERR, "Invalid json format. root must be an object"); return PM3_EFILE; } } else { @@ -1461,7 +1464,7 @@ static int CmdEMVScan(const char *Cmd) { if (channel == ECC_CONTACTLESS) { // iso 14443 select - PrintAndLogEx(NORMAL, "--> GET UID, ATS."); + PrintAndLogEx(INFO, "GET UID, ATS"); iso14a_card_select_t card; if (Hf14443_4aGetCardData(&card)) { @@ -1474,7 +1477,7 @@ static int CmdEMVScan(const char *Cmd) { JsonSaveHex(root, "$.Card.Contactless.SAK", card.sak, 0); JsonSaveBufAsHex(root, "$.Card.Contactless.ATS", (uint8_t *)card.ats, card.ats_len); } else { - PrintAndLogEx(NORMAL, "--> GET ATR."); + PrintAndLogEx(INFO, "GET ATR"); smart_card_atr_t card; smart_select(true, &card); @@ -1492,7 +1495,7 @@ static int CmdEMVScan(const char *Cmd) { struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); // EMV PPSE - PrintAndLogEx(NORMAL, "--> PPSE."); + PrintAndLogEx(INFO, "PPSE"); res = EMVSelectPSE(channel, true, true, 2, buf, sizeof(buf), &len, &sw); if (!res && sw == 0x9000) { @@ -1518,9 +1521,9 @@ static int CmdEMVScan(const char *Cmd) { } else { // EMV SEARCH with AID list SetAPDULogging(false); - PrintAndLogEx(NORMAL, "--> AID search."); + PrintAndLogEx(INFO, "AID search."); if (EMVSearch(channel, false, true, decodeTLV, tlvSelect)) { - PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit..."); + PrintAndLogEx(ERR, "Can't found any of EMV AID, exiting..."); tlvdb_free(tlvSelect); DropFieldEx(channel); return PM3_ERFTRANS; @@ -1537,7 +1540,7 @@ static int CmdEMVScan(const char *Cmd) { tlvdb_free(tlvSelect); if (!AIDlen) { - PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit..."); + PrintAndLogEx(INFO, "Can't select AID. EMV AID not found, exiting..."); DropFieldEx(channel); return PM3_ERFTRANS; } @@ -1550,12 +1553,12 @@ static int CmdEMVScan(const char *Cmd) { // EMV SELECT applet - PrintAndLogEx(NORMAL, "\n-->Selecting AID:%s.", sprint_hex_inrow(AID, AIDlen)); + PrintAndLogEx(INFO, "Selecting AID: " _GREEN_("%s"), sprint_hex_inrow(AID, AIDlen)); SetAPDULogging(showAPDU); res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { - PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res); + PrintAndLogEx(ERR, "Can't select AID (%d), exiting...", res); tlvdb_free(tlvRoot); DropFieldEx(channel); return PM3_ERFTRANS; @@ -1577,13 +1580,13 @@ static int CmdEMVScan(const char *Cmd) { tlvdb_free(fci); // create transaction parameters - PrintAndLogEx(NORMAL, "-->Init transaction parameters."); + PrintAndLogEx(INFO, "Init transaction parameters"); InitTransactionParameters(tlvRoot, paramLoadJSON, TrType, GenACGPO); - PrintAndLogEx(NORMAL, "-->Calc PDOL."); + PrintAndLogEx(INFO, "Calc PDOL"); struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83); if (!pdol_data_tlv) { - PrintAndLogEx(ERR, "Can't create PDOL TLV."); + PrintAndLogEx(ERR, "Can't create PDOL TLV"); tlvdb_free(tlvRoot); DropFieldEx(channel); return PM3_ESOFT; @@ -1592,7 +1595,7 @@ static int CmdEMVScan(const char *Cmd) { size_t pdol_data_tlv_data_len; unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len); if (!pdol_data_tlv_data) { - PrintAndLogEx(ERR, "Can't create PDOL data."); + PrintAndLogEx(ERR, "Can't create PDOL data"); tlvdb_free(tlvRoot); free(pdol_data_tlv); DropFieldEx(channel); @@ -1600,14 +1603,14 @@ static int CmdEMVScan(const char *Cmd) { } PrintAndLogEx(INFO, "PDOL data[%zu]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); - PrintAndLogEx(INFO, "-->GPO."); + PrintAndLogEx(INFO, "GPO"); res = EMVGPO(channel, 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); if (res) { - PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw); + PrintAndLogEx(ERR, "GPO error(%d): %4x, exiting...", res, sw); tlvdb_free(tlvRoot); DropFieldEx(channel); return PM3_ERFTRANS; @@ -1625,7 +1628,7 @@ static int CmdEMVScan(const char *Cmd) { tlvdb_free(gpofci); - PrintAndLogEx(INFO, "-->Read records from AFL."); + PrintAndLogEx(INFO, "Read records from AFL"); const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL); while (AFL && AFL->len) { @@ -1650,15 +1653,16 @@ static int CmdEMVScan(const char *Cmd) { uint8_t SFIstart = AFL->value[i * 4 + 1]; uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIoffline = AFL->value[i * 4 + 3]; + bool first_time = SFIoffline; - PrintAndLogEx(INFO, "--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); + PrintAndLogEx(INFO, " SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { PrintAndLogEx(ERR, "SFI ERROR! Skipped..."); continue; } for (int n = SFIstart; n <= SFIend; n++) { - PrintAndLogEx(INFO, "---->SFI[%02x] %d", SFI, n); + PrintAndLogEx(INFO, " SFI[%02x] %d", SFI, n); res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { @@ -1666,6 +1670,26 @@ static int CmdEMVScan(const char *Cmd) { continue; } + // Build Input list for Offline Data Authentication + // EMV 4.3 book3 10.3, page 96 + if (first_time && SFIoffline) { + if (SFI < 11) { + const unsigned char *abuf = buf; + size_t elmlen = len; + struct tlv e; + if (tlv_parse_tl(&abuf, &elmlen, &e)) { + memcpy(ODAI_list + ODAI_listlen, &buf[len - elmlen], elmlen); + ODAI_listlen += elmlen; + } else { + PrintAndLogEx(WARNING, "Error SFI[%02x]. Creating input list for Offline Data Authentication error", SFI); + } + } else { + memcpy(ODAI_list + ODAI_listlen, buf, len); + ODAI_listlen += len; + } + first_time = false; + } + if (decodeTLV) { TLVPrintFromBuffer(buf, len); PrintAndLogEx(NORMAL, ""); @@ -1683,16 +1707,23 @@ static int CmdEMVScan(const char *Cmd) { JsonSaveTLVTree(root, jsonelm, "$.Data", rsfi); else JsonSaveTLVTreeElm(jsonelm, "$.Data", rsfi, true, true, false); - tlvdb_free(rsfi); + + tlvdb_free(rsfi); } } - break; } + // copy Input list for Offline Data Authentication + if (ODAI_listlen) { + struct tlvdb *oda = tlvdb_fixed(0x21, ODAI_listlen, ODAI_list); // not a standard tag + tlvdb_add(tlvRoot, oda); + PrintAndLogEx(INFO, "Input list for Offline Data Authentication added to TLV [%d bytes]", ODAI_listlen); + } + // getting certificates if (tlvdb_get(tlvRoot, 0x90, NULL)) { - PrintAndLogEx(INFO, "-->Recovering certificates."); + PrintAndLogEx(INFO, "Recovering certificates"); PKISetStrictExecution(false); RecoveryCertificates(tlvRoot, root); PKISetStrictExecution(true); @@ -1712,7 +1743,6 @@ static int CmdEMVScan(const char *Cmd) { // free json object json_decref(root); - return PM3_SUCCESS; } @@ -1921,13 +1951,13 @@ static int CmdEMVRoca(const char *Cmd) { size_t elmlen = len; struct tlv e; if (tlv_parse_tl(&abuf, &elmlen, &e)) { - memcpy(&ODAI_list[ODAI_listlen], &buf[len - elmlen], elmlen); + memcpy(ODAI_list + ODAI_listlen, &buf[len - elmlen], elmlen); ODAI_listlen += elmlen; } else { PrintAndLogEx(WARNING, "Error SFI[%02x]. Creating input list for Offline Data Authentication error", SFI); } } else { - memcpy(&ODAI_list[ODAI_listlen], buf, len); + memcpy(ODAI_list + ODAI_listlen, buf, len); ODAI_listlen += len; } SFIoffline--; diff --git a/client/src/emv/emvcore.c b/client/src/emv/emvcore.c index f2244fa05..3d9d3702f 100644 --- a/client/src/emv/emvcore.c +++ b/client/src/emv/emvcore.c @@ -205,10 +205,10 @@ void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv) { const struct tlv *tgPrio = tlvdb_get_inchild(ttmp, 0x87, NULL); if (!tgAID) break; - PrintAndLogEx(INFO, "|%s| %s |%s|", - sprint_hex_inrow_ex(tgAID->value, tgAID->len, 18), + PrintAndLogEx(INFO, "| %s| %s | %s|", + sprint_hex_inrow_ex(tgAID->value, tgAID->len, 17), (tgPrio) ? sprint_hex(tgPrio->value, 1) : " ", - (tgName) ? sprint_ascii_ex(tgName->value, tgName->len, 25) : " "); + (tgName) ? sprint_ascii_ex(tgName->value, tgName->len, 24) : " "); ttmp = tlvdb_find_next(ttmp, 0x6f); } @@ -387,7 +387,7 @@ static int EMVSelectWithRetry(EMVCommandChannel channel, bool ActivateField, boo } else { // card select error, proxmark error if (res == 1) { - PrintAndLogEx(WARNING, "Exit..."); + PrintAndLogEx(WARNING, "exiting..."); return 1; } @@ -551,7 +551,7 @@ int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, if (!LeaveFieldON) DropFieldEx(channel); - PrintAndLogEx(WARNING, "Exit..."); + PrintAndLogEx(WARNING, "exiting..."); return 1; } @@ -681,9 +681,9 @@ int trSDA(struct tlvdb *tlv) { } PrintAndLogEx(SUCCESS, "Issuer Public key recovered RID " _YELLOW_("%s") " IDX " _YELLOW_("%02hhx") " CSN " _YELLOW_("%s"), - sprint_hex(issuer_pk->rid, 5), - issuer_pk->index, - sprint_hex(issuer_pk->serial, 3) + sprint_hex(issuer_pk->rid, 5), + issuer_pk->index, + sprint_hex(issuer_pk->serial, 3) ); const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL); @@ -740,9 +740,9 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { } PrintAndLogEx(SUCCESS, "Issuer Public key recovered RID " _YELLOW_("%s") " IDX " _YELLOW_("%02hhx") " CSN " _YELLOW_("%s"), - sprint_hex(issuer_pk->rid, 5), - issuer_pk->index, - sprint_hex(issuer_pk->serial, 3) + sprint_hex(issuer_pk->rid, 5), + issuer_pk->index, + sprint_hex(issuer_pk->serial, 3) ); struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv); @@ -762,7 +762,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { if (tlvdb_get(tlv, 0x9f2d, NULL)) { struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv); if (!icc_pe_pk) { - PrintAndLogEx(WARNING, "WARNING: ICC PE PK recover error. "); + PrintAndLogEx(WARNING, "WARNING: ICC PE Public key recover error"); } else { PrintAndLogEx(SUCCESS, "ICC PE Public key recovered. RID " _YELLOW_("%s") " IDX " _YELLOW_("%02hhx") " CSN " _YELLOW_("%s"), sprint_hex(icc_pe_pk->rid, 5), @@ -947,9 +947,9 @@ int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, st } PrintAndLogEx(SUCCESS, "Issuer Public key recovered RID " _YELLOW_("%s") " IDX " _YELLOW_("%02hhx") " CSN " _YELLOW_("%s"), - sprint_hex(issuer_pk->rid, 5), - issuer_pk->index, - sprint_hex(issuer_pk->serial, 3) + sprint_hex(issuer_pk->rid, 5), + issuer_pk->index, + sprint_hex(issuer_pk->serial, 3) ); struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv); @@ -1015,9 +1015,9 @@ int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) { } PrintAndLogEx(SUCCESS, "Issuer Public key recovered RID " _YELLOW_("%s") " IDX " _YELLOW_("%02hhx") " CSN " _YELLOW_("%s"), - sprint_hex(issuer_pk->rid, 5), - issuer_pk->index, - sprint_hex(issuer_pk->serial, 3) + sprint_hex(issuer_pk->rid, 5), + issuer_pk->index, + sprint_hex(issuer_pk->serial, 3) ); JsonSaveBufAsHex(root, "$.ApplicationData.RID", issuer_pk->rid, 5); @@ -1027,24 +1027,20 @@ int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) { JsonSaveBufAsHex(root, "$.ApplicationData.IssuerPublicKeyModulus", issuer_pk->modulus, issuer_pk->mlen); free(issuer_pk_c); - struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlvRoot, NULL); + const struct tlv *sda_tlv = tlvdb_get(tlvRoot, 0x21, NULL); + struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlvRoot, sda_tlv); if (!icc_pk) { emv_pk_free(pk); emv_pk_free(issuer_pk); PrintAndLogEx(WARNING, "WARNING: ICC certificate not found, exiting"); return 2; } - PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", - icc_pk->rid[0], - icc_pk->rid[1], - icc_pk->rid[2], - icc_pk->rid[3], - icc_pk->rid[4], - icc_pk->index, - icc_pk->serial[0], - icc_pk->serial[1], - icc_pk->serial[2] - ); + + PrintAndLogEx(SUCCESS, "ICC Public key recovered RID " _YELLOW_("%s") " IDX " _YELLOW_("%02hhx") " CSN " _YELLOW_("%s"), + sprint_hex(icc_pk->rid, 5), + icc_pk->index, + sprint_hex(icc_pk->serial, 3) + ); char *icc_pk_c = emv_pk_dump_pk(icc_pk); JsonSaveStr(root, "$.ApplicationData.ICCPublicKeyDec", icc_pk_c);