diff --git a/csca/20191206_DEMasterList.ml b/csca/20191206_DEMasterList.ml new file mode 100644 index 0000000000000000000000000000000000000000..13ec46d493ee11aa409b3a065892590b41ce0852 Binary files /dev/null and b/csca/20191206_DEMasterList.ml differ diff --git a/lib b/lib index c61c1ad48c8325c94469d2f6fe535e4a581aed2a..f34669620b10e1354a4e467932b5c1adb7b2938c 160000 --- a/lib +++ b/lib @@ -1 +1 @@ -Subproject commit c61c1ad48c8325c94469d2f6fe535e4a581aed2a +Subproject commit f34669620b10e1354a4e467932b5c1adb7b2938c diff --git a/linux32_release/csca/20191206_DEMasterList.ml b/linux32_release/csca/20191206_DEMasterList.ml new file mode 100644 index 0000000000000000000000000000000000000000..13ec46d493ee11aa409b3a065892590b41ce0852 Binary files /dev/null and b/linux32_release/csca/20191206_DEMasterList.ml differ diff --git a/linux32_release/ePassport_mrtd b/linux32_release/ePassport_mrtd index 9ba386d47a878645253ea67390ed6ce8ad76f94e..c74b024575e0c92ff5fd1f7c3b82772f2f923872 100644 Binary files a/linux32_release/ePassport_mrtd and b/linux32_release/ePassport_mrtd differ diff --git a/linux64_release/csca/20191206_DEMasterList.ml b/linux64_release/csca/20191206_DEMasterList.ml new file mode 100644 index 0000000000000000000000000000000000000000..13ec46d493ee11aa409b3a065892590b41ce0852 Binary files /dev/null and b/linux64_release/csca/20191206_DEMasterList.ml differ diff --git a/linux64_release/ePassport_mrtd b/linux64_release/ePassport_mrtd index ea8156eba77007c4da96b0339cb12b8954ef827d..b011c89ef23735a680a7c9c2453fc281046c2978 100644 Binary files a/linux64_release/ePassport_mrtd and b/linux64_release/ePassport_mrtd differ diff --git a/src/f_utils.c b/src/f_utils.c index e92fc95b8e81d40a9f2ce90acea4b3d7d5f0a838..0fda5e2445fd0bc415ce16fc11fda21702b96110 100644 --- a/src/f_utils.c +++ b/src/f_utils.c @@ -155,226 +155,6 @@ void show_files_tag_list(const uint8_t *files_tag_list, const int tag_list_size) printf("\n"); } -void to_space(char *s) { - - while(*s != '\0') { - if (*s == '<') - *s = ' '; - else if ((*s < '0' && *s > '9') && (*s < 'A' && *s > 'Z')) - *s = ' '; - ++s; - } -} - -void to_date(const char *s, char *date, uint8_t year_threshold) { - uint32_t year; - - year = (((uint8_t) s[0] - 0x30) * 10) + ((uint8_t) s[1] - 0x30); - - memcpy(date, &s[4], 2); // day - memcpy(&date[3], &s[2], 2); // month - memcpy(&date[8], s, 2); // year, second part - // year, first part: - if (year > year_threshold) - memcpy(&date[6], "19", 2); - else - memcpy(&date[6], "20", 2); - date[2] = date[5] = date[10] = '.'; - date[11] = '\0'; -} - -void show_mrz_data_td1_format(const char *mrz) { - char temp[40]; - - memcpy(temp, mrz, 2); - temp[2] = '\0'; - to_space(temp); - printf(" Document code: %s", temp); - if (temp[0] == 'P' && temp[1] == ' ') - printf(" (ePassport)"); - printf("\n"); - mrz += 2; - - memcpy(temp, mrz, 3); - temp[3] = '\0'; - to_space(temp); - printf(" Issuing State or organization: %s\n", temp); - mrz += 3; - - memcpy(temp, mrz, 9); - temp[9] = '\0'; - to_space(temp); - printf(" Document number: %s\n", temp); - mrz += 9; // +1 for check digit - - if (mrz[0] == '<') - printf(" document number extension: "); - else - printf(" Optional data: "); - ++mrz; - - memcpy(temp, mrz, 15); - temp[15] = '\0'; - to_space(temp); - printf(" %s\n", temp); - mrz += 15; - - to_date(mrz, temp, 20); - printf(" Date of birth (dd.MM.yyyy.): %s\n", temp); - mrz += 7; // +1 for check digit - - printf(" Sex: "); - if (mrz[0] == 'M') - printf("male"); - else if (mrz[0] == 'F') - printf("female"); - else - printf("unknown"); - printf("\n"); - mrz += 1; - - to_date(mrz, temp, 100); - printf(" Date of expiry (dd.MM.yyyy.): %s\n", temp); - mrz += 7; // +1 for check digit - - memcpy(temp, mrz, 3); - temp[3] = '\0'; - to_space(temp); - printf(" Nationality: %s\n", temp); - mrz += 3; - - memcpy(temp, mrz, 11); - temp[11] = '\0'; - to_space(temp); - printf(" Optional data: %s\n", temp); - mrz += 11; - - memcpy(temp, mrz, 30); - temp[30] = '\0'; - to_space(temp); - printf(" Name of holder: %s\n", temp); -} - -void show_mrz_data_td2_format(const char *mrz) { - char temp[40]; - - memcpy(temp, mrz, 2); - temp[2] = '\0'; - to_space(temp); - printf(" Document code: %s", temp); - if (temp[0] == 'P' && temp[1] == ' ') - printf(" (ePassport)"); - printf("\n"); - mrz += 2; - - memcpy(temp, mrz, 3); - temp[3] = '\0'; - to_space(temp); - printf(" Issuing State or organization: %s\n", temp); - mrz += 3; - - memcpy(temp, mrz, 31); - temp[31] = '\0'; - to_space(temp); - printf(" Name of holder: %s\n", temp); - mrz += 31; - - memcpy(temp, mrz, 9); - temp[9] = '\0'; - to_space(temp); - printf(" Document number: %s\n", temp); - mrz += 10; // +1 for check digit - - memcpy(temp, mrz, 3); - temp[3] = '\0'; - to_space(temp); - printf(" Nationality: %s\n", temp); - mrz += 3; - - to_date(mrz, temp, 20); - printf(" Date of birth (dd.MM.yyyy.): %s\n", temp); - mrz += 7; // +1 for check digit - - printf(" Sex: "); - if (mrz[0] == 'M') - printf("male"); - else if (mrz[0] == 'F') - printf("female"); - else - printf("unknown"); - printf("\n"); - mrz += 1; - - to_date(mrz, temp, 100); - printf(" Date of expiry (dd.MM.yyyy.): %s\n", temp); - mrz += 7; // +1 for check digit - - memcpy(temp, mrz, 7); - temp[7] = '\0'; - to_space(temp); - printf(" Optional data: %s\n", temp); -} - -void show_mrz_data_td3_format(const char *mrz) { - char temp[40]; - - memcpy(temp, mrz, 2); - temp[2] = '\0'; - to_space(temp); - printf(" Document code: %s", temp); - if (temp[0] == 'P' && temp[1] == ' ') - printf(" (ePassport)"); - printf("\n"); - mrz += 2; - - memcpy(temp, mrz, 3); - temp[3] = '\0'; - to_space(temp); - printf(" Issuing State or organization: %s\n", temp); - mrz += 3; - - memcpy(temp, mrz, 39); - temp[39] = '\0'; - to_space(temp); - printf(" Name of holder: %s\n", temp); - mrz += 39; - - memcpy(temp, mrz, 9); - temp[9] = '\0'; - to_space(temp); - printf(" Document number: %s\n", temp); - mrz += 10; // +1 for check digit - - memcpy(temp, mrz, 3); - temp[3] = '\0'; - to_space(temp); - printf(" Nationality: %s\n", temp); - mrz += 3; - - to_date(mrz, temp, 20); - printf(" Date of birth (dd.MM.yyyy.): %s\n", temp); - mrz += 7; // +1 for check digit - - printf(" Sex: "); - if (mrz[0] == 'M') - printf("male"); - else if (mrz[0] == 'F') - printf("female"); - else - printf("unknown"); - printf("\n"); - mrz += 1; - - to_date(mrz, temp, 100); - printf(" Date of expiry (dd.MM.yyyy.): %s\n", temp); - mrz += 7; // +1 for check digit - - memcpy(temp, mrz, 14); - temp[14] = '\0'; - to_space(temp); - printf(" Optional data: %s\n", temp); -} - bool isBigEndian(void) { uint32_t ui = 1; uint8_t *ptr = (uint8_t *) &ui; diff --git a/src/ini.h b/src/ini.h index 3d1d9dd0fe5056c97ffd62b744ccdb3147febafb..1add3beda08d9977260e323ffa30460ec1e2f782 100644 --- a/src/ini.h +++ b/src/ini.h @@ -5,6 +5,17 @@ #ifndef INI_H_ #define INI_H_ -#define APP_VERSION "1.3" +#define APP_VERSION "1.4" + +#define EXIT_ON_WRONG_FW_DEPENDENCY +#define EXIT_ON_WRONG_LIB_DEPENDENCY + +#define MIN_DEPEND_LIB_VER_MAJOR 5 +#define MIN_DEPEND_LIB_VER_MINOR 0 +#define MIN_DEPEND_LIB_VER_BUILD 25 + +#define MIN_DEPEND_FW_VER_MAJOR 5 +#define MIN_DEPEND_FW_VER_MINOR 0 +#define MIN_DEPEND_FW_VER_BUILD 22 #endif /* INI_H_ */ diff --git a/src/main.c b/src/main.c index 7530102346c60dbb7e429df7cd02ce6b45827099..6c469c83bfe07f3e18ae8a578d4bec86fbbc98b0 100644 --- a/src/main.c +++ b/src/main.c @@ -6,8 +6,7 @@ Copyright : 2009-2019. Digital Logic Ltd. Description : "ePassport, MRTD uFR NFC reader example" in C, Ansi-style Dependencies: uFR firmware minimal version: 5.0.22 - uFCoder library minimal version: 5.0.12 (5.0.21 for the verification of the - MRTD data validity) + uFCoder library minimal version: 5.0.25 ============================================================================ */ @@ -36,13 +35,6 @@ #define READER_RESET #define DL_FREE(x) if (x) free(x) //------------------------------------------------------------------------------ -enum E_SEARCH_CYCLES { - SEARCH_FOR_CERT, - SEARCH_FOR_ML, - - SEARCH_CYCLES_NUM -}; -//------------------------------------------------------------------------------ void usage(void); void menu(char key); UFR_STATUS NewCardInField(uint8_t sak, uint8_t *uid, uint8_t uid_size); @@ -257,6 +249,12 @@ UFR_STATUS NewCardInField(uint8_t sak, uint8_t *uid, uint8_t uid_size) { print_hex_ln(uid, uid_size, ":"); print_ln('-'); + + /*/ DEBUG + MRTD_MRZSubjacentToMRZProtoKey("0087110562SRB0210199M15040991910002762013<26", mrz_proto_key); + mrz_proto_key_defined = true; + ReadDG1();*/ + return UFR_OK; } //------------------------------------------------------------------------------ @@ -510,6 +508,7 @@ void ReadSODSaveToFile(void) { void ReadDG1(void) { UFR_STATUS status; uint8_t *file_content; + char *sbuffer; uint32_t file_len; if (!CheckMRZProtoKey()) @@ -540,55 +539,17 @@ void ReadDG1(void) { printf(" Raw data: \n"); print_hex_lnlimit(file_content, file_len, " ", 24); - printf(" Simple parsing the EF.DG1 raw data:\n"); - - uint8_t field_len; - uint8_t *raw; - uint32_t raw_len; - uint32_t len; - - if (file_content[0] != 0x61) - printf(" Error: wrong EF.DG1 tag 0x%02X and should be 0x61\n", file_content[0]); - if (!get_tlv_len(file_content + 1, &field_len, &raw_len)) { - printf(" Error: unknown TLV length coding\n"); - break; - } - if (file_len != (raw_len + field_len + 1)) { - printf(" Error: wrong file length.\n"); - break; - } - raw = file_content + field_len + 1; // +1 for tag - - if (raw[0] == 0x5F && raw[1] == 0x1F) { - - raw += 2; - if (!get_tlv_len(raw, &field_len, &len)) { - printf(" Error: unknown TLV length coding\n"); - // No need for exit_loop = true; (last loop in do {} while(0);) - break; - } - raw += field_len; + printf(" Parsing the EF.DG1 raw data:\n"); - switch (len) { - case 0x5A: // size = 90(dec) => TD1 format - show_mrz_data_td1_format((const char *) raw); - break; - case 0x48: // size = 72(dec) => TD2 format - show_mrz_data_td2_format((const char *) raw); - break; - case 0x58: // size = 88(dec) => TD3 format - show_mrz_data_td3_format((const char *) raw); - break; - default: - printf(" Error: wrong LDS version length (%d bytes and should be 4).\n", len); - break; - } - } else { - printf(" Error: wrong MRZ data object tag '%02X %02X' '5F 1F'\n", raw[0], raw[1]); + status = MRTDParseDG1ToHeap(&sbuffer, "\n", file_content, file_len); + if (status != UFR_OK) { + printf(" Error while parsing EF.DG1 file: %s\n", UFR_Status2String(status)); break; } + printf("%s\n", sbuffer); } while (0); // <-- finally + DL_FREE(sbuffer); if (file_content) free(file_content); @@ -667,14 +628,9 @@ void ReadDG2SaveToFile(void) { //------------------------------------------------------------------------------ void ReadFacialImageSaveToFile(void) { UFR_STATUS status; - uint8_t *file_content; - const uint8_t *image; - uint32_t file_len; - uint32_t image_size; - char *extension; + uint8_t *dg2 = NULL; + uint32_t dg2_len; char file_path_name[257]; - FILE *f = NULL; - size_t wresult; if (!CheckMRZProtoKey()) return; @@ -697,54 +653,35 @@ void ReadFacialImageSaveToFile(void) { break; } - status = MRTDFileReadBacToHeap((const uint8_t *) "\x01\x02", &file_content, &file_len, ksenc, ksmac, &send_sequence_cnt); + status = MRTDFileReadBacToHeap((const uint8_t *) "\x01\x02", &dg2, &dg2_len, ksenc, ksmac, &send_sequence_cnt); if (status != UFR_OK) { printf(" Error while reading file from tag: %s\n", UFR_Status2String(status)); break; } - printf("\n EF.DG2 has been successfully read. File length is %d bytes\n", file_len); + printf("\n EF.DG2 has been successfully read. File length is %d bytes\n", dg2_len); s_block_deselect(100); - // Attention: parameter image is only pointer to the image start position in to file_content bytes. - // Do not try to free image afterwards! - if (!decode_image_from_dg2(file_content, file_len, &image, &image_size, &extension)) { - printf(" Error while trying to decode image. Can not save the image file.\n"); - break; - } - printf(" Image has been decoded successfully.\n"); - printf("\n The extension is automatically set based on the detected image type.\n" " Please enter image file path and name (maximum 256 characters) without extension:\n"); my_scanf("%256s", file_path_name); if (!strlen(file_path_name)) { printf("\n Input error.\n"); - return; - } - printf("\n"); - - strcat(file_path_name, extension); - f = fopen(file_path_name, "wb"); - if (!f) { - printf(" Host file system error: %s\n", strerror(errno)); break; } + printf("\n"); - wresult = fwrite(image, 1, image_size, f); - if (wresult != image_size) { - printf(" Host file system error while reading file.\n"); + status = MRTDGetImageFromDG2ToFile(dg2, dg2_len, file_path_name); + if (status != UFR_OK) { + printf(" Error while extracting image from data group 2 file. Status is: %s\n", UFR_Status2String(status)); break; } printf("\n Facial image has been successfully written to a host file system.\n"); } while (0); // <-- finally - if (file_content) - free(file_content); - if (extension) - free(extension); - if (f) - fclose(f); + if (dg2) + free(dg2); s_block_deselect(100); print_ln('-'); } @@ -826,16 +763,16 @@ void ReadDGxSaveToFile(void) { print_ln('-'); } //------------------------------------------------------------------------------ +enum E_SEARCH_CYCLES { + SEARCH_FOR_CERT, + SEARCH_FOR_ML, + + SEARCH_CYCLES_NUM +}; + void VerifyMRTDDataValidity(void) { - uint32_t sod_len, cert_len, sig_len, com_len, dg_len, hash_alg, hash_len, stored_hash_len, lds_so_len; - uint8_t dg_cnt; // Pointers that have to be freed after use: - uint8_t *sod = NULL, *dg = NULL, *cacert = NULL, *cert = NULL, *hash = NULL, *sig = NULL, *com = NULL, *sig_attrs = NULL; - uint8_t *dg_lst, *stored_hash, *lds_so; // pointers to already allocated memory - bool ufr_in_iso14443_4_mode = false, dir_opened = false, to_finally = false; - FILE *f = NULL; - struct dirent *de; - DIR *dr; + char *printout; UFR_STATUS status; print_ln('-'); @@ -848,7 +785,6 @@ void VerifyMRTDDataValidity(void) { printf(" Error while switching into ISO 14443-4 mode, uFR status is: %s\n", UFR_Status2String(status)); break; } - ufr_in_iso14443_4_mode = true; status = MRTDAppSelectAndAuthenticateBac(mrz_proto_key, ksenc, ksmac, &send_sequence_cnt); if (status != UFR_OK) { @@ -856,446 +792,18 @@ void VerifyMRTDDataValidity(void) { break; } - status = MRTDFileReadBacToHeap((const uint8_t *) "\x01\x1E", &com, &com_len, ksenc, ksmac, &send_sequence_cnt); - if (status != UFR_OK) { - printf(" Error while reading file from tag, uFR status is: %s\n", UFR_Status2String(status)); - break; - } - - status = MRTDFileReadBacToHeap((const uint8_t *) "\x01\x1D", &sod, &sod_len, ksenc, ksmac, &send_sequence_cnt); - if (status != UFR_OK) { - printf(" Error while reading file from tag, uFR status is: %s\n", UFR_Status2String(status)); - break; - } - - status = pkcs7GetDataGroupsHashAlgorithm(sod, sod_len, &hash_alg); - if (status != UFR_OK) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); - break; - } - status = DLGetHashOutputByteLength(hash_alg, &hash_len); - if (status) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); - break; - } - hash = malloc(hash_len); - if (hash == NULL) { - printf(" Memory allocation error while parsing SOD\n"); - break; - } - - printf(" Hash algorithm for data groups used: %s\n\n", DLGetHashName(hash_alg)); - - status = MRTDGetDGTagListFromCOM(com, com_len, &dg_lst, &dg_cnt); - if (status != UFR_OK) { - printf(" Error while parsing EF.COM file, status is: %s\n", UFR_Status2String(status)); - break; - } - - uint8_t dg_idx; - uint8_t fid[2] = { 0x01, 0x00 }; - - for (uint32_t i = 0; i < dg_cnt; i++) { - - dg_idx = MRTDGetDgIndex(dg_lst[i]); - if (dg_idx == 0) { - printf(" Error while parsing EF.COM file, unknown DG tag\n"); - to_finally = true; - break; - } - fid[1] = dg_idx; - - status = pkcs7GetDataGroupHash(sod, sod_len, dg_idx, &stored_hash, &stored_hash_len); - if (status != UFR_OK) { - printf(" Error while parsing EF.COM file, can't found stored hash for EF.DG%d\n", dg_idx); - to_finally = true; - break; - } - if (hash_len != stored_hash_len) { - printf(" Error while parsing EF.COM file, wrong hash length for EF.DG%d\n", dg_idx); - to_finally = true; - break; - } - - status = MRTDFileReadBacToHeap(fid, &dg, &dg_len, ksenc, ksmac, &send_sequence_cnt); - if (status == UFR_APDU_SW_SECURITY_STATUS_NOT_SATISFIED) { - printf(" Data group %d: NOT CALCULATED\n (Unreadable data without using EAC - state issued certificate needed)\n", dg_idx); - printf(" Stored : "); - print_hex_lnlimit(stored_hash, stored_hash_len, " ", 32); - printf("\n"); - continue; - } else if (status != UFR_OK) { - printf(" Error while reading file from tag: %s\n", UFR_Status2String(status)); - to_finally = true; - break; - } - - status = DLGetHash(hash_alg, dg, dg_len, hash, hash_len); - DL_FREE(dg); - dg = NULL; - - printf(" Data group %d: \n", dg_idx); - printf(" Stored : "); - print_hex_lnlimit(stored_hash, stored_hash_len, " ", 32); - printf(" Calculated: "); - print_hex_lnlimit(hash, hash_len, " ", 32); - if (status == UFR_OK) { - if (!memcmp(hash, stored_hash, hash_len)) - printf(" HASH IS MATCHED\n"); - else - printf(" ERROR, HASH IS NOT MATCHING! DATA IS TAMPERED!\n"); - } else - printf(" Error while calculating hash value, status is: %s\n", UFR_Status2String(status)); - printf("\n"); - } - if (to_finally) - break; - - //------------------------------------------------------------------ - uint32_t digest_alg; - - status = pkcs7GetSignedAttrsDigestAlgorithm(sod, sod_len, &digest_alg); - if (status != UFR_OK) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); - break; - } - - if (digest_alg != hash_alg) { - free(hash); - hash_alg = digest_alg; - status = DLGetHashOutputByteLength(hash_alg, &hash_len); - if (status) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); - break; - } - hash = malloc(hash_len); - if (hash == NULL) { - printf(" Memory allocation error while parsing SOD\n"); - break; - } - } - printf("\n Digest algorithm for LDS Security Object and Signed Attributes used: %s\n\n", DLGetHashName(hash_alg)); - - status = pkcs7GetLDSSecurityObjectDigest(sod, sod_len, &stored_hash, &stored_hash_len); - if (status != UFR_OK) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); - break; - } - - status = pkcs7GetLDSSecurityObject(sod, sod_len, &lds_so, &lds_so_len); - if (status != UFR_OK) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); - break; - } - - status = DLGetHash(hash_alg, lds_so, lds_so_len, hash, hash_len); - - printf(" LDS Security Object: \n"); - printf(" Stored : "); - print_hex_lnlimit(stored_hash, stored_hash_len, " ", 32); - printf(" Calculated: "); - print_hex_lnlimit(hash, hash_len, " ", 32); - - if (status == UFR_OK) { - if (!memcmp(hash, stored_hash, hash_len)) - printf(" DIGEST IS MATCHED\n"); - else - printf(" ERROR, DIGEST IS NOT MATCHING! DATA IS TAMPERED!\n"); - } else - printf(" Error while calculating hash value, status is: %s\n", UFR_Status2String(status)); - printf("\n"); - - //---------------------------------------------------------------------- - // SOD and Document Signing (DS) certificate scrutiny: - uint8_t *pub_key, *pub_key_params; - uint32_t pub_key_byte_size, pub_key_bit_size, pub_key_type, ecc_curve; - - status = pkcs7GetCert(sod, sod_len, &cert, &cert_len); - if (status != UFR_OK) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); - break; - } - - status = X509ParsePubKey(cert, &pub_key, &pub_key_byte_size, &pub_key_bit_size, &pub_key_type, &ecc_curve, &pub_key_params); - if (status != UFR_OK) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); - break; - } - - if (pub_key_type == PUB_KEY_TYPE_RSA) { - printf(" Document Signing (DS) certificate contains RSA public key\n RSA public key bit-size is %d\n\n", pub_key_bit_size); - - } else if (pub_key_type == PUB_KEY_TYPE_ECDSA_NAMED_CURVE || pub_key_type == PUB_KEY_TYPE_ECDSA_DOMAIN_PARAMS) { - if (pub_key_type == PUB_KEY_TYPE_ECDSA_NAMED_CURVE) { - printf(" Document Signing (DS) certificate contains ECC public key\n" - " Elliptic curve name: %s\n\n", DLGetEccCurveName(ecc_curve)); - } else if (pub_key_type == PUB_KEY_TYPE_ECDSA_DOMAIN_PARAMS) { - printf(" Document Signing (DS) certificate contains ECC public key with domain parameters\n" - " ECC public key (field) bit-size is %d\n\n", pub_key_bit_size); - } - - } else { - printf(" Error while parsing Document Signing (DS) certificate, unknown public key type\n"); - break; - } - - status = pkcs7GetSignature(sod, sod_len, &sig, &sig_len); - if (status != UFR_OK) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); - break; - } - - uint8_t *sig_alg_data; - uint32_t sig_alg_data_len; - status = pkcs7GetSignatureAlgorithm(sod, sod_len, &sig_alg_data, &sig_alg_data_len); - if (status != UFR_OK) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); - break; - } - - uint32_t sig_sch, sig_sch_type, sig_sch_params_len; - uint8_t *sig_sch_params; - status = pkcs7ParseDERSignatureShceme(sig_alg_data, &sig_sch, &sig_sch_type, &sig_sch_params, &sig_sch_params_len); - if (status != UFR_OK) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); - break; - } - printf(" Signature scheme used for Signed Attributes signature verification: %s\n", DLGetSignatureSchemeName(sig_sch)); - - //---------------------------------------------------------------------- - // SOD and files data validity verification: - status = pkcs7VerifySignature(sod, sod_len); - switch (status) { - case UFR_OK: - printf(" Signed Attributes signature is OK.\n"); - break; - case PKCS7_WRONG_SIGNATURE: - printf(" WRONG Signed Attributes signature. DATA IS TAMPERED!\n\n"); - break; - case PKCS7_SIG_SCH_NOT_MATCH_CERT_KEY_TYPE: - printf(" Error, signature scheme doesn't match with an Document Signing (DS) certificate key type\n"); - break; - case UFR_NO_MEMORY_ERROR: - printf(" Memory allocation error during signature verification \n"); - break; - case PKCS7_UNSUPPORTED_SIGNATURE_SCHEME: - printf(" Error while parsing SOD, unknown signature scheme\n"); - break; - default: - printf(" Error while parsing SOD, status is: %s/n", UFR_Status2String(status)); - } - - printf("\n"); - - // Certificate scrutiny: - // --------------------- - char file_path[1024]; // Improvement required - uint8_t *ski, *aki, *root_ski, *root_aki, *root_subject, *ds_issuer; - uint32_t ski_len, aki_len, root_ski_len, root_aki_len, root_subject_len, ds_issuer_len; - - status = X509GetIssuerSeq(cert, cert_len, &ds_issuer, &ds_issuer_len); + printf("eMRTDocument is validated. This may take a few seconds. Please wait.\n\n"); + status = MRTDValidate("./csca", &printout, "\n", PRINT_ALL_PLUS_STATUSES, ksenc, ksmac, &send_sequence_cnt); + printf("%s", printout); + DLFree(printout); if (status != UFR_OK) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); + printf(" Error during verification, uFR status is: %s\n", UFR_Status2String(status)); break; } - - status = X509GetSKIFromCert(cert, cert_len, &ski, &ski_len); - if (status == UFR_OK) { - printf(" Document Signing (DS) certificate SKI: "); - print_hex_lnlimit(ski, ski_len, " ", 32); - } else if (status != X509_EXTENSION_NOT_FOUND) - break; - - status = X509GetAKIFromCert(cert, cert_len, &aki, &aki_len); - if (status == UFR_OK) { - printf(" Document Signing (DS) certificate AKI: "); - print_hex_lnlimit(aki, aki_len, " ", 32); - } - - bool csca_founded = false, csca_verified = false, root_csca_verified = false, critical_stop = false; - uint32_t search_cycle = SEARCH_FOR_CERT; - - // CSCA Certificate: - dr = opendir("./csca"); - if (dr == NULL) { - printf("\n Error, can not find and/or open csca directory\n"); - printf("\n Can not find CSCA (i.e. trust anchor) certificate\n"); - break; - } else { - dir_opened = true; - } - - while (!csca_founded) { - uint8_t *csca_cert = NULL; - uint32_t csca_cert_len; - - if ((de = readdir(dr)) == NULL) { - if (++search_cycle == SEARCH_CYCLES_NUM) - break; - else { - rewinddir(dr); - continue; - } - } - - char *ptr; - if (strlen(de->d_name) < 4) // Skip e.g. "." and ".." - continue; - if ((ptr = strrchr(de->d_name, (int) '.')) == NULL) // File don't have extension - continue; - - if (search_cycle != SEARCH_FOR_ML && !memcmp(ptr, ".ml", 3) && strlen(ptr) == 3) - continue; - if (search_cycle == SEARCH_FOR_ML && (memcmp(ptr, ".ml", 3) || strlen(ptr) != 3)) - continue; - - strcpy(file_path, "csca/"); - strcat(file_path, de->d_name); - - do { // __try - - if (search_cycle == SEARCH_FOR_CERT) { - - status = X509GetCertFromFile(file_path, &csca_cert, &csca_cert_len); - if (status) { - printf(" Error while processing potentially certificate file '%s' processing, status is: %s\n", de->d_name, - UFR_Status2String(status)); - break; - } - - } else { - // Master List file processing: - status = icaoMlOpen(file_path, &f); - if (status) { - printf(" Error during Master List file '%s' processing, status is: %s\n", de->d_name, UFR_Status2String(status)); - break; - } - - // Search through Master List file, check root certificate serial_num, subject and SKI - // If certificate founded, extract and ... csca_founded = true; - icaoMlSearchCriteria_t criteria; - icaoMlClearSearchCriteria(&criteria); - criteria.subject = ds_issuer; - criteria.subject_len = ds_issuer_len; - criteria.SKI = aki; - criteria.SKI_len = aki_len; - - status = icaoMlFindCert(f, &criteria, &csca_cert, &csca_cert_len); - if (status == ICAO_ML_CERTIFICATE_NOT_FOUND) { - icaoMlClose(f); - break; // Next .ml file - } - else if (status) { - icaoMlClose(f); - printf(" Error during Master List file '%s' processing, status is: %s\n", de->d_name, UFR_Status2String(status)); - break; - } - icaoMlClose(f); - } - - // check root certificate serial_num, subject and SKI and if valid ... csca_founded = true; - { - status = X509GetSubjectSeq(csca_cert, csca_cert_len, &root_subject, &root_subject_len); - if (status != UFR_OK) { - printf(" Error while parsing SOD, status is: %s\n", UFR_Status2String(status)); - break; - } - - if (root_subject_len != ds_issuer_len) - break; - if (memcmp(root_subject, ds_issuer, ds_issuer_len)) - break; - - bool ski_ok = false, aki_ok = false; - status = X509GetSKIFromCert(csca_cert, csca_cert_len, &root_ski, &root_ski_len); - if (status == UFR_OK) - ski_ok = true; - status = X509GetAKIFromCert(csca_cert, csca_cert_len, &root_aki, &root_aki_len); - if (status == UFR_OK) - aki_ok = true; - - if (ski_ok && aki_ok) { - // If both SKI and AKI are present in the CSCA certificate, they should be - // the same or there is the Link CSCA certificate: - if (root_ski_len != root_aki_len) - break; - if (memcmp(root_ski, root_aki, aki_len)) - break; - } - - if (root_ski_len != aki_len) - break; - if (memcmp(root_ski, aki, aki_len)) - break; - - csca_founded = true; - printf("\n Root CSCA certificate has been found\n"); - - if (ski_ok) { - printf(" CSCA certificate SKI: "); - print_hex_lnlimit(root_ski, root_ski_len, " ", 32); - } - if (aki_ok) { - printf(" CSCA certificate AKI: "); - print_hex_lnlimit(root_aki, root_aki_len, " ", 32); - } - - status = X509VerifyDerCertSignature(cert, cert_len, csca_cert, csca_cert_len); - if (status == UFR_OK) - csca_verified = true; - - // Self-signed CSCA (root) certificate signature verification: - status = X509VerifyDerCertSignature(csca_cert, csca_cert_len, csca_cert, csca_cert_len); - if (status == UFR_OK) - root_csca_verified = true; - - break; - } - - } while (0); //__finally - - DL_FREE(csca_cert); - - if (critical_stop || csca_founded) - break; - } - - if (!csca_founded) { - printf("\n Can not find CSCA (i.e. trust anchor) certificate\n"); - break; - } else if (!csca_verified || !root_csca_verified) { - if (!csca_verified) { - printf(" Document Signing (DS) certificate signature verification failed. Wrong signature!\n"); - } - if (!root_csca_verified) { - printf(" Root CSCA self signed certificate signature verification failed!\n" - " Root CSCA have wrong signature! Compromised trust anchor!\n"); - } - break; - } - - if (critical_stop) - break; - - printf("\n Document validity confirmed\n\n"); } while (0); // <-- finally print_ln('-'); - DL_FREE(sod); - DL_FREE(dg); - DL_FREE(hash); - DL_FREE(com); - DL_FREE(sig_attrs); - DL_FREE(cacert); - - if (dir_opened) { - closedir(dr); - } - if (ufr_in_iso14443_4_mode) { - s_block_deselect(100); - } - if (f != NULL) - fclose(f); + s_block_deselect(100); } //------------------------------------------------------------------------------ diff --git a/win32_release/csca/20191206_DEMasterList.ml b/win32_release/csca/20191206_DEMasterList.ml new file mode 100644 index 0000000000000000000000000000000000000000..13ec46d493ee11aa409b3a065892590b41ce0852 Binary files /dev/null and b/win32_release/csca/20191206_DEMasterList.ml differ diff --git a/win32_release/ePassport_mrtd.exe b/win32_release/ePassport_mrtd.exe index c35a98d7676ddf0fb9535d7e437a4a2c16278276..361b1ff8f09dd85c26e4bf9b7555b527d8fe1802 100644 Binary files a/win32_release/ePassport_mrtd.exe and b/win32_release/ePassport_mrtd.exe differ diff --git a/win64_release/csca/20191206_DEMasterList.ml b/win64_release/csca/20191206_DEMasterList.ml new file mode 100644 index 0000000000000000000000000000000000000000..13ec46d493ee11aa409b3a065892590b41ce0852 Binary files /dev/null and b/win64_release/csca/20191206_DEMasterList.ml differ diff --git a/win64_release/ePassport_mrtd.exe b/win64_release/ePassport_mrtd.exe index 0a14bae818df3add4dd1a8ffded635cc2146ec94..f0b3c74c9d45e8e999d03dc18389da227622d4e0 100644 Binary files a/win64_release/ePassport_mrtd.exe and b/win64_release/ePassport_mrtd.exe differ