From 36cf0be239f43e63fb1aca12e12ef5713172d15b Mon Sep 17 00:00:00 2001 From: Ave Ozkal Date: Fri, 18 Dec 2020 21:12:57 +0300 Subject: [PATCH 1/4] emrtd: Basic EF_DG11 support on hf emrtd info --- client/src/cmdhfemrtd.c | 107 ++++++++++++++++++++++++++++++++-------- 1 file changed, 87 insertions(+), 20 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index deff0d4df..c1e9bcbce 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1118,7 +1118,7 @@ static void emrtd_print_document_number(char *mrz, int offset) { } } -static void emrtd_print_name(char *mrz, int offset, int max_length) { +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); @@ -1128,20 +1128,30 @@ static void emrtd_print_name(char *mrz, int offset, int max_length) { final_name[namelen] = ' '; memcpy(final_name + namelen + 1, mrz + offset, sep); - PrintAndLogEx(SUCCESS, "Legal Name............: " _YELLOW_("%s"), final_name); + if (localized) { + PrintAndLogEx(SUCCESS, "Legal Name (Localized): " _YELLOW_("%s"), final_name); + } else { + PrintAndLogEx(SUCCESS, "Legal Name............: " _YELLOW_("%s"), final_name); + } } -static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool is_expiry) { - char temp_year[3] = { 0x00 }; - - memcpy(temp_year, mrz + offset, 2); - // If it's > 20, assume 19xx. - if (strtol(temp_year, NULL, 10) < 20 || is_expiry) { - final_date[0] = '2'; - final_date[1] = '0'; +static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool is_expiry, bool is_full) { + if (is_full) { + // If we get the full date, use the first two characters from that for year + memcpy(final_date, mrz, 2); + // and do + 2 on offset so that rest of code uses the right data + offset += 2; } else { - final_date[0] = '1'; - final_date[1] = '9'; + char temp_year[3] = { 0x00 }; + memcpy(temp_year, mrz + offset, 2); + // If it's > 20, assume 19xx. + if (strtol(temp_year, NULL, 10) < 20 || is_expiry) { + final_date[0] = '2'; + final_date[1] = '0'; + } else { + final_date[0] = '1'; + final_date[1] = '9'; + } } memcpy(final_date + 2, mrz + offset, 2); @@ -1151,20 +1161,20 @@ static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool memcpy(final_date + 8, mrz + offset + 4, 2); } -static void emrtd_print_dob(char *mrz, int offset) { +static void emrtd_print_dob(char *mrz, int offset, bool full) { char final_date[12] = { 0x00 }; - emrtd_mrz_convert_date(mrz, offset, final_date, false); + emrtd_mrz_convert_date(mrz, offset, final_date, false, full); PrintAndLogEx(SUCCESS, "Date of birth.........: " _YELLOW_("%s"), final_date); - if (!emrtd_mrz_verify_check_digit(mrz, offset, 6)) { + if (!full && !emrtd_mrz_verify_check_digit(mrz, offset, 6)) { PrintAndLogEx(SUCCESS, _RED_("Date of Birth check digit is invalid.")); } } static void emrtd_print_expiry(char *mrz, int offset) { char final_date[12] = { 0x00 }; - emrtd_mrz_convert_date(mrz, offset, final_date, true); + emrtd_mrz_convert_date(mrz, offset, final_date, true, false); PrintAndLogEx(SUCCESS, "Date of expiry........: " _YELLOW_("%s"), final_date); @@ -1173,6 +1183,57 @@ static void emrtd_print_expiry(char *mrz, int offset) { } } +static bool emrtd_print_ef_dg11_info(bool *BAC, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool *use_14b) { + uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + int resplen = 0; + + uint8_t taglist[100] = { 0x00 }; + int taglistlen = 0; + uint8_t tagdata[1000] = { 0x00 }; + int tagdatalen = 0; + + PrintAndLogEx(INFO, "=====EF_DG11====="); + + if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_DG11, ks_enc, ks_mac, ssc, *BAC, *use_14b)) { + PrintAndLogEx(ERR, "Failed to read EF_DG11."); + return 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); + // Special behavior for two char tags + if (taglist[i] == 0x5f) { + switch (taglist[i + 1]) { + case 0x0e: + emrtd_print_name((char *) tagdata, 0, tagdatalen, true); + break; + case 0x10: + PrintAndLogEx(SUCCESS, "Personal Number.......: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x11: + PrintAndLogEx(SUCCESS, "Place of Birth........: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x2b: + emrtd_print_dob((char *) tagdata, 0, true); + break; + default: + PrintAndLogEx(SUCCESS, "Unknown Field %02X%02X....: %s", taglist[i], taglist[i + 1], sprint_hex_inrow(tagdata, tagdatalen)); + break; + } + + i += 1; + } else { + PrintAndLogEx(INFO, "Reading %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; @@ -1208,6 +1269,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } + PrintAndLogEx(INFO, "=====EF_DG1====="); + // MRZ on TD1 is 90 characters, 30 on each row. // MRZ on TD3 is 88 characters, 44 on each row. char mrz[90] = { 0x00 }; @@ -1251,9 +1314,9 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab if (td_variant == 3) { // Passport form factor PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 44 + 10); - emrtd_print_name(mrz, 5, 38); + emrtd_print_name(mrz, 5, 38, false); emrtd_print_document_number(mrz, 44); - emrtd_print_dob(mrz, 44 + 13); + emrtd_print_dob(mrz, 44 + 13, false); emrtd_print_legal_sex(&mrz[44 + 20]); emrtd_print_expiry(mrz, 44 + 21); emrtd_print_optional_elements(mrz, 44 + 28, 14, true); @@ -1270,9 +1333,9 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } else if (td_variant == 1) { // ID form factor PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 30 + 15); - emrtd_print_name(mrz, 60, 30); + emrtd_print_name(mrz, 60, 30, false); emrtd_print_document_number(mrz, 5); - emrtd_print_dob(mrz, 30); + emrtd_print_dob(mrz, 30, false); emrtd_print_legal_sex(&mrz[30 + 7]); emrtd_print_expiry(mrz, 30 + 8); emrtd_print_optional_elements(mrz, 15, 15, false); @@ -1284,6 +1347,10 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } } + // Print EF_DG11 info + // TODO: verify existence from file list, also print file list in info. + emrtd_print_ef_dg11_info(&BAC, ssc, ks_enc, ks_mac, &use_14b); + DropField(); return PM3_SUCCESS; } From 27b7ecf1cdcdfe440850b06d680b99361cdb45e9 Mon Sep 17 00:00:00 2001 From: Ave Ozkal Date: Fri, 18 Dec 2020 21:25:46 +0300 Subject: [PATCH 2/4] emrtd: Complete EF_DG11 support on hf emrtd info --- client/src/cmdhfemrtd.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index c1e9bcbce..62555d11b 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1216,8 +1216,35 @@ static bool emrtd_print_ef_dg11_info(bool *BAC, uint8_t *ssc, uint8_t *ks_enc, u PrintAndLogEx(SUCCESS, "Personal Number.......: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; case 0x11: + // TODO: acc for < separation PrintAndLogEx(SUCCESS, "Place of Birth........: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; + case 0x42: + // TODO: acc for < separation + PrintAndLogEx(SUCCESS, "Permanent Address.....: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x12: + PrintAndLogEx(SUCCESS, "Telephone.............: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x13: + PrintAndLogEx(SUCCESS, "Profession............: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x14: + PrintAndLogEx(SUCCESS, "Title.................: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x15: + PrintAndLogEx(SUCCESS, "Personal Summary......: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x16: + saveFile("ProofOfCitizenship", ".jpg", tagdata, tagdatalen); + break; + case 0x17: + // TODO: acc for < separation + PrintAndLogEx(SUCCESS, "Other valid TDs nums..: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x18: + PrintAndLogEx(SUCCESS, "Custody Information...: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; case 0x2b: emrtd_print_dob((char *) tagdata, 0, true); break; @@ -1228,7 +1255,8 @@ static bool emrtd_print_ef_dg11_info(bool *BAC, uint8_t *ssc, uint8_t *ks_enc, u i += 1; } else { - PrintAndLogEx(INFO, "Reading %02X: %s", taglist[i], sprint_hex_inrow(tagdata, tagdatalen)); + // TODO: Account for A0 + PrintAndLogEx(SUCCESS, "Unknown Field %02X......: %s", taglist[i], sprint_hex_inrow(tagdata, tagdatalen)); } } return true; From 8e89eb12064f6e0fdfa19f6c81f891e62046c4a3 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 22:33:13 +0300 Subject: [PATCH 3/4] hf emrtd info: fancier output for files --- client/src/cmdhfemrtd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 62555d11b..908b6e689 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1192,7 +1192,8 @@ static bool emrtd_print_ef_dg11_info(bool *BAC, uint8_t *ssc, uint8_t *ks_enc, u uint8_t tagdata[1000] = { 0x00 }; int tagdatalen = 0; - PrintAndLogEx(INFO, "=====EF_DG11====="); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG11") " -------------------"); if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_DG11, ks_enc, ks_mac, ssc, *BAC, *use_14b)) { PrintAndLogEx(ERR, "Failed to read EF_DG11."); @@ -1281,6 +1282,9 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab // Select and authenticate with the eMRTD bool auth_result = emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac, &use_14b); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "------------------ " _CYAN_("Basic Info") " ------------------"); PrintAndLogEx(SUCCESS, "Communication standard: %s", use_14b ? _YELLOW_("ISO/IEC 14443(B)") : _YELLOW_("ISO/IEC 14443(A)")); PrintAndLogEx(SUCCESS, "BAC...................: %s", BAC ? _GREEN_("Enforced") : _RED_("Not enforced")); PrintAndLogEx(SUCCESS, "Authentication result.: %s", auth_result ? _GREEN_("Successful") : _RED_("Failed")); @@ -1297,7 +1301,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } - PrintAndLogEx(INFO, "=====EF_DG1====="); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG1") " --------------------"); // MRZ on TD1 is 90 characters, 30 on each row. // MRZ on TD3 is 88 characters, 44 on each row. From fa217875316a4837b428c1c5aafa0e304a799b92 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 23:52:42 +0300 Subject: [PATCH 4/4] hf emrtd info: Split EF_DG1 into its own func, read file list --- client/src/cmdhfemrtd.c | 189 ++++++++++++++++++++++------------------ 1 file changed, 102 insertions(+), 87 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 908b6e689..f2c3a60d3 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1045,7 +1045,7 @@ static bool emrtd_compare_check_digit(char *datain, int datalen, char expected_c memcpy(tempdata, datain, datalen); uint8_t check_digit = emrtd_calculate_check_digit(tempdata) + 0x30; - bool res =check_digit == expected_check_digit; + bool res = check_digit == expected_check_digit; PrintAndLogEx(DEBUG, "emrtd_compare_check_digit, expected %c == %c calculated ( %s )" , expected_check_digit , check_digit @@ -1183,10 +1183,91 @@ static void emrtd_print_expiry(char *mrz, int offset) { } } -static bool emrtd_print_ef_dg11_info(bool *BAC, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool *use_14b) { - uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - int resplen = 0; +static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { + int td_variant = 0; + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG1") " --------------------"); + + // MRZ on TD1 is 90 characters, 30 on each row. + // MRZ on TD3 is 88 characters, 44 on each row. + char mrz[90] = { 0x00 }; + int mrzlen = 0; + + 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; + } + + // Determine and print the document type + if (mrz[0] == 'I' && mrz[1] == 'P') { + td_variant = 1; + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport Card")); + } else if (mrz[0] == 'I') { + td_variant = 1; + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("ID Card")); + } else if (mrz[0] == 'P') { + td_variant = 3; + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport")); + } else { + td_variant = 1; + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Unknown")); + PrintAndLogEx(INFO, "Assuming ID-style MRZ."); + } + PrintAndLogEx(SUCCESS, "Document Form Factor..: " _YELLOW_("TD%i"), td_variant); + + // Print the MRZ + if (td_variant == 1) { + PrintAndLogEx(DEBUG, "MRZ Row 1: " _YELLOW_("%.30s"), mrz); + PrintAndLogEx(DEBUG, "MRZ Row 2: " _YELLOW_("%.30s"), mrz + 30); + PrintAndLogEx(DEBUG, "MRZ Row 3: " _YELLOW_("%.30s"), mrz + 60); + } else if (td_variant == 3) { + PrintAndLogEx(DEBUG, "MRZ Row 1: " _YELLOW_("%.44s"), mrz); + PrintAndLogEx(DEBUG, "MRZ Row 2: " _YELLOW_("%.44s"), mrz + 44); + } + + PrintAndLogEx(SUCCESS, "Issuing state.........: " _YELLOW_("%.3s"), mrz + 2); + + if (td_variant == 3) { + // Passport form factor + 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_legal_sex(&mrz[44 + 20]); + emrtd_print_expiry(mrz, 44 + 21); + emrtd_print_optional_elements(mrz, 44 + 28, 14, true); + + // Calculate and verify composite check digit + char composite_check_data[50] = { 0x00 }; + memcpy(composite_check_data, mrz + 44, 10); + memcpy(composite_check_data + 10, mrz + 44 + 13, 7); + memcpy(composite_check_data + 17, mrz + 44 + 21, 23); + + if (!emrtd_compare_check_digit(composite_check_data, 39, mrz[87])) { + PrintAndLogEx(SUCCESS, _RED_("Composite check digit is invalid.")); + } + } else if (td_variant == 1) { + // ID form factor + 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_legal_sex(&mrz[30 + 7]); + emrtd_print_expiry(mrz, 30 + 8); + emrtd_print_optional_elements(mrz, 15, 15, false); + emrtd_print_optional_elements(mrz, 30 + 18, 11, false); + + // Calculate and verify composite check digit + if (!emrtd_compare_check_digit(mrz, 59, mrz[59])) { + PrintAndLogEx(SUCCESS, _RED_("Composite check digit is invalid.")); + } + } + + return true; +} + +static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { uint8_t taglist[100] = { 0x00 }; int taglistlen = 0; uint8_t tagdata[1000] = { 0x00 }; @@ -1195,11 +1276,6 @@ static bool emrtd_print_ef_dg11_info(bool *BAC, uint8_t *ssc, uint8_t *ks_enc, u PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG11") " -------------------"); - if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_DG11, ks_enc, ks_mac, ssc, *BAC, *use_14b)) { - PrintAndLogEx(ERR, "Failed to read EF_DG11."); - return 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; @@ -1272,8 +1348,6 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab bool BAC = false; bool use_14b = false; - int td_variant = 0; - // Select the eMRTD if (!emrtd_connect(&use_14b)) { DropField(); @@ -1294,96 +1368,37 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } - // Select EF_DG1 - if (emrtd_select_and_read(response, &resplen, EMRTD_EF_DG1, ks_enc, ks_mac, ssc, BAC, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to read EF_DG1."); + if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_COM, ks_enc, ks_mac, ssc, BAC, use_14b)) { + PrintAndLogEx(ERR, "Failed to read EF_COM."); DropField(); return PM3_ESOFT; } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG1") " --------------------"); + uint8_t filelist[50]; + int filelistlen = 0; - // MRZ on TD1 is 90 characters, 30 on each row. - // MRZ on TD3 is 88 characters, 44 on each row. - char mrz[90] = { 0x00 }; - int mrzlen = 0; - - 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."); + 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; } - // Determine and print the document type - if (mrz[0] == 'I' && mrz[1] == 'P') { - td_variant = 1; - PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport Card")); - } else if (mrz[0] == 'I') { - td_variant = 1; - PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("ID Card")); - } else if (mrz[0] == 'P') { - td_variant = 3; - PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport")); - } else { - td_variant = 1; - PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Unknown")); - PrintAndLogEx(INFO, "Assuming ID-style MRZ."); - } - PrintAndLogEx(SUCCESS, "Document Form Factor..: " _YELLOW_("TD%i"), td_variant); - - // Print the MRZ - if (td_variant == 1) { - PrintAndLogEx(DEBUG, "MRZ Row 1: " _YELLOW_("%.30s"), mrz); - PrintAndLogEx(DEBUG, "MRZ Row 2: " _YELLOW_("%.30s"), mrz + 30); - PrintAndLogEx(DEBUG, "MRZ Row 3: " _YELLOW_("%.30s"), mrz + 60); - } else if (td_variant == 3) { - PrintAndLogEx(DEBUG, "MRZ Row 1: " _YELLOW_("%.44s"), mrz); - PrintAndLogEx(DEBUG, "MRZ Row 2: " _YELLOW_("%.44s"), mrz + 44); - } - - PrintAndLogEx(SUCCESS, "Issuing state.........: " _YELLOW_("%.3s"), mrz + 2); - - if (td_variant == 3) { - // Passport form factor - 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_legal_sex(&mrz[44 + 20]); - emrtd_print_expiry(mrz, 44 + 21); - emrtd_print_optional_elements(mrz, 44 + 28, 14, true); - - // Calculate and verify composite check digit - char composite_check_data[50] = { 0x00 }; - memcpy(composite_check_data, mrz + 44, 10); - memcpy(composite_check_data + 10, mrz + 44 + 13, 7); - memcpy(composite_check_data + 17, mrz + 44 + 21, 23); - - if (!emrtd_compare_check_digit(composite_check_data, 39, mrz[87])) { - PrintAndLogEx(SUCCESS, _RED_("Composite check digit is invalid.")); + // 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]); + continue; } - } else if (td_variant == 1) { - // ID form factor - 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_legal_sex(&mrz[30 + 7]); - emrtd_print_expiry(mrz, 30 + 8); - emrtd_print_optional_elements(mrz, 15, 15, false); - emrtd_print_optional_elements(mrz, 30 + 18, 11, false); - // Calculate and verify composite check digit - if (!emrtd_compare_check_digit(mrz, 59, mrz[59])) { - PrintAndLogEx(SUCCESS, _RED_("Composite check digit is invalid.")); + 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); } } - // Print EF_DG11 info - // TODO: verify existence from file list, also print file list in info. - emrtd_print_ef_dg11_info(&BAC, ssc, ks_enc, ks_mac, &use_14b); - DropField(); return PM3_SUCCESS; }