/*-
* 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 { \
cut_assert_equal_int (OPERATION_OK, mifare_desfire_last_picc_error (tag), cut_message ("PICC replied %s", mifare_desfire_error_lookup (mifare_desfire_last_picc_error (tag)))); \
cut_assert_not_equal_int (-1, res, cut_message ("Wrong return value")); \
} while (0)
void
test_mifare_desfire_ev1_aes (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()");
/* Change master key to AES */
MifareDESFireKey key = mifare_desfire_aes_key_new_with_version (key_data_aes, key_data_aes_version);
mifare_desfire_change_key (tag, 0, key, NULL);
cut_assert_success ("mifare_desfire_change_key()");
res = mifare_desfire_authenticate_aes (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate_aes()");
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_aes_key_new (key_data_aes);
res = mifare_desfire_authenticate_aes (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate_aes()");
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 (key_data_aes_version, key_version, 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_aes (tag, aid_b, 0xEF, 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_aes (tag, aid_c, 0xC2, 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];
memset (ref_buffer, 0, 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