mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-26 03:39:58 -07:00
Merge branch 'pr/401' into 420
This commit is contained in:
@@ -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(©.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(©.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(©.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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user