mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-23 22:55:37 -07:00
commit
7559eb9475
1 changed files with 82 additions and 30 deletions
|
@ -731,11 +731,10 @@ static bool emrtd_dump_ef_dg2(uint8_t *file_contents, int file_length) {
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) {
|
static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) {
|
||||||
uint8_t data[EMRTD_MAX_FILE_SIZE];
|
uint8_t data[EMRTD_MAX_FILE_SIZE];
|
||||||
int datalen = 0;
|
int datalen = 0;
|
||||||
|
@ -746,7 +745,7 @@ static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (datalen < EMRTD_MAX_FILE_SIZE) {
|
if (datalen < EMRTD_MAX_FILE_SIZE) {
|
||||||
saveFile("EF_DG5", ".jpg", data, datalen);
|
saveFile("EF_DG5", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg5) datalen out-of-bounds");
|
PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg5) datalen out-of-bounds");
|
||||||
return false;
|
return false;
|
||||||
|
@ -754,6 +753,24 @@ static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) {
|
||||||
return true;
|
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", data[0] == 0xFF ? ".jpg" : ".jp2", 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) {
|
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 fieldlen = emrtd_get_asn1_field_length(file_contents, file_length, 1);
|
||||||
int datalen = emrtd_get_asn1_data_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);
|
emrtd_dump_ef_dg2(response, resplen);
|
||||||
} else if (strcmp(file, EMRTD_EF_DG5) == 0) {
|
} else if (strcmp(file, EMRTD_EF_DG5) == 0) {
|
||||||
emrtd_dump_ef_dg5(response, resplen);
|
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) {
|
} else if (strcmp(file, EMRTD_EF_SOD) == 0) {
|
||||||
emrtd_dump_ef_sod(response, resplen);
|
emrtd_dump_ef_sod(response, resplen);
|
||||||
}
|
}
|
||||||
|
@ -1087,12 +1106,20 @@ 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) {
|
static int emrtd_mrz_determine_separator(char *mrz, int offset, int max_length) {
|
||||||
int i;
|
int i;
|
||||||
for (i = max_length; i >= 0; i--) {
|
for (i = max_length - 1; i > 0; i--) {
|
||||||
if (mrz[offset + i - 1] == '<' && mrz[offset + i] == '<') {
|
if (mrz[offset + i] == '<' && mrz[offset + i + 1] == '<') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i - 1;
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
static void emrtd_print_optional_elements(char *mrz, int offset, int length, bool verify_check_digit) {
|
||||||
|
@ -1120,13 +1147,22 @@ static void emrtd_print_document_number(char *mrz, int offset) {
|
||||||
|
|
||||||
static void emrtd_print_name(char *mrz, int offset, int max_length, bool localized) {
|
static void emrtd_print_name(char *mrz, int offset, int max_length, bool localized) {
|
||||||
char final_name[100] = { 0x00 };
|
char final_name[100] = { 0x00 };
|
||||||
int i = emrtd_mrz_determine_length(mrz, offset, max_length);
|
int namelen = emrtd_mrz_determine_length(mrz, offset, max_length);
|
||||||
int sep = emrtd_mrz_determine_separator(mrz, offset, i);
|
int sep = emrtd_mrz_determine_separator(mrz, offset, namelen);
|
||||||
int namelen = (i - (sep + 2));
|
|
||||||
|
|
||||||
memcpy(final_name, mrz + offset + sep + 2, namelen);
|
// Account for mononyms
|
||||||
final_name[namelen] = ' ';
|
if (sep != 0) {
|
||||||
memcpy(final_name + namelen + 1, mrz + offset, sep);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace < characters with spaces
|
||||||
|
emrtd_mrz_replace_pad(final_name, namelen, ' ');
|
||||||
|
|
||||||
if (localized) {
|
if (localized) {
|
||||||
PrintAndLogEx(SUCCESS, "Legal Name (Localized): " _YELLOW_("%s"), final_name);
|
PrintAndLogEx(SUCCESS, "Legal Name (Localized): " _YELLOW_("%s"), final_name);
|
||||||
|
@ -1135,15 +1171,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 (is_full) {
|
||||||
// If we get the full date, use the first two characters from that for year
|
// 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
|
// and do + 2 on offset so that rest of code uses the right data
|
||||||
offset += 2;
|
offset += 2;
|
||||||
} else {
|
} else {
|
||||||
char temp_year[3] = { 0x00 };
|
char temp_year[3] = { 0x00 };
|
||||||
memcpy(temp_year, mrz + offset, 2);
|
memcpy(temp_year, work_date, 2);
|
||||||
// If it's > 20, assume 19xx.
|
// If it's > 20, assume 19xx.
|
||||||
if (strtol(temp_year, NULL, 10) < 20 || is_expiry) {
|
if (strtol(temp_year, NULL, 10) < 20 || is_expiry) {
|
||||||
final_date[0] = '2';
|
final_date[0] = '2';
|
||||||
|
@ -1154,16 +1203,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] = '-';
|
final_date[4] = '-';
|
||||||
memcpy(final_date + 5, mrz + offset + 2, 2);
|
memcpy(final_date + 5, work_date + offset + 2, 2);
|
||||||
final_date[7] = '-';
|
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 };
|
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);
|
PrintAndLogEx(SUCCESS, "Date of birth.........: " _YELLOW_("%s"), final_date);
|
||||||
|
|
||||||
|
@ -1174,7 +1223,7 @@ static void emrtd_print_dob(char *mrz, int offset, bool full) {
|
||||||
|
|
||||||
static void emrtd_print_expiry(char *mrz, int offset) {
|
static void emrtd_print_expiry(char *mrz, int offset) {
|
||||||
char final_date[12] = { 0x00 };
|
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);
|
PrintAndLogEx(SUCCESS, "Date of expiry........: " _YELLOW_("%s"), final_date);
|
||||||
|
|
||||||
|
@ -1183,9 +1232,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 };
|
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);
|
PrintAndLogEx(SUCCESS, "Date of issue.........: " _YELLOW_("%s"), final_date);
|
||||||
}
|
}
|
||||||
|
@ -1249,7 +1298,7 @@ static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) {
|
||||||
PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 44 + 10);
|
PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 44 + 10);
|
||||||
emrtd_print_name(mrz, 5, 38, false);
|
emrtd_print_name(mrz, 5, 38, false);
|
||||||
emrtd_print_document_number(mrz, 44);
|
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_legal_sex(&mrz[44 + 20]);
|
||||||
emrtd_print_expiry(mrz, 44 + 21);
|
emrtd_print_expiry(mrz, 44 + 21);
|
||||||
emrtd_print_optional_elements(mrz, 44 + 28, 14, true);
|
emrtd_print_optional_elements(mrz, 44 + 28, 14, true);
|
||||||
|
@ -1268,7 +1317,7 @@ static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) {
|
||||||
PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 30 + 15);
|
PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 30 + 15);
|
||||||
emrtd_print_name(mrz, 60, 30, false);
|
emrtd_print_name(mrz, 60, 30, false);
|
||||||
emrtd_print_document_number(mrz, 5);
|
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_legal_sex(&mrz[30 + 7]);
|
||||||
emrtd_print_expiry(mrz, 30 + 8);
|
emrtd_print_expiry(mrz, 30 + 8);
|
||||||
emrtd_print_optional_elements(mrz, 15, 15, false);
|
emrtd_print_optional_elements(mrz, 15, 15, false);
|
||||||
|
@ -1305,6 +1354,9 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) {
|
||||||
case 0x0e:
|
case 0x0e:
|
||||||
emrtd_print_name((char *) tagdata, 0, tagdatalen, true);
|
emrtd_print_name((char *) tagdata, 0, tagdatalen, true);
|
||||||
break;
|
break;
|
||||||
|
case 0x0f:
|
||||||
|
emrtd_print_name((char *) tagdata, 0, tagdatalen, false);
|
||||||
|
break;
|
||||||
case 0x10:
|
case 0x10:
|
||||||
PrintAndLogEx(SUCCESS, "Personal Number.......: " _YELLOW_("%.*s"), tagdatalen, tagdata);
|
PrintAndLogEx(SUCCESS, "Personal Number.......: " _YELLOW_("%.*s"), tagdatalen, tagdata);
|
||||||
break;
|
break;
|
||||||
|
@ -1329,7 +1381,7 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) {
|
||||||
PrintAndLogEx(SUCCESS, "Personal Summary......: " _YELLOW_("%.*s"), tagdatalen, tagdata);
|
PrintAndLogEx(SUCCESS, "Personal Summary......: " _YELLOW_("%.*s"), tagdatalen, tagdata);
|
||||||
break;
|
break;
|
||||||
case 0x16:
|
case 0x16:
|
||||||
saveFile("ProofOfCitizenship", ".jpg", tagdata, tagdatalen);
|
saveFile("ProofOfCitizenship", tagdata[0] == 0xFF ? ".jpg" : ".jp2", tagdata, tagdatalen);
|
||||||
break;
|
break;
|
||||||
case 0x17:
|
case 0x17:
|
||||||
// TODO: acc for < separation
|
// TODO: acc for < separation
|
||||||
|
@ -1339,7 +1391,7 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) {
|
||||||
PrintAndLogEx(SUCCESS, "Custody Information...: " _YELLOW_("%.*s"), tagdatalen, tagdata);
|
PrintAndLogEx(SUCCESS, "Custody Information...: " _YELLOW_("%.*s"), tagdatalen, tagdata);
|
||||||
break;
|
break;
|
||||||
case 0x2b:
|
case 0x2b:
|
||||||
emrtd_print_dob((char *) tagdata, 0, true);
|
emrtd_print_dob((char *) tagdata, 0, true, tagdatalen != 4);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(SUCCESS, "Unknown Field %02X%02X....: %s", taglist[i], taglist[i + 1], sprint_hex_inrow(tagdata, tagdatalen));
|
PrintAndLogEx(SUCCESS, "Unknown Field %02X%02X....: %s", taglist[i], taglist[i + 1], sprint_hex_inrow(tagdata, tagdatalen));
|
||||||
|
@ -1380,7 +1432,7 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) {
|
||||||
PrintAndLogEx(SUCCESS, "Issuing Authority.....: " _YELLOW_("%.*s"), tagdatalen, tagdata);
|
PrintAndLogEx(SUCCESS, "Issuing Authority.....: " _YELLOW_("%.*s"), tagdatalen, tagdata);
|
||||||
break;
|
break;
|
||||||
case 0x26:
|
case 0x26:
|
||||||
emrtd_print_issuance((char *) tagdata);
|
emrtd_print_issuance((char *) tagdata, tagdatalen != 4);
|
||||||
break;
|
break;
|
||||||
case 0x1b:
|
case 0x1b:
|
||||||
PrintAndLogEx(SUCCESS, "Endorsements & Observations: " _YELLOW_("%.*s"), tagdatalen, tagdata);
|
PrintAndLogEx(SUCCESS, "Endorsements & Observations: " _YELLOW_("%.*s"), tagdatalen, tagdata);
|
||||||
|
@ -1389,10 +1441,10 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) {
|
||||||
PrintAndLogEx(SUCCESS, "Tax/Exit Requirements.: " _YELLOW_("%.*s"), tagdatalen, tagdata);
|
PrintAndLogEx(SUCCESS, "Tax/Exit Requirements.: " _YELLOW_("%.*s"), tagdatalen, tagdata);
|
||||||
break;
|
break;
|
||||||
case 0x1d:
|
case 0x1d:
|
||||||
saveFile("FrontOfDocument", ".jpg", tagdata, tagdatalen);
|
saveFile("FrontOfDocument", tagdata[0] == 0xFF ? ".jpg" : ".jp2", tagdata, tagdatalen);
|
||||||
break;
|
break;
|
||||||
case 0x1e:
|
case 0x1e:
|
||||||
saveFile("BackOfDocument", ".jpg", tagdata, tagdatalen);
|
saveFile("BackOfDocument", tagdata[0] == 0xFF ? ".jpg" : ".jp2", tagdata, tagdatalen);
|
||||||
break;
|
break;
|
||||||
case 0x55:
|
case 0x55:
|
||||||
emrtd_print_personalization_timestamp(tagdata);
|
emrtd_print_personalization_timestamp(tagdata);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue