diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 68fab6b..91a29e0 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,11 +1,13 @@
# $Id$
set(EXAMPLES-SOURCES
mifare-classic-format
+ mifare-classic-read-ndef
mifare-classic-write-ndef
mifare-desfire-access
mifare-desfire-create-ndef
mifare-desfire-format
mifare-desfire-info
+ mifare-desfire-read-ndef
mifare-desfire-write-ndef
mifare-desfire-ev1-configure-ats
mifare-desfire-ev1-configure-default-key
diff --git a/examples/Makefile.am b/examples/Makefile.am
index d8cc667..67825a0 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -13,6 +13,7 @@ bin_PROGRAMS = mifare-classic-format \
mifare-desfire-ev1-configure-random-uid \
mifare-desfire-format \
mifare-desfire-info \
+ mifare-desfire-read-ndef \
mifare-desfire-write-ndef
mifare_classic_format_SOURCES = mifare-classic-format.c
@@ -45,6 +46,9 @@ mifare_desfire_format_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la
mifare_desfire_info_SOURCES = mifare-desfire-info.c
mifare_desfire_info_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la -lm
+mifare_desfire_read_ndef_SOURCES = mifare-desfire-read-ndef.c
+mifare_desfire_read_ndef_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la
+
mifare_desfire_write_ndef_SOURCES = mifare-desfire-write-ndef.c
mifare_desfire_write_ndef_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la
diff --git a/examples/mifare-classic-read-ndef.c b/examples/mifare-classic-read-ndef.c
index 9131de6..50210e1 100644
--- a/examples/mifare-classic-read-ndef.c
+++ b/examples/mifare-classic-read-ndef.c
@@ -47,11 +47,18 @@
#define MIN(a,b) ((a < b) ? a: b)
+struct {
+ bool interactive;
+} read_options = {
+ .interactive = true
+};
+
void
usage(char *progname)
{
fprintf (stderr, "usage: %s -o FILE\n", progname);
fprintf (stderr, "\nOptions:\n");
+ fprintf (stderr, " -y Do not ask for confirmation\n");
fprintf (stderr, " -o Extract NDEF message if available in FILE\n");
}
@@ -65,13 +72,16 @@ main(int argc, char *argv[])
int ch;
char *ndef_output = NULL;
- while ((ch = getopt (argc, argv, "ho:")) != -1) {
+ while ((ch = getopt (argc, argv, "hyo:")) != -1) {
switch (ch) {
case 'h':
usage(argv[0]);
exit (EXIT_SUCCESS);
break;
- case 'o':
+ case 'y':
+ read_options.interactive = false;
+ break;
+ case 'o':
ndef_output = optarg;
break;
case '?':
@@ -137,9 +147,16 @@ main(int argc, char *argv[])
char *tag_uid = freefare_get_tag_uid (tags[i]);
char buffer[BUFSIZ];
- fprintf (message_stream, "Found %s with UID %s. Read NDEF [yN] ", freefare_get_tag_friendly_name (tags[i]), tag_uid);
- fgets (buffer, BUFSIZ, stdin);
- bool read_ndef = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
+ fprintf (message_stream, "Found %s with UID %s. ", freefare_get_tag_friendly_name (tags[i]), tag_uid);
+
+ bool read_ndef = true;
+ if (read_options.interactive) {
+ printf ("Read NDEF [yN] ");
+ fgets (buffer, BUFSIZ, stdin);
+ read_ndef = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
+ } else {
+ printf ("\n");
+ }
if (read_ndef) {
// NFCForum card has a MAD, load it.
diff --git a/examples/mifare-desfire-read-ndef.c b/examples/mifare-desfire-read-ndef.c
new file mode 100644
index 0000000..7f1c3c1
--- /dev/null
+++ b/examples/mifare-desfire-read-ndef.c
@@ -0,0 +1,245 @@
+/*-
+ * Copyright (C) 2010, Audrey Diacre.
+ *
+ * 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 "config.h"
+
+#include
+#include
+#include
+#include
+
+#include
+
+/*
+ * This example was written based on information provided by the
+ * following documents:
+ *
+ * Mifare DESFire as Type 4 Tag
+ * NFC Forum Type 4 Tag Extensions for Mifare DESFire
+ * Rev. 1.1 - 21 August 2007
+ *
+ */
+
+// Note that it is using specific Desfire commands, not ISO7816 NDEF Tag Type4 commands
+
+uint8_t key_data_app[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+uint8_t *cc_data;
+uint8_t *ndef_msg;
+uint16_t ndef_msg_len;
+
+struct {
+ bool interactive;
+} read_options = {
+ .interactive = true
+};
+
+void
+usage(char *progname)
+{
+ fprintf (stderr, "usage: %s [-y] -o FILE [-k 11223344AABBCCDD]\n", progname);
+ fprintf (stderr, "\nOptions:\n");
+ fprintf (stderr, " -y Do not ask for confirmation\n");
+ fprintf (stderr, " -o Extract NDEF message if available in FILE\n");
+ fprintf (stderr, " -k Provide another NDEF Tag Application key than the default one\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ int error = EXIT_SUCCESS;
+ nfc_device *device = NULL;
+ MifareTag *tags = NULL;
+
+ char *ndef_output = NULL;
+ while ((ch = getopt (argc, argv, "hyo:k:")) != -1) {
+ switch (ch) {
+ case 'h':
+ usage(argv[0]);
+ exit (EXIT_SUCCESS);
+ break;
+ case 'y':
+ read_options.interactive = false;
+ break;
+ case 'o':
+ ndef_output = optarg;
+ break;
+ case 'k':
+ if (strlen(optarg) != 16) {
+ usage(argv[0]);
+ exit (EXIT_FAILURE);
+ }
+ uint64_t n = strtoull(optarg, NULL, 16);
+ int i;
+ for (i=7; i>=0; i--) {
+ key_data_app[i] = (uint8_t) n;
+ n >>= 8;
+ }
+ break;
+ default:
+ usage(argv[0]);
+ exit (EXIT_FAILURE);
+ }
+ }
+ // Remaining args, if any, are in argv[optind .. (argc-1)]
+
+ printf ("NOTE: This application reads a NDEF payload from a Mifare DESFire formatted as NFC Forum Type 4 Tag.\n");
+
+ if (ndef_output == NULL) {
+ usage (argv[0]);
+ exit (EXIT_FAILURE);
+ }
+ FILE* message_stream = NULL;
+ FILE* ndef_stream = NULL;
+
+ if ((strlen (ndef_output) == 1) && (ndef_output[0] == '-')) {
+ message_stream = stderr;
+ ndef_stream = stdout;
+ } else {
+ message_stream = stdout;
+ ndef_stream = fopen(ndef_output, "wb");
+ if (!ndef_stream) {
+ fprintf (stderr, "Could not open file %s.\n", ndef_output);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ nfc_connstring devices[8];
+ size_t device_count;
+
+ nfc_init(NULL);
+
+ device_count = nfc_list_devices (NULL, devices, 8);
+ if (device_count <= 0)
+ errx (EXIT_FAILURE, "No NFC device found.");
+
+ for (size_t d = 0; d < device_count; d++) {
+ device = nfc_open (NULL, devices[d]);
+
+ if (!device) {
+ warnx ("nfc_open() failed.");
+ error = EXIT_FAILURE;
+ continue;
+ }
+
+ tags = freefare_get_tags (device);
+ if (!tags) {
+ nfc_close (device);
+ errx (EXIT_FAILURE, "Error listing tags.");
+ }
+
+ for (int i = 0; (!error) && tags[i]; i++) {
+ if (DESFIRE != freefare_get_tag_type (tags[i]))
+ continue;
+
+ char *tag_uid = freefare_get_tag_uid (tags[i]);
+ char buffer[BUFSIZ];
+
+ fprintf (message_stream, "Found %s with UID %s. ", freefare_get_tag_friendly_name (tags[i]), tag_uid);
+
+ bool read_ndef = true;
+ if (read_options.interactive) {
+ printf ("Read NDEF [yN] ");
+ fgets (buffer, BUFSIZ, stdin);
+ read_ndef = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
+ } else {
+ printf ("\n");
+ }
+
+ if (read_ndef) {
+ int res;
+
+ res = mifare_desfire_connect (tags[i]);
+ if (res < 0) {
+ warnx ("Can't connect to Mifare DESFire target.");
+ error = EXIT_FAILURE;
+ break;
+ }
+
+ MifareDESFireKey key_app;
+ key_app = mifare_desfire_des_key_new_with_version (key_data_app);
+
+ // Mifare DESFire SelectApplication (Select application)
+ MifareDESFireAID aid = mifare_desfire_aid_new(0xEEEE10);
+ res = mifare_desfire_select_application(tags[i], aid);
+ if (res < 0)
+ errx (EXIT_FAILURE, "Application selection failed. Try mifare-desfire-create-ndef before running %s.", argv[0]);
+ free (aid);
+
+ // Authentication with NDEF Tag Application master key (Authentication with key 0)
+ res = mifare_desfire_authenticate (tags[i], 0, key_app);
+ if (res < 0)
+ errx (EXIT_FAILURE, "Authentication with NDEF Tag Application master key failed");
+
+ // Read Capability Container file E103
+ uint8_t lendata[2];
+ res = mifare_desfire_read_data (tags[i], 0x03, 0, 2, lendata);
+ if (res < 0)
+ errx (EXIT_FAILURE, "Read CC len failed");
+ uint16_t cclen = (((uint16_t) lendata[0]) << 8) + ((uint16_t) lendata[1]);
+ if (cclen < 15)
+ errx (EXIT_FAILURE, "CC too short IMHO");
+ if (!(cc_data = malloc(cclen)))
+ errx (EXIT_FAILURE, "malloc");
+ res = mifare_desfire_read_data (tags[i], 0x03, 0, cclen, cc_data);
+ if (res < 0)
+ errx (EXIT_FAILURE, "Read CC data failed");
+ // Search NDEF File Control TLV
+ uint8_t off = 7;
+ while (((off+7) < cclen) && (cc_data[off] != 0x04)) {
+ // Skip TLV
+ off += cc_data[off+1] + 2;
+ }
+ if (off+7 >= cclen)
+ errx (EXIT_FAILURE, "CC does not contain expected NDEF File Control TLV");
+ if (cc_data[off+2] != 0xE1)
+ errx (EXIT_FAILURE, "Unknown NDEF File reference in CC");
+ uint8_t file_no = cc_data[off+3];
+ uint16_t ndefmaxlen = (((uint16_t) cc_data[off+4]) << 8) + ((uint16_t) cc_data[off+5]);
+ fprintf (message_stream, "Max NDEF size: %i bytes\n", ndefmaxlen);
+ if (!(ndef_msg = malloc(ndefmaxlen)))
+ errx (EXIT_FAILURE, "malloc");
+
+ res = mifare_desfire_read_data (tags[i], file_no, 0, 2, lendata);
+ if (res < 0)
+ errx (EXIT_FAILURE, "Read NDEF len failed");
+ ndef_msg_len = (((uint16_t) lendata[0]) << 8) + ((uint16_t) lendata[1]);
+ fprintf (message_stream, "NDEF size: %i bytes\n", ndef_msg_len);
+ if (ndef_msg_len + 2 > ndefmaxlen)
+ errx (EXIT_FAILURE, "Declared NDEF size larger than max NDEF size");
+ res = mifare_desfire_read_data (tags[i], file_no, 2, ndef_msg_len, ndef_msg);
+ if (res < 0)
+ errx (EXIT_FAILURE, "Read data failed");
+ if (fwrite (ndef_msg, 1, ndef_msg_len, ndef_stream) != ndef_msg_len)
+ errx (EXIT_FAILURE, "Write to file failed");
+ free (cc_data);
+ free (ndef_msg);
+ mifare_desfire_key_free (key_app);
+
+ mifare_desfire_disconnect (tags[i]);
+ }
+ free (tag_uid);
+ }
+ freefare_free_tags (tags);
+ nfc_close (device);
+ }
+ nfc_exit(NULL);
+ exit (error);
+}
diff --git a/examples/mifare-desfire-write-ndef.c b/examples/mifare-desfire-write-ndef.c
index d57f3b1..d468205 100644
--- a/examples/mifare-desfire-write-ndef.c
+++ b/examples/mifare-desfire-write-ndef.c
@@ -48,6 +48,7 @@ const uint8_t ndef_default_msg[33] = {
0x67
};
+uint8_t *cc_data;
uint8_t *ndef_msg;
size_t ndef_msg_len;
@@ -216,20 +217,43 @@ main(int argc, char *argv[])
if (res < 0)
errx (EXIT_FAILURE, "Authentication with NDEF Tag Application master key failed");
-// TODO: read and check Capability Container
-// Steps not implemented at this stage:
-// Read and parse CC (E103)
-// - Read NDEF file pointer (can be != E104)
- uint8_t file_no = 0x04;
-// - Check available space for storing NDEF
-// ndef_msg_len + 2 <= max_len ?
-// - Check is writing is allowed and propose to overrule it if needed
+ // Read Capability Container file E103
+ uint8_t lendata[2];
+ res = mifare_desfire_read_data (tags[i], 0x03, 0, 2, lendata);
+ if (res < 0)
+ errx (EXIT_FAILURE, "Read CC len failed");
+ uint16_t cclen = (((uint16_t) lendata[0]) << 8) + ((uint16_t) lendata[1]);
+ if (cclen < 15)
+ errx (EXIT_FAILURE, "CC too short IMHO");
+ if (!(cc_data = malloc(cclen)))
+ errx (EXIT_FAILURE, "malloc");
+ res = mifare_desfire_read_data (tags[i], 0x03, 0, cclen, cc_data);
+ if (res < 0)
+ errx (EXIT_FAILURE, "Read CC data failed");
+ // Search NDEF File Control TLV
+ uint8_t off = 7;
+ while (((off+7) < cclen) && (cc_data[off] != 0x04)) {
+ // Skip TLV
+ off += cc_data[off+1] + 2;
+ }
+ if (off+7 >= cclen)
+ errx (EXIT_FAILURE, "CC does not contain expected NDEF File Control TLV");
+ if (cc_data[off+2] != 0xE1)
+ errx (EXIT_FAILURE, "Unknown NDEF File reference in CC");
+ uint8_t file_no = cc_data[off+3];
+ uint16_t ndefmaxlen = (((uint16_t) cc_data[off+4]) << 8) + ((uint16_t) cc_data[off+5]);
+ fprintf (stdout, "Max NDEF size: %i bytes\n", ndefmaxlen);
+ if (!(ndef_msg = malloc(ndefmaxlen)))
+ errx (EXIT_FAILURE, "malloc");
+ if (ndef_msg_len > ndefmaxlen)
+ errx (EXIT_FAILURE, "Supplied NDEF larger than max NDEF size");
//Mifare DESFire WriteData to write the content of the NDEF File with NLEN equal to NDEF Message length and NDEF Message
res = mifare_desfire_write_data(tags[i], file_no, 0, ndef_msg_len, (uint8_t *) ndef_msg);
if (res < 0)
errx (EXIT_FAILURE, " Write data failed");
+ free(cc_data);
mifare_desfire_key_free (key_app);
mifare_desfire_disconnect (tags[i]);