From 5a4e77d7afa35352c05c5867f179111288f69cac Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 01:05:09 +0300 Subject: [PATCH 01/21] hf emrtd info: Parse and print info about EF_DG12 --- client/src/cmdhfemrtd.c | 77 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index f2c3a60d3..82e9753c2 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1183,6 +1183,22 @@ static void emrtd_print_expiry(char *mrz, int offset) { } } +static void emrtd_print_issuance(char *data) { + char final_date[12] = { 0x00 }; + emrtd_mrz_convert_date(data, 0, final_date, true, true); + + PrintAndLogEx(SUCCESS, "Date of issue.........: " _YELLOW_("%s"), final_date); +} + +static void emrtd_print_personalization_timestamp(uint8_t *data) { + char str_date[0x0F] = { 0x00 }; + strcpy(str_date, sprint_hex_inrow(data, 0x0E)); + char final_date[20] = { 0x00 }; + sprintf(final_date, "%.4s-%.2s-%.2s %.2s:%.2s:%.2s", str_date, str_date + 4, str_date + 6, str_date + 8, str_date + 10, str_date + 12); + + PrintAndLogEx(SUCCESS, "Personalization at....: " _YELLOW_("%s"), final_date); +} + static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { int td_variant = 0; @@ -1339,6 +1355,65 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { return true; } +static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { + uint8_t taglist[100] = { 0x00 }; + int taglistlen = 0; + uint8_t tagdata[1000] = { 0x00 }; + int tagdatalen = 0; + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG12") " -------------------"); + + if (!emrtd_lds_get_data_by_tag(response, &resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { + PrintAndLogEx(ERR, "Failed to read file list from EF_DG12."); + return false; + } + + for (int i = 0; i < taglistlen; i++) { + emrtd_lds_get_data_by_tag(response, &resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + // Special behavior for two char tags + if (taglist[i] == 0x5f) { + // Several things here are longer than the rest but I can't think of a way to shorten them + // ...and I doubt many states are using them. + switch (taglist[i + 1]) { + case 0x19: + PrintAndLogEx(SUCCESS, "Issuing Authority.....: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x26: + emrtd_print_issuance((char *) tagdata); + break; + case 0x1b: + PrintAndLogEx(SUCCESS, "Endorsements & Observations: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x1c: + PrintAndLogEx(SUCCESS, "Tax/Exit Requirements.: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x1d: + saveFile("FrontOfDocument", ".jpg", tagdata, tagdatalen); + break; + case 0x1e: + saveFile("BackOfDocument", ".jpg", tagdata, tagdatalen); + break; + case 0x55: + emrtd_print_personalization_timestamp(tagdata); + break; + case 0x56: + PrintAndLogEx(SUCCESS, "Serial of Personalization System: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + default: + PrintAndLogEx(SUCCESS, "Unknown Field %02X%02X....: %s", taglist[i], taglist[i + 1], sprint_hex_inrow(tagdata, tagdatalen)); + break; + } + + i += 1; + } else { + // TODO: Account for A0 + PrintAndLogEx(SUCCESS, "Unknown Field %02X......: %s", taglist[i], sprint_hex_inrow(tagdata, tagdatalen)); + } + } + return true; +} + int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; @@ -1396,6 +1471,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab emrtd_print_ef_dg1_info(response, resplen); } else if (strcmp(file_name, "EF_DG11") == 0 && emrtd_select_and_read(response, &resplen, EMRTD_EF_DG11, ks_enc, ks_mac, ssc, BAC, use_14b)) { emrtd_print_ef_dg11_info(response, resplen); + } else if (strcmp(file_name, "EF_DG12") == 0 && emrtd_select_and_read(response, &resplen, EMRTD_EF_DG12, ks_enc, ks_mac, ssc, BAC, use_14b)) { + emrtd_print_ef_dg12_info(response, resplen); } } From 24b0e042cbbfbac02091ddaa7c9d48954ba7f77e Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 01:35:32 +0300 Subject: [PATCH 02/21] Resolve coverity 308206 and 308207 --- client/src/cmdhfemrtd.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 82e9753c2..796e765b0 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1523,7 +1523,8 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { uint8_t dob[7] = { 0x00 }; uint8_t expiry[7] = { 0x00 }; bool BAC = true; - int slen = 0; // unused + bool error = false; + int slen = 0; // Go through all args, if even one isn't supplied, mark BAC as unavailable if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { BAC = false; @@ -1541,7 +1542,7 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { if (!validate_date(dob, slen)) { PrintAndLogEx(ERR, "Date of birth date format is incorrect, cannot continue."); PrintAndLogEx(HINT, "Use the format YYMMDD."); - return PM3_ESOFT; + error = true; } } @@ -1551,11 +1552,14 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { if (!validate_date(expiry, slen)) { PrintAndLogEx(ERR, "Expiry date format is incorrect, cannot continue."); PrintAndLogEx(HINT, "Use the format YYMMDD."); - return PM3_ESOFT; + error = true; } } CLIParserFree(ctx); + if (error) { + return PM3_ESOFT; + } return dumpHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); } @@ -1579,7 +1583,8 @@ static int cmd_hf_emrtd_info(const char *Cmd) { uint8_t dob[7] = { 0x00 }; uint8_t expiry[7] = { 0x00 }; bool BAC = true; - int slen = 0; // unused + bool error = false; + int slen = 0; // Go through all args, if even one isn't supplied, mark BAC as unavailable if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { BAC = false; @@ -1596,7 +1601,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { if (!validate_date(dob, slen)) { PrintAndLogEx(ERR, "Date of birth date format is incorrect, cannot continue."); PrintAndLogEx(HINT, "Use the format YYMMDD."); - return PM3_ESOFT; + error = true; } } @@ -1606,11 +1611,14 @@ static int cmd_hf_emrtd_info(const char *Cmd) { if (!validate_date(expiry, slen)) { PrintAndLogEx(ERR, "Expiry date format is incorrect, cannot continue."); PrintAndLogEx(HINT, "Use the format YYMMDD."); - return PM3_ESOFT; + error = true; } } CLIParserFree(ctx); + if (error) { + return PM3_ESOFT; + } return infoHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); } From 7a9e129ad9513666852550ee417406aff25f7870 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 00:19:11 +0100 Subject: [PATCH 03/21] hf emrtd info: add option to load from files --- client/src/cmdhfemrtd.c | 76 +++++++++++++++++++++++++++++++++++++++-- client/src/cmdhfemrtd.h | 1 + 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 796e765b0..97b8264df 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1480,6 +1480,70 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_SUCCESS; } +int infoHF_EMRTD_offline(const char *path) { + uint8_t *data; + int datalen = 0; + char *filepath = calloc(strlen(path) + 100, sizeof(char)); + if (filepath == NULL) + return PM3_EMALLOC; + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, "EF_COM"); + + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to read EF_COM."); + free(filepath); + return PM3_ESOFT; + } + uint8_t filelist[50]; + int filelistlen = 0; + int res = emrtd_lds_get_data_by_tag(data, &datalen, filelist, &filelistlen, 0x5c, 0x00, false); + free(data); + if (!res) { + PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); + free(filepath); + return PM3_ESOFT; + } + + // Read files in the file list + for (int i = 0; i < filelistlen; i++) { + char file_id[5] = { 0x00 }; + char file_name[8] = { 0x00 }; + if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { + PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + continue; + } + + if (strcmp(file_name, "EF_DG1") == 0) { + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, "EF_DG1"); + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) == PM3_SUCCESS) { + emrtd_print_ef_dg1_info(data, datalen); + free(data); + } + } else if (strcmp(file_name, "EF_DG11") == 0) { + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, "EF_DG11"); + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) == PM3_SUCCESS) { + emrtd_print_ef_dg11_info(data, datalen); + free(data); + } + } else if (strcmp(file_name, "EF_DG12") == 0) { + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, "EF_DG12"); + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) == PM3_SUCCESS) { + emrtd_print_ef_dg12_info(data, datalen); + free(data); + } + } + } + free(filepath); + return PM3_SUCCESS; +} + static void text_to_upper(uint8_t *data, int datalen) { // Loop over text to make lowercase text uppercase for (int i = 0; i < datalen; i++) { @@ -1575,6 +1639,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { arg_str0("n", "documentnumber", "", "document number, up to 9 chars"), arg_str0("d", "dateofbirth", "", "date of birth in YYMMDD format"), arg_str0("e", "expiry", "", "expiry in YYMMDD format"), + arg_str0("p", "path", "", "display info from offline dump stored in dirpath"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -1614,12 +1679,17 @@ static int cmd_hf_emrtd_info(const char *Cmd) { error = true; } } - + uint8_t path[FILENAME_MAX] = { 0x00 }; + bool offline = CLIParamStrToBuf(arg_get_str(ctx, 4), path, sizeof(path), &slen) == 0 && slen > 0; CLIParserFree(ctx); if (error) { return PM3_ESOFT; } - return infoHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); + if (offline) { + return infoHF_EMRTD_offline((const char *)path); + } else { + return infoHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); + } } static int cmd_hf_emrtd_list(const char *Cmd) { @@ -1635,7 +1705,7 @@ static int cmd_hf_emrtd_list(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"dump", cmd_hf_emrtd_dump, IfPm3Iso14443, "Dump eMRTD files to binary files"}, - {"info", cmd_hf_emrtd_info, IfPm3Iso14443, "Display info about an eMRTD"}, + {"info", cmd_hf_emrtd_info, AlwaysAvailable, "Display info about an eMRTD"}, {"list", cmd_hf_emrtd_list, AlwaysAvailable, "List ISO 14443A/7816 history"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index f19a71ac0..3cfcd3cbd 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -17,4 +17,5 @@ int CmdHFeMRTD(const char *Cmd); int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available); int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available); +int infoHF_EMRTD_offline(const char *path); #endif From bdcf84f90de080bc32332cbbe6fcb9205d9f7342 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 00:59:27 +0100 Subject: [PATCH 04/21] fix emrtd info offline bug --- client/src/cmdhfemrtd.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 97b8264df..fda90889f 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -568,14 +568,14 @@ static int emrtd_read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uin return true; } -static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int *datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag) { +static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag) { int offset = 1; - offset += emrtd_get_asn1_field_length(datain, *datainlen, offset); + offset += emrtd_get_asn1_field_length(datain, datainlen, offset); int e_idlen = 0; int e_datalen = 0; int e_fieldlen = 0; - while (offset < *datainlen) { + while (offset < datainlen) { PrintAndLogEx(DEBUG, "emrtd_lds_get_data_by_tag, offset: %i, data: %X", offset, *(datain + offset)); // Determine element ID length to set as offset on asn1datalength if ((*(datain + offset) == 0x5F) || (*(datain + offset) == 0x7F)) { @@ -585,14 +585,14 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int *datainlen, uint8_t * } // Get the length of the element - e_datalen = emrtd_get_asn1_data_length(datain + offset, *datainlen - offset, e_idlen); + e_datalen = emrtd_get_asn1_data_length(datain + offset, datainlen - offset, e_idlen); // Get the length of the element's length - e_fieldlen = emrtd_get_asn1_field_length(datain + offset, *datainlen - offset, e_idlen); + e_fieldlen = emrtd_get_asn1_field_length(datain + offset, datainlen - offset, e_idlen); // If the element is what we're looking for, get the data and return true if (*(datain + offset) == tag1 && (!twobytetag || *(datain + offset + 1) == tag2)) { - if (*datainlen > e_datalen) { + if (datainlen > e_datalen) { *dataoutlen = e_datalen; memcpy(dataout, datain + offset + e_idlen + e_fieldlen, e_datalen); return true; @@ -741,7 +741,7 @@ static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { int datalen = 0; // If we can't find image in EF_DG5, return false. - if (emrtd_lds_get_data_by_tag(file_contents, &file_length, data, &datalen, 0x5F, 0x40, true) == false) { + if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x40, true) == false) { return false; } @@ -1013,7 +1013,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab uint8_t filelist[50]; int filelistlen = 0; - if (!emrtd_lds_get_data_by_tag(response, &resplen, filelist, &filelistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); DropField(); return PM3_ESOFT; @@ -1210,7 +1210,7 @@ static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { char mrz[90] = { 0x00 }; int mrzlen = 0; - if (!emrtd_lds_get_data_by_tag(response, &resplen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true)) { PrintAndLogEx(ERR, "Failed to read MRZ from EF_DG1."); return false; } @@ -1292,13 +1292,13 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG11") " -------------------"); - if (!emrtd_lds_get_data_by_tag(response, &resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG11."); return false; } for (int i = 0; i < taglistlen; i++) { - emrtd_lds_get_data_by_tag(response, &resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + emrtd_lds_get_data_by_tag(response, resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); // Special behavior for two char tags if (taglist[i] == 0x5f) { switch (taglist[i + 1]) { @@ -1364,13 +1364,13 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG12") " -------------------"); - if (!emrtd_lds_get_data_by_tag(response, &resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG12."); return false; } for (int i = 0; i < taglistlen; i++) { - emrtd_lds_get_data_by_tag(response, &resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + emrtd_lds_get_data_by_tag(response, resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); // Special behavior for two char tags if (taglist[i] == 0x5f) { // Several things here are longer than the rest but I can't think of a way to shorten them @@ -1452,7 +1452,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab uint8_t filelist[50]; int filelistlen = 0; - if (!emrtd_lds_get_data_by_tag(response, &resplen, filelist, &filelistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); DropField(); return PM3_ESOFT; @@ -1482,7 +1482,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab int infoHF_EMRTD_offline(const char *path) { uint8_t *data; - int datalen = 0; + size_t datalen = 0; char *filepath = calloc(strlen(path) + 100, sizeof(char)); if (filepath == NULL) return PM3_EMALLOC; @@ -1497,7 +1497,7 @@ int infoHF_EMRTD_offline(const char *path) { } uint8_t filelist[50]; int filelistlen = 0; - int res = emrtd_lds_get_data_by_tag(data, &datalen, filelist, &filelistlen, 0x5c, 0x00, false); + int res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false); free(data); if (!res) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); @@ -1513,7 +1513,6 @@ int infoHF_EMRTD_offline(const char *path) { PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); continue; } - if (strcmp(file_name, "EF_DG1") == 0) { strcpy(filepath, path); strncat(filepath, PATHSEP, 1); @@ -1639,7 +1638,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { arg_str0("n", "documentnumber", "", "document number, up to 9 chars"), arg_str0("d", "dateofbirth", "", "date of birth in YYMMDD format"), arg_str0("e", "expiry", "", "expiry in YYMMDD format"), - arg_str0("p", "path", "", "display info from offline dump stored in dirpath"), + arg_str0(NULL, "path", "", "display info from offline dump stored in dirpath"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); From 6ca472fc8ffa74a2c063a73dc6859aecfd863dea Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 03:27:48 +0300 Subject: [PATCH 05/21] emrtd: Dump image from EF_DG7 too --- client/src/cmdhfemrtd.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index fda90889f..a06beff9a 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -735,7 +735,6 @@ static bool emrtd_dump_ef_dg2(uint8_t *file_contents, int file_length) { return true; } - static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { uint8_t data[EMRTD_MAX_FILE_SIZE]; int datalen = 0; @@ -754,6 +753,24 @@ static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { return true; } +static bool emrtd_dump_ef_dg7(uint8_t *file_contents, int file_length) { + uint8_t data[EMRTD_MAX_FILE_SIZE]; + int datalen = 0; + + // If we can't find image in EF_DG7, return false. + if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x42, true) == false) { + return false; + } + + if (datalen < EMRTD_MAX_FILE_SIZE) { + saveFile("EF_DG7", ".jpg", data, datalen); + } else { + PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg7) datalen out-of-bounds"); + return false; + } + return true; +} + static bool emrtd_dump_ef_sod(uint8_t *file_contents, int file_length) { int fieldlen = emrtd_get_asn1_field_length(file_contents, file_length, 1); int datalen = emrtd_get_asn1_data_length(file_contents, file_length, 1); @@ -783,6 +800,8 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons emrtd_dump_ef_dg2(response, resplen); } else if (strcmp(file, EMRTD_EF_DG5) == 0) { emrtd_dump_ef_dg5(response, resplen); + } else if (strcmp(file, EMRTD_EF_DG7) == 0) { + emrtd_dump_ef_dg7(response, resplen); } else if (strcmp(file, EMRTD_EF_SOD) == 0) { emrtd_dump_ef_sod(response, resplen); } From 88f0de3176e21d30b2667839cea4e70b5e0f09ae Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 05:28:21 +0300 Subject: [PATCH 06/21] emrtd: Use .jp2 ext when saving JPG 2000 files --- client/src/cmdhfemrtd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index a06beff9a..e6875fc63 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -731,7 +731,7 @@ static bool emrtd_dump_ef_dg2(uint8_t *file_contents, int file_length) { return false; } - saveFile("EF_DG2", ".jpg", file_contents + offset, datalen); + saveFile("EF_DG2", file_contents[offset] == 0xFF ? ".jpg" : ".jp2", file_contents + offset, datalen); return true; } @@ -745,7 +745,7 @@ static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { } if (datalen < EMRTD_MAX_FILE_SIZE) { - saveFile("EF_DG5", ".jpg", data, datalen); + saveFile("EF_DG5", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg5) datalen out-of-bounds"); return false; @@ -763,7 +763,7 @@ static bool emrtd_dump_ef_dg7(uint8_t *file_contents, int file_length) { } if (datalen < EMRTD_MAX_FILE_SIZE) { - saveFile("EF_DG7", ".jpg", data, datalen); + saveFile("EF_DG7", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg7) datalen out-of-bounds"); return false; @@ -1348,7 +1348,7 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Personal Summary......: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; case 0x16: - saveFile("ProofOfCitizenship", ".jpg", tagdata, tagdatalen); + saveFile("ProofOfCitizenship", tagdata[0] == 0xFF ? ".jpg" : ".jp2", tagdata, tagdatalen); break; case 0x17: // TODO: acc for < separation @@ -1408,10 +1408,10 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Tax/Exit Requirements.: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; case 0x1d: - saveFile("FrontOfDocument", ".jpg", tagdata, tagdatalen); + saveFile("FrontOfDocument", tagdata[0] == 0xFF ? ".jpg" : ".jp2", tagdata, tagdatalen); break; case 0x1e: - saveFile("BackOfDocument", ".jpg", tagdata, tagdatalen); + saveFile("BackOfDocument", tagdata[0] == 0xFF ? ".jpg" : ".jp2", tagdata, tagdatalen); break; case 0x55: emrtd_print_personalization_timestamp(tagdata); From 333afad302852c22ca03130a98eb65af84821953 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 06:49:21 +0300 Subject: [PATCH 07/21] hf emrtd info: Fixes for hungarian passports --- client/src/cmdhfemrtd.c | 46 +++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index e6875fc63..389d10f53 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1154,15 +1154,28 @@ static void emrtd_print_name(char *mrz, int offset, int max_length, bool localiz } } -static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool is_expiry, bool is_full) { +static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool is_expiry, bool is_full, bool is_ascii) { + char work_date[9] = { 0x00 }; + int len = is_full ? 8 : 6; + + // Copy the data to a working array in the right format + if (!is_ascii) { + memcpy(work_date, sprint_hex_inrow((uint8_t *)mrz + offset, len / 2), len); + } else { + memcpy(work_date, mrz + offset, len); + } + + // Set offset to 0 as we've now copied data. + offset = 0; + if (is_full) { // If we get the full date, use the first two characters from that for year - memcpy(final_date, mrz, 2); + memcpy(final_date, work_date, 2); // and do + 2 on offset so that rest of code uses the right data offset += 2; } else { char temp_year[3] = { 0x00 }; - memcpy(temp_year, mrz + offset, 2); + memcpy(temp_year, work_date, 2); // If it's > 20, assume 19xx. if (strtol(temp_year, NULL, 10) < 20 || is_expiry) { final_date[0] = '2'; @@ -1173,16 +1186,16 @@ static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool } } - memcpy(final_date + 2, mrz + offset, 2); + memcpy(final_date + 2, work_date + offset, 2); final_date[4] = '-'; - memcpy(final_date + 5, mrz + offset + 2, 2); + memcpy(final_date + 5, work_date + offset + 2, 2); final_date[7] = '-'; - memcpy(final_date + 8, mrz + offset + 4, 2); + memcpy(final_date + 8, work_date + offset + 4, 2); } -static void emrtd_print_dob(char *mrz, int offset, bool full) { +static void emrtd_print_dob(char *mrz, int offset, bool full, bool ascii) { char final_date[12] = { 0x00 }; - emrtd_mrz_convert_date(mrz, offset, final_date, false, full); + emrtd_mrz_convert_date(mrz, offset, final_date, false, full, ascii); PrintAndLogEx(SUCCESS, "Date of birth.........: " _YELLOW_("%s"), final_date); @@ -1193,7 +1206,7 @@ static void emrtd_print_dob(char *mrz, int offset, bool full) { static void emrtd_print_expiry(char *mrz, int offset) { char final_date[12] = { 0x00 }; - emrtd_mrz_convert_date(mrz, offset, final_date, true, false); + emrtd_mrz_convert_date(mrz, offset, final_date, true, false, true); PrintAndLogEx(SUCCESS, "Date of expiry........: " _YELLOW_("%s"), final_date); @@ -1202,9 +1215,9 @@ static void emrtd_print_expiry(char *mrz, int offset) { } } -static void emrtd_print_issuance(char *data) { +static void emrtd_print_issuance(char *data, bool ascii) { char final_date[12] = { 0x00 }; - emrtd_mrz_convert_date(data, 0, final_date, true, true); + emrtd_mrz_convert_date(data, 0, final_date, true, true, ascii); PrintAndLogEx(SUCCESS, "Date of issue.........: " _YELLOW_("%s"), final_date); } @@ -1268,7 +1281,7 @@ static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 44 + 10); emrtd_print_name(mrz, 5, 38, false); emrtd_print_document_number(mrz, 44); - emrtd_print_dob(mrz, 44 + 13, false); + emrtd_print_dob(mrz, 44 + 13, false, true); emrtd_print_legal_sex(&mrz[44 + 20]); emrtd_print_expiry(mrz, 44 + 21); emrtd_print_optional_elements(mrz, 44 + 28, 14, true); @@ -1287,7 +1300,7 @@ static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 30 + 15); emrtd_print_name(mrz, 60, 30, false); emrtd_print_document_number(mrz, 5); - emrtd_print_dob(mrz, 30, false); + emrtd_print_dob(mrz, 30, false, true); emrtd_print_legal_sex(&mrz[30 + 7]); emrtd_print_expiry(mrz, 30 + 8); emrtd_print_optional_elements(mrz, 15, 15, false); @@ -1324,6 +1337,9 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { case 0x0e: emrtd_print_name((char *) tagdata, 0, tagdatalen, true); break; + case 0x0f: + emrtd_print_name((char *) tagdata, 0, tagdatalen, false); + break; case 0x10: PrintAndLogEx(SUCCESS, "Personal Number.......: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; @@ -1358,7 +1374,7 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Custody Information...: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; case 0x2b: - emrtd_print_dob((char *) tagdata, 0, true); + emrtd_print_dob((char *) tagdata, 0, true, tagdatalen != 4); break; default: PrintAndLogEx(SUCCESS, "Unknown Field %02X%02X....: %s", taglist[i], taglist[i + 1], sprint_hex_inrow(tagdata, tagdatalen)); @@ -1399,7 +1415,7 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Issuing Authority.....: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; case 0x26: - emrtd_print_issuance((char *) tagdata); + emrtd_print_issuance((char *) tagdata, tagdatalen != 4); break; case 0x1b: PrintAndLogEx(SUCCESS, "Endorsements & Observations: " _YELLOW_("%.*s"), tagdatalen, tagdata); From 013a8abcd885ffcb19a8311517618935b287a171 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 07:01:03 +0300 Subject: [PATCH 08/21] hf emrtd info: Fix segfaults on mononyms --- client/src/cmdhfemrtd.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 389d10f53..f925c2809 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1106,12 +1106,13 @@ static int emrtd_mrz_determine_length(char *mrz, int offset, int max_length) { static int emrtd_mrz_determine_separator(char *mrz, int offset, int max_length) { int i; - for (i = max_length; i >= 0; i--) { + for (i = max_length; i > 0; i--) { if (mrz[offset + i - 1] == '<' && mrz[offset + i] == '<') { break; } } - return i - 1; + // Return i - 1 unless we couldn't find anything (in that case return 0). + return i ? i - 1 : 0; } static void emrtd_print_optional_elements(char *mrz, int offset, int length, bool verify_check_digit) { @@ -1139,13 +1140,19 @@ static void emrtd_print_document_number(char *mrz, int offset) { static void emrtd_print_name(char *mrz, int offset, int max_length, bool localized) { char final_name[100] = { 0x00 }; - int i = emrtd_mrz_determine_length(mrz, offset, max_length); - int sep = emrtd_mrz_determine_separator(mrz, offset, i); - int namelen = (i - (sep + 2)); + int namelen = emrtd_mrz_determine_length(mrz, offset, max_length); + int sep = emrtd_mrz_determine_separator(mrz, offset, namelen); - memcpy(final_name, mrz + offset + sep + 2, namelen); - final_name[namelen] = ' '; - memcpy(final_name + namelen + 1, mrz + offset, sep); + // Account for mononyms + if (sep != 0) { + int firstnamelen = (namelen - (sep + 2)); + + memcpy(final_name, mrz + offset + sep + 2, firstnamelen); + final_name[firstnamelen] = ' '; + memcpy(final_name + firstnamelen + 1, mrz + offset, sep); + } else { + memcpy(final_name, mrz + offset, namelen); + } if (localized) { PrintAndLogEx(SUCCESS, "Legal Name (Localized): " _YELLOW_("%s"), final_name); From 9945107016ce0c05345c43ee4c6ad825f6b908eb Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 07:08:39 +0300 Subject: [PATCH 09/21] hf emrtd info: Replace padding with spaces on names --- client/src/cmdhfemrtd.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index f925c2809..32d42f523 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1115,6 +1115,14 @@ static int emrtd_mrz_determine_separator(char *mrz, int offset, int max_length) return i ? i - 1 : 0; } +static void emrtd_mrz_replace_pad(char *data, int datalen, char newchar) { + for (int i = 0; i < datalen; i++) { + if (data[i] == '<') { + data[i] = newchar; + } + } +} + static void emrtd_print_optional_elements(char *mrz, int offset, int length, bool verify_check_digit) { int i = emrtd_mrz_determine_length(mrz, offset, length); @@ -1154,6 +1162,9 @@ static void emrtd_print_name(char *mrz, int offset, int max_length, bool localiz memcpy(final_name, mrz + offset, namelen); } + // Replace < characters with spaces + emrtd_mrz_replace_pad(final_name, namelen, ' '); + if (localized) { PrintAndLogEx(SUCCESS, "Legal Name (Localized): " _YELLOW_("%s"), final_name); } else { From d23ebec93c0e81819f649fab15b963157d63d946 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 07:25:28 +0300 Subject: [PATCH 10/21] emrtd: Make emrtd_mrz_determine_separator less hacky --- client/src/cmdhfemrtd.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 32d42f523..14abc8c90 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1106,13 +1106,12 @@ static int emrtd_mrz_determine_length(char *mrz, int offset, int max_length) { static int emrtd_mrz_determine_separator(char *mrz, int offset, int max_length) { int i; - for (i = max_length; i > 0; i--) { - if (mrz[offset + i - 1] == '<' && mrz[offset + i] == '<') { + for (i = max_length - 1; i > 0; i--) { + if (mrz[offset + i] == '<' && mrz[offset + i + 1] == '<') { break; } } - // Return i - 1 unless we couldn't find anything (in that case return 0). - return i ? i - 1 : 0; + return i; } static void emrtd_mrz_replace_pad(char *data, int datalen, char newchar) { From 263eb5774900e1c5d12f078c011ef797cac69fee Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 16:14:27 +0300 Subject: [PATCH 11/21] emrtd: fixes for some belgian passports --- client/src/cmdhfemrtd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 14abc8c90..827faa4e0 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1105,6 +1105,7 @@ static int emrtd_mrz_determine_length(char *mrz, int offset, int max_length) { } static int emrtd_mrz_determine_separator(char *mrz, int offset, int max_length) { + // Note: this function does not account for len=0 int i; for (i = max_length - 1; i > 0; i--) { if (mrz[offset + i] == '<' && mrz[offset + i + 1] == '<') { @@ -1146,6 +1147,9 @@ static void emrtd_print_document_number(char *mrz, int offset) { } static void emrtd_print_name(char *mrz, int offset, int max_length, bool localized) { + if (max_length == 0) { + return; + } char final_name[100] = { 0x00 }; int namelen = emrtd_mrz_determine_length(mrz, offset, max_length); int sep = emrtd_mrz_determine_separator(mrz, offset, namelen); From 3e4a03ec336783df1cca28cc46a6332979608fbd Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 16:17:44 +0300 Subject: [PATCH 12/21] emrtd: Implement a better fix for parsing empty tags --- client/src/cmdhfemrtd.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 827faa4e0..0af2d406f 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1147,9 +1147,6 @@ static void emrtd_print_document_number(char *mrz, int offset) { } static void emrtd_print_name(char *mrz, int offset, int max_length, bool localized) { - if (max_length == 0) { - return; - } char final_name[100] = { 0x00 }; int namelen = emrtd_mrz_determine_length(mrz, offset, max_length); int sep = emrtd_mrz_determine_separator(mrz, offset, namelen); @@ -1352,6 +1349,10 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { for (int i = 0; i < taglistlen; i++) { emrtd_lds_get_data_by_tag(response, resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + // Don't bother with empty tags + if (tagdatalen == 0) { + continue; + } // Special behavior for two char tags if (taglist[i] == 0x5f) { switch (taglist[i + 1]) { @@ -1427,6 +1428,10 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { for (int i = 0; i < taglistlen; i++) { emrtd_lds_get_data_by_tag(response, resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + // Don't bother with empty tags + if (tagdatalen == 0) { + continue; + } // Special behavior for two char tags if (taglist[i] == 0x5f) { // Several things here are longer than the rest but I can't think of a way to shorten them From 9bed791026ac1585fa119e92b758baf59f4de8c1 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 16:25:09 +0300 Subject: [PATCH 13/21] emrtd: Account for undocumented 5F85 tag --- client/src/cmdhfemrtd.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 0af2d406f..2fcc849b0 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1249,6 +1249,14 @@ static void emrtd_print_personalization_timestamp(uint8_t *data) { PrintAndLogEx(SUCCESS, "Personalization at....: " _YELLOW_("%s"), final_date); } +static void emrtd_print_unknown_timestamp_5f85(uint8_t *data) { + char final_date[20] = { 0x00 }; + sprintf(final_date, "%.4s-%.2s-%.2s %.2s:%.2s:%.2s", data, data + 4, data + 6, data + 8, data + 10, data + 12); + + PrintAndLogEx(SUCCESS, "Unknown timestamp 5F85: " _YELLOW_("%s"), final_date); + PrintAndLogEx(HINT, "This is very likely the personalization timestamp, but it is using an undocumented tag."); +} + static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { int td_variant = 0; @@ -1461,6 +1469,9 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { case 0x56: PrintAndLogEx(SUCCESS, "Serial of Personalization System: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; + case 0x85: + emrtd_print_unknown_timestamp_5f85(tagdata); + break; default: PrintAndLogEx(SUCCESS, "Unknown Field %02X%02X....: %s", taglist[i], taglist[i + 1], sprint_hex_inrow(tagdata, tagdatalen)); break; From e277eaaab2263b5641e9e6b693ca3a5cdb6b758e Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 16:48:37 +0100 Subject: [PATCH 14/21] emrtd: add COM description, add big DG table --- client/src/cmdhfemrtd.c | 335 ++++++++++++++++++++-------------------- client/src/cmdhfemrtd.h | 11 ++ 2 files changed, 180 insertions(+), 166 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 2fcc849b0..241a4750b 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -44,25 +44,11 @@ #define EMRTD_P2_PROPRIETARY "0C" // File IDs +// TODO -> dg_table #define EMRTD_EF_CARDACCESS "011C" +#define EMRTD_EF_SOD "011D" #define EMRTD_EF_COM "011E" #define EMRTD_EF_DG1 "0101" -#define EMRTD_EF_DG2 "0102" -#define EMRTD_EF_DG3 "0103" -#define EMRTD_EF_DG4 "0104" -#define EMRTD_EF_DG5 "0105" -#define EMRTD_EF_DG6 "0106" -#define EMRTD_EF_DG7 "0107" -#define EMRTD_EF_DG8 "0108" -#define EMRTD_EF_DG9 "0109" -#define EMRTD_EF_DG10 "010A" -#define EMRTD_EF_DG11 "010B" -#define EMRTD_EF_DG12 "010C" -#define EMRTD_EF_DG13 "010D" -#define EMRTD_EF_DG14 "010E" -#define EMRTD_EF_DG15 "010F" -#define EMRTD_EF_DG16 "0110" -#define EMRTD_EF_SOD "011D" // App IDs #define EMRTD_AID_MRTD "A0000002471001" @@ -71,6 +57,40 @@ const uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; const uint8_t KMAC_type[4] = {0x00, 0x00, 0x00, 0x02}; +static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length); +static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length); +static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length); +static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length); +static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen); +static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen); +static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen); +static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen); +static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen); +static emrtd_dg_t dg_table[] = { + {0x60, "011E", "EF_COM", "Header and Data Group Presence Information", true, emrtd_print_ef_com_info, NULL, true}, + {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", false, NULL, NULL, true}, + {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", false, NULL, NULL, true}, + {0x61, "0101", "EF_DG1", "Details recorded in MRZ", true, emrtd_print_ef_dg1_info, NULL, true}, + {0x75, "0102", "EF_DG2", "Encoded Face", true, NULL, emrtd_dump_ef_dg2, false}, + // These cases are commented out as they require PACE + //{0x63, "0103", "EF_DG3", "Encoded Finger(s)", false, NULL, false}, + //{0x76, "0104", "EF_DG4", "Encoded Eye(s)", false, NULL, false}, + {0x65, "0105", "EF_DG5", "Displayed Portrait", false, NULL, emrtd_dump_ef_dg5, false}, + {0x66, "0106", "EF_DG6", "Reserved for Future Use", false, NULL, NULL, false}, + {0x67, "0107", "EF_DG7", "Displayed Signature or Usual Mark", false, NULL, emrtd_dump_ef_dg7, false}, + {0x68, "0108", "EF_DG8", "Data Feature(s)", false, NULL, NULL, true}, + {0x69, "0109", "EF_DG9", "Structure Feature(s)", false, NULL, NULL, true}, + {0x6a, "010A", "EF_DG10", "Substance Feature(s)", false, NULL, NULL, true}, + {0x6b, "010B", "EF_DG11", "Additional Personal Detail(s)", false, emrtd_print_ef_dg11_info, NULL, true}, + {0x6c, "010C", "EF_DG12", "Additional Document Detail(s)", false, emrtd_print_ef_dg12_info, NULL, true}, + {0x6d, "010D", "EF_DG13", "Optional Detail(s)", false, NULL, NULL, true}, + {0x6e, "010E", "EF_DG14", "Security Options", false, NULL, NULL, true}, + {0x6f, "010F", "EF_DG15", "Active Authentication Public Key Info", false, NULL, NULL, true}, + {0x70, "0110", "EF_DG16", "Person(s) to Notify", false, NULL, NULL, true}, + {0x77, "011D", "EF_SOD", "Document Security Object", false, emrtd_print_ef_sod_info, emrtd_dump_ef_sod, true}, + {0x00, NULL, NULL, NULL, false, NULL, NULL, false} +}; + static int CmdHelp(const char *Cmd); static uint16_t get_sw(uint8_t *d, uint8_t n) { @@ -608,86 +628,14 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *d } static bool emrtd_file_tag_to_file_id(uint8_t *datain, char *filenameout, char *dataout) { - // imagine bothering with a hashmap or writing good code - // couldn't be me - switch (*datain) { - case 0x60: - memcpy(dataout, EMRTD_EF_COM, 4); - memcpy(filenameout, "EF_COM", 6); - break; - case 0x61: - memcpy(dataout, EMRTD_EF_DG1, 4); - memcpy(filenameout, "EF_DG1", 6); - break; - case 0x75: - memcpy(dataout, EMRTD_EF_DG2, 4); - memcpy(filenameout, "EF_DG2", 6); - break; - // These cases are commented out as they require PACE - // case 0x63: - // memcpy(dataout, EMRTD_EF_DG3, 4); - // memcpy(filenameout, "EF_DG3", 6); - // break; - // case 0x76: - // memcpy(dataout, EMRTD_EF_DG4, 4); - // memcpy(filenameout, "EF_DG4", 6); - // break; - case 0x65: - memcpy(dataout, EMRTD_EF_DG5, 4); - memcpy(filenameout, "EF_DG5", 6); - break; - case 0x66: - memcpy(dataout, EMRTD_EF_DG6, 4); - memcpy(filenameout, "EF_DG6", 6); - break; - case 0x67: - memcpy(dataout, EMRTD_EF_DG7, 4); - memcpy(filenameout, "EF_DG7", 6); - break; - case 0x68: - memcpy(dataout, EMRTD_EF_DG8, 4); - memcpy(filenameout, "EF_DG8", 6); - break; - case 0x69: - memcpy(dataout, EMRTD_EF_DG9, 4); - memcpy(filenameout, "EF_DG9", 6); - break; - case 0x6a: - memcpy(dataout, EMRTD_EF_DG10, 4); - memcpy(filenameout, "EF_DG10", 7); - break; - case 0x6b: - memcpy(dataout, EMRTD_EF_DG11, 4); - memcpy(filenameout, "EF_DG11", 7); - break; - case 0x6c: - memcpy(dataout, EMRTD_EF_DG12, 4); - memcpy(filenameout, "EF_DG12", 7); - break; - case 0x6d: - memcpy(dataout, EMRTD_EF_DG13, 4); - memcpy(filenameout, "EF_DG13", 7); - break; - case 0x6e: - memcpy(dataout, EMRTD_EF_DG14, 4); - memcpy(filenameout, "EF_DG14", 7); - break; - case 0x6f: - memcpy(dataout, EMRTD_EF_DG15, 4); - memcpy(filenameout, "EF_DG15", 7); - break; - case 0x70: - memcpy(dataout, EMRTD_EF_DG16, 4); - memcpy(filenameout, "EF_DG16", 7); - break; - case 0x77: - memcpy(dataout, EMRTD_EF_SOD, 4); - memcpy(filenameout, "EF_SOD", 6); - break; - default: - return false; + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if (dg_table[dgi].tag == *datain) { + strcpy(dataout, dg_table[dgi].fileid); + strcpy(filenameout, dg_table[dgi].filename); + return true; + } } - return true; + return false; } static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char *file, uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, bool use_secure, bool use_14b) { @@ -710,7 +658,7 @@ static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char return true; } -static bool emrtd_dump_ef_dg2(uint8_t *file_contents, int file_length) { +static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length) { int offset, datalen = 0; // This is a hacky impl that just looks for the image header. I'll improve it eventually. @@ -728,60 +676,60 @@ static bool emrtd_dump_ef_dg2(uint8_t *file_contents, int file_length) { // If we didn't get any data, return false. if (datalen == 0) { - return false; + return PM3_ESOFT; } saveFile("EF_DG2", file_contents[offset] == 0xFF ? ".jpg" : ".jp2", file_contents + offset, datalen); - return true; + return PM3_SUCCESS; } -static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { +static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length) { uint8_t data[EMRTD_MAX_FILE_SIZE]; int datalen = 0; // If we can't find image in EF_DG5, return false. if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x40, true) == false) { - return false; + return PM3_ESOFT; } if (datalen < EMRTD_MAX_FILE_SIZE) { saveFile("EF_DG5", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg5) datalen out-of-bounds"); - return false; + return PM3_ESOFT; } - return true; + return PM3_SUCCESS; } -static bool emrtd_dump_ef_dg7(uint8_t *file_contents, int file_length) { +static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length) { uint8_t data[EMRTD_MAX_FILE_SIZE]; int datalen = 0; // If we can't find image in EF_DG7, return false. if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x42, true) == false) { - return false; + return PM3_ESOFT; } if (datalen < EMRTD_MAX_FILE_SIZE) { saveFile("EF_DG7", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg7) datalen out-of-bounds"); - return false; + return PM3_ESOFT; } - return true; + return PM3_SUCCESS; } -static bool emrtd_dump_ef_sod(uint8_t *file_contents, int file_length) { +static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length) { int fieldlen = emrtd_get_asn1_field_length(file_contents, file_length, 1); int datalen = emrtd_get_asn1_data_length(file_contents, file_length, 1); if (fieldlen + 1 > EMRTD_MAX_FILE_SIZE) { PrintAndLogEx(ERR, "error (emrtd_dump_ef_sod) fieldlen out-of-bounds"); - return false; + return PM3_SUCCESS; } saveFile("EF_SOD", ".p7b", file_contents + fieldlen + 1, datalen); - return true; + return PM3_ESOFT; } static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char *file, const char *name, bool use_secure, bool use_14b) { @@ -796,16 +744,13 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); saveFile(name, ".BIN", response, resplen); - if (strcmp(file, EMRTD_EF_DG2) == 0) { - emrtd_dump_ef_dg2(response, resplen); - } else if (strcmp(file, EMRTD_EF_DG5) == 0) { - emrtd_dump_ef_dg5(response, resplen); - } else if (strcmp(file, EMRTD_EF_DG7) == 0) { - emrtd_dump_ef_dg7(response, resplen); - } else if (strcmp(file, EMRTD_EF_SOD) == 0) { - emrtd_dump_ef_sod(response, resplen); + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if (strcmp(dg_table[dgi].fileid, file) == 0) { + if (dg_table[dgi].dumper != NULL) + dg_table[dgi].dumper(response, resplen); + break; + } } - return true; } @@ -1257,7 +1202,36 @@ static void emrtd_print_unknown_timestamp_5f85(uint8_t *data) { PrintAndLogEx(HINT, "This is very likely the personalization timestamp, but it is using an undocumented tag."); } -static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { +static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen) { + uint8_t filelist[50]; + int filelistlen = 0; + int res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false); + if (!res) { + PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); + return PM3_ESOFT; + } + + // List files in the file list + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_COM") " --------------------"); + for (int i = 0; i < filelistlen; i++) { + char file_id[5] = { 0x00 }; + char file_name[8] = { 0x00 }; + if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { + PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + continue; + } + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if (strcmp(dg_table[dgi].filename, file_name) == 0) { + PrintAndLogEx(SUCCESS, "%-7s...............: " _YELLOW_("%s"), file_name, dg_table[dgi].desc); + break; + } + } + } + return PM3_SUCCESS; +} + +static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen) { int td_variant = 0; PrintAndLogEx(NORMAL, ""); @@ -1268,9 +1242,9 @@ static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { char mrz[90] = { 0x00 }; int mrzlen = 0; - if (!emrtd_lds_get_data_by_tag(response, resplen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true)) { PrintAndLogEx(ERR, "Failed to read MRZ from EF_DG1."); - return false; + return PM3_ESOFT; } // Determine and print the document type @@ -1338,10 +1312,10 @@ static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { } } - return true; + return PM3_SUCCESS; } -static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { +static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen) { uint8_t taglist[100] = { 0x00 }; int taglistlen = 0; uint8_t tagdata[1000] = { 0x00 }; @@ -1350,13 +1324,13 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG11") " -------------------"); - if (!emrtd_lds_get_data_by_tag(response, resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, taglist, &taglistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG11."); - return false; + return PM3_ESOFT; } for (int i = 0; i < taglistlen; i++) { - emrtd_lds_get_data_by_tag(response, resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + emrtd_lds_get_data_by_tag(data, datalen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); // Don't bother with empty tags if (tagdatalen == 0) { continue; @@ -1417,10 +1391,10 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Unknown Field %02X......: %s", taglist[i], sprint_hex_inrow(tagdata, tagdatalen)); } } - return true; + return PM3_SUCCESS; } -static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { +static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen) { uint8_t taglist[100] = { 0x00 }; int taglistlen = 0; uint8_t tagdata[1000] = { 0x00 }; @@ -1429,13 +1403,13 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG12") " -------------------"); - if (!emrtd_lds_get_data_by_tag(response, resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, taglist, &taglistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG12."); - return false; + return PM3_ESOFT; } for (int i = 0; i < taglistlen; i++) { - emrtd_lds_get_data_by_tag(response, resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + emrtd_lds_get_data_by_tag(data, datalen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); // Don't bother with empty tags if (tagdatalen == 0) { continue; @@ -1483,7 +1457,14 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Unknown Field %02X......: %s", taglist[i], sprint_hex_inrow(tagdata, tagdatalen)); } } - return true; + return PM3_SUCCESS; +} + +static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); + PrintAndLogEx(WARNING, "TODO"); + return PM3_SUCCESS; } int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { @@ -1521,6 +1502,12 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } + int res = emrtd_print_ef_com_info(response, resplen); + if ( res != PM3_SUCCESS) { + DropField(); + return res; + } + uint8_t filelist[50]; int filelistlen = 0; @@ -1539,14 +1526,20 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab continue; } - if (strcmp(file_name, "EF_DG1") == 0 && emrtd_select_and_read(response, &resplen, EMRTD_EF_DG1, ks_enc, ks_mac, ssc, BAC, use_14b)) { - emrtd_print_ef_dg1_info(response, resplen); - } else if (strcmp(file_name, "EF_DG11") == 0 && emrtd_select_and_read(response, &resplen, EMRTD_EF_DG11, ks_enc, ks_mac, ssc, BAC, use_14b)) { - emrtd_print_ef_dg11_info(response, resplen); - } else if (strcmp(file_name, "EF_DG12") == 0 && emrtd_select_and_read(response, &resplen, EMRTD_EF_DG12, ks_enc, ks_mac, ssc, BAC, use_14b)) { - emrtd_print_ef_dg12_info(response, resplen); + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if ((strcmp(dg_table[dgi].filename, file_name) == 0) && dg_table[dgi].fastdump) { + if (emrtd_select_and_read(response, &resplen, dg_table[dgi].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (dg_table[dgi].parser != NULL) + dg_table[dgi].parser(response, resplen); + } + break; + } } } +// TODO + if (emrtd_select_and_read(response, &resplen, EMRTD_EF_SOD, ks_enc, ks_mac, ssc, BAC, use_14b)) { + emrtd_print_ef_sod_info(response, resplen); + } DropField(); return PM3_SUCCESS; @@ -1562,55 +1555,65 @@ int infoHF_EMRTD_offline(const char *path) { strncat(filepath, PATHSEP, 1); strcat(filepath, "EF_COM"); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) != PM3_SUCCESS) { + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to read EF_COM."); free(filepath); return PM3_ESOFT; } + + int res = emrtd_print_ef_com_info(data, datalen); + if ( res != PM3_SUCCESS) { + free(data); + free(filepath); + return res; + } + uint8_t filelist[50]; int filelistlen = 0; - int res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false); - free(data); + res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false); if (!res) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); + free(data); free(filepath); return PM3_ESOFT; } - + free(data); // Read files in the file list for (int i = 0; i < filelistlen; i++) { char file_id[5] = { 0x00 }; char file_name[8] = { 0x00 }; if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { - PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + //PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); continue; } - if (strcmp(file_name, "EF_DG1") == 0) { - strcpy(filepath, path); - strncat(filepath, PATHSEP, 1); - strcat(filepath, "EF_DG1"); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) == PM3_SUCCESS) { - emrtd_print_ef_dg1_info(data, datalen); - free(data); - } - } else if (strcmp(file_name, "EF_DG11") == 0) { - strcpy(filepath, path); - strncat(filepath, PATHSEP, 1); - strcat(filepath, "EF_DG11"); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) == PM3_SUCCESS) { - emrtd_print_ef_dg11_info(data, datalen); - free(data); - } - } else if (strcmp(file_name, "EF_DG12") == 0) { - strcpy(filepath, path); - strncat(filepath, PATHSEP, 1); - strcat(filepath, "EF_DG12"); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) == PM3_SUCCESS) { - emrtd_print_ef_dg12_info(data, datalen); - free(data); + + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if (strcmp(dg_table[dgi].filename, file_name) == 0) { + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, dg_table[dgi].filename); + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) + { + // we won't halt on parsing errors + if (dg_table[dgi].parser != NULL) + dg_table[dgi].parser(data, datalen); + free(data); + } + break; } } } +// TODO + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, "EF_SOD"); + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) + { + // we won't halt on parsing errors + emrtd_print_ef_sod_info(data, datalen); + free(data); + } + free(filepath); return PM3_SUCCESS; } diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index 3cfcd3cbd..aa1c4e1e1 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -13,6 +13,17 @@ #include "common.h" +typedef struct emrtd_dg_s { + uint8_t tag; + const char *fileid; + const char *filename; + const char *desc; + bool required; + int (*parser)(uint8_t *data, size_t datalen); + int (*dumper)(uint8_t *data, size_t datalen); + bool fastdump; +} emrtd_dg_t; + int CmdHFeMRTD(const char *Cmd); int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available); From 019f4a7e94698db45860601b75d54be40b7bf07a Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 17:12:08 +0100 Subject: [PATCH 15/21] emrtd table: pace flag --- client/src/cmdhfemrtd.c | 57 ++++++++++++++++++++++------------------- client/src/cmdhfemrtd.h | 5 ++-- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 241a4750b..33a6e0f8f 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -67,28 +67,28 @@ static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen); static emrtd_dg_t dg_table[] = { - {0x60, "011E", "EF_COM", "Header and Data Group Presence Information", true, emrtd_print_ef_com_info, NULL, true}, - {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", false, NULL, NULL, true}, - {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", false, NULL, NULL, true}, - {0x61, "0101", "EF_DG1", "Details recorded in MRZ", true, emrtd_print_ef_dg1_info, NULL, true}, - {0x75, "0102", "EF_DG2", "Encoded Face", true, NULL, emrtd_dump_ef_dg2, false}, - // These cases are commented out as they require PACE - //{0x63, "0103", "EF_DG3", "Encoded Finger(s)", false, NULL, false}, - //{0x76, "0104", "EF_DG4", "Encoded Eye(s)", false, NULL, false}, - {0x65, "0105", "EF_DG5", "Displayed Portrait", false, NULL, emrtd_dump_ef_dg5, false}, - {0x66, "0106", "EF_DG6", "Reserved for Future Use", false, NULL, NULL, false}, - {0x67, "0107", "EF_DG7", "Displayed Signature or Usual Mark", false, NULL, emrtd_dump_ef_dg7, false}, - {0x68, "0108", "EF_DG8", "Data Feature(s)", false, NULL, NULL, true}, - {0x69, "0109", "EF_DG9", "Structure Feature(s)", false, NULL, NULL, true}, - {0x6a, "010A", "EF_DG10", "Substance Feature(s)", false, NULL, NULL, true}, - {0x6b, "010B", "EF_DG11", "Additional Personal Detail(s)", false, emrtd_print_ef_dg11_info, NULL, true}, - {0x6c, "010C", "EF_DG12", "Additional Document Detail(s)", false, emrtd_print_ef_dg12_info, NULL, true}, - {0x6d, "010D", "EF_DG13", "Optional Detail(s)", false, NULL, NULL, true}, - {0x6e, "010E", "EF_DG14", "Security Options", false, NULL, NULL, true}, - {0x6f, "010F", "EF_DG15", "Active Authentication Public Key Info", false, NULL, NULL, true}, - {0x70, "0110", "EF_DG16", "Person(s) to Notify", false, NULL, NULL, true}, - {0x77, "011D", "EF_SOD", "Document Security Object", false, emrtd_print_ef_sod_info, emrtd_dump_ef_sod, true}, - {0x00, NULL, NULL, NULL, false, NULL, NULL, false} +// tag fileid filename desc pace req fast parser dumper + {0x60, "011E", "EF_COM", "Header and Data Group Presence Information", false, true, true, emrtd_print_ef_com_info, NULL}, + {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", true, true, true, NULL, NULL}, + {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, true, NULL, NULL}, + {0x61, "0101", "EF_DG1", "Details recorded in MRZ", false, true, true, emrtd_print_ef_dg1_info, NULL}, + {0x75, "0102", "EF_DG2", "Encoded Face", false, true, false, NULL, emrtd_dump_ef_dg2}, + {0x63, "0103", "EF_DG3", "Encoded Finger(s)", true, false, false, NULL, NULL}, + {0x76, "0104", "EF_DG4", "Encoded Eye(s)", true, false, false, NULL, NULL}, + {0x65, "0105", "EF_DG5", "Displayed Portrait", false, false, false, NULL, emrtd_dump_ef_dg5}, + {0x66, "0106", "EF_DG6", "Reserved for Future Use", false, false, false, NULL, NULL}, + {0x67, "0107", "EF_DG7", "Displayed Signature or Usual Mark", false, false, false, NULL, emrtd_dump_ef_dg7}, + {0x68, "0108", "EF_DG8", "Data Feature(s)", false, false, true, NULL, NULL}, + {0x69, "0109", "EF_DG9", "Structure Feature(s)", false, false, true, NULL, NULL}, + {0x6a, "010A", "EF_DG10", "Substance Feature(s)", false, false, true, NULL, NULL}, + {0x6b, "010B", "EF_DG11", "Additional Personal Detail(s)", false, false, true, emrtd_print_ef_dg11_info, NULL}, + {0x6c, "010C", "EF_DG12", "Additional Document Detail(s)", false, false, true, emrtd_print_ef_dg12_info, NULL}, + {0x6d, "010D", "EF_DG13", "Optional Detail(s)", false, false, true, NULL, NULL}, + {0x6e, "010E", "EF_DG14", "Security Options", false, false, true, NULL, NULL}, + {0x6f, "010F", "EF_DG15", "Active Authentication Public Key Info", false, false, true, NULL, NULL}, + {0x70, "0110", "EF_DG16", "Person(s) to Notify", false, false, true, NULL, NULL}, + {0x77, "011D", "EF_SOD", "Document Security Object", false, false, true, emrtd_print_ef_sod_info, emrtd_dump_ef_sod}, + {0x00, NULL, NULL, NULL, false, false, false, NULL, NULL} }; static int CmdHelp(const char *Cmd); @@ -994,7 +994,13 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab continue; } PrintAndLogEx(DEBUG, "Current file: %s", file_name); - emrtd_dump_file(ks_enc, ks_mac, ssc, file_id, file_name, BAC, use_14b); + + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if ((strcmp(dg_table[dgi].filename, file_name) == 0) && !dg_table[dgi].pace) { + emrtd_dump_file(ks_enc, ks_mac, ssc, file_id, file_name, BAC, use_14b); + break; + } + } } // Dump EF_SOD @@ -1525,9 +1531,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); continue; } - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if ((strcmp(dg_table[dgi].filename, file_name) == 0) && dg_table[dgi].fastdump) { + if ((strcmp(dg_table[dgi].filename, file_name) == 0) && dg_table[dgi].fastdump && !dg_table[dgi].pace) { if (emrtd_select_and_read(response, &resplen, dg_table[dgi].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { if (dg_table[dgi].parser != NULL) dg_table[dgi].parser(response, resplen); @@ -1588,7 +1593,7 @@ int infoHF_EMRTD_offline(const char *path) { } for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if (strcmp(dg_table[dgi].filename, file_name) == 0) { + if ((strcmp(dg_table[dgi].filename, file_name) == 0) && (!dg_table[dgi].pace)) { strcpy(filepath, path); strncat(filepath, PATHSEP, 1); strcat(filepath, dg_table[dgi].filename); diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index aa1c4e1e1..9df7846ad 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -18,10 +18,11 @@ typedef struct emrtd_dg_s { const char *fileid; const char *filename; const char *desc; - bool required; + bool pace; + bool required; // some are required only if PACE + bool fastdump; // fast to dump int (*parser)(uint8_t *data, size_t datalen); int (*dumper)(uint8_t *data, size_t datalen); - bool fastdump; } emrtd_dg_t; int CmdHFeMRTD(const char *Cmd); From 34cc523546207f08cae7c744083c6fddeb787d1d Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 17:37:28 +0100 Subject: [PATCH 16/21] emrtd: add helper fcts to search the table --- client/src/cmdhfemrtd.c | 116 +++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 67 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 33a6e0f8f..4475cfa3a 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -91,6 +91,23 @@ static emrtd_dg_t dg_table[] = { {0x00, NULL, NULL, NULL, false, false, false, NULL, NULL} }; +static emrtd_dg_t *emrtd_tag_to_dg(uint8_t tag) { + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if (dg_table[dgi].tag == tag) { + return &dg_table[dgi]; + } + } + return NULL; +} +static emrtd_dg_t *emrtd_fileid_to_dg(const char *file_id) { + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if (strcmp(dg_table[dgi].fileid, file_id) == 0) { + return &dg_table[dgi]; + } + } + return NULL; +} + static int CmdHelp(const char *Cmd); static uint16_t get_sw(uint8_t *d, uint8_t n) { @@ -627,17 +644,6 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *d return false; } -static bool emrtd_file_tag_to_file_id(uint8_t *datain, char *filenameout, char *dataout) { - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if (dg_table[dgi].tag == *datain) { - strcpy(dataout, dg_table[dgi].fileid); - strcpy(filenameout, dg_table[dgi].filename); - return true; - } - } - return false; -} - static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char *file, uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, bool use_secure, bool use_14b) { if (use_secure) { if (emrtd_secure_select_file(ks_enc, ks_mac, ssc, EMRTD_P1_SELECT_BY_EF, file, use_14b) == false) { @@ -743,13 +749,9 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons PrintAndLogEx(INFO, "Read %s, len: %i.", name, resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); saveFile(name, ".BIN", response, resplen); - - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if (strcmp(dg_table[dgi].fileid, file) == 0) { - if (dg_table[dgi].dumper != NULL) - dg_table[dgi].dumper(response, resplen); - break; - } + emrtd_dg_t * dg = emrtd_fileid_to_dg(file); + if ((dg != NULL) && (dg->dumper != NULL)) { + dg->dumper(response, resplen); } return true; } @@ -987,19 +989,14 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { - char file_id[5] = { 0x00 }; - char file_name[8] = { 0x00 }; - if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { + emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + if (dg == NULL) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; } - PrintAndLogEx(DEBUG, "Current file: %s", file_name); - - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if ((strcmp(dg_table[dgi].filename, file_name) == 0) && !dg_table[dgi].pace) { - emrtd_dump_file(ks_enc, ks_mac, ssc, file_id, file_name, BAC, use_14b); - break; - } + PrintAndLogEx(DEBUG, "Current file: %s", dg->filename); + if (!dg->pace) { + emrtd_dump_file(ks_enc, ks_mac, ssc, dg->fileid, dg->filename, BAC, use_14b); } } @@ -1221,18 +1218,12 @@ static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_COM") " --------------------"); for (int i = 0; i < filelistlen; i++) { - char file_id[5] = { 0x00 }; - char file_name[8] = { 0x00 }; - if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { - PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + if (dg == NULL) { + PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; } - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if (strcmp(dg_table[dgi].filename, file_name) == 0) { - PrintAndLogEx(SUCCESS, "%-7s...............: " _YELLOW_("%s"), file_name, dg_table[dgi].desc); - break; - } - } + PrintAndLogEx(SUCCESS, "%-7s...............: " _YELLOW_("%s"), dg->filename, dg->desc); } return PM3_SUCCESS; } @@ -1525,19 +1516,15 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { - char file_id[5] = { 0x00 }; - char file_name[8] = { 0x00 }; - if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { - PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + if (dg == NULL) { + PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; } - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if ((strcmp(dg_table[dgi].filename, file_name) == 0) && dg_table[dgi].fastdump && !dg_table[dgi].pace) { - if (emrtd_select_and_read(response, &resplen, dg_table[dgi].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { - if (dg_table[dgi].parser != NULL) - dg_table[dgi].parser(response, resplen); - } - break; + if (dg->fastdump && !dg->pace) { + if (emrtd_select_and_read(response, &resplen, dg->fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (dg->parser != NULL) + dg->parser(response, resplen); } } } @@ -1585,26 +1572,21 @@ int infoHF_EMRTD_offline(const char *path) { free(data); // Read files in the file list for (int i = 0; i < filelistlen; i++) { - char file_id[5] = { 0x00 }; - char file_name[8] = { 0x00 }; - if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { - //PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + if (dg == NULL) { + PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; } - - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if ((strcmp(dg_table[dgi].filename, file_name) == 0) && (!dg_table[dgi].pace)) { - strcpy(filepath, path); - strncat(filepath, PATHSEP, 1); - strcat(filepath, dg_table[dgi].filename); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) - { - // we won't halt on parsing errors - if (dg_table[dgi].parser != NULL) - dg_table[dgi].parser(data, datalen); - free(data); - } - break; + if (!dg->pace) { + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, dg->filename); + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) + { + // we won't halt on parsing errors + if (dg->parser != NULL) + dg->parser(data, datalen); + free(data); } } } From e16249252e5c64e864d9c2bbc307266b2deb434e Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 17:58:22 +0100 Subject: [PATCH 17/21] emrtd: remove last defs and integrate SOD in com lists --- client/src/cmdhfemrtd.c | 77 +++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 4475cfa3a..eb399f3cc 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -43,13 +43,6 @@ #define EMRTD_P1_SELECT_BY_NAME "04" #define EMRTD_P2_PROPRIETARY "0C" -// File IDs -// TODO -> dg_table -#define EMRTD_EF_CARDACCESS "011C" -#define EMRTD_EF_SOD "011D" -#define EMRTD_EF_COM "011E" -#define EMRTD_EF_DG1 "0101" - // App IDs #define EMRTD_AID_MRTD "A0000002471001" @@ -66,11 +59,33 @@ static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen); + +typedef enum { // list must match dg_table + EF_COM=0, + EF_DG1, + EF_DG2, + EF_DG3, + EF_DG4, + EF_DG5, + EF_DG6, + EF_DG7, + EF_DG8, + EF_DG9, + EF_DG10, + EF_DG11, + EF_DG12, + EF_DG13, + EF_DG14, + EF_DG15, + EF_DG16, + EF_SOD, + EF_CardAccess, + EF_CardSecurity, +} emrtd_dg_enum; + static emrtd_dg_t dg_table[] = { // tag fileid filename desc pace req fast parser dumper {0x60, "011E", "EF_COM", "Header and Data Group Presence Information", false, true, true, emrtd_print_ef_com_info, NULL}, - {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", true, true, true, NULL, NULL}, - {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, true, NULL, NULL}, {0x61, "0101", "EF_DG1", "Details recorded in MRZ", false, true, true, emrtd_print_ef_dg1_info, NULL}, {0x75, "0102", "EF_DG2", "Encoded Face", false, true, false, NULL, emrtd_dump_ef_dg2}, {0x63, "0103", "EF_DG3", "Encoded Finger(s)", true, false, false, NULL, NULL}, @@ -88,6 +103,8 @@ static emrtd_dg_t dg_table[] = { {0x6f, "010F", "EF_DG15", "Active Authentication Public Key Info", false, false, true, NULL, NULL}, {0x70, "0110", "EF_DG16", "Person(s) to Notify", false, false, true, NULL, NULL}, {0x77, "011D", "EF_SOD", "Document Security Object", false, false, true, emrtd_print_ef_sod_info, emrtd_dump_ef_sod}, + {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", true, true, true, NULL, NULL}, + {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, true, NULL, NULL}, {0x00, NULL, NULL, NULL, false, false, false, NULL, NULL} }; @@ -905,13 +922,13 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA } // Select EF_COM - if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_COM, *use_14b) == false) { + if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, dg_table[EF_COM].fileid, *use_14b) == false) { *BAC = true; PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { *BAC = false; // Select EF_DG1 - emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_DG1, *use_14b); + emrtd_select_file(EMRTD_P1_SELECT_BY_EF, dg_table[EF_DG1].fileid, *use_14b); if (emrtd_read_file(response, &resplen, NULL, NULL, NULL, false, *use_14b) == false) { *BAC = true; @@ -955,7 +972,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } // Dump EF_CardAccess (if available) - if (!emrtd_dump_file(ks_enc, ks_mac, ssc, EMRTD_EF_CARDACCESS, "EF_CardAccess", BAC, use_14b)) { + if (!emrtd_dump_file(ks_enc, ks_mac, ssc, dg_table[EF_CardAccess].fileid, dg_table[EF_CardAccess].filename, BAC, use_14b)) { PrintAndLogEx(INFO, "Couldn't dump EF_CardAccess, card does not support PACE."); PrintAndLogEx(HINT, "This is expected behavior for cards without PACE, and isn't something to be worried about."); } @@ -967,14 +984,14 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } // Select EF_COM - if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_COM, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (!emrtd_select_and_read(response, &resplen, dg_table[EF_COM].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { PrintAndLogEx(ERR, "Failed to read EF_COM."); DropField(); return PM3_ESOFT; } PrintAndLogEx(INFO, "Read EF_COM, len: %i.", resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile("EF_COM", ".BIN", response, resplen); + saveFile(dg_table[EF_COM].filename, ".BIN", response, resplen); uint8_t filelist[50]; int filelistlen = 0; @@ -986,7 +1003,8 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } PrintAndLogEx(DEBUG, "File List: %s", sprint_hex_inrow(filelist, filelistlen)); - + // Add EF_SOD to the list + filelist[filelistlen++] = 0x77; // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); @@ -999,10 +1017,6 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab emrtd_dump_file(ks_enc, ks_mac, ssc, dg->fileid, dg->filename, BAC, use_14b); } } - - // Dump EF_SOD - emrtd_dump_file(ks_enc, ks_mac, ssc, EMRTD_EF_SOD, "EF_SOD", BAC, use_14b); - DropField(); return PM3_SUCCESS; } @@ -1493,7 +1507,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } - if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_COM, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (!emrtd_select_and_read(response, &resplen, dg_table[EF_COM].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { PrintAndLogEx(ERR, "Failed to read EF_COM."); DropField(); return PM3_ESOFT; @@ -1513,7 +1527,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab DropField(); return PM3_ESOFT; } - + // Add EF_SOD to the list + filelist[filelistlen++] = 0x77; // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); @@ -1528,11 +1543,6 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } } } -// TODO - if (emrtd_select_and_read(response, &resplen, EMRTD_EF_SOD, ks_enc, ks_mac, ssc, BAC, use_14b)) { - emrtd_print_ef_sod_info(response, resplen); - } - DropField(); return PM3_SUCCESS; } @@ -1545,7 +1555,7 @@ int infoHF_EMRTD_offline(const char *path) { return PM3_EMALLOC; strcpy(filepath, path); strncat(filepath, PATHSEP, 1); - strcat(filepath, "EF_COM"); + strcat(filepath, dg_table[EF_COM].filename); if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to read EF_COM."); @@ -1570,6 +1580,8 @@ int infoHF_EMRTD_offline(const char *path) { return PM3_ESOFT; } free(data); + // Add EF_SOD to the list + filelist[filelistlen++] = 0x77; // Read files in the file list for (int i = 0; i < filelistlen; i++) { emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); @@ -1590,17 +1602,6 @@ int infoHF_EMRTD_offline(const char *path) { } } } -// TODO - strcpy(filepath, path); - strncat(filepath, PATHSEP, 1); - strcat(filepath, "EF_SOD"); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) - { - // we won't halt on parsing errors - emrtd_print_ef_sod_info(data, datalen); - free(data); - } - free(filepath); return PM3_SUCCESS; } From 97eaab27a189afe4ee901ca4f78c9e7a886c213d Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 18:01:19 +0100 Subject: [PATCH 18/21] emrtd: remove few hardcoded filenames --- client/src/cmdhfemrtd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index eb399f3cc..7a46c6850 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -702,7 +702,7 @@ static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length) { return PM3_ESOFT; } - saveFile("EF_DG2", file_contents[offset] == 0xFF ? ".jpg" : ".jp2", file_contents + offset, datalen); + saveFile(dg_table[EF_DG2].filename, file_contents[offset] == 0xFF ? ".jpg" : ".jp2", file_contents + offset, datalen); return PM3_SUCCESS; } @@ -716,7 +716,7 @@ static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length) { } if (datalen < EMRTD_MAX_FILE_SIZE) { - saveFile("EF_DG5", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); + saveFile(dg_table[EF_DG5].filename, data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg5) datalen out-of-bounds"); return PM3_ESOFT; @@ -734,7 +734,7 @@ static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length) { } if (datalen < EMRTD_MAX_FILE_SIZE) { - saveFile("EF_DG7", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); + saveFile(dg_table[EF_DG7].filename, data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg7) datalen out-of-bounds"); return PM3_ESOFT; @@ -751,7 +751,7 @@ static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length) { return PM3_SUCCESS; } - saveFile("EF_SOD", ".p7b", file_contents + fieldlen + 1, datalen); + saveFile(dg_table[EF_SOD].filename, ".p7b", file_contents + fieldlen + 1, datalen); return PM3_ESOFT; } From 415dd84a8d6ddf752224bd12803f48ebf0544ced Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 19:32:06 +0100 Subject: [PATCH 19/21] fix print_buffer out-of-boundaries bug --- client/src/util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/util.c b/client/src/util.c index 4ba4af108..1dad2cd4b 100644 --- a/client/src/util.c +++ b/client/src/util.c @@ -208,7 +208,9 @@ void print_buffer(const uint8_t *data, const size_t len, int level) { char buf[UTIL_BUFFER_SIZE_SPRINT + 3]; int i; for (i = 0; i < len; i += 16) { - + if (len - i < 16) { // incomplete block, will be treated out of the loop + break; + } // (16 * 3) + (16) + + 1 memset(buf, 0, sizeof(buf)); sprintf(buf, "%*s%02x: ", (level * 4), " ", i); From 669eea1f7412d2f198695b3d1edba143fe7d9037 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 19:44:26 +0100 Subject: [PATCH 20/21] emrtd: hide SOD todo for now --- client/src/cmdhfemrtd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 7a46c6850..9d8332ba7 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1472,9 +1472,9 @@ static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen) { } static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); - PrintAndLogEx(WARNING, "TODO"); +// PrintAndLogEx(NORMAL, ""); +// PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); +// PrintAndLogEx(WARNING, "TODO"); return PM3_SUCCESS; } From 3098f01dd9561d6f6ea95af623222920a5c0a2f9 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 20:53:16 +0100 Subject: [PATCH 21/21] emrtd: non-BAC: tested! remove debug print --- client/src/cmdhfemrtd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 9d8332ba7..af586e59a 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -935,7 +935,6 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { *BAC = false; - PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex(response, resplen)); } }