From 76d325f47b483cb3d4d8d5a9a7569e409485a0d7 Mon Sep 17 00:00:00 2001 From: Romuald Conty Date: Thu, 22 Sep 2011 10:16:52 +0000 Subject: [PATCH] Add a new example to extract NDEF Message from a "MIFARE Classic as NFC Forum enable tag". --- examples/Makefile.am | 4 + examples/mifare-classic-read-ndef.c | 213 ++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 examples/mifare-classic-read-ndef.c diff --git a/examples/Makefile.am b/examples/Makefile.am index c92abed..57c96ce 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -5,6 +5,7 @@ AM_LDFLAGS = @LIBNFC_LIBS@ bin_PROGRAMS = mifare-classic-format \ mifare-classic-write-ndef \ + mifare-classic-read-ndef \ mifare-desfire-access \ mifare-desfire-ev1-configure-ats \ mifare-desfire-ev1-configure-default-key \ @@ -16,6 +17,9 @@ bin_PROGRAMS = mifare-classic-format \ mifare_classic_format_SOURCES = mifare-classic-format.c mifare_classic_format_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la +mifare_classic_read_ndef_SOURCES = mifare-classic-read-ndef.c +mifare_classic_read_ndef_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la + mifare_classic_write_ndef_SOURCES = mifare-classic-write-ndef.c mifare_classic_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 new file mode 100644 index 0000000..1e595d7 --- /dev/null +++ b/examples/mifare-classic-read-ndef.c @@ -0,0 +1,213 @@ +/*- + * Copyright (C) 2011, Romain Tartiere, Romuald Conty. + * + * 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: mifare-classic-write-ndef.c 581 2010-09-07 14:29:11Z rtartiere@il4p.fr $ + */ + +/* + * This implementation was written based on information provided by the + * following documents: + * + * Mifare Std as NFC Forum Enabled, + * Extensions for Mifare standard 1k/4k as NFC Forum Enable Tag + * Application note + * Revision 1.1 — 21 August 2007 + * + * NXP Type MF1K/4K Tag Operation, NXP Semiconductors [ANNFC1K4K] + * Application Note + * Revision 1.1 — 21 August 2007 + * Document Identifier 130410 + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define MIN(a,b) ((a < b) ? a: b) + +void +usage(char *progname) +{ + fprintf (stderr, "usage: %s -o FILE\n", progname); + fprintf (stderr, "\nOptions:\n"); + fprintf (stderr, " -o Extract NDEF message if available in FILE\n"); +} + +int +main(int argc, char *argv[]) +{ + int error = 0; + nfc_device_t *device = NULL; + MifareTag *tags = NULL; + Mad mad; + + int ch; + char *ndef_output = NULL; + while ((ch = getopt (argc, argv, "ho:")) != -1) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (EXIT_SUCCESS); + break; + case 'o': + ndef_output = optarg; + break; + case '?': + if (optopt == 'o') + fprintf (stderr, "Option -%c requires an argument.\n", optopt); + default: + usage (argv[0]); + exit (EXIT_FAILURE); + } + } + + 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_device_desc_t devices[8]; + size_t device_count; + + nfc_list_devices (devices, 8, &device_count); + if (!device_count) + errx (EXIT_FAILURE, "No NFC device found."); + + for (size_t d = 0; d < device_count; d++) { + device = nfc_connect (&(devices[d])); + if (!device) { + warnx ("nfc_connect() failed."); + error = EXIT_FAILURE; + continue; + } + + tags = freefare_get_tags (device); + if (!tags) { + nfc_disconnect (device); + errx (EXIT_FAILURE, "Error listing MIFARE classic tag."); + } + + for (int i = 0; (!error) && tags[i]; i++) { + switch (freefare_get_tag_type (tags[i])) { + case CLASSIC_1K: + case CLASSIC_4K: + break; + default: + continue; + } + + 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')); + + if (read_ndef) { + // NFCForum card has a MAD, load it. + if (0 == mifare_classic_connect (tags[i])) { + } else { + nfc_perror (device, "mifare_classic_connect"); + error = EXIT_FAILURE; + goto error; + } + + if ((mad = mad_read (tags[i]))) { + // Dump the NFCForum application using MAD information + uint8_t buffer[4096]; + ssize_t len; + if ((len = mifare_application_read (tags[i], mad, mad_nfcforum_aid, buffer, sizeof(buffer), mifare_classic_nfcforum_public_key_a, MFC_KEY_A)) != -1) { + uint8_t tlv_type; + uint16_t tlv_data_len; + + uint8_t * tlv_data = tlv_decode (buffer, &tlv_type, &tlv_data_len); + switch (tlv_type) { + case 0x00: + fprintf (stderr, "NFCForum application contains a \"NULL TLV\".\n"); // FIXME: According to [ANNFC1K4K], we should skip this TLV to read further TLV blocks. + error = EXIT_FAILURE; + goto error; + break; + case 0x03: + fprintf (message_stream, "NFCForum application contains a \"NDEF Message TLV\".\n"); + break; + case 0xFD: + fprintf (stderr, "NFCForum application contains a \"Proprietary TLV\".\n"); // FIXME: According to [ANNFC1K4K], we should skip this TLV to read further TLV blocks. + error = EXIT_FAILURE; + goto error; + break; + case 0xFE: + fprintf (stderr, "NFCForum application contains a \"Terminator TLV\", no available data.\n"); + error = EXIT_FAILURE; + goto error; + break; + default: + fprintf (stderr, "NFCForum application contains an invalid TLV.\n"); + error = EXIT_FAILURE; + goto error; + break; + } + if (fwrite (tlv_data, 1, tlv_data_len, ndef_stream) != tlv_data_len) { + fprintf (stderr, "Could not write to file.\n"); + error = EXIT_FAILURE; + goto error; + } + free (tlv_data); + } else { + fprintf (stderr, "No NFC Forum application.\n"); + error = EXIT_FAILURE; + goto error; + } + } else { + fprintf (stderr, "No MAD detected.\n"); + error = EXIT_FAILURE; + goto error; + } + free (mad); + } + +error: + free (tag_uid); + } + + freefare_free_tags (tags); + nfc_disconnect (device); + } + + exit (error); +}