Merge branch 'pr/401' into 420

This commit is contained in:
RogueMaster
2022-11-04 13:18:52 -04:00
12 changed files with 409 additions and 85 deletions

View File

@@ -1,4 +1,7 @@
#include <furi_hal_random.h>
#include <storage/storage.h>
#include <dialogs/dialogs.h>
#include <nfc/nfc_device.h>
#include "../helpers/iso7816.h"
@@ -19,6 +22,9 @@
#define num_elements(A) (sizeof(A) / sizeof(A[0]))
static const char* mrtd_auth_file_header = "Flipper MRTD params";
static const uint32_t mrtd_auth_file_version = 1;
static void hexdump(FuriLogLevel level, char* prefix, void* data, size_t length) {
if(furi_log_get_level() >= level) {
printf("%s ", prefix);
@@ -425,7 +431,7 @@ bool parse_ef_dg1(EF_DG1_contents* DG1, const uint8_t* data, size_t length) {
return true;
}
bool mrtd_read_parse_file(MrtdApplication* app, MrtdData* mrtd_data, EFFile file) {
bool mrtd_read_parse_file(MrtdApplication* app, EFFile file) {
uint8_t buffer[100];
size_t buf_len;
@@ -450,13 +456,13 @@ bool mrtd_read_parse_file(MrtdApplication* app, MrtdData* mrtd_data, EFFile file
bool result = false;
if(file.file_id == EF.COM.file_id) {
result = parse_ef_com(&mrtd_data->files.EF_COM, buffer, buf_len);
result = parse_ef_com(&app->mrtd_data->files.EF_COM, buffer, buf_len);
FURI_LOG_D(TAG, "Parsed EF.COM");
} else if(file.file_id == EF.DIR.file_id) {
result = parse_ef_dir(&mrtd_data->files.EF_DIR, buffer, buf_len);
result = parse_ef_dir(&app->mrtd_data->files.EF_DIR, buffer, buf_len);
FURI_LOG_D(TAG, "Parsed EF.DIR");
} else if(file.file_id == EF.DG1.file_id) {
result = parse_ef_dg1(&mrtd_data->files.DG1, buffer, buf_len);
result = parse_ef_dg1(&app->mrtd_data->files.DG1, buffer, buf_len);
} else {
FURI_LOG_W(TAG, "Don't know how to parse file with id 0x%04X", file.file_id);
}
@@ -464,52 +470,11 @@ bool mrtd_read_parse_file(MrtdApplication* app, MrtdData* mrtd_data, EFFile file
return result;
}
//TODO: remove testing function
void mrtd_test(MrtdApplication* app, MrtdData* mrtd_data) {
FURI_LOG_D(TAG, "Mrtd Test");
//mrtd_read_dump(app, EF.ATR);
//mrtd_read_dump(app, EF.COM);
//mrtd_read_dump(app, EF.DIR);
//mrtd_read_dump(app, EF.CardAccess);
//mrtd_read_dump(app, EF.CardSecurity);
mrtd_select_app(app, AID.eMRTDApplication);
MrtdAuthMethod method = mrtd_data->auth.method;
mrtd_data->auth_success = false;
FURI_LOG_D(TAG, "Auth method: %d", method);
switch(method) {
case MrtdAuthMethodAny:
//TODO: try PACE, then BAC
case MrtdAuthMethodBac:
mrtd_data->auth_success = mrtd_bac(app, &mrtd_data->auth);
break;
case MrtdAuthMethodPace:
FURI_LOG_E(TAG, "Auth method PACE not implemented");
break;
case MrtdAuthMethodNone:
default:
break;
}
if(!mrtd_data->auth_success) {
return;
}
mrtd_read_parse_file(app, mrtd_data, EF.COM);
//mrtd_read_parse_file(app, mrtd_data, EF.DIR);
mrtd_read_parse_file(app, mrtd_data, EF.DG1);
//mrtd_read_dump(app, EF.DG2);
//mrtd_read_dump(app, EF.DG14);
//mrtd_read_dump(app, EF.DG15);
}
MrtdApplication* mrtd_alloc_init(FuriHalNfcTxRxContext* tx_rx) {
MrtdApplication* mrtd_alloc_init(FuriHalNfcTxRxContext* tx_rx, MrtdData* mrtd_data) {
MrtdApplication* app = malloc(sizeof(MrtdApplication));
app->tx_rx = tx_rx;
app->mrtd_data = mrtd_data;
return app;
}
@@ -612,3 +577,168 @@ bool mrtd_bac(MrtdApplication* app, MrtdAuthData* auth) {
return true;
}
bool mrtd_authenticate(MrtdApplication* app) {
MrtdAuthMethod method = app->mrtd_data->auth.method;
app->mrtd_data->auth_success = false;
app->mrtd_data->auth_method_used = MrtdAuthMethodNone;
FURI_LOG_D(TAG, "Auth method: %d", method);
switch(method) {
case MrtdAuthMethodAny:
//TODO: try PACE, then BAC. For now, fall through to just BAC
case MrtdAuthMethodBac:
app->mrtd_data->auth_success = mrtd_bac(app, &app->mrtd_data->auth);
app->mrtd_data->auth_method_used = MrtdAuthMethodBac;
break;
case MrtdAuthMethodPace:
FURI_LOG_E(TAG, "Auth method PACE not implemented");
break;
case MrtdAuthMethodNone:
default:
break;
}
if(!app->mrtd_data->auth_success) {
return false;
}
return true;
}
bool mrtd_auth_params_save(Storage* storage, DialogsApp* dialogs, MrtdAuthData* auth_data, const char* file_name) {
return mrtd_auth_params_save_file(storage, dialogs, auth_data, file_name, MRTD_APP_FOLDER, MRTD_APP_EXTENSION);
}
void mrtd_date_prepare_format_string(MrtdDate date, FuriString* format_string) {
furi_string_printf(
format_string, "%02u%02u%02u",
date.year,
date.month,
date.day);
}
bool mrtd_date_parse_format_string(MrtdDate* date, FuriString* format_string) {
int year;
int month;
int day;
int ret = sscanf(furi_string_get_cstr(format_string), "%02d%02d%02d", &year, &month, &day);
if(ret != 3) {
return false;
}
date->year = year;
date->month = month;
date->day = day;
return true;
}
bool mrtd_auth_params_save_file(Storage* storage, DialogsApp* dialogs, MrtdAuthData* auth_data, const char* file_name, const char* folder, const char* extension) {
furi_assert(auth_data);
bool saved = false;
FlipperFormat* file = flipper_format_file_alloc(storage);
FuriString* temp_str;
temp_str = furi_string_alloc();
do {
// Create mrtd directory if necessary
if(!storage_simply_mkdir(storage, MRTD_APP_FOLDER)) break;
furi_string_printf(temp_str, "%s/%s%s", folder, file_name, extension);
// Open file
if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
// Write header
if(!flipper_format_write_header_cstr(file, mrtd_auth_file_header, mrtd_auth_file_version)) break;
// Write auth method
furi_string_set(temp_str, mrtd_auth_method_string(auth_data->method));
if(!flipper_format_write_string(file, "Method", temp_str)) break;
// Write birth date
mrtd_date_prepare_format_string(auth_data->birth_date, temp_str);
if(!flipper_format_write_string(file, "BirthDate", temp_str)) break;
// Write expiry date
mrtd_date_prepare_format_string(auth_data->expiry_date, temp_str);
if(!flipper_format_write_string(file, "ExpiryDate", temp_str)) break;
// Write docnr
furi_string_set(temp_str, auth_data->doc_number);
if(!flipper_format_write_string(file, "DocNr", temp_str)) break;
saved = true;
} while(false);
if(!saved) {
dialog_message_show_storage_error(dialogs, "Can not save\nparams file");
}
furi_string_free(temp_str);
flipper_format_free(file);
return saved;
}
bool mrtd_auth_params_load(Storage* storage, DialogsApp* dialogs, MrtdAuthData* auth_data, const char* file_path, bool show_dialog) {
furi_assert(storage);
furi_assert(dialogs);
furi_assert(auth_data);
furi_assert(file_path);
bool parsed = false;
FlipperFormat* file = flipper_format_file_alloc(storage);
bool deprecated_version = false;
FuriString* temp_str;
temp_str = furi_string_alloc();
MrtdAuthData copy;
FURI_LOG_D(TAG, "Load auth params");
do {
if(!flipper_format_file_open_existing(file, file_path)) break;
uint32_t version = 0;
if(!flipper_format_read_header(file, temp_str, &version)) break;
FURI_LOG_D(TAG, "Version: %s", furi_string_get_cstr(temp_str));
if(furi_string_cmp_str(temp_str, mrtd_auth_file_header) || (version != mrtd_auth_file_version)) {
deprecated_version = true;
break;
}
if(!flipper_format_read_string(file, "Method", temp_str)) break;
FURI_LOG_D(TAG, "Method: %s", furi_string_get_cstr(temp_str));
if(!mrtd_auth_method_parse_string(&copy.method, furi_string_get_cstr(temp_str))) break;
if(!flipper_format_read_string(file, "BirthDate", temp_str)) break;
FURI_LOG_D(TAG, "BirthDate: %s", furi_string_get_cstr(temp_str));
if(!mrtd_date_parse_format_string(&copy.birth_date, temp_str)) break;
if(!flipper_format_read_string(file, "ExpiryDate", temp_str)) break;
FURI_LOG_D(TAG, "ExpiryDate: %s", furi_string_get_cstr(temp_str));
if(!mrtd_date_parse_format_string(&copy.expiry_date, temp_str)) break;
if(!flipper_format_read_string(file, "DocNr", temp_str)) break;
FURI_LOG_D(TAG, "DocNr: %s", furi_string_get_cstr(temp_str));
strlcpy(copy.doc_number, furi_string_get_cstr(temp_str), MRTD_DOCNR_MAX_LENGTH);
// Everything went fine. Save copy to pointed auth data
*auth_data = copy;
parsed = true;
} while(false);
FURI_LOG_D(TAG, "Load done, success: %d", parsed);
if(!parsed && show_dialog) {
if(deprecated_version) {
dialog_message_show_storage_error(dialogs, "File format deprecated");
} else {
dialog_message_show_storage_error(dialogs, "Can not parse\nfile");
}
}
furi_string_free(temp_str);
flipper_format_free(file);
return parsed;
}