diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 04e10ffb8..0e8ea2d00 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -203,30 +203,6 @@ typedef struct aidhdr { uint8_t name[16]; } PACKED aidhdr_t; -typedef struct { - const uint32_t aidnum; - const char *aid; - const char *comment; -} mfdesCommonAID_t; - -/* -PACS application id(s) - HID Factory, CP1000 Standard, Mobile, Custom and Elite -We have HID Factory, Field Encoder == CP1000 (?) -No mobile, Custom or Elite -*/ - -static const mfdesCommonAID_t commonAids[] = { - { 0x53494F, "\x53\x49\x4F", "SIO DESFire EV1 - HID Factory" }, - { 0xD3494F, "\xD3\x49\x4F", "SIO DESFire EV1 - Field Encoder" }, - { 0xD9494F, "\xD9\x49\x4F", "SIO DESFire EV1 - Field Encoder" }, - { 0xF484E3, "\xF4\x84\xE3", "SE Enhanced" }, - { 0xF484E4, "\xF4\x84\xE4", "SE Enhanced" }, - { 0xF4812F, "\xf4\x81\x2f", "Gallagher card data application" }, - { 0xF48120, "\xf4\x81\x20", "Gallagher card application directory" }, // Can be 0xF48120 - 0xF4812B, but I've only ever seen 0xF48120 - { 0xF47300, "\xf4\x73\x00", "Inner Range card application" }, - { 0xF51CD6, "\xF5\x1C\xD6", "LEAF Verified Open Application" }, -}; - typedef enum { MFDES_BRUTEAID_PRESET_FULL = 0, MFDES_BRUTEAID_PRESET_ASCII = 1, @@ -269,15 +245,6 @@ static int CLIGetUint32Hex(CLIParserContext *ctx, uint8_t paramnum, uint32_t def return PM3_SUCCESS; } -static const char *getAidCommentStr(uint32_t aid) { - for (int i = 0; i < ARRAYLEN(commonAids); i++) { - if (aid == commonAids[i].aidnum) { - return commonAids[i].comment; - } - } - return ""; -} - nxp_cardtype_t getCardType(uint8_t type, uint8_t major, uint8_t minor) { // DESFire MF3ICD40 @@ -1010,7 +977,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { j = 0; for (int i = 0; i < aidbuflen; i += 3, j++) { uint32_t aid = DesfireAIDByteToUint(&aidbuf[i]); - PrintAndLogEx(SUCCESS, _YELLOW_("%06X") ", %s", aid, getAidCommentStr(aid)); + PrintAndLogEx(SUCCESS, _YELLOW_("%06X") ", %s", aid, AIDDFGetCommentStr(aid)); } PrintAndLogEx(NORMAL, ""); } @@ -4956,7 +4923,7 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { PrintAndLogEx(SUCCESS, "--- " _CYAN_("AID list") " ( " _YELLOW_("%u") " found )", j); for (int i = 0; i < buflen; i += 3) { uint32_t aid = DesfireAIDByteToUint(&buf[i]); - PrintAndLogEx(SUCCESS, _YELLOW_("%06X") " %s", aid, getAidCommentStr(aid)); + PrintAndLogEx(SUCCESS, _YELLOW_("%06X") " %s", aid, AIDDFGetCommentStr(aid)); } PrintAndLogEx(NORMAL, ""); } else { diff --git a/client/src/mifare/aiddesfire.c b/client/src/mifare/aiddesfire.c index 26bf9adf6..d46c65508 100644 --- a/client/src/mifare/aiddesfire.c +++ b/client/src/mifare/aiddesfire.c @@ -17,6 +17,10 @@ //----------------------------------------------------------------------------- #include "aiddesfire.h" +#include +#include +#include +#include #include "pm3_cmd.h" #include "fileutils.h" #include "jansson.h" @@ -218,6 +222,7 @@ const char *nxp_cluster_to_text(uint8_t cluster) { } static json_t *df_known_aids = NULL; +static bool df_known_aids_load_tried = false; static int open_aiddf_file(json_t **root, bool verbose) { @@ -230,6 +235,7 @@ static int open_aiddf_file(json_t **root, bool verbose) { int retval = PM3_SUCCESS; json_error_t error; + *root = NULL; *root = json_load_file(path, 0, &error); if (!*root) { PrintAndLogEx(ERR, "json (%s) error on line %d: %s", path, error.line, error.text); @@ -239,6 +245,8 @@ static int open_aiddf_file(json_t **root, bool verbose) { if (!json_is_array(*root)) { PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", path); + json_decref(*root); + *root = NULL; retval = PM3_ESOFT; goto out; } @@ -255,19 +263,28 @@ out: return retval; } -static int close_aiddf_file(json_t *root) { - json_decref(root); - return PM3_SUCCESS; +static int ensure_aiddf_file_loaded(void) { + if (df_known_aids != NULL) { + return PM3_SUCCESS; + } + + if (df_known_aids_load_tried) { + return PM3_EFILE; + } + + df_known_aids_load_tried = true; + return open_aiddf_file(&df_known_aids, false); } -static const char *aiddf_json_get_str(json_t *data, const char *name) { +static const char *aiddf_json_get_str_ex(json_t *data, const char *name, bool verbose) { json_t *jstr = json_object_get(data, name); if (jstr == NULL) return NULL; if (!json_is_string(jstr)) { - PrintAndLogEx(WARNING, _YELLOW_("`%s`") " is not a string", name); + if (verbose) + PrintAndLogEx(WARNING, _YELLOW_("`%s`") " is not a string", name); return NULL; } @@ -278,28 +295,63 @@ static const char *aiddf_json_get_str(json_t *data, const char *name) { return cstr; } -static int print_aiddf_description(json_t *root, uint8_t aid[3], char *fmt, bool verbose) { - char laid[7] = {0}; - snprintf(laid, sizeof(laid), "%02x%02x%02x", aid[2], aid[1], aid[0]); // must be lowercase +static const char *aiddf_json_get_str(json_t *data, const char *name) { + return aiddf_json_get_str_ex(data, name, true); +} - json_t *elm = NULL; +static const char *aiddf_json_get_str_quiet(json_t *data, const char *name) { + return aiddf_json_get_str_ex(data, name, false); +} + +static bool aiddf_parse_aid_str(const char *aid_str, uint32_t *aid) { + if (aid_str == NULL || aid == NULL || strlen(aid_str) != 6) { + return false; + } + + for (int c = 0; c < 6; c++) { + if (isxdigit((uint8_t)aid_str[c]) == 0) { + return false; + } + } + + char *end = NULL; + unsigned long parsed_aid = strtoul(aid_str, &end, 16); + if (end == NULL || *end != '\0' || parsed_aid > 0xFFFFFFUL) { + return false; + } + + *aid = (uint32_t)parsed_aid; + return true; +} + +static json_t *find_aiddf_entry(json_t *root, uint32_t aid) { + if (json_is_array(root) == false) { + return NULL; + } for (uint32_t idx = 0; idx < json_array_size(root); idx++) { json_t *data = json_array_get(root, idx); if (!json_is_object(data)) { - PrintAndLogEx(ERR, "data [%d] is not an object\n", idx); continue; } - const char *faid = aiddf_json_get_str(data, "AID"); - char lfaid[strlen(faid) + 1]; - strcpy(lfaid, faid); - str_lower(lfaid); - if (strcmp(laid, lfaid) == 0) { - elm = data; - break; + + uint32_t db_aid = 0; + if (aiddf_parse_aid_str(aiddf_json_get_str_quiet(data, "AID"), &db_aid) == false) { + continue; + } + + if (db_aid == aid) { + return data; } } + return NULL; +} + +static int print_aiddf_description(json_t *root, uint8_t aid[3], char *fmt, bool verbose) { + uint32_t aid_num = aid[0] | ((uint32_t)aid[1] << 8) | ((uint32_t)aid[2] << 16); + json_t *elm = find_aiddf_entry(root, aid_num); + if (elm == NULL) { PrintAndLogEx(INFO, fmt, " (unknown)"); return PM3_ENODATA; @@ -334,12 +386,41 @@ static int print_aiddf_description(json_t *root, uint8_t aid[3], char *fmt, bool return PM3_SUCCESS; } +const char *AIDDFGetCommentStr(uint32_t aid) { + static char result[256] = {0}; + result[0] = '\0'; + + if (ensure_aiddf_file_loaded() != PM3_SUCCESS) { + return ""; + } + + json_t *elm = find_aiddf_entry(df_known_aids, aid); + if (elm == NULL) { + return ""; + } + + const char *name = aiddf_json_get_str_quiet(elm, "Name"); + const char *vendor = aiddf_json_get_str_quiet(elm, "Vendor"); + const char *description = aiddf_json_get_str_quiet(elm, "Description"); + + if (name && vendor) { + snprintf(result, sizeof(result), "%s [%s]", name, vendor); + } else if (name) { + snprintf(result, sizeof(result), "%s", name); + } else if (description) { + snprintf(result, sizeof(result), "%s", description); + } + + return result; +} + int AIDDFDecodeAndPrint(uint8_t aid[3]) { - open_aiddf_file(&df_known_aids, false); + if (ensure_aiddf_file_loaded() != PM3_SUCCESS) { + return PM3_EFILE; + } char fmt[80]; snprintf(fmt, sizeof(fmt), " DF AID Function... %02X%02X%02X :" _YELLOW_("%s"), aid[2], aid[1], aid[0], "%s"); print_aiddf_description(df_known_aids, aid, fmt, false); - close_aiddf_file(df_known_aids); return PM3_SUCCESS; } diff --git a/client/src/mifare/aiddesfire.h b/client/src/mifare/aiddesfire.h index 6dfd22674..c9c18fca2 100644 --- a/client/src/mifare/aiddesfire.h +++ b/client/src/mifare/aiddesfire.h @@ -22,6 +22,7 @@ #include "common.h" const char *nxp_cluster_to_text(uint8_t cluster); +const char *AIDDFGetCommentStr(uint32_t aid); int AIDDFDecodeAndPrint(uint8_t aid[3]); #endif // _AIDDESFIRE_H_