/*- * Copyright (C) 2010, Romain Tartiere. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see * * $Id$ */ #include #include #include #include #include #include "freefare_internal.h" #include "mifare_desfire_ev1_fixture.h" #include "common/mifare_desfire_auto_authenticate.h" #define cut_assert_success(last_command) \ do { \ if ((res < 0) || (mifare_desfire_last_picc_error (tag) != OPERATION_OK)) { \ cut_fail ("%s returned %d, error: %s, errno: %s\n", last_command, res, mifare_desfire_error_lookup (mifare_desfire_last_picc_error (tag)), strerror (errno)); \ } \ } while (0) void test_mifare_desfire_ev1_3k3des (void) { int res; /* Select the master application */ res = mifare_desfire_select_application (tag, NULL); cut_assert_success ("mifare_desfire_select_application()"); /* Get version information */ struct mifare_desfire_version_info version_info; res = mifare_desfire_get_version (tag, &version_info); cut_assert_success ("mifare_desfire_get_version()"); mifare_desfire_auto_authenticate (tag, 0); /* * This unit test change key settings to more restrictive ones, so reset * them to factory defaults in case the previous run failed unexpectedly. */ res = mifare_desfire_change_key_settings (tag, 0xF); cut_assert_success ("mifare_desfire_change_key_settings()"); res = mifare_desfire_change_key_settings (tag, 0xF); cut_assert_success ("mifare_desfire_change_key_settings()"); /* Change master key to AES */ MifareDESFireKey key = mifare_desfire_3k3des_key_new_with_version (key_data_3k3des); mifare_desfire_change_key (tag, 0, key, NULL); cut_assert_success ("mifare_desfire_change_key()"); res = mifare_desfire_authenticate_iso (tag, 0, key); cut_assert_success ("mifare_desfire_authenticate_iso()"); mifare_desfire_key_free (key); /* Wipeout the card */ res = mifare_desfire_format_picc (tag); cut_assert_success ("mifare_desfire_format_picc()"); /* Create 3 applications */ res = mifare_desfire_select_application (tag, NULL); cut_assert_success ("mifare_desfire_select_application()"); key = mifare_desfire_3k3des_key_new_with_version (key_data_3k3des); res = mifare_desfire_authenticate_iso (tag, 0, key); cut_assert_success ("mifare_desfire_authenticate_iso()"); mifare_desfire_key_free (key); uint8_t key_version; res = mifare_desfire_get_key_version (tag, 0, &key_version); cut_assert_success ("mifare_desfire_get_key_version()"); cut_assert_equal_int (0x55, 0x55, cut_message ("Wrong key_version value.")); uint32_t size; res = mifare_desfire_free_mem (tag, &size); cut_assert_success ("mifare_desfire_free_mem()"); MifareDESFireAID aid_a = mifare_desfire_aid_new (0x00AAAAAA); //cut_assert_not_null (aid_a, cut_message ("Cannot allocate AID")); res = mifare_desfire_create_application (tag, aid_a, 0xFF, 0); cut_assert_success ("mifare_desfire_create_application()"); MifareDESFireAID aid_b = mifare_desfire_aid_new (0x00BBBBBB); cut_assert_not_null (aid_b, cut_message ("Cannot allocate AID")); res = mifare_desfire_create_application (tag, aid_b, 0xEF, 0x40 | 6); cut_assert_success ("mifare_desfire_create_application()"); MifareDESFireAID aid_c = mifare_desfire_aid_new (0x00CCCCCC); cut_assert_not_null (aid_c, cut_message ("Cannot allocate AID")); res = mifare_desfire_create_application (tag, aid_c, 0xC2, 0x40 | 14); cut_assert_success ("mifare_desfire_create_application()"); // Ensure we can find the created applications MifareDESFireAID *aids = NULL; size_t aid_count; res = mifare_desfire_get_application_ids (tag, &aids, &aid_count); cut_assert_success ("mifare_desfire_get_application_ids()"); cut_assert_equal_int (3, aid_count, cut_message ("Wrong application count")); mifare_desfire_free_application_ids (aids); // Create files in the application A res = mifare_desfire_select_application (tag, aid_a); cut_assert_success ("mifare_desfire_select_application()"); uint8_t std_data_file_id = 15; res = mifare_desfire_create_std_data_file (tag, std_data_file_id, MDCM_PLAIN, 0xEEEE, 100); cut_assert_success ("mifare_desfire_create_std_data_file()"); res = mifare_desfire_create_backup_data_file (tag, 5, MDCM_PLAIN, 0xEEEE, 64); cut_assert_success ("mifare_desfire_create_backup_data_file()"); res = mifare_desfire_create_value_file (tag, 4, MDCM_PLAIN, 0xEEEE, 0, 1000, 0, 0); cut_assert_success ("mifare_desfire_create_value_file()"); res = mifare_desfire_create_cyclic_record_file (tag, 0, MDCM_PLAIN, 0xEEEE, 4, 10); cut_assert_success ("mifare_desfire_create_cyclic_record_file()"); // Write some data in the standard data file res = mifare_desfire_write_data (tag, std_data_file_id, 0, 30, (uint8_t *)"Some data to write to the card"); cut_assert_success ("mifare_desfire_write_data()"); cut_assert_equal_int (30, res, cut_message ("Wrong number of bytes writen")); res = mifare_desfire_write_data (tag, std_data_file_id, 34, 22, (uint8_t *)"Another block of data."); cut_assert_success ("mifare_desfire_write_data()"); cut_assert_equal_int (22, res, cut_message ("Wrong number of bytes writen")); // Make the file read-only res = mifare_desfire_change_file_settings (tag, std_data_file_id, MDCM_PLAIN, 0xEFFF); cut_assert_success ("mifare_desfire_change_file_settings()"); // Read a part of the file uint8_t buffer[120]; res = mifare_desfire_read_data (tag, std_data_file_id, 10, 50, &buffer); cut_assert_success ("mifare_desfire_read_data()"); cut_assert_equal_int (50, res, cut_message ("Wrong number of bytes read")); cut_assert_equal_memory ("to write to the card\0\0\0\0Another block of data.\0\0\0\0", 50, buffer, 50, cut_message ("Wrong data")); // Read all the file at once res = mifare_desfire_read_data (tag, std_data_file_id, 0, 0, &buffer); cut_assert_success ("mifare_desfire_read_data()"); cut_assert_equal_int (100, res, cut_message ("Wrong number of bytes read")); cut_assert_equal_memory ("Some data to write to the" " card\0\0\0\0Another block of" " data.\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 100, buffer, 100, cut_message ("Wrong data")); // Try to overwrute the file res = mifare_desfire_write_data (tag, std_data_file_id, 20, 5, (char *)"Test!"); cut_assert_equal_int (-1, res, cut_message ("Wrong return value")); cut_assert_equal_int (PERMISSION_ERROR, mifare_desfire_last_picc_error (tag), cut_message ("Wrong PICC error")); int32_t expected_value = 0; for (int transaction = 0; transaction < 15; transaction++) { char data_buffer[3]; sprintf (data_buffer, "%02d", transaction); // Write to the backup file res = mifare_desfire_write_data (tag, 5, 3*transaction, 3, data_buffer); cut_assert_success ("mifare_desfire_write_data()"); // Manipulate the value file res = mifare_desfire_credit (tag, 4, 100); cut_assert_success ("mifare_desfire_credit()"); res = mifare_desfire_debit (tag, 4, 97); cut_assert_success ("mifare_desfire_debit()"); // Write to the cyclic record file res = mifare_desfire_write_record (tag, 0, 2, 2, data_buffer); cut_assert_success ("mifare_desfire_write_record()"); // Overwrite the cyclic record file res = mifare_desfire_write_record (tag, 0, 0, 2, (char *)"r."); cut_assert_success("mifare_desfire_write_record()"); // Ensure that no content was changed yet char ref_buffer[64]; bzero (ref_buffer, sizeof (ref_buffer)); for (int n = 0; n < transaction; n++) { sprintf (ref_buffer + 3 * n, "%02d", n); } res = mifare_desfire_read_data (tag, 5, 0, 0, buffer); cut_assert_success ("mifare_desfire_read_data()"); cut_assert_equal_int (64, res, cut_message ("Wrong number of bytes read")); cut_assert_equal_memory (buffer, 64, ref_buffer, 64, cut_message ("Wrong data")); int32_t value; res = mifare_desfire_get_value (tag, 4, &value); cut_assert_success ("mifare_desfire_get_value()"); cut_assert_equal_int (expected_value, value, cut_message ("Wrong value")); // Reading records from an empty file would abort the transaction if (0 != transaction) { // Get the latest record res = mifare_desfire_read_records (tag, 0, 0, 1, buffer); cut_assert_success ("mifare_desfire_read_records()"); sprintf (ref_buffer, "r.%02d", transaction); cut_assert_not_equal_memory (ref_buffer, 4, buffer, res, cut_message ("Wrong data")); } // Commit ! res = mifare_desfire_commit_transaction (tag); cut_assert_success ("mifare_desfire_commit_transaction()"); res = mifare_desfire_read_data (tag, 5, 3*transaction, 3, buffer); cut_assert_success ("mifare_desfire_read_data()"); cut_assert_equal_memory (data_buffer, 3, buffer, res, cut_message ("Wrong data")); expected_value += 3; res = mifare_desfire_get_value (tag, 4, &value); cut_assert_success ("mifare_desfire_get_value()"); cut_assert_equal_int (expected_value, value, cut_message ("Wrong value")); res = mifare_desfire_read_records (tag, 0, 0, 1, buffer); cut_assert_success ("mifare_desfire_read_records()"); sprintf (ref_buffer, "r.%02d", transaction); cut_assert_equal_memory (ref_buffer, 4, buffer, res, cut_message ("Wrong data")); } // Ensure limited credit is disabled res = mifare_desfire_limited_credit (tag, 4, 20); cut_assert_equal_int (-1, res, cut_message ("mifare_desfire_limited_credit() should fail")); // Get all files uint8_t *files; size_t file_count; res = mifare_desfire_get_file_ids (tag, &files, &file_count); cut_assert_success ("mifare_desfire_get_file_ids()"); cut_assert_equal_int (4, file_count, cut_message ("Wrong number of files")); for (size_t i=0; i