diff --git a/configure.ac b/configure.ac index 9c2eadc..3812a36 100644 --- a/configure.ac +++ b/configure.ac @@ -71,6 +71,8 @@ if test x$ac_cv_with_cutter = xyes -a x$ac_cv_use_cutter = xno; then fi AM_CONDITIONAL([WITH_CUTTER], [test "$ac_cv_use_cutter" != "no"]) +PKG_CHECK_MODULES(PCSC, libpcsclite) + m4_ifdef([AC_CHECK_COVERAGE], [AC_CHECK_COVERAGE]) if test x$cutter_enable_coverage = xyes; then diff --git a/examples/Makefile.am b/examples/Makefile.am index 565171e..7ae574e 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,7 +1,7 @@ # $Id$ -AM_CFLAGS = -I. -I$(top_srcdir)/libfreefare @LIBNFC_CFLAGS@ -AM_LDFLAGS = @LIBNFC_LIBS@ +AM_CFLAGS = -I. -I$(top_srcdir)/libfreefare @LIBNFC_CFLAGS@ @PCSC_CFLAGS@ +AM_LDFLAGS = @LIBNFC_LIBS@ @PCSC_LIBS@ bin_PROGRAMS = mifare-classic-format \ mifare-classic-write-ndef \ @@ -13,9 +13,11 @@ bin_PROGRAMS = mifare-classic-format \ mifare-desfire-ev1-configure-random-uid \ mifare-desfire-format \ mifare-desfire-info \ + mifare-desfire-info-pcsc \ mifare-desfire-read-ndef \ mifare-desfire-write-ndef \ - mifare-ultralight-info + mifare-ultralight-info \ + mifare-ultralight-info-pcsc mifare_classic_format_SOURCES = mifare-classic-format.c mifare_classic_format_LDADD = $(top_builddir)/libfreefare/libfreefare.la @@ -47,6 +49,9 @@ mifare_desfire_format_LDADD = $(top_builddir)/libfreefare/libfreefare.la mifare_desfire_info_SOURCES = mifare-desfire-info.c mifare_desfire_info_LDADD = $(top_builddir)/libfreefare/libfreefare.la -lm +mifare_desfire_info_pcsc_SOURCES = mifare-desfire-info-pcsc.c +mifare_desfire_info_pcsc_LDADD = $(top_builddir)/libfreefare/libfreefare.la -lm + mifare_desfire_read_ndef_SOURCES = mifare-desfire-read-ndef.c mifare_desfire_read_ndef_LDADD = $(top_builddir)/libfreefare/libfreefare.la @@ -56,4 +61,7 @@ mifare_desfire_write_ndef_LDADD = $(top_builddir)/libfreefare/libfreefare.la mifare_ultralight_info_SOURCES = mifare-ultralight-info.c mifare_ultralight_info_LDADD = $(top_builddir)/libfreefare/libfreefare.la +mifare_ultralight_info_pcsc_SOURCES = mifare-ultralight-info-pcsc.c +mifare_ultralight_info_pcsc_LDADD = $(top_builddir)/libfreefare/libfreefare.la + CLEANFILES= *.gcno diff --git a/examples/mifare-desfire-info-pcsc b/examples/mifare-desfire-info-pcsc new file mode 100755 index 0000000..42cad65 --- /dev/null +++ b/examples/mifare-desfire-info-pcsc @@ -0,0 +1,228 @@ +#! /bin/sh + +# mifare-desfire-info-pcsc - temporary wrapper script for .libs/mifare-desfire-info-pcsc +# Generated by libtool (GNU libtool) 2.4.2 +# +# The mifare-desfire-info-pcsc program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command="(cd /home/simon/Dropbox/Uni/Semester_5/PASST/RainerSCT/libfreefare-pcsc/libfreefare/examples; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; { test -z \"\${LD_LIBRARY_PATH+set}\" || unset LD_LIBRARY_PATH || { LD_LIBRARY_PATH=; export LD_LIBRARY_PATH; }; }; PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/bin/vendor_perl:/usr/bin/core_perl; export PATH; gcc -I. -I../libfreefare -pthread -I/home/simon/Dropbox/Uni/Semester_5/PASST/RainerSCT/build/include -I/usr/include/libusb-1.0 -I/usr/include/PCSC -g -O2 -std=c99 -o \$progdir/\$file mifare-desfire-info-pcsc.o -L/home/simon/Dropbox/Uni/Semester_5/PASST/RainerSCT/build/lib ../libfreefare/.libs/libfreefare.so /home/simon/Dropbox/Uni/Semester_5/PASST/RainerSCT/build/lib/libnfc.so -lusb -lpcsclite -lm -lcrypto -pthread -Wl,-rpath -Wl,/home/simon/Dropbox/Uni/Semester_5/PASST/RainerSCT/libfreefare-pcsc/libfreefare/libfreefare/.libs -Wl,-rpath -Wl,/home/simon/Dropbox/Uni/Semester_5/PASST/RainerSCT/build/lib -Wl,-rpath -Wl,/home/simon/Dropbox/Uni/Semester_5/PASST/RainerSCT/build/lib)" + +# This environment variable determines our operation mode. +if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then + # install mode needs the following variables: + generated_by_libtool_version='2.4.2' + notinst_deplibs=' ../libfreefare/libfreefare.la' +else + # When we are sourced in execute mode, $file and $ECHO are already set. + if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then + file="$0" + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + ECHO="printf %s\\n" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string --lt- +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's ../libtool value, followed by no. +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=$0 + shift + for lt_opt + do + case "$lt_opt" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%/[^/]*$%%'` + test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=. + lt_dump_F=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%^.*/%%'` + cat "$lt_dump_D/$lt_dump_F" + exit 0 + ;; + --lt-*) + $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n "$lt_option_debug"; then + echo "mifare-desfire-info-pcsc:mifare-desfire-info-pcsc:${LINENO}: libtool wrapper (GNU libtool) 2.4.2" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + $ECHO "mifare-desfire-info-pcsc:mifare-desfire-info-pcsc:${LINENO}: newargv[$lt_dump_args_N]: $lt_arg" + lt_dump_args_N=`expr $lt_dump_args_N + 1` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ + + if test -n "$lt_option_debug"; then + $ECHO "mifare-desfire-info-pcsc:mifare-desfire-info-pcsc:${LINENO}: newargv[0]: $progdir/$program" 1>&2 + func_lt_dump_args ${1+"$@"} 1>&2 + fi + exec "$progdir/$program" ${1+"$@"} + + $ECHO "$0: cannot exec $program $*" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from $@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case " $* " in + *\ --lt-*) + for lt_wr_arg + do + case $lt_wr_arg in + --lt-*) ;; + *) set x "$@" "$lt_wr_arg"; shift;; + esac + shift + done ;; + esac + func_exec_program_core ${1+"$@"} +} + + # Parse options + func_parse_lt_options "$0" ${1+"$@"} + + # Find the directory that this script lives in. + thisdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'` + test "x$thisdir" = "x$file" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=`ls -ld "$file" | /usr/bin/sed -n 's/.*-> //p'` + while test -n "$file"; do + destdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'` + + # If there was a directory component, then change thisdir. + if test "x$destdir" != "x$file"; then + case "$destdir" in + [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;; + *) thisdir="$thisdir/$destdir" ;; + esac + fi + + file=`$ECHO "$file" | /usr/bin/sed 's%^.*/%%'` + file=`ls -ld "$thisdir/$file" | /usr/bin/sed -n 's/.*-> //p'` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no + if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then + # special case for '.' + if test "$thisdir" = "."; then + thisdir=`pwd` + fi + # remove .libs from thisdir + case "$thisdir" in + *[\\/].libs ) thisdir=`$ECHO "$thisdir" | /usr/bin/sed 's%[\\/][^\\/]*$%%'` ;; + .libs ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=`cd "$thisdir" && pwd` + test -n "$absdir" && thisdir="$absdir" + + program=lt-'mifare-desfire-info-pcsc' + progdir="$thisdir/.libs" + + if test ! -f "$progdir/$program" || + { file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /usr/bin/sed 1q`; \ + test "X$file" != "X$progdir/$program"; }; then + + file="$$-$program" + + if test ! -d "$progdir"; then + mkdir "$progdir" + else + rm -f "$progdir/$file" + fi + + # relink executable if necessary + if test -n "$relink_command"; then + if relink_command_output=`eval $relink_command 2>&1`; then : + else + printf %s\n "$relink_command_output" >&2 + rm -f "$progdir/$file" + exit 1 + fi + fi + + mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null || + { rm -f "$progdir/$program"; + mv -f "$progdir/$file" "$progdir/$program"; } + rm -f "$progdir/$file" + fi + + if test -f "$progdir/$program"; then + if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then + # Run the actual program with our arguments. + func_exec_program ${1+"$@"} + fi + else + # The program doesn't exist. + $ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2 + $ECHO "This script is just a wrapper for $program." 1>&2 + $ECHO "See the libtool documentation for more information." 1>&2 + exit 1 + fi +fi diff --git a/examples/mifare-desfire-info-pcsc.c b/examples/mifare-desfire-info-pcsc.c new file mode 100644 index 0000000..bb35f6b --- /dev/null +++ b/examples/mifare-desfire-info-pcsc.c @@ -0,0 +1,166 @@ +/*- + * Copyright (C) 2010, 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 +#include + +#include + +#include + +int +main(int argc, char *argv[]) +{ + int error = EXIT_SUCCESS; + + struct pcsc_context *context; + MifareTag *tags = NULL; + char *str = NULL; + char *reader = NULL; + LONG err; + + if (argc > 1) + errx (EXIT_FAILURE, "usage: %s", argv[0]); + + pcsc_init(&context); + if (!context) + { + fprintf(stderr, "unable to init pcsc context\n"); + exit(EXIT_FAILURE); + } + + err = pcsc_list_devices(context, &str); + if (err != SCARD_S_SUCCESS) + { + fprintf(stderr, "no readers found\n"); + exit(EXIT_FAILURE); + } + + size_t device_count = 0; + reader = str; + while(*reader != '\0') + { + printf("Reader %s found\n", reader); + device_count++; + reader += strlen(reader) + 1; + } + + reader = str; + + for (size_t d = 0; d < device_count; d++) + { + tags = freefare_get_tags_pcsc (context, reader); + if (!tags) { + pcsc_exit(context); + errx (EXIT_FAILURE, "Error listing tags."); + } + + for (int i = 0; (!error) && tags[i]; i++) { + if (DESFIRE != freefare_get_tag_type (tags[i])) + continue; + + int res; + char *tag_uid = freefare_get_tag_uid (tags[i]); + + struct mifare_desfire_version_info info; + + res = mifare_desfire_connect (tags[i]); + if (res < 0) { + warnx ("Can't connect to Mifare DESFire target."); + error = 1; + break; + } + + res = mifare_desfire_get_version (tags[i], &info); + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_get_version"); + error = 1; + break; + } + + printf ("===> Version information for tag %s:\n", tag_uid); + printf ("UID: 0x%02x%02x%02x%02x%02x%02x%02x\n", info.uid[0], info.uid[1], info.uid[2], info.uid[3], info.uid[4], info.uid[5], info.uid[6]); + printf ("Batch number: 0x%02x%02x%02x%02x%02x\n", info.batch_number[0], info.batch_number[1], info.batch_number[2], info.batch_number[3], info.batch_number[4]); + printf ("Production date: week %x, 20%02x\n", info.production_week, info.production_year); + printf ("Hardware Information:\n"); + printf (" Vendor ID: 0x%02x\n", info.hardware.vendor_id); + printf (" Type: 0x%02x\n", info.hardware.type); + printf (" Subtype: 0x%02x\n", info.hardware.subtype); + printf (" Version: %d.%d\n", info.hardware.version_major, info.hardware.version_minor); + printf (" Storage size: 0x%02x (%s%d bytes)\n", info.hardware.storage_size, (info.hardware.storage_size & 1) ? ">" : "=", 1 << (info.hardware.storage_size >> 1)); + printf (" Protocol: 0x%02x\n", info.hardware.protocol); + printf ("Software Information:\n"); + printf (" Vendor ID: 0x%02x\n", info.software.vendor_id); + printf (" Type: 0x%02x\n", info.software.type); + printf (" Subtype: 0x%02x\n", info.software.subtype); + printf (" Version: %d.%d\n", info.software.version_major, info.software.version_minor); + printf (" Storage size: 0x%02x (%s%d bytes)\n", info.software.storage_size, (info.software.storage_size & 1) ? ">" : "=", 1 << (info.software.storage_size >> 1)); + printf (" Protocol: 0x%02x\n", info.software.protocol); + + uint8_t settings; + uint8_t max_keys; + res = mifare_desfire_get_key_settings (tags[i], &settings, &max_keys); + if (res == 0) { + printf ("Master Key settings (0x%02x):\n", settings); + printf (" 0x%02x configuration changeable;\n", settings & 0x08); + printf (" 0x%02x PICC Master Key not required for create / delete;\n", settings & 0x04); + printf (" 0x%02x Free directory list access without PICC Master Key;\n", settings & 0x02); + printf (" 0x%02x Allow changing the Master Key;\n", settings & 0x01); + } else if (AUTHENTICATION_ERROR == mifare_desfire_last_picc_error (tags[i])) { + printf ("Master Key settings: LOCKED\n"); + } else { + freefare_perror (tags[i], "mifare_desfire_get_key_settings"); + error = 1; + break; + } + + uint8_t version; + mifare_desfire_get_key_version (tags[i], 0, &version); + printf ("Master Key version: %d (0x%02x)\n", version, version); + + uint32_t size; + res = mifare_desfire_free_mem (tags[i], &size); + printf ("Free memory: "); + if (0 == res) { + printf ("%d bytes\n", size); + } else { + printf ("unknown\n"); + } + + printf ("Use random UID: %s\n", (strlen (tag_uid) / 2 == 4) ? "yes" : "no"); + + free (tag_uid); + + mifare_desfire_disconnect (tags[i]); + } + + while(*reader != '\0') // goto next reader for the next loop + { + reader += strlen(reader) + 1; + } + + freefare_free_tags (tags); + } + + pcsc_exit(context); + exit (error); +} /* main() */ + diff --git a/examples/mifare-ultralight-info-pcsc.c b/examples/mifare-ultralight-info-pcsc.c new file mode 100644 index 0000000..27bfa52 --- /dev/null +++ b/examples/mifare-ultralight-info-pcsc.c @@ -0,0 +1,87 @@ +/*- + * Copyright (C) 2012, 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 + +#include + +#include + +int +main (int argc, char *argv[]) +{ + int error = EXIT_SUCCESS; + MifareTag *tags = NULL; + + struct pcsc_context *context; + char *str = NULL; + char *reader; + long err; + + if (argc > 1) + errx (EXIT_FAILURE, "usage: %s", argv[0]); + + pcsc_init(&context); + if (context == NULL) + errx(EXIT_FAILURE, "Unable to init pcsc (malloc)"); + + err = pcsc_list_devices (context, &str); + if (err) + errx (EXIT_FAILURE, "No pcsc device found"); + + for (reader = str; *reader != '\0'; reader += strlen(reader) + 1) { + if (!(tags = freefare_get_tags_pcsc(context, reader))) { + /* no tags found on this reader */ + continue; + } + + for (int i = 0; (!error) && tags[i]; i++) { + switch (freefare_get_tag_type (tags[i])) { + case ULTRALIGHT: + case ULTRALIGHT_C: + break; + default: + continue; + } + + char *tag_uid = freefare_get_tag_uid (tags[i]); + printf ("Tag with UID %s is a %s\n", tag_uid, freefare_get_tag_friendly_name (tags[i])); + if (freefare_get_tag_type (tags[i]) == ULTRALIGHT_C) { + MifareTag tag = tags[i]; + int res; + MifareDESFireKey key; + uint8_t key1_3des_data[16] = { 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 }; + key = mifare_desfire_3des_key_new (key1_3des_data); + if (mifare_ultralight_connect (tag) < 0) + errx (EXIT_FAILURE, "Error connecting to tag."); + res = mifare_ultralightc_authenticate (tag, key); + printf ("Authentication with default key: %s\n", res ? "fail" : "success"); + mifare_desfire_key_free (key); + mifare_ultralight_disconnect (tag); + } + free (tag_uid); + } + + freefare_free_tags (tags); + } + + pcsc_exit (context); + exit(error); +} diff --git a/libfreefare/Makefile.am b/libfreefare/Makefile.am index d530df3..f5ddcf0 100644 --- a/libfreefare/Makefile.am +++ b/libfreefare/Makefile.am @@ -1,6 +1,6 @@ # $Id$ -AM_CFLAGS = @LIBNFC_CFLAGS@ +AM_CFLAGS = @LIBNFC_CFLAGS@ @PCSC_CFLAGS@ AM_LDFLAGS = @LIBNFC_LIBS@ lib_LTLIBRARIES = libfreefare.la diff --git a/libfreefare/freefare.c b/libfreefare/freefare.c index d9ddc4b..b2e8d4e 100644 --- a/libfreefare/freefare.c +++ b/libfreefare/freefare.c @@ -21,9 +21,12 @@ #include #include - +#include +#include #include "freefare_internal.h" +#include "freefare_pcsc_tags.h" + #define MAX_CANDIDATES 16 #define NXP_MANUFACTURER_CODE 0x04 @@ -96,7 +99,145 @@ freefare_tag_new (nfc_device *device, nfc_iso14443a_info nai) return tag; } - +MifareTag +freefare_tag_new_pcsc (struct pcsc_context *context, const char *reader) +{ + struct supported_tag *tag_info = NULL; + enum mifare_tag_type tagtype; + MifareTag tag; + bool found = false; + LONG l; + LPBYTE pbAttr = NULL; + DWORD atrlen = SCARD_AUTOALLOCATE; + DWORD dwActiveProtocol; + SCARDHANDLE hCard; + uint8_t buf[] = { 0xFF, 0xCA, 0x00, 0x00, 0x00 }; + uint8_t ret[12]; + SCARD_IO_REQUEST ioreq; + DWORD retlen; + + l = SCardConnect(context->context, reader, SCARD_SHARE_SHARED, + SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol); + if(l != SCARD_S_SUCCESS) + { + return NULL; + } + + /* get and card uid */ + retlen = sizeof(ret); + l = SCardTransmit(hCard, SCARD_PCI_T0, buf, sizeof(buf), &ioreq, ret, &retlen); + if (l != SCARD_S_SUCCESS) + { + fprintf(stderr, "freefare_tag_new_pcsc: getting uid failed\n"); + return NULL; + } + + LONG err; + err = SCardGetAttrib ( hCard , SCARD_ATTR_ATR_STRING, (LPBYTE) &pbAttr, &atrlen ); + + if (err) + { + printf("SCardGetAttrib: err=%lx %s\n ", err, pcsc_stringify_error(err)); + return NULL; + } + + found = false; + for (int i = 0; pcsc_supported_atrs[i].len != 0; i++){ + if (atrlen != pcsc_supported_atrs[i].len) { + continue; + } + if ( pcsc_supported_atrs[i].mask == NULL ){ + /* no bitmask here */ + if ( ! memcmp(pcsc_supported_atrs[i].tag ,pbAttr ,atrlen) ) { + tagtype = pcsc_supported_atrs[i].type; + found = true; + break; + } + } else { + /* bitmask case */ + int c; + for (c = 0; c < pcsc_supported_atrs[i].len; c++){ + if (pcsc_supported_atrs[i].tag[c] & pcsc_supported_atrs[i].mask[c] == pbAttr[c] & pcsc_supported_atrs[i].mask[c]){ + break; + } + } + if (c == pcsc_supported_atrs[i].len) { + tagtype = pcsc_supported_atrs[i].type; + found = true; + break; + } + } + } + if (!found) { + return NULL; + } + printf("tagtype: %d\n", tagtype); + + found = false; + + + for (size_t i = 0; i < sizeof (supported_tags) / sizeof (struct supported_tag); i++) { + if(supported_tags[i].type == tagtype) { + tag_info = &(supported_tags[i]); + found = true; + break; + } + } + + if(!found) + return NULL; + + char crc = 0x00; + for (int crc_count = 1 /*! 1. Byte wird ignoriert*/ ; crc_count < atrlen; crc_count++ ) + { + crc ^= pbAttr[crc_count]; + } + printf("checking \"CRC\": %s (crc=0x%02x)\n", (crc) ? "fail" : "succeed", crc); + + err = SCardFreeMemory (context->context, pbAttr); + if (err) + { + printf("SCardFreeMemory %lx\n", err); + } + + + + /* Allocate memory for the found MIFARE target */ + switch (tag_info->type) { + case CLASSIC_1K: + case CLASSIC_4K: + tag = mifare_classic_tag_new (); + break; + case DESFIRE: + tag = mifare_desfire_tag_new (); + break; + case ULTRALIGHT: + case ULTRALIGHT_C: + tag = mifare_ultralight_tag_new (); + break; + } + + if (!tag) + return NULL; + + /* + * Initialize common fields + * (Target specific fields are initialized in mifare_*_tag_new()) + */ + memcpy(tag->info.abtUid, ret, retlen - 2); + tag->info.szUidLen = retlen - 2; + tag->device = NULL; + tag->hContext = context->context; + tag->hCard = hCard; + tag->active = 0; + tag->tag_info = tag_info; + FILL_SZREADER(tag, reader); + + tag->lastPCSCerror = SCardDisconnect(tag->hCard, SCARD_LEAVE_CARD); + + return tag; +} + /* * MIFARE card common functions * @@ -160,6 +301,35 @@ freefare_get_tags (nfc_device *device) return tags; } +/* + * Get a list of the MIFARE targets near to the provided NFC initiator. + * (Usally its just one tag, because pcsc can not detect more) + * phContext must be established with SCardEstablishContext before + * calling this function. + * mszReader is the Name of the SmartCard Reader to use + * The list has to be freed using the freefare_free_tags() function. + */ +MifareTag * +freefare_get_tags_pcsc (struct pcsc_context *context, const char *reader) +{ + MifareTag *tags = NULL; + + tags = malloc(2*sizeof (MifareTag)); + if(!tags) + { + fprintf(stderr, "freefare_get_tags_pcsc: malloc failed !!\n"); + return NULL; + } + tags[0] = freefare_tag_new_pcsc(context, reader); + tags[1] = NULL; + if(tags[0] == NULL) + return NULL; + + + + return tags; +} + /* * Returns the type of the provided tag. */ @@ -184,10 +354,10 @@ freefare_get_tag_friendly_name (MifareTag tag) char * freefare_get_tag_uid (MifareTag tag) { - char *res = malloc (2 * tag->info.szUidLen + 1); - for (size_t i =0; i < tag->info.szUidLen; i++) - snprintf (res + 2*i, 3, "%02x", tag->info.abtUid[i]); - return res; + char *res = malloc (2 * tag->info.szUidLen + 1); + for (size_t i =0; i < tag->info.szUidLen; i++) + snprintf (res + 2*i, 3, "%02x", tag->info.abtUid[i]); + return res; } /* @@ -197,19 +367,21 @@ void freefare_free_tag (MifareTag tag) { if (tag) { - switch (tag->tag_info->type) { - case CLASSIC_1K: - case CLASSIC_4K: - mifare_classic_tag_free (tag); - break; - case DESFIRE: - mifare_desfire_tag_free (tag); - break; - case ULTRALIGHT: - case ULTRALIGHT_C: - mifare_ultralight_tag_free (tag); - break; + switch (tag->tag_info->type) + { + case CLASSIC_1K: + case CLASSIC_4K: + mifare_classic_tag_free (tag); + break; + case DESFIRE: + mifare_desfire_tag_free (tag); + break; + case ULTRALIGHT: + case ULTRALIGHT_C: + mifare_ultralight_tag_free (tag); + break; } + FREE_SZREADER(tag->szReader); } } @@ -217,16 +389,23 @@ const char * freefare_strerror (MifareTag tag) { const char *p = "Unknown error"; - if (nfc_device_get_last_error (tag->device) < 0) { - p = nfc_strerror (tag->device); - } else { - if (tag->tag_info->type == DESFIRE) { - if (MIFARE_DESFIRE (tag)->last_pcd_error) { - p = mifare_desfire_error_lookup (MIFARE_DESFIRE (tag)->last_pcd_error); - } else if (MIFARE_DESFIRE (tag)->last_picc_error) { - p = mifare_desfire_error_lookup (MIFARE_DESFIRE (tag)->last_picc_error); - } - } + if(tag->device != NULL) // we use libnfc + { + if (nfc_device_get_last_error (tag->device) < 0) { + p = nfc_strerror (tag->device); + } else { + if (tag->tag_info->type == DESFIRE) { + if (MIFARE_DESFIRE (tag)->last_pcd_error) { + p = mifare_desfire_error_lookup (MIFARE_DESFIRE (tag)->last_pcd_error); + } else if (MIFARE_DESFIRE (tag)->last_picc_error) { + p = mifare_desfire_error_lookup (MIFARE_DESFIRE (tag)->last_picc_error); + } + } + } + } + else // we use the pcsc protocol + { + p = (const char*) pcsc_stringify_error(tag->lastPCSCerror); } return p; } @@ -257,6 +436,60 @@ freefare_free_tags (MifareTag *tags) } } +/* + * create context for pcsc readers + */ + +void +pcsc_init(struct pcsc_context** context) +{ + LONG err; + struct pcsc_context *con = malloc(sizeof(struct pcsc_context)); + err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &con->context); + if (err < 0) + { + *context = NULL; + return; + } + *context = con; +} + +/* + * destroy context for pcsc readers + */ +void +pcsc_exit(struct pcsc_context* context) +{ + if (context->readers) + SCardFreeMemory(context->context, context->readers); + SCardReleaseContext(context->context); +} + +/* + * list pcsc devices + */ + +LONG +pcsc_list_devices(struct pcsc_context* context, LPSTR *string) +{ + LONG err; + LPSTR str = NULL; + DWORD size; + static char empty[] = "\0"; + size = SCARD_AUTOALLOCATE; + err = SCardListReaders(context->context, NULL, (LPSTR)&str, &size); + if (err != SCARD_S_SUCCESS) + { + context->readers = NULL; + *string = empty; + } + else + { + *string = str; + context->readers = str; + } + return err; +} /* * Low-level API diff --git a/libfreefare/freefare.h b/libfreefare/freefare.h index 2789968..d4c34c3 100644 --- a/libfreefare/freefare.h +++ b/libfreefare/freefare.h @@ -25,6 +25,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -52,8 +53,19 @@ typedef struct mifare_desfire_key *MifareDESFireKey; typedef uint8_t MifareUltralightPageNumber; typedef unsigned char MifareUltralightPage[4]; +struct pcsc_context { + SCARDCONTEXT context; + LPSTR readers; +}; + +void pcsc_init(struct pcsc_context** context); +void pcsc_exit(struct pcsc_context* context); +LONG pcsc_list_devices(struct pcsc_context* context, LPSTR* string); + MifareTag *freefare_get_tags (nfc_device *device); +MifareTag *freefare_get_tags_pcsc (struct pcsc_context *context, const char *reader); MifareTag freefare_tag_new (nfc_device *device, nfc_iso14443a_info nai); +MifareTag freefare_tag_new_pcsc(struct pcsc_context *context, const char *reader); enum mifare_tag_type freefare_get_tag_type (MifareTag tag); const char *freefare_get_tag_friendly_name (MifareTag tag); char *freefare_get_tag_uid (MifareTag tag); diff --git a/libfreefare/freefare_internal.h b/libfreefare/freefare_internal.h index c8e1d6f..47cc9c8 100644 --- a/libfreefare/freefare_internal.h +++ b/libfreefare/freefare_internal.h @@ -186,10 +186,37 @@ struct supported_tag { struct mifare_tag { nfc_device *device; nfc_iso14443a_info info; + // PCSC things + SCARDCONTEXT hContext; + SCARDHANDLE hCard; + char* szReader; + LONG lastPCSCerror; + // End of PCSC things const struct supported_tag *tag_info; int active; }; +#define FILL_SZREADER(tag, szRd) \ + do { \ + tag->szReader = malloc(strlen(szRd) * sizeof(char) + 1); \ + if(NULL == tag->szReader) \ + { \ + fprintf(stderr, "malloc failed !! (in freefare_get_tags_pcsc)\n"); \ + } \ + strcpy(tag->szReader, (const char *)szRd); \ + } while(0) + +#define FREE_SZREADER(szRd) \ + do { \ + if(NULL != szRd) \ + { \ + free(szRd); \ + szRd = NULL; \ + } \ + } while (0) + + + struct mifare_classic_tag { struct mifare_tag __tag; diff --git a/libfreefare/freefare_pcsc_tags.h b/libfreefare/freefare_pcsc_tags.h new file mode 100644 index 0000000..7bfece5 --- /dev/null +++ b/libfreefare/freefare_pcsc_tags.h @@ -0,0 +1,24 @@ +#ifndef __FREEFARE_PCSC_TAGS_H__ +#define __FREEFARE_PCSC_TAGS_H__ + +struct pcsc_atr_info { + + enum mifare_tag_type type; + int len; + unsigned char* tag; + unsigned char* mask; + +}; + +struct pcsc_atr_info pcsc_supported_atrs[] = { + { DESFIRE , 6, "\x3b\x04\x41\x11\x77\x81", NULL}, + { DESFIRE , 6, "\x3b\x81\x80\x01\x80\x80", NULL }, + { CLASSIC_1K , 20, "\x3b\x8f\x80\x01\x80\x4f\x0c\xa0\x00\x00\x03\x06\x03\x00\x01\x00\x00\x00\x00\x6a", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00" }, + { CLASSIC_4K , 20, "\x3b\x8f\x80\x01\x80\x4f\x0c\xa0\x00\x00\x03\x06\x03\x00\x02\x00\x00\x00\x00\x69", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00" }, + { ULTRALIGHT , 20, "\x3b\x8f\x80\x01\x80\x4f\x0c\xa0\x00\x00\x03\x06\x03\x00\x03\x00\x00\x00\x00\x68", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00" }, + { ULTRALIGHT , 20, "\x3b\x8f\x80\x01\x80\x4f\x0c\xa0\x00\x00\x03\x06\x03\x00\x03\x00\x00\x00\x00\x68", "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\x00" }, + { DESFIRE , 0 , NULL, NULL} +}; + +#endif /* __FREEFARE_PCSC_TAGS_H__ */ + diff --git a/libfreefare/mifare_classic.c b/libfreefare/mifare_classic.c index 71f8c75..bbc92f0 100644 --- a/libfreefare/mifare_classic.c +++ b/libfreefare/mifare_classic.c @@ -90,11 +90,30 @@ errno = 0; \ DEBUG_XFER (msg, __##msg##_n, "===> "); \ int _res; \ - if ((_res = nfc_initiator_transceive_bytes (tag->device, msg, __##msg##_n, res, __##res##_size, 0)) < 0) { \ - if (disconnect) { \ - tag->active = false; \ + if (tag->device != NULL) /* nfc way */ \ + { \ + if ((_res = nfc_initiator_transceive_bytes (tag->device, msg, __##msg##_n, res, __##res##_size, 0)) < 0) \ + { \ + if (disconnect) \ + { \ + tag->active = false; \ + } \ + return errno = EIO, -1; \ } \ - return errno = EIO, -1; \ + } \ + else /* pcsc way */ \ + { \ + SCARD_IO_REQUEST __pcsc_rcv_pci; \ + DWORD __pcsc_recv_len = __##res##_size + 1; \ + if ((SCARD_S_SUCCESS != SCardTransmit(tag->hCard, SCARD_PCI_T0, msg, __##msg##_n, &__pcsc_rcv_pci, (LPBYTE)&_res, &__pcsc_recv_len)) < 0) \ + { \ + if (disconnect) \ + { \ + tag->active = false; \ + } \ + return errno = EIO, -1; \ + } \ + _res = __pcsc_recv_len; \ } \ __##res##_n = _res; \ DEBUG_XFER (res, __##res##_n, "<=== "); \ @@ -230,16 +249,33 @@ mifare_classic_connect (MifareTag tag) ASSERT_INACTIVE (tag); ASSERT_MIFARE_CLASSIC (tag); - nfc_target pnti; - nfc_modulation modulation = { - .nmt = NMT_ISO14443A, - .nbr = NBR_106 - }; - if (nfc_initiator_select_passive_target (tag->device, modulation, tag->info.abtUid, tag->info.szUidLen, &pnti) >= 0) { + if(NULL != tag->device) // nfc way + { + nfc_target pnti; + nfc_modulation modulation = { + .nmt = NMT_ISO14443A, + .nbr = NBR_106 + }; + if (nfc_initiator_select_passive_target (tag->device, modulation, tag->info.abtUid, tag->info.szUidLen, &pnti) >= 0) { + tag->active = 1; + } else { + errno = EIO; + return -1; + } + } + else // pcsc way + { + DWORD dwActiveProtocol; + tag->lastPCSCerror = SCardConnect(tag->hContext, tag->szReader, SCARD_SHARE_SHARED, + SCARD_PROTOCOL_T0, &(tag->hCard), &dwActiveProtocol); + if(SCARD_S_SUCCESS != tag->lastPCSCerror) + { + errno = EIO; + fprintf(stderr, "borked %lx\n", tag->lastPCSCerror); + return -1; + } tag->active = 1; - } else { - errno = EIO; - return -1; + } return 0; } @@ -253,12 +289,28 @@ mifare_classic_disconnect (MifareTag tag) ASSERT_ACTIVE (tag); ASSERT_MIFARE_CLASSIC (tag); - if (nfc_initiator_deselect_target (tag->device) >= 0) { - tag->active = 0; - } else { - errno = EIO; - return -1; + if(NULL != tag->device) // nfclib way + { + if (nfc_initiator_deselect_target (tag->device) >= 0) { + tag->active = 0; + } else { + errno = EIO; + return -1; + } } + else // pcsc way + { + tag->lastPCSCerror = SCardDisconnect(tag->hCard, SCARD_LEAVE_CARD); + if(SCARD_S_SUCCESS == tag->lastPCSCerror) + { + tag->active = 0; + } + else { + errno = EIO; + return -1; + } + } + return 0; } diff --git a/libfreefare/mifare_desfire.c b/libfreefare/mifare_desfire.c index 3083fea..d154fe0 100644 --- a/libfreefare/mifare_desfire.c +++ b/libfreefare/mifare_desfire.c @@ -137,7 +137,6 @@ static ssize_t read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_ } \ } while (0) - /* * Convenience macros. */ @@ -184,8 +183,18 @@ static ssize_t read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_ MIFARE_DESFIRE (tag)->last_pcd_error = OPERATION_OK; \ DEBUG_XFER (__msg, __len, "===> "); \ int _res; \ - if ((_res = nfc_initiator_transceive_bytes (tag->device, __msg, __len, __res, __##res##_size + 1, 0)) < 0) { \ - return errno = EIO, -1; \ + if (tag->device == NULL) { /* pcsc branch */ \ + SCARD_IO_REQUEST __pcsc_rcv_pci; \ + DWORD __pcsc_recv_len = __##res##_size + 1; \ + if ((SCARD_S_SUCCESS != SCardTransmit(tag->hCard, SCARD_PCI_T0, __msg, __len, &__pcsc_rcv_pci, __res, &__pcsc_recv_len)) < 0) { \ + return errno = EIO, -1; \ + } \ + _res = __pcsc_recv_len; \ + } \ + else { /* nfc branch */ \ + if ((_res = nfc_initiator_transceive_bytes (tag->device, __msg, __len, __res, __##res##_size + 1, 0)) < 0) { \ + return errno = EIO, -1; \ + } \ } \ __##res##_n = _res; \ DEBUG_XFER (__res, __##res##_n, "<=== "); \ @@ -197,7 +206,8 @@ static ssize_t read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_ memcpy (res, __res, __##res##_n - 1); \ } while (0) - + + /* * Miscellaneous low-level memory manipulation functions. */ @@ -238,7 +248,7 @@ le24toh (uint8_t data[3]) return (data[2] << 16) | (data[1] << 8) | data[0]; } - + /* * Memory management functions. */ @@ -271,7 +281,6 @@ mifare_desfire_tag_free (MifareTag tag) free (tag); } - /* * MIFARE card communication preparation functions * @@ -289,23 +298,45 @@ mifare_desfire_connect (MifareTag tag) ASSERT_INACTIVE (tag); ASSERT_MIFARE_DESFIRE (tag); - nfc_target pnti; - nfc_modulation modulation = { - .nmt = NMT_ISO14443A, - .nbr = NBR_106 - }; - if (nfc_initiator_select_passive_target (tag->device, modulation, tag->info.abtUid, tag->info.szUidLen, &pnti) >= 0) { - tag->active = 1; - free (MIFARE_DESFIRE (tag)->session_key); - MIFARE_DESFIRE (tag)->session_key = NULL; - MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; - MIFARE_DESFIRE (tag)->last_pcd_error = OPERATION_OK; - MIFARE_DESFIRE (tag)->authenticated_key_no = NOT_YET_AUTHENTICATED; - MIFARE_DESFIRE (tag)->selected_application = 0; - } else { - errno = EIO; - return -1; + if(NULL != tag->device) // nfc way + { + nfc_target pnti; + nfc_modulation modulation = { + .nmt = NMT_ISO14443A, + .nbr = NBR_106 + }; + int ret = nfc_initiator_select_passive_target (tag->device, modulation, tag->info.abtUid, tag->info.szUidLen, &pnti); + if( !(ret >= 0 )) // selecting a pasive target got some error + { + errno = EIO; + return -1; + } + } + else // pcsc way + { + DWORD dwActiveProtocol; + + tag->lastPCSCerror = SCardConnect(tag->hContext, tag->szReader, SCARD_SHARE_SHARED, + SCARD_PROTOCOL_T0, &(tag->hCard), &dwActiveProtocol); + + if(SCARD_S_SUCCESS != tag->lastPCSCerror) + { + errno = EIO; + fprintf(stderr, "szReader: %s\n", tag->szReader); + fprintf(stderr, "borked %lx\n", tag->lastPCSCerror); + return -1; + } + } + + tag->active = 1; + free (MIFARE_DESFIRE (tag)->session_key); + MIFARE_DESFIRE (tag)->session_key = NULL; + MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; + MIFARE_DESFIRE (tag)->last_pcd_error = OPERATION_OK; + MIFARE_DESFIRE (tag)->authenticated_key_no = NOT_YET_AUTHENTICATED; + MIFARE_DESFIRE (tag)->selected_application = 0; + return 0; } @@ -320,15 +351,27 @@ mifare_desfire_disconnect (MifareTag tag) free (MIFARE_DESFIRE (tag)->session_key); MIFARE_DESFIRE(tag)->session_key = NULL; - - if (nfc_initiator_deselect_target (tag->device) >= 0) { - tag->active = 0; + + if(NULL != tag->device) // nfclib way + { + if (nfc_initiator_deselect_target (tag->device) >= 0) { + tag->active = 0; + } + } + else // pcsc way + { + tag->lastPCSCerror = SCardDisconnect(tag->hCard, SCARD_LEAVE_CARD); + if(SCARD_S_SUCCESS == tag->lastPCSCerror) + { + tag->active = 0; + } } + + + return 0; } - - #define AUTHENTICATE_LEGACY 0x0A #define AUTHENTICATE_ISO 0x1A #define AUTHENTICATE_AES 0xAA @@ -648,7 +691,6 @@ mifare_desfire_get_key_version (MifareTag tag, uint8_t key_no, uint8_t *version) return 0; } - static int 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) @@ -1136,7 +1178,6 @@ mifare_desfire_get_card_uid (MifareTag tag, char **uid) return 0; } - /* Application level commands */ @@ -1502,7 +1543,6 @@ mifare_desfire_delete_file (MifareTag tag, uint8_t file_no) return 0; } - /* * Data manipulation commands. */ diff --git a/libfreefare/mifare_ultralight.c b/libfreefare/mifare_ultralight.c index b442aa4..30ecc1a 100644 --- a/libfreefare/mifare_ultralight.c +++ b/libfreefare/mifare_ultralight.c @@ -61,37 +61,51 @@ #define ULTRALIGHT_TRANSCEIVE(tag, msg, res) \ do { \ errno = 0; \ + int _res ; \ DEBUG_XFER (msg, __##msg##_n, "===> "); \ - int _res; \ - if ((_res = nfc_initiator_transceive_bytes (tag->device, msg, __##msg##_n, res, __##res##_size, 0)) < 0) { \ - return errno = EIO, -1; \ + if (tag->device == NULL) {\ + /* PCSC branch */\ + SCARD_IO_REQUEST __pcsc_rcv_pci; \ + DWORD __pcsc_recv_len = __##res##_size; \ + if ((SCARD_S_SUCCESS != SCardTransmit(tag->hCard, SCARD_PCI_T0, msg, __##msg##_n, &__pcsc_rcv_pci, res, &__pcsc_recv_len)) < 0) { \ + return errno = EIO, -1; \ + } \ + _res = __pcsc_recv_len; \ + } else { \ + /* nfc branch */ \ + if ((_res = nfc_initiator_transceive_bytes (tag->device, msg, __##msg##_n, res, __##res##_size, 0)) < 0) { \ + return errno = EIO, -1; \ + } \ + __##res##_n = _res; \ + DEBUG_XFER (res, __##res##_n, "<=== "); \ } \ - __##res##_n = _res; \ - DEBUG_XFER (res, __##res##_n, "<=== "); \ } while (0) #define ULTRALIGHT_TRANSCEIVE_RAW(tag, msg, res) \ - do { \ - errno = 0; \ - if (nfc_device_set_property_bool (tag->device, NP_EASY_FRAMING, false) < 0) { \ - errno = EIO; \ - return -1; \ - } \ - DEBUG_XFER (msg, __##msg##_n, "===> "); \ - int _res; \ - if ((_res = nfc_initiator_transceive_bytes (tag->device, msg, __##msg##_n, res, __##res##_size, 0)) < 0) { \ - nfc_device_set_property_bool (tag->device, NP_EASY_FRAMING, true); \ - return errno = EIO, -1; \ - } \ - __##res##_n = _res; \ - DEBUG_XFER (res, __##res##_n, "<=== "); \ - if (nfc_device_set_property_bool (tag->device, NP_EASY_FRAMING, true) < 0) { \ +do { \ + if (tag->device == NULL){\ + ULTRALIGHT_TRANSCEIVE(tag, msg, res); \ + } else { \ + errno = 0; \ + if (nfc_device_set_property_bool (tag->device, NP_EASY_FRAMING, false) < 0) { \ errno = EIO; \ return -1; \ + } \ + DEBUG_XFER (msg, __##msg##_n, "===> "); \ + int _res; \ + if ((_res = nfc_initiator_transceive_bytes (tag->device, msg, __##msg##_n, res, __##res##_size, 0)) < 0) { \ + nfc_device_set_property_bool (tag->device, NP_EASY_FRAMING, true); \ + return errno = EIO, -1; \ + } \ + __##res##_n = _res; \ + DEBUG_XFER (res, __##res##_n, "<=== "); \ + if (nfc_device_set_property_bool (tag->device, NP_EASY_FRAMING, true) < 0) { \ + errno = EIO; \ + return -1; \ + } \ } \ - } while (0) +} while (0) - /* * Memory management functions. */ @@ -133,18 +147,35 @@ mifare_ultralight_connect (MifareTag tag) ASSERT_INACTIVE (tag); ASSERT_MIFARE_ULTRALIGHT (tag); - nfc_target pnti; - nfc_modulation modulation = { - .nmt = NMT_ISO14443A, - .nbr = NBR_106 - }; - if (nfc_initiator_select_passive_target (tag->device, modulation, tag->info.abtUid, tag->info.szUidLen, &pnti) >= 0) { + if (tag->device == NULL) { /* pcsc branch */ + + DWORD dwActiveProtocol; + + tag->lastPCSCerror = SCardConnect(tag->hContext, tag->szReader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &(tag->hCard), &dwActiveProtocol); + if(SCARD_S_SUCCESS != tag->lastPCSCerror){ + return errno = EIO, -1; + } + tag->active = 1; for (int i = 0; i < MIFARE_ULTRALIGHT_MAX_PAGE_COUNT; i++) MIFARE_ULTRALIGHT(tag)->cached_pages[i] = 0; - } else { - errno = EIO; - return -1; + + } + else { /* nfc branch */ + nfc_target pnti; + nfc_modulation modulation = { + .nmt = NMT_ISO14443A, + .nbr = NBR_106 + }; + if (nfc_initiator_select_passive_target (tag->device, modulation, tag->info.abtUid, tag->info.szUidLen, &pnti) >= 0) { + tag->active = 1; + for (int i = 0; i < MIFARE_ULTRALIGHT_MAX_PAGE_COUNT; i++) + MIFARE_ULTRALIGHT(tag)->cached_pages[i] = 0; + } else { + errno = EIO; + return -1; + } + } return 0; } @@ -158,16 +189,34 @@ mifare_ultralight_disconnect (MifareTag tag) ASSERT_ACTIVE (tag); ASSERT_MIFARE_ULTRALIGHT (tag); - if (nfc_initiator_deselect_target (tag->device) >= 0) { - tag->active = 0; - } else { - errno = EIO; - return -1; + if (tag->device == NULL) { + /* pcsc branch */ + + if ( (tag->lastPCSCerror = SCardDisconnect (tag->hCard, SCARD_LEAVE_CARD) ) == SCARD_S_SUCCESS ) + { + tag->active = 0; + return 0; + } + else + { + errno = EIO; + return -1; + } + + } + else /* nfc branch */ + { + if (nfc_initiator_deselect_target (tag->device) >= 0) { + tag->active = 0; + } else { + errno = EIO; + return -1; + } + return 0; } - return 0; } - + /* * Card manipulation functions *