Complete ISO 7816 compatibility for Mifare DESFire EV1

Fixes issue 37
This commit is contained in:
Romain Tartiere 2011-03-26 13:22:48 +00:00
parent b41f93cd5b
commit f27352180c
5 changed files with 217 additions and 14 deletions

14
NEWS
View file

@ -1,7 +1,19 @@
Changes between 0.3.1 and 0.3.2 [XX xxx XXXX]
*) New API functions mifare_desfire_create_application_3k3des() and
*) New API functions to ease up creation of applications with strong
cryptography on Mifare DESFire EV1:
mifare_desfire_create_application_3k3des(),
mifare_desfire_create_application_aes().
*) New API functions for ISO 7616 support om Mifare DESFire EV1:
mifare_desfire_create_application_iso(),
mifare_desfire_create_application_3k3des_iso(),
mifare_desfire_create_application_aes_iso(),
mifare_desfire_get_df_names(),
mifare_desfire_get_iso_file_ids(),
mifare_desfire_create_std_data_file_iso(),
mifare_desfire_create_backup_data_file_iso(),
mifare_desfire_create_linear_record_file_iso(),
mifare_desfire_create_cyclic_record_file_iso().
Changes between 0.3.0 and 0.3.1 [23 feb 2011]

View file

@ -353,13 +353,18 @@ int mifare_desfire_set_default_key (MifareTag tag, MifareDESFireKey key);
int mifare_desfire_set_ats (MifareTag tag, uint8_t *ats);
int mifare_desfire_get_card_uid (MifareTag tag, char **uid);
int mifare_desfire_get_file_ids (MifareTag tag, uint8_t *files[], size_t *count);
int mifare_desfire_get_iso_file_ids (MifareTag tag, uint16_t *files[], size_t *count);
int mifare_desfire_get_file_settings (MifareTag tag, uint8_t file_no, struct mifare_desfire_file_settings *settings);
int mifare_desfire_change_file_settings (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights);
int mifare_desfire_create_std_data_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size);
int mifare_desfire_create_std_data_file_iso (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size, uint16_t iso_file_id);
int mifare_desfire_create_backup_data_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size);
int mifare_desfire_create_backup_data_file_iso (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size, uint16_t iso_file_id);
int mifare_desfire_create_value_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, int32_t lower_limit, int32_t upper_limit, int32_t value, uint8_t limited_credit_enable);
int mifare_desfire_create_linear_record_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records);
int mifare_desfire_create_linear_record_file_iso (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records, uint16_t iso_file_id);
int mifare_desfire_create_cyclic_record_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records);
int mifare_desfire_create_cyclic_record_file_iso (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records, uint16_t iso_file_id);
int mifare_desfire_delete_file (MifareTag tag, uint8_t file_no);
ssize_t mifare_desfire_read_data (MifareTag tag, uint8_t file_no, off_t offset, size_t length, void *data);

View file

@ -1,4 +1,4 @@
.\" Copyright (C) 2010 Romain Tartiere
.\" Copyright (C) 2010,2011 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
@ -15,7 +15,7 @@
.\"
.\" $Id$
.\"
.Dd July 11, 2010
.Dd March 26, 2011
.Dt MIFARE_DESFIRE 3
.Os
.\" _ _
@ -39,9 +39,13 @@
.Nm mifare_desfire_create_application ,
.Nm mifare_desfire_create_application_3k3des ,
.Nm mifare_desfire_create_application_aes ,
.Nm mifare_desfire_create_application_iso ,
.Nm mifare_desfire_create_application_3k3des_iso ,
.Nm mifare_desfire_create_application_aes_iso ,
.Nm mifare_desfire_delete_application ,
.Nm mifare_desfire_get_application_ids ,
.Nm mifare_desfire_free_application_ids ,
.Nm mifare_desfire_get_df_names ,
.Nm mifare_desfire_select_application ,
.\"
.Nm mifare_desfire_format_picc ,
@ -54,13 +58,18 @@
.Nm mifare_desfire_get_card_uid ,
.\"
.Nm mifare_desfire_get_file_ids ,
.Nm mifare_desfire_get_iso_file_ids ,
.Nm mifare_desfire_get_file_settings ,
.Nm mifare_desfire_change_file_settings ,
.Nm mifare_desfire_create_std_data_file ,
.Nm mifare_desfire_create_backup_data_file ,
.Nm mifare_desfire_create_std_data_file_iso ,
.Nm mifare_desfire_create_backup_data_file ,
.Nm mifare_desfire_create_backup_data_file_iso ,
.Nm mifare_desfire_create_value_file ,
.Nm mifare_desfire_create_linear_record_file ,
.Nm mifare_desfire_create_linear_record_file_iso ,
.Nm mifare_desfire_create_cyclic_record_file ,
.Nm mifare_desfire_create_cyclic_record_file_iso ,
.Nm mifare_desfire_delete_file ,
.\"
.Nm mifare_desfire_read_data ,
@ -124,12 +133,20 @@ Mifare card manipulation library (libfreefare, \-lfreefare)
.Ft int
.Fn mifare_desfire_create_application_3k3des "MifareTag tag" "MifareDESFireAID aid" "uint8_t settings" "uint8_t key_no"
.Ft int
.Fn mifare_desfire_create_application_iso "MifareTag tag" "MifareDESFireAID aid" "uint8_t settings" "uint8_t key_no" "int want_iso_file_identifiers" "uint16_t iso_file_id" "uint8_t *iso_file_name" "size_t iso_file_name_len"
.Ft int
.Fn mifare_desfire_create_application_3k3des_iso "MifareTag tag" "MifareDESFireAID aid" "uint8_t settings" "uint8_t key_no" "int want_iso_file_identifiers" "uint16_t iso_file_id" "uint8_t *iso_file_name" "size_t iso_file_name_len"
.Ft int
.Fn mifare_desfire_create_application_aes_iso "MifareTag tag" "MifareDESFireAID aid" "uint8_t settings" "uint8_t key_no" "int want_iso_file_identifiers" "uint16_t iso_file_id" "uint8_t *iso_file_name" "size_t iso_file_name_len"
.Ft int
.Fn mifare_desfire_delete_application "MifareTag tag" "MifareDESFireAID aid"
.Ft int
.Fn mifare_desfire_get_application_ids "MifareTag tag" "MifareDESFireAID *aids[]" "size_t *count"
.Ft void
.Fn mifare_desfire_free_application_ids "MifareDESFireAID aids[]"
.Ft int
.Fn mifare_desfire_get_df_names "MifareTag tag" "MifareDESFireDF *dfs[]" "size_t *count"
.Ft int
.Fn mifare_desfire_select_application "MifareTag tag" "MifareDESFireAID aid"
.Ft int
.Fn mifare_desfire_format_picc "MifareTag tag"
@ -148,19 +165,29 @@ Mifare card manipulation library (libfreefare, \-lfreefare)
.Ft int
.Fn mifare_desfire_get_file_ids "MifareTag tag" "uint8_t *files[]" "size_t *count"
.Ft int
.Fn mifare_desfire_get_iso_file_ids "MifareTag tag" "uint16_t *files[]" "size_t *count"
.Ft int
.Fn mifare_desfire_get_file_settings "MifareTag tag" "uint8_t file_no" "struct mifare_desfire_file_settings *settings"
.Ft int
.Fn mifare_desfire_change_file_settings "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights"
.Ft int
.Fn mifare_desfire_create_std_data_file "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t file_size"
.Ft int
.Fn mifare_desfire_create_std_data_file_iso "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t file_size" "uint16_t iso_file_id"
.Ft int
.Fn mifare_desfire_create_backup_data_file "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t file_size"
.Ft int
.Fn mifare_desfire_create_backup_data_file_iso "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t file_size" "uint16_t iso_file_id"
.Ft int
.Fn mifare_desfire_create_value_file "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "int32_t lower_limit" "int32_t upper_limit" "int32_t value" "uint8_t limited_credit_enable"
.Ft int
.Fn mifare_desfire_create_linear_record_file "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t record_size" "uint32_t max_number_of_records"
.Ft int
.Fn mifare_desfire_create_cyclic_record_file "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t record_size" "uint32_t max_number_of_records"
.Fn mifare_desfire_create_linear_record_file_iso "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t record_size" "uint32_t max_number_of_records"
.Ft int
.Fn mifare_desfire_create_cyclic_record_file "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t record_size" "uint32_t max_number_of_records" "uint16_t iso_file_id"
.Ft int
.Fn mifare_desfire_create_cyclic_record_file_iso "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t record_size" "uint32_t max_number_of_records" "uint16_t iso_file_id"
.Ft int
.Fn mifare_desfire_delete_file "MifareTag tag" "uint8_t file_no"
.Ft ssize_t
@ -374,6 +401,31 @@ or
respectively.
.Pp
The
.Fn mifare_desfire_create_application_iso
acts as the
.Fn mifare_desfire_create_application
function but allows to specify if the created files within the application shall have an ISO file identifier setting
.Vt want_iso_file_identifiers
to a non-NULL value, a DF can be provided using
.Vt iso_file_id ,
as long as an optional file name
.Vt iso_file_name
of length
.Vt iso_file_name_len
(in bytes).
.Pp
The
.Fn mifare_desfire_create_application_3k3des_iso
and
.Fn mifare_desfire_create_application_aes_iso
function acts as the regular
.Fn mifare_desfire_create_application_3k3des
and
.Fn mifare_desfire_create_application_aes
functions, providing the same extensions ISO parameters of
.Fn mifare_desfire_create_application_iso .
.Pp
The
.Fn mifare_desfire_delete_application
deletes the application identified by AID
.Vt aid .
@ -385,6 +437,18 @@ function returns a list of all applications of the card. The
array has to be freed after usage calling
.Fn mifare_desfire_free_application_ids .
.Pp
The
.Fn mifare_desfire_get_df_names
retrieves the list of DF
.Vt dfs
from
.Vt tag
and set
.Vt count
to the number of idems in the allocated array. Memory has to be freed by the
user using
.Xr free 3 .
.Pp
.Ss File-level operations
The
.Fn mifare_desfire_get_file_ids
@ -398,6 +462,17 @@ has to be reclaimed using
.Xr free 3 .
.Pp
The
.Fn mifare_desfire_get_iso_file_ids
function returns the list of
.Vt count
file ISO identifiers as
.Vt files .
The memory allocated for
.Vt files
has to be reclaimed using
.Xr free 3 .
.Pp
The
.Fn mifare_desfire_get_file_settings
function retrieves the
.Vt settings
@ -456,6 +531,13 @@ records of size
.El
.Pp
The
.Fn mifare_desfire_create_*_iso
family of functions acts as the functions without the
.Vt _iso
suffix but provide an additionnal argument
.Vt iso_file_id .
.Pp
The
.Fn mifare_desfire_delete_file
removes the file
.Vt file_no

View file

@ -101,8 +101,8 @@ static struct mifare_desfire_file_settings cached_file_settings[MAX_FILE_COUNT];
static bool cached_file_settings_current[MAX_FILE_COUNT];
static int authenticate (MifareTag tag, uint8_t cmd, uint8_t key_no, MifareDESFireKey key);
static int create_file1 (MifareTag tag, uint8_t command, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size);
static int create_file2 (MifareTag tag, uint8_t command, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records);
static int create_file1 (MifareTag tag, uint8_t command, uint8_t file_no, int has_iso_file_id, uint16_t iso_file_id, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size);
static int create_file2 (MifareTag tag, uint8_t command, uint8_t file_no, int has_iso_file_id, uint16_t iso_file_id, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records);
static ssize_t write_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_t length, void *data, int cs);
static ssize_t read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_t length, void *data, int cs);
@ -1111,6 +1111,49 @@ mifare_desfire_get_file_ids (MifareTag tag, uint8_t *files[], size_t *count)
return 0;
}
int
mifare_desfire_get_iso_file_ids (MifareTag tag, uint16_t *files[], size_t *count)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 1);
BUFFER_INIT (res, 2*27 + 1);
BUFFER_APPEND (cmd, 0x61);
uint8_t *data;
if (!(data = malloc ((27 + 5) * 2 + 8)))
return -1;
off_t offset = 0;
uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND);
do {
DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res);
memcpy (data + offset, res, __res_n - 1);
offset += __res_n - 1;
p[0] = 0XAF;
} while (res[__res_n-1] == 0xAF);
ssize_t sn = offset;
p = mifare_cryto_postprocess_data (tag, data, &sn, MDCM_PLAIN | CMAC_COMMAND);
*count = sn / 2;
*files = malloc (sizeof (**files) * *count);
if (!*files)
return -1;
for (size_t i = 0; i < *count; i++) {
(*files)[i] = le16toh (*(uint16_t *)(p + (2*i)));
}
return 0;
}
int
mifare_desfire_get_file_settings (MifareTag tag, uint8_t file_no, struct mifare_desfire_file_settings *settings)
{
@ -1215,16 +1258,18 @@ mifare_desfire_change_file_settings (MifareTag tag, uint8_t file_no, uint8_t com
}
static int
create_file1 (MifareTag tag, uint8_t command, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size)
create_file1 (MifareTag tag, uint8_t command, uint8_t file_no, int has_iso_file_id, uint16_t iso_file_id, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
BUFFER_INIT (cmd, 8 + CMAC_LENGTH);
BUFFER_INIT (cmd, 10 + CMAC_LENGTH);
BUFFER_INIT (res, 1 + CMAC_LENGTH);
BUFFER_APPEND (cmd, command);
BUFFER_APPEND (cmd, file_no);
if (iso_file_id >= 0)
BUFFER_APPEND_LE (cmd, iso_file_id, sizeof (iso_file_id), sizeof (iso_file_id));
BUFFER_APPEND (cmd, communication_settings);
BUFFER_APPEND_LE (cmd, access_rights, 2, sizeof (uint16_t));
BUFFER_APPEND_LE (cmd, file_size, 3, sizeof (uint32_t));
@ -1244,13 +1289,25 @@ create_file1 (MifareTag tag, uint8_t command, uint8_t file_no, uint8_t communica
int
mifare_desfire_create_std_data_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size)
{
return create_file1 (tag, 0xCD, file_no, communication_settings, access_rights, file_size);
return create_file1 (tag, 0xCD, file_no, 0, 0x0000, communication_settings, access_rights, file_size);
}
int
mifare_desfire_create_std_data_file_iso (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size, uint16_t iso_file_id)
{
return create_file1 (tag, 0xCD, file_no, 1, iso_file_id, communication_settings, access_rights, file_size);
}
int
mifare_desfire_create_backup_data_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size)
{
return create_file1 (tag, 0xCB, file_no, communication_settings, access_rights, file_size);
return create_file1 (tag, 0xCB, file_no, 0, 0x0000, communication_settings, access_rights, file_size);
}
int
mifare_desfire_create_backup_data_file_iso (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size, uint16_t iso_file_id)
{
return create_file1 (tag, 0xCB, file_no, 1, iso_file_id, communication_settings, access_rights, file_size);
}
int
@ -1284,7 +1341,7 @@ mifare_desfire_create_value_file (MifareTag tag, uint8_t file_no, uint8_t commun
}
static int
create_file2 (MifareTag tag, uint8_t command, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records)
create_file2 (MifareTag tag, uint8_t command, uint8_t file_no, int has_iso_file_id, uint16_t iso_file_id, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records)
{
ASSERT_ACTIVE (tag);
ASSERT_MIFARE_DESFIRE (tag);
@ -1294,6 +1351,8 @@ create_file2 (MifareTag tag, uint8_t command, uint8_t file_no, uint8_t communica
BUFFER_APPEND (cmd, command);
BUFFER_APPEND (cmd, file_no);
if (has_iso_file_id)
BUFFER_APPEND_LE (cmd, iso_file_id, sizeof (iso_file_id), sizeof (iso_file_id));
BUFFER_APPEND (cmd, communication_settings);
BUFFER_APPEND_LE (cmd, access_rights, 2, sizeof (uint16_t));
BUFFER_APPEND_LE (cmd, record_size, 3, sizeof (uint32_t));
@ -1314,13 +1373,25 @@ create_file2 (MifareTag tag, uint8_t command, uint8_t file_no, uint8_t communica
int
mifare_desfire_create_linear_record_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records)
{
return create_file2 (tag, 0xC1, file_no, communication_settings, access_rights, record_size, max_number_of_records);
return create_file2 (tag, 0xC1, file_no, 0, 0x0000, communication_settings, access_rights, record_size, max_number_of_records);
}
int
mifare_desfire_create_linear_record_file_iso (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records, uint16_t iso_file_id)
{
return create_file2 (tag, 0xC1, file_no, 1, iso_file_id, communication_settings, access_rights, record_size, max_number_of_records);
}
int
mifare_desfire_create_cyclic_record_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records)
{
return create_file2 (tag, 0xC0, file_no, communication_settings, access_rights, record_size, max_number_of_records);
return create_file2 (tag, 0xC0, file_no, 0, 0x000, communication_settings, access_rights, record_size, max_number_of_records);
}
int
mifare_desfire_create_cyclic_record_file_iso (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records, uint16_t iso_file_id)
{
return create_file2 (tag, 0xC0, file_no, 1, iso_file_id, communication_settings, access_rights, record_size, max_number_of_records);
}
int

View file

@ -96,4 +96,37 @@ test_mifare_desfire_ev1_iso (void)
cut_assert_equal_int (sizeof (app3), dfs[2].df_name_len, cut_message ("Wrong value"));
cut_assert_equal_memory (app3, sizeof (app3), dfs[2].df_name, dfs[2].df_name_len, cut_message ("Wrong value"));
free (dfs);
aid = mifare_desfire_aid_new (0x555550);
res = mifare_desfire_create_application_iso (tag, aid, 0xff, 1, 1, 0x555F, NULL, 0);
cut_assert_success ("mifare_desfire_create_application_iso");
res = mifare_desfire_select_application (tag, aid);
cut_assert_success ("mifare_desfire_select_application");
res = mifare_desfire_create_std_data_file_iso (tag, 1, MDCM_PLAIN, 0xEEEE, 32, 0x1234);
cut_assert_success ("mifare_desfire_create_std_data_file_iso");
res = mifare_desfire_create_backup_data_file_iso (tag, 2, MDCM_PLAIN, 0xEEEE, 32, 0x2345);
cut_assert_success ("mifare_desfire_create_std_data_file_iso");
res = mifare_desfire_create_linear_record_file_iso (tag, 3, MDCM_PLAIN, 0xEEEE, 32, 10, 0x3456);
cut_assert_success ("mifare_desfire_create_linear_record_file_iso");
res = mifare_desfire_create_cyclic_record_file_iso (tag, 4, MDCM_PLAIN, 0xEEEE, 32, 10, 0x4567);
cut_assert_success ("mifare_desfire_create_cyclic_record_file_iso");
uint16_t *ids;
res = mifare_desfire_get_iso_file_ids (tag, &ids, &count);
cut_assert_success ("mifare_desfire_get_iso_file_ids");
cut_assert_equal_int (4, count, cut_message ("Invalid file count"));
cut_assert_equal_int (0x1234, ids[0], cut_message ("Wrong file ID"));
cut_assert_equal_int (0x2345, ids[1], cut_message ("Wrong file ID"));
cut_assert_equal_int (0x3456, ids[2], cut_message ("Wrong file ID"));
cut_assert_equal_int (0x4567, ids[3], cut_message ("Wrong file ID"));
free (ids);
free (aid);
}