diff --git a/NEWS b/NEWS index a2b7980..481d7fa 100644 --- a/NEWS +++ b/NEWS @@ -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] diff --git a/libfreefare/freefare.h b/libfreefare/freefare.h index 776519a..33548d4 100644 --- a/libfreefare/freefare.h +++ b/libfreefare/freefare.h @@ -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); diff --git a/libfreefare/mifare_desfire.3 b/libfreefare/mifare_desfire.3 index 270a23e..33ff039 100644 --- a/libfreefare/mifare_desfire.3 +++ b/libfreefare/mifare_desfire.3 @@ -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 diff --git a/libfreefare/mifare_desfire.c b/libfreefare/mifare_desfire.c index 10eac12..a28f5b4 100644 --- a/libfreefare/mifare_desfire.c +++ b/libfreefare/mifare_desfire.c @@ -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 diff --git a/test/test_mifare_desfire_ev1_iso.c b/test/test_mifare_desfire_ev1_iso.c index 51e22f4..14b7ce9 100644 --- a/test/test_mifare_desfire_ev1_iso.c +++ b/test/test_mifare_desfire_ev1_iso.c @@ -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); + }