From a1077d9f7d4fb75d0f8ac02f44be01ff502ba5f0 Mon Sep 17 00:00:00 2001 From: kormax <3392860+kormax@users.noreply.github.com> Date: Fri, 8 May 2026 19:45:27 +0300 Subject: [PATCH 1/4] Retrieve GET DATA objects in 'hf calypso info' --- client/src/cmdhfcalypso.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/client/src/cmdhfcalypso.c b/client/src/cmdhfcalypso.c index edaa6b1f1..38d87aef5 100644 --- a/client/src/cmdhfcalypso.c +++ b/client/src/cmdhfcalypso.c @@ -1754,6 +1754,39 @@ static void calypso_print_ef_list_lids(const calypso_ef_list_t *ef_list) { PrintAndLogEx(SUCCESS, " EF List LIDs : " _YELLOW_("%s") "%s", lids, ef_list->truncated ? " (truncated)" : ""); } +static void calypso_print_info_data_objects(void) { + bool printed_header = false; + + for (size_t i = 0; i < ARRAYLEN(calypso_get_data_probes); i++) { + const calypso_get_data_probe_t *probe = &calypso_get_data_probes[i]; + if (probe->tag != 0x0185 && probe->tag != 0x5F52) { + continue; + } + + uint8_t response[APDU_RES_LEN] = {0}; + size_t response_len = 0; + uint16_t sw = 0; + int res = calypso_get_data_object(probe->tag, response, sizeof(response), &response_len, &sw); + bool has_data = res == PM3_SUCCESS && calypso_read_sw_has_data(sw, response_len); + + if (printed_header == false && has_data) { + PrintAndLogEx(INFO, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Get Data Objects") " ----------------------"); + printed_header = true; + } + + if (res != PM3_SUCCESS) { + continue; + } + + if (has_data == false) { + continue; + } + + PrintAndLogEx(SUCCESS, " %04X %-24s : " _YELLOW_("%s"), probe->tag, probe->name, sprint_hex(response, response_len)); + } +} + static size_t calypso_probe_get_data_objects(json_t *entries, bool print_results, bool verbose, calypso_ef_list_t *ef_list) { size_t found = 0; @@ -2924,6 +2957,8 @@ static int CmdHFCalypsoInfo(const char *Cmd) { calypso_print_select_info(&selected, verbose); calypso_reselect_exact_df_name(&selected, verbose); + calypso_print_info_data_objects(); + calypso_reselect_exact_df_name(&selected, verbose); uint8_t icc[CALYPSO_ICC_RECORD_LEN] = {0}; size_t icc_len = 0; From b2f5ae43c67e5b509ac46a679acdab61c8d12067 Mon Sep 17 00:00:00 2001 From: kormax <3392860+kormax@users.noreply.github.com> Date: Fri, 8 May 2026 19:45:58 +0300 Subject: [PATCH 2/4] Format big GET DATA object entries --- client/src/cmdhfcalypso.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/client/src/cmdhfcalypso.c b/client/src/cmdhfcalypso.c index 38d87aef5..8c5e0f1f9 100644 --- a/client/src/cmdhfcalypso.c +++ b/client/src/cmdhfcalypso.c @@ -56,6 +56,9 @@ #define CALYPSO_DUMP_FILENAME_MAX_SERIALS 8 #define CALYPSO_MAX_EF_LIST_LIDS 128 #define CALYPSO_MAX_LID_CANDIDATES 384 +#define CALYPSO_GET_DATA_INLINE_MAX 32 +#define CALYPSO_GET_DATA_HEX_BREAK 32 +#define CALYPSO_GET_DATA_HEX_INDENT " " #define CALYPSO_MANUFACTURERS_RESOURCE "calypso/manufacturers" #define CALYPSO_IC_FAMILIES_RESOURCE "calypso/ic_families" @@ -1736,22 +1739,21 @@ static bool calypso_ef_list_contains_lid(const calypso_ef_list_t *ef_list, uint1 return false; } -static void calypso_print_ef_list_lids(const calypso_ef_list_t *ef_list) { - if (ef_list == NULL || ef_list->count == 0) { +static void calypso_print_get_data_hex_block(const uint8_t *data, size_t data_len) { + for (size_t pos = 0; pos < data_len; pos += CALYPSO_GET_DATA_HEX_BREAK) { + size_t chunk_len = MIN(data_len - pos, CALYPSO_GET_DATA_HEX_BREAK); + PrintAndLogEx(INFO, CALYPSO_GET_DATA_HEX_INDENT _YELLOW_("%s"), sprint_hex(data + pos, chunk_len)); + } +} + +static void calypso_print_get_data_object(const calypso_get_data_probe_t *probe, const uint8_t *data, size_t data_len) { + if (data_len <= CALYPSO_GET_DATA_INLINE_MAX) { + PrintAndLogEx(SUCCESS, " %04X %-24s : " _YELLOW_("%s"), probe->tag, probe->name, sprint_hex(data, data_len)); return; } - char lids[CALYPSO_MAX_EF_LIST_LIDS * 6 + 1] = {0}; - size_t pos = 0; - for (size_t i = 0; i < ef_list->count && pos < sizeof(lids); i++) { - int written = snprintf(lids + pos, sizeof(lids) - pos, "%s%04X", i == 0 ? "" : " ", ef_list->lids[i]); - if (written < 0 || (size_t)written >= sizeof(lids) - pos) { - break; - } - pos += (size_t)written; - } - - PrintAndLogEx(SUCCESS, " EF List LIDs : " _YELLOW_("%s") "%s", lids, ef_list->truncated ? " (truncated)" : ""); + PrintAndLogEx(SUCCESS, " %04X %-24s : " _YELLOW_("%zu bytes"), probe->tag, probe->name, data_len); + calypso_print_get_data_hex_block(data, data_len); } static void calypso_print_info_data_objects(void) { @@ -1783,7 +1785,7 @@ static void calypso_print_info_data_objects(void) { continue; } - PrintAndLogEx(SUCCESS, " %04X %-24s : " _YELLOW_("%s"), probe->tag, probe->name, sprint_hex(response, response_len)); + calypso_print_get_data_object(probe, response, response_len); } } @@ -1811,7 +1813,7 @@ static size_t calypso_probe_get_data_objects(json_t *entries, bool print_results if (calypso_read_sw_has_data(sw, response_len)) { if (print_results || verbose) { - PrintAndLogEx(SUCCESS, " %04X %-24s : " _YELLOW_("%s"), probe->tag, probe->name, sprint_hex(response, response_len)); + calypso_print_get_data_object(probe, response, response_len); if (verbose && probe->tlv) { TLVPrintFromBuffer(response, (int)response_len); } @@ -1821,7 +1823,6 @@ static size_t calypso_probe_get_data_objects(json_t *entries, bool print_results } if (probe->tag == 0x00C0) { calypso_parse_ef_list_object(response, response_len, ef_list); - calypso_print_ef_list_lids(ef_list); } found++; continue; From e96b6931e6b3f62c2ec3ab4555482775ddae4014 Mon Sep 17 00:00:00 2001 From: kormax <3392860+kormax@users.noreply.github.com> Date: Fri, 8 May 2026 19:46:21 +0300 Subject: [PATCH 3/4] Skip attempting GET DATA if reported as unsupported --- client/src/cmdhfcalypso.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/client/src/cmdhfcalypso.c b/client/src/cmdhfcalypso.c index 8c5e0f1f9..8dc37ceea 100644 --- a/client/src/cmdhfcalypso.c +++ b/client/src/cmdhfcalypso.c @@ -1781,6 +1781,10 @@ static void calypso_print_info_data_objects(void) { continue; } + if (sw == ISO7816_INS_NOT_SUPPORTED) { + break; + } + if (has_data == false) { continue; } @@ -1811,6 +1815,13 @@ static size_t calypso_probe_get_data_objects(json_t *entries, bool print_results continue; } + if (sw == ISO7816_INS_NOT_SUPPORTED) { + if (verbose) { + PrintAndLogEx(INFO, " %04X %-24s : " _YELLOW_("%04X") " - %s", probe->tag, probe->name, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xFF)); + } + break; + } + if (calypso_read_sw_has_data(sw, response_len)) { if (print_results || verbose) { calypso_print_get_data_object(probe, response, response_len); From 7ee697aa02e9f32512e13c811029afae3d2edc8e Mon Sep 17 00:00:00 2001 From: kormax <3392860+kormax@users.noreply.github.com> Date: Fri, 8 May 2026 21:41:35 +0300 Subject: [PATCH 4/4] Add new hex print helper --- client/src/cmdhfcalypso.c | 9 +-------- client/src/util.c | 32 ++++++++++++++++++++++++++++++++ client/src/util.h | 1 + 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhfcalypso.c b/client/src/cmdhfcalypso.c index 8dc37ceea..e28985899 100644 --- a/client/src/cmdhfcalypso.c +++ b/client/src/cmdhfcalypso.c @@ -1739,13 +1739,6 @@ static bool calypso_ef_list_contains_lid(const calypso_ef_list_t *ef_list, uint1 return false; } -static void calypso_print_get_data_hex_block(const uint8_t *data, size_t data_len) { - for (size_t pos = 0; pos < data_len; pos += CALYPSO_GET_DATA_HEX_BREAK) { - size_t chunk_len = MIN(data_len - pos, CALYPSO_GET_DATA_HEX_BREAK); - PrintAndLogEx(INFO, CALYPSO_GET_DATA_HEX_INDENT _YELLOW_("%s"), sprint_hex(data + pos, chunk_len)); - } -} - static void calypso_print_get_data_object(const calypso_get_data_probe_t *probe, const uint8_t *data, size_t data_len) { if (data_len <= CALYPSO_GET_DATA_INLINE_MAX) { PrintAndLogEx(SUCCESS, " %04X %-24s : " _YELLOW_("%s"), probe->tag, probe->name, sprint_hex(data, data_len)); @@ -1753,7 +1746,7 @@ static void calypso_print_get_data_object(const calypso_get_data_probe_t *probe, } PrintAndLogEx(SUCCESS, " %04X %-24s : " _YELLOW_("%zu bytes"), probe->tag, probe->name, data_len); - calypso_print_get_data_hex_block(data, data_len); + print_hex_noascii_break_ex(data, data_len, CALYPSO_GET_DATA_HEX_BREAK, CALYPSO_GET_DATA_HEX_INDENT "\x1b[33m", ' ', AEND); } static void calypso_print_info_data_objects(void) { diff --git a/client/src/util.c b/client/src/util.c index 8f4b5589a..2e7627892 100644 --- a/client/src/util.c +++ b/client/src/util.c @@ -339,6 +339,38 @@ void print_hex_noascii_break(const uint8_t *data, const size_t len, uint8_t brea } } +void print_hex_noascii_break_ex(const uint8_t *data, const size_t len, uint8_t breaks, const char *prefix, char separator, const char *suffix) { + if (data == NULL || len == 0 || breaks == 0) return; + + if (prefix == NULL) { + prefix = ""; + } + if (suffix == NULL) { + suffix = ""; + } + char sep[2] = {separator, '\0'}; + + for (size_t pos = 0; pos < len; pos += breaks) { + char buf[UTIL_BUFFER_SIZE_SPRINT + 3] = {0}; + size_t chunk_len = len - pos; + if (chunk_len > breaks) { + chunk_len = breaks; + } + + char *p = buf; + size_t remaining = sizeof(buf); + for (size_t i = 0; i < chunk_len; i++) { + int written = snprintf(p, remaining, "%s%02X", (i > 0 && separator != '\0') ? sep : "", data[pos + i]); + if (written < 0 || (size_t)written >= remaining) { + break; + } + p += written; + remaining -= (size_t)written; + } + PrintAndLogEx(INFO, "%s%s%s", prefix, buf, suffix); + } +} + static void print_buffer_ex(const uint8_t *data, const size_t len, int level, uint8_t breaks) { // sanity checks diff --git a/client/src/util.h b/client/src/util.h index 75cd7c9b3..727c95545 100644 --- a/client/src/util.h +++ b/client/src/util.h @@ -84,6 +84,7 @@ void hex_to_buffer(uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, void print_hex(const uint8_t *data, const size_t len); void print_hex_break(const uint8_t *data, const size_t len, const uint8_t breaks); void print_hex_noascii_break(const uint8_t *data, const size_t len, uint8_t breaks); +void print_hex_noascii_break_ex(const uint8_t *data, const size_t len, uint8_t breaks, const char *prefix, char separator, const char *suffix); char *sprint_hex(const uint8_t *data, const size_t len); char *sprint_hex_inrow(const uint8_t *data, const size_t len);