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:
		@@ -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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user