nfc: DESFire fixes (#1334)

* nfc: don't give up on reading DESFire card if GET_KEY_SETTINGS fails
  Some cards are configured to refuse to provide key settings, but still
  provide other info.  For example, Ubiquiti UniFi Protect access cards
  won't list keys or applications, but will still answer GET_FREE_MEMORY.
* nfc: don't show error when saving DESFire card with no applications
* nfc: fix DESFire load with 0 applications or no PICC key settings

Co-authored-by: Kevin Wallace <git+flipperzero@kevin.wallace.seattle.wa.us>
Co-authored-by: gornekich <n.gorbadey@gmail.com>
Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Kevin Wallace 2022-06-21 07:58:22 -07:00 committed by GitHub
parent 92f763e553
commit 88facf20c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 52 deletions

View file

@ -495,16 +495,17 @@ static bool nfc_device_save_mifare_df_data(FlipperFormat* file, NfcDevice* dev)
n_apps++; n_apps++;
} }
if(!flipper_format_write_uint32(file, "Application Count", &n_apps, 1)) break; if(!flipper_format_write_uint32(file, "Application Count", &n_apps, 1)) break;
if(n_apps == 0) break; if(n_apps) {
tmp = malloc(n_apps * 3); tmp = malloc(n_apps * 3);
int i = 0; int i = 0;
for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
memcpy(tmp + i, app->id, 3); memcpy(tmp + i, app->id, 3);
i += 3; i += 3;
} }
if(!flipper_format_write_hex(file, "Application IDs", tmp, n_apps * 3)) break; if(!flipper_format_write_hex(file, "Application IDs", tmp, n_apps * 3)) break;
for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
if(!nfc_device_save_mifare_df_app(file, app)) break; if(!nfc_device_save_mifare_df_app(file, app)) break;
}
} }
saved = true; saved = true;
} while(false); } while(false);
@ -532,32 +533,36 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) {
break; break;
} }
} }
data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); if(flipper_format_key_exist(file, "PICC Change Key ID")) {
memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings)); data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings));
if(!nfc_device_load_mifare_df_key_settings(file, data->master_key_settings, "PICC")) { memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings));
free(data->master_key_settings); if(!nfc_device_load_mifare_df_key_settings(file, data->master_key_settings, "PICC")) {
data->master_key_settings = NULL; free(data->master_key_settings);
break; data->master_key_settings = NULL;
break;
}
} }
uint32_t n_apps; uint32_t n_apps;
if(!flipper_format_read_uint32(file, "Application Count", &n_apps, 1)) break; if(!flipper_format_read_uint32(file, "Application Count", &n_apps, 1)) break;
tmp = malloc(n_apps * 3); if(n_apps) {
if(!flipper_format_read_hex(file, "Application IDs", tmp, n_apps * 3)) break; tmp = malloc(n_apps * 3);
bool parsed_apps = true; if(!flipper_format_read_hex(file, "Application IDs", tmp, n_apps * 3)) break;
MifareDesfireApplication** app_head = &data->app_head; bool parsed_apps = true;
for(uint32_t i = 0; i < n_apps; i++) { MifareDesfireApplication** app_head = &data->app_head;
MifareDesfireApplication* app = malloc(sizeof(MifareDesfireApplication)); for(uint32_t i = 0; i < n_apps; i++) {
memset(app, 0, sizeof(MifareDesfireApplication)); MifareDesfireApplication* app = malloc(sizeof(MifareDesfireApplication));
memcpy(app->id, &tmp[i * 3], 3); memset(app, 0, sizeof(MifareDesfireApplication));
if(!nfc_device_load_mifare_df_app(file, app)) { memcpy(app->id, &tmp[i * 3], 3);
free(app); if(!nfc_device_load_mifare_df_app(file, app)) {
parsed_apps = false; free(app);
break; parsed_apps = false;
break;
}
*app_head = app;
app_head = &app->next;
} }
*app_head = app; if(!parsed_apps) break;
app_head = &app->next;
} }
if(!parsed_apps) break;
parsed = true; parsed = true;
} while(false); } while(false);

View file

@ -576,28 +576,27 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response");
free(data->master_key_settings); free(data->master_key_settings);
data->master_key_settings = NULL; data->master_key_settings = NULL;
continue; } else {
} MifareDesfireKeyVersion** key_version_head =
&data->master_key_settings->key_version_head;
MifareDesfireKeyVersion** key_version_head = for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) {
&data->master_key_settings->key_version_head; tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id);
for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id); FURI_LOG_W(TAG, "Bad exchange getting key version");
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) { continue;
FURI_LOG_W(TAG, "Bad exchange getting key version"); }
continue; MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion));
memset(key_version, 0, sizeof(MifareDesfireKeyVersion));
key_version->id = key_id;
if(!mf_df_parse_get_key_version_response(
tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) {
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response");
free(key_version);
continue;
}
*key_version_head = key_version;
key_version_head = &key_version->next;
} }
MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion));
memset(key_version, 0, sizeof(MifareDesfireKeyVersion));
key_version->id = key_id;
if(!mf_df_parse_get_key_version_response(
tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) {
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response");
free(key_version);
continue;
}
*key_version_head = key_version;
key_version_head = &key_version->next;
} }
} }