2011-09-22 12:16:52 +02:00
/*
* This implementation was written based on information provided by the
* following documents :
*
* Mifare Std as NFC Forum Enabled ,
* Extensions for Mifare standard 1 k / 4 k as NFC Forum Enable Tag
* Application note
* Revision 1.1 — 21 August 2007
*
* NXP Type MF1K / 4 K Tag Operation , NXP Semiconductors [ ANNFC1K4K ]
* Application Note
* Revision 1.1 — 21 August 2007
* Document Identifier 130410
*/
2017-04-12 13:45:33 +02:00
# if defined(HAVE_CONFIG_H)
2017-06-29 12:25:53 +02:00
# include "config.h"
2017-04-12 13:45:33 +02:00
# endif
2011-09-22 12:16:52 +02:00
# include <err.h>
# include <errno.h>
# include <stdlib.h>
# include <string.h>
# include <strings.h>
# include <unistd.h>
# include <nfc/nfc.h>
# include <freefare.h>
# define MIN(a,b) ((a < b) ? a: b)
2012-03-15 02:48:43 +01:00
struct {
bool interactive ;
} read_options = {
. interactive = true
} ;
2012-05-18 18:18:45 +02:00
static void
2011-09-22 12:16:52 +02:00
usage ( char * progname )
{
2017-06-27 13:58:31 +02:00
fprintf ( stderr , " usage: %s -o FILE \n " , progname ) ;
fprintf ( stderr , " \n Options: \n " ) ;
fprintf ( stderr , " -y Do not ask for confirmation \n " ) ;
fprintf ( stderr , " -o Extract NDEF message if available in FILE \n " ) ;
2011-09-22 12:16:52 +02:00
}
int
main ( int argc , char * argv [ ] )
{
int error = 0 ;
2012-01-25 10:58:16 +01:00
nfc_device * device = NULL ;
2015-05-11 18:48:10 +02:00
FreefareTag * tags = NULL ;
2011-09-22 12:16:52 +02:00
Mad mad ;
int ch ;
char * ndef_output = NULL ;
2017-06-27 13:58:31 +02:00
while ( ( ch = getopt ( argc , argv , " hyo: " ) ) ! = - 1 ) {
2011-09-22 12:16:52 +02:00
switch ( ch ) {
case ' h ' :
usage ( argv [ 0 ] ) ;
2017-06-27 13:58:31 +02:00
exit ( EXIT_SUCCESS ) ;
2011-09-22 12:16:52 +02:00
break ;
2012-03-15 02:48:43 +01:00
case ' y ' :
read_options . interactive = false ;
break ;
case ' o ' :
2011-09-22 12:16:52 +02:00
ndef_output = optarg ;
break ;
case ' ? ' :
if ( optopt = = ' o ' )
2017-06-27 13:58:31 +02:00
fprintf ( stderr , " Option -%c requires an argument. \n " , optopt ) ;
/* FALLTHROUGH */
2011-09-22 12:16:52 +02:00
default :
2017-06-27 13:58:31 +02:00
usage ( argv [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
2011-09-22 12:16:52 +02:00
}
}
if ( ndef_output = = NULL ) {
2017-06-27 13:58:31 +02:00
usage ( argv [ 0 ] ) ;
exit ( EXIT_FAILURE ) ;
2011-09-22 12:16:52 +02:00
}
2017-06-27 13:58:31 +02:00
FILE * message_stream = NULL ;
FILE * ndef_stream = NULL ;
2011-09-22 12:16:52 +02:00
2017-06-27 13:58:31 +02:00
if ( ( strlen ( ndef_output ) = = 1 ) & & ( ndef_output [ 0 ] = = ' - ' ) ) {
2011-09-22 12:16:52 +02:00
message_stream = stderr ;
ndef_stream = stdout ;
} else {
message_stream = stdout ;
ndef_stream = fopen ( ndef_output , " wb " ) ;
if ( ! ndef_stream ) {
2017-06-27 13:58:31 +02:00
fprintf ( stderr , " Could not open file %s. \n " , ndef_output ) ;
exit ( EXIT_FAILURE ) ;
2011-09-22 12:16:52 +02:00
}
}
2012-01-25 10:58:16 +01:00
nfc_connstring devices [ 8 ] ;
2011-09-22 12:16:52 +02:00
size_t device_count ;
2012-12-23 22:30:10 +01:00
nfc_context * context ;
2017-06-27 13:58:31 +02:00
nfc_init ( & context ) ;
2013-03-30 18:07:34 +01:00
if ( context = = NULL )
errx ( EXIT_FAILURE , " Unable to init libnfc (malloc) " ) ;
2012-12-23 22:30:10 +01:00
2017-06-27 13:58:31 +02:00
device_count = nfc_list_devices ( context , devices , 8 ) ;
2012-01-25 10:58:16 +01:00
if ( device_count < = 0 )
2017-06-27 13:58:31 +02:00
errx ( EXIT_FAILURE , " No NFC device found. " ) ;
2011-09-22 12:16:52 +02:00
for ( size_t d = 0 ; d < device_count ; d + + ) {
2017-06-27 13:58:31 +02:00
device = nfc_open ( context , devices [ d ] ) ;
if ( ! device ) {
warnx ( " nfc_open() failed. " ) ;
error = EXIT_FAILURE ;
continue ;
}
tags = freefare_get_tags ( device ) ;
2011-09-22 12:16:52 +02:00
if ( ! tags ) {
2017-06-27 13:58:31 +02:00
nfc_close ( device ) ;
errx ( EXIT_FAILURE , " Error listing MIFARE classic tag. " ) ;
2011-09-22 12:16:52 +02:00
}
for ( int i = 0 ; ( ! error ) & & tags [ i ] ; i + + ) {
2017-06-27 13:58:31 +02:00
switch ( freefare_get_tag_type ( tags [ i ] ) ) {
2015-05-12 13:29:21 +02:00
case MIFARE_CLASSIC_1K :
case MIFARE_CLASSIC_4K :
2011-09-22 12:16:52 +02:00
break ;
default :
continue ;
}
2017-06-27 13:58:31 +02:00
char * tag_uid = freefare_get_tag_uid ( tags [ i ] ) ;
2011-09-22 12:16:52 +02:00
char buffer [ BUFSIZ ] ;
2017-06-27 13:58:31 +02:00
fprintf ( message_stream , " Found %s with UID %s. " , freefare_get_tag_friendly_name ( tags [ i ] ) , tag_uid ) ;
2012-03-15 02:48:43 +01:00
bool read_ndef = true ;
if ( read_options . interactive ) {
2017-06-27 13:58:31 +02:00
fprintf ( message_stream , " Read NDEF [yN] " ) ;
fgets ( buffer , BUFSIZ , stdin ) ;
2012-03-15 02:48:43 +01:00
read_ndef = ( ( buffer [ 0 ] = = ' y ' ) | | ( buffer [ 0 ] = = ' Y ' ) ) ;
} else {
2017-06-27 13:58:31 +02:00
fprintf ( message_stream , " \n " ) ;
2012-03-15 02:48:43 +01:00
}
2011-09-22 12:16:52 +02:00
if ( read_ndef ) {
// NFCForum card has a MAD, load it.
2017-06-27 13:58:31 +02:00
if ( 0 = = mifare_classic_connect ( tags [ i ] ) ) {
2011-09-22 12:16:52 +02:00
} else {
2017-06-27 13:58:31 +02:00
nfc_perror ( device , " mifare_classic_connect " ) ;
2011-09-22 12:16:52 +02:00
error = EXIT_FAILURE ;
goto error ;
}
2017-06-27 13:58:31 +02:00
if ( ( mad = mad_read ( tags [ i ] ) ) ) {
2011-09-22 12:16:52 +02:00
// Dump the NFCForum application using MAD information
uint8_t buffer [ 4096 ] ;
ssize_t len ;
2017-06-27 13:58:31 +02:00
if ( ( len = mifare_application_read ( tags [ i ] , mad , mad_nfcforum_aid , buffer , sizeof ( buffer ) , mifare_classic_nfcforum_public_key_a , MFC_KEY_A ) ) ! = - 1 ) {
2011-09-22 12:16:52 +02:00
uint8_t tlv_type ;
uint16_t tlv_data_len ;
2017-06-27 13:58:31 +02:00
uint8_t * tlv_data ;
uint8_t * pbuffer = buffer ;
2013-07-14 21:18:22 +02:00
decode_tlv :
2017-06-27 13:58:31 +02:00
tlv_data = tlv_decode ( pbuffer , & tlv_type , & tlv_data_len ) ;
2011-09-22 12:16:52 +02:00
switch ( tlv_type ) {
2017-06-27 13:58:31 +02:00
case 0x00 :
fprintf ( message_stream , " NFC Forum application contains a \" NULL TLV \" , Skipping... \n " ) ; // According to [ANNFC1K4K], we skip this Tag to read further TLV blocks.
pbuffer + = tlv_record_length ( pbuffer , NULL , NULL ) ;
if ( pbuffer > = buffer + sizeof ( buffer ) ) {
2011-09-22 12:16:52 +02:00
error = EXIT_FAILURE ;
goto error ;
2017-06-27 13:58:31 +02:00
}
goto decode_tlv ;
break ;
case 0x03 :
fprintf ( message_stream , " NFC Forum application contains a \" NDEF Message TLV \" . \n " ) ;
break ;
case 0xFD :
fprintf ( message_stream , " NFC Forum application contains a \" Proprietary TLV \" , Skipping... \n " ) ; // According to [ANNFC1K4K], we can skip this TLV to read further TLV blocks.
pbuffer + = tlv_record_length ( pbuffer , NULL , NULL ) ;
if ( pbuffer > = buffer + sizeof ( buffer ) ) {
2011-09-22 12:16:52 +02:00
error = EXIT_FAILURE ;
goto error ;
2017-06-27 13:58:31 +02:00
}
goto decode_tlv ;
break ;
case 0xFE :
fprintf ( stderr , " NFC Forum application contains a \" Terminator TLV \" , no available data. \n " ) ;
error = EXIT_FAILURE ;
goto error ;
break ;
default :
fprintf ( stderr , " NFC Forum application contains an invalid TLV. \n " ) ;
error = EXIT_FAILURE ;
goto error ;
break ;
2011-09-22 12:16:52 +02:00
}
2017-06-27 13:58:31 +02:00
if ( fwrite ( tlv_data , 1 , tlv_data_len , ndef_stream ) ! = tlv_data_len ) {
fprintf ( stderr , " Could not write to file. \n " ) ;
2011-09-22 12:16:52 +02:00
error = EXIT_FAILURE ;
goto error ;
}
2017-06-27 13:58:31 +02:00
free ( tlv_data ) ;
2011-09-22 12:16:52 +02:00
} else {
2017-06-27 13:58:31 +02:00
fprintf ( stderr , " No NFC Forum application. \n " ) ;
2011-09-22 12:16:52 +02:00
error = EXIT_FAILURE ;
goto error ;
}
} else {
2017-06-27 13:58:31 +02:00
fprintf ( stderr , " No MAD detected. \n " ) ;
2011-09-22 12:16:52 +02:00
error = EXIT_FAILURE ;
goto error ;
}
2017-06-27 13:58:31 +02:00
free ( mad ) ;
2011-09-22 12:16:52 +02:00
}
error :
2017-06-27 13:58:31 +02:00
free ( tag_uid ) ;
2011-09-22 12:16:52 +02:00
}
2017-06-27 13:58:31 +02:00
fclose ( ndef_stream ) ;
freefare_free_tags ( tags ) ;
nfc_close ( device ) ;
2011-09-22 12:16:52 +02:00
}
2015-05-12 13:19:00 +02:00
2017-06-27 13:58:31 +02:00
nfc_exit ( context ) ;
exit ( error ) ;
2011-09-22 12:16:52 +02:00
}