diff --git a/libfreefare/freefare.h b/libfreefare/freefare.h index 52c5c36..776519a 100644 --- a/libfreefare/freefare.h +++ b/libfreefare/freefare.h @@ -257,6 +257,14 @@ enum mifare_desfire_file_types { struct mifare_desfire_aid; typedef struct mifare_desfire_aid *MifareDESFireAID; +struct mifare_desfire_df { + uint32_t aid; + uint16_t fid; + uint8_t df_name[16]; + size_t df_name_len; +}; +typedef struct mifare_desfire_df MifareDESFireDF; + MifareDESFireAID mifare_desfire_aid_new (uint32_t aid); MifareDESFireAID mifare_desfire_aid_new_with_mad_aid (MadAid mad_aid, uint8_t n); uint32_t mifare_desfire_aid_get_aid (MifareDESFireAID aid); @@ -327,8 +335,14 @@ int mifare_desfire_get_key_version (MifareTag tag, uint8_t key_no, uint8_t *ve int mifare_desfire_create_application (MifareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no); int mifare_desfire_create_application_3k3des (MifareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no); int mifare_desfire_create_application_aes (MifareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no); + +int 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); +int 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); +int 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); + int mifare_desfire_delete_application (MifareTag tag, MifareDESFireAID aid); int mifare_desfire_get_application_ids (MifareTag tag, MifareDESFireAID *aids[], size_t *count); +int mifare_desfire_get_df_names (MifareTag tag, MifareDESFireDF *dfs[], size_t *count); void mifare_desfire_free_application_ids (MifareDESFireAID aids[]); int mifare_desfire_select_application (MifareTag tag, MifareDESFireAID aid); int mifare_desfire_format_picc (MifareTag tag); diff --git a/libfreefare/mifare_desfire.c b/libfreefare/mifare_desfire.c index e0329c9..10eac12 100644 --- a/libfreefare/mifare_desfire.c +++ b/libfreefare/mifare_desfire.c @@ -625,22 +625,28 @@ mifare_desfire_get_key_version (MifareTag tag, uint8_t key_no, uint8_t *version) int -create_application (MifareTag tag, MifareDESFireAID aid, uint8_t settings1, uint8_t settings2, uint16_t iso_file_id, char *iso_file_name) +create_application (MifareTag tag, MifareDESFireAID aid, uint8_t settings1, uint8_t settings2, int want_iso_application, int want_iso_file_identifiers, uint16_t iso_file_id, uint8_t *iso_file_name, size_t iso_file_name_len) { - (void) iso_file_id; - (void) iso_file_name; - ASSERT_ACTIVE (tag); ASSERT_MIFARE_DESFIRE (tag); BUFFER_INIT (cmd, 22); BUFFER_INIT (res, 1 + CMAC_LENGTH); + if (want_iso_file_identifiers) + settings2 |= 0x20; + BUFFER_APPEND (cmd, 0xCA); BUFFER_APPEND_LE (cmd, aid->data, sizeof (aid->data), sizeof (aid->data)); BUFFER_APPEND (cmd, settings1); BUFFER_APPEND (cmd, settings2); + if (want_iso_application) + BUFFER_APPEND_LE (cmd, iso_file_id, sizeof (iso_file_id), sizeof (iso_file_id)); + + if (iso_file_name_len) + BUFFER_APPEND_BYTES (cmd, iso_file_name, iso_file_name_len); + uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); @@ -654,19 +660,37 @@ create_application (MifareTag tag, MifareDESFireAID aid, uint8_t settings1, uint int mifare_desfire_create_application (MifareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no) { - return create_application (tag, aid, settings, key_no, 0, NULL); + return create_application (tag, aid, settings, key_no, 0, 0, 0, NULL, 0); +} + +int +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) +{ + return create_application (tag, aid, settings, key_no, 1, want_iso_file_identifiers, iso_file_id, iso_file_name, iso_file_name_len); } int mifare_desfire_create_application_3k3des (MifareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no) { - return create_application (tag, aid, settings, APPLICATION_CRYPTO_3K3DES | key_no, 0, NULL); + return create_application (tag, aid, settings, APPLICATION_CRYPTO_3K3DES | key_no, 0, 0, 0, NULL, 0); +} + +int +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) +{ + return create_application (tag, aid, settings, APPLICATION_CRYPTO_3K3DES | key_no, 1, want_iso_file_identifiers, iso_file_id, iso_file_name, iso_file_name_len); } int mifare_desfire_create_application_aes (MifareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no) { - return create_application (tag, aid, settings, APPLICATION_CRYPTO_AES | key_no, 0, NULL); + return create_application (tag, aid, settings, APPLICATION_CRYPTO_AES | key_no, 0, 0, 0, NULL, 0); +} + +int +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) +{ + return create_application (tag, aid, settings, APPLICATION_CRYPTO_AES | key_no, 1, want_iso_file_identifiers, iso_file_id, iso_file_name, iso_file_name_len); } int @@ -754,6 +778,43 @@ mifare_desfire_get_application_ids (MifareTag tag, MifareDESFireAID *aids[], siz return 0; } +int +mifare_desfire_get_df_names (MifareTag tag, MifareDESFireDF *dfs[], size_t *count) +{ + ASSERT_ACTIVE (tag); + ASSERT_MIFARE_DESFIRE (tag); + + *count = 0; + *dfs = NULL; + + BUFFER_INIT (cmd, 1); + BUFFER_INIT (res, 22 + CMAC_LENGTH); + + BUFFER_APPEND (cmd, 0x6D); + + uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); + + do { + DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + + if (__res_n > 1) { + MifareDESFireDF *new_dfs; + if ((new_dfs = realloc (*dfs, sizeof (*new_dfs) * (*count + 1)))) { + new_dfs[*count].aid = le24toh (res); + new_dfs[*count].fid = le16toh (*(uint16_t *)(res + 3)); + memcpy (new_dfs[*count].df_name, res + 5, __res_n - 6); + new_dfs[*count].df_name_len = __res_n - 6; + *dfs = new_dfs; + *count += 1; + } + } + + p[0] = 0XAF; + } while (res[__res_n-1] == 0xAF); + + return 0; +} + void mifare_desfire_free_application_ids (MifareDESFireAID aids[]) { diff --git a/test/Makefile.am b/test/Makefile.am index 6d03098..a56a171 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -66,6 +66,7 @@ test_mifare_desfire_ev1_la_SOURCES = test_mifare_desfire_ev1.c \ test_mifare_desfire_ev1_3des.c \ test_mifare_desfire_ev1_3k3des.c \ test_mifare_desfire_ev1_aes.c \ + test_mifare_desfire_ev1_iso.c \ mifare_desfire_ev1_fixture.c \ mifare_desfire_ev1_fixture.h test_mifare_desfire_ev1_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la \ @@ -88,4 +89,7 @@ echo-cutter: EXTRA_DIST = run-test.sh CLEANFILES = *.gcno +update: + $(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES) + endif diff --git a/test/test_mifare_desfire_ev1_iso.c b/test/test_mifare_desfire_ev1_iso.c new file mode 100644 index 0000000..51e22f4 --- /dev/null +++ b/test/test_mifare_desfire_ev1_iso.c @@ -0,0 +1,99 @@ +/*- + * Copyright (C) 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 + * 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 "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_iso (void) +{ + int res; + MifareDESFireKey key; + + mifare_desfire_auto_authenticate (tag, 0); + + res = mifare_desfire_format_picc (tag); + cut_assert_equal_int (res, 0, cut_message ("mifare_desfire_format_picc()")); + + MifareDESFireDF *dfs; + size_t count; + res = mifare_desfire_get_df_names (tag, &dfs, &count); + cut_assert_equal_int (res, 0, cut_message ("mifare_desfire_get_df_names()")); + cut_assert_equal_int (count, 0, cut_message ("Wrong DF count")); + cut_assert_null (dfs, cut_message ("DF should be NULL")); + + MifareDESFireAID aid = mifare_desfire_aid_new (0x111110); + res = mifare_desfire_create_application_iso (tag, aid, 0xFF, 1, 0, 0x111F, NULL, 0); + cut_assert_success ("mifare_desfire_create_application_iso"); + free (aid); + + uint8_t app2[] = "App2"; + aid = mifare_desfire_aid_new (0x222220); + res = mifare_desfire_create_application_iso (tag, aid, 0xFF, 1, 0, 0x222F, app2, sizeof (app2)); + cut_assert_success ("mifare_desfire_create_application_iso"); + free (aid); + + uint8_t app3[] = "App3"; + aid = mifare_desfire_aid_new (0x333330); + res = mifare_desfire_create_application_iso (tag, aid, 0xFF, 1, 0, 0x333F, app3, sizeof (app3)); + cut_assert_success ("mifare_desfire_create_application_iso"); + free (aid); + + aid = mifare_desfire_aid_new (0x444440); + res = mifare_desfire_create_application_iso (tag, aid, 0xFF, 1, 0, 0x111F, NULL, 0); + cut_assert_equal_int (-1, res, cut_message ("Should fail")); + cut_assert_equal_int (DUPLICATE_ERROR, mifare_desfire_last_picc_error (tag), cut_message ("Should be a duplicate error")); + + res = mifare_desfire_create_application_iso (tag, aid, 0xFF, 1, 0, 0x444F, app2, sizeof (app2)); + cut_assert_equal_int (-1, res, cut_message ("Should fail")); + cut_assert_equal_int (DUPLICATE_ERROR, mifare_desfire_last_picc_error (tag), cut_message ("Should be a duplicate error")); + free (aid); + + + res = mifare_desfire_get_df_names (tag, &dfs, &count); + cut_assert_equal_int (0, res, cut_message ("mifare_desfire_get_df_names()")); + cut_assert_equal_int (3, count, cut_message ("Wrong DF count")); + cut_assert_not_null (dfs, cut_message ("DF should not be NULL")); + + cut_assert_equal_int (0x111110, dfs[0].aid, cut_message ("Wrong value")); + cut_assert_equal_int (0x111F, dfs[0].fid, cut_message ("Wrong value")); + cut_assert_equal_int (0, dfs[0].df_name_len, cut_message ("Wrong value")); + + cut_assert_equal_int (0x222220, dfs[1].aid, cut_message ("Wrong value")); + cut_assert_equal_int (0x222F, dfs[1].fid, cut_message ("Wrong value")); + cut_assert_equal_int (sizeof (app2), dfs[1].df_name_len, cut_message ("Wrong value")); + cut_assert_equal_memory (app2, sizeof (app2), dfs[1].df_name, dfs[1].df_name_len, cut_message ("Wrong value")); + + cut_assert_equal_int (0x333330, dfs[2].aid, cut_message ("Wrong value")); + cut_assert_equal_int (0x333F, dfs[2].fid, cut_message ("Wrong value")); + 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); +}