diff --git a/examples/Makefile.am b/examples/Makefile.am index 830e456..6c920e4 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,6 +2,7 @@ bin_PROGRAMS = \ nfc-anticol \ nfc-emulate \ nfc-emulate-ndef \ + nfc-emulate-tag \ nfc-list \ nfc-mfclassic \ nfc-mfultralight \ @@ -51,7 +52,15 @@ nfc_emulate_LDADD = $(top_builddir)/libnfc/libnfc.la \ nfc_emulate_ndef_SOURCES = nfc-emulate-ndef.c nfc_emulate_ndef_LDADD = $(top_builddir)/libnfc/libnfc.la \ - libnfcutils.la + libnfcutils.la + +nfc_emulate_tag_SOURCES = nfc-emulate-tag.c +nfc_emulate_tag_LDADD = $(top_builddir)/libnfc/libnfc.la \ + libnfcutils.la + +nfc_sam_SOURCES = nfc-sam.c +nfc_sam_LDADD = $(top_builddir)/libnfc/libnfc.la \ + libnfcutils.la nfcip_target_SOURCES = nfcip-target.c nfcip_target_LDADD = $(top_builddir)/libnfc/libnfc.la @@ -61,17 +70,13 @@ nfcip_initiator_LDADD = $(top_builddir)/libnfc/libnfc.la pn53x_diagnose_SOURCES = pn53x-diagnose.c pn53x_diagnose_LDADD = $(top_builddir)/libnfc/libnfc.la \ - libnfcutils.la + libnfcutils.la pn53x_tamashell_SOURCES = pn53x-tamashell.c pn53x_tamashell_LDADD = $(top_builddir)/libnfc/libnfc.la \ libnfcutils.la pn53x_tamashell_LDFLAGS = @READLINE_LIBS@ -nfc_sam_SOURCES = nfc-sam.c -nfc_sam_LDADD = $(top_builddir)/libnfc/libnfc.la \ - libnfcutils.la - dist_man_MANS = nfc-anticol.1 nfc-emulate.1 nfc-list.1 nfc-mfclassic.1 nfc-mfultralight.1 nfc-relay.1 nfc-sam.1 EXTRA_DIST = CMakeLists.txt diff --git a/examples/nfc-emulate-ndef.c b/examples/nfc-emulate-ndef.c index 2e9f6b2..0dd6501 100644 --- a/examples/nfc-emulate-ndef.c +++ b/examples/nfc-emulate-ndef.c @@ -91,7 +91,17 @@ main (int argc, char *argv[]) printf ("[+] Connected to NFC device: %s\n", pnd->acName); printf ("[+] Emulating NDEF tag now, please touch it with a second NFC device\n"); - if (!nfc_target_init (pnd, NTM_PICC, abtRx, &szRxLen)) { + + nfc_target_t nt = { + .ntt = NTT_MIFARE, + .nti.nai.abtAtqa = { 0x00, 0x04 }, + .nti.nai.abtUid = { 0x08, 0x00, 0xb0, 0x0b }, + .nti.nai.btSak = 0x20, + .nti.nai.szUidLen = 4, + .nti.nai.szAtsLen = 0, + }; + + if (!nfc_target_init (pnd, NTM_PICC, nt, abtRx, &szRxLen)) { nfc_perror (pnd, "nfc_target_init"); ERR("Could not come out of auto-emulation, no command was received"); return EXIT_FAILURE; diff --git a/examples/nfc-emulate-tag.c b/examples/nfc-emulate-tag.c new file mode 100644 index 0000000..a16f198 --- /dev/null +++ b/examples/nfc-emulate-tag.c @@ -0,0 +1,152 @@ +/*- + * Public platform independent Near Field Communication (NFC) library + * + * Copyright (C) 2010, 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 + */ + +/** + * @file nfc-emulate-ndef.c + * @brief Emulate a tag + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif // HAVE_CONFIG_H + +#include +#include +#include +#include +#include + +#include + +#include +#include "nfc-utils.h" + +#define MAX_FRAME_LEN 264 + +static byte_t abtRx[MAX_FRAME_LEN]; +static size_t szRxLen; +static nfc_device_t *pnd; +static bool quiet_output = false; + +bool +target_io( const nfc_target_t nt, const byte_t * pbtInput, const size_t szInput, byte_t * pbtOutput, size_t *pszOutput ) +{ + bool loop = true; + *pszOutput = 0; + + // Show transmitted command + if (!quiet_output) { + printf (" In: "); + print_hex (pbtInput, szInput); + } + if(szInput) { + switch(pbtInput[0]) { + case 0xe0: // RATS + // Send ATS + *pszOutput = nt.nti.nai.szAtsLen + 1; + pbtOutput[0] = nt.nti.nai.szAtsLen + 1; // ISO14443-4 says that ATS contains ATS_Lenght as first byte + if(nt.nti.nai.szAtsLen) { + memcpy(pbtOutput+1, nt.nti.nai.abtAts, nt.nti.nai.szAtsLen); + } + break; + default: // Unknown + if (!quiet_output) { + printf("Unknown frame, emulated target abort.\n"); + } + loop = false; + } + } + // Show transmitted command + if (!quiet_output) { + printf (" Out: "); + print_hex (pbtOutput, *pszOutput); + } + return loop; +} + +bool +nfc_target_emulate_tag(nfc_device_t* pnd, const nfc_target_t nt) +{ + size_t szTx; + byte_t abtTx[MAX_FRAME_LEN]; + bool loop = true; + + if (!nfc_target_init (pnd, NTM_PASSIVE, nt, abtRx, &szRxLen)) { + return false; + } + + while ( loop ) { + loop = target_io( nt, abtRx, szRxLen, abtTx, &szTx ); + if (szTx) { + if (!nfc_target_send_bytes(pnd, abtTx, szTx)) { + return false; + } + } + if ( loop ) { + if (!nfc_target_receive_bytes(pnd, abtRx, &szRxLen)) { + return false; + } + } + } + return true; +} + +int +main (int argc, char *argv[]) +{ + const char *acLibnfcVersion; + + // Try to open the NFC reader + pnd = nfc_connect (NULL); + + // Display libnfc version + acLibnfcVersion = nfc_version (); + printf ("%s use libnfc %s\n", argv[0], acLibnfcVersion); + + if (pnd == NULL) { + ERR("Unable to connect to NFC device"); + return EXIT_FAILURE; + } + + printf ("Connected to NFC device: %s\n", pnd->acName); + + nfc_target_t nt = { + .ntt = NTT_MIFARE, + .nti.nai.abtAtqa = { 0x03, 0x44 }, + .nti.nai.abtUid = { 0x08, 0xab, 0xcd, 0xef }, + .nti.nai.btSak = 0x20, + .nti.nai.szUidLen = 4, + .nti.nai.abtAts = { 0x75, 0x77, 0x81, 0x02, 0x80 }, + .nti.nai.szAtsLen = 5, + }; + + printf ("%s will emulate this ISO14443-A tag:\n", argv[0]); + print_nfc_iso14443a_info( nt.nti.nai ); + + printf ("NFC device (configured as target) is now emulating the tag, please touch it with a second NFC device (initiator)\n"); + if (!nfc_target_emulate_tag (pnd, nt)) { + nfc_perror (pnd, "nfc_target_emulate_tag"); + ERR("Could not come out of auto-emulation, no command was received"); + return EXIT_FAILURE; + } + + nfc_disconnect(pnd); + exit (EXIT_SUCCESS); +} + diff --git a/examples/nfc-emulate.c b/examples/nfc-emulate.c index 799614b..b9e8c32 100644 --- a/examples/nfc-emulate.c +++ b/examples/nfc-emulate.c @@ -19,7 +19,7 @@ /** * @file nfc-emulate.c - * @brief + * @brief This example can be used to emulate a tag which which have a "really" custom UID */ #ifdef HAVE_CONFIG_H @@ -106,7 +106,17 @@ main (int argc, char *argv[]) printf ("[+] Try to break out the auto-emulation, this requires a second reader!\n"); printf ("[+] To do this, please send any command after the anti-collision\n"); printf ("[+] For example, send a RATS command or use the \"nfc-anticol\" tool\n"); - if (!nfc_target_init (pnd, NTM_PASSIVE, abtRecv, &szRecvBits)) { + + // Note: We have to build a "fake" nfc_target_t in order to do exactly the same that was done before the new nfc_target_init() was introduced. + nfc_target_t nt = { + .ntt = NTT_GENERIC_PASSIVE_106, + .nti.nai.abtAtqa = "\x04\x00", + .nti.nai.abtUid = "\xde\xad\xbe\xaf\x62", + .nti.nai.btSak = 0x20, + .nti.nai.szUidLen = 5, + .nti.nai.szAtsLen = 0, + }; + if (!nfc_target_init (pnd, NTM_PASSIVE, nt, abtRecv, &szRecvBits)) { printf ("Error: Could not come out of auto-emulation, no command was received\n"); return 1; } diff --git a/examples/nfc-relay.c b/examples/nfc-relay.c index be38d64..124ba5a 100644 --- a/examples/nfc-relay.c +++ b/examples/nfc-relay.c @@ -125,7 +125,18 @@ main (int argc, char *argv[]) printf ("[+] Try to break out the auto-emulation, this requires a second reader!\n"); printf ("[+] To do this, please send any command after the anti-collision\n"); printf ("[+] For example, send a RATS command or use the \"nfc-anticol\" tool\n"); - if (!nfc_target_init (pndTag, NTM_PASSIVE, abtReaderRx, &szReaderRxBits)) { + + // Note: We have to build a "fake" nfc_target_t in order to do exactly the same that was done before the new nfc_target_init() was introduced. + nfc_target_t nt = { + .ntt = NTT_GENERIC_PASSIVE_106, + .nti.nai.abtAtqa = "\x04\x00", + .nti.nai.abtUid = "\xde\xad\xbe\xaf\x62", + .nti.nai.btSak = 0x20, + .nti.nai.szUidLen = 5, + .nti.nai.szAtsLen = 0, + }; + + if (!nfc_target_init (pndTag, NTM_PASSIVE, nt, abtReaderRx, &szReaderRxBits)) { ERR ("%s", "Initialization of NFC emulator failed"); nfc_disconnect (pndTag); return EXIT_FAILURE; diff --git a/examples/nfc-sam.c b/examples/nfc-sam.c index 4662801..4bb1646 100644 --- a/examples/nfc-sam.c +++ b/examples/nfc-sam.c @@ -19,7 +19,7 @@ /** * @file nfc-sam.c - * @brief Configure the reader to comunicate with a SAM (Secure Access Module). + * @brief Configure the NFC device to comunicate with a SAM (Secure Access Module). */ #ifdef HAVE_CONFIG_H @@ -129,7 +129,7 @@ main (int argc, const char *argv[]) return EXIT_FAILURE; } - printf ("Connected to NFC reader: %s\n", pnd->acName); + printf ("Connected to NFC device: %s\n", pnd->acName); // Print the example's menu printf ("\nSelect the comunication mode:\n"); @@ -152,7 +152,7 @@ main (int argc, const char *argv[]) switch (mode) { case VIRTUAL_CARD_MODE: { - // FIXME: after the loop the reader doesn't respond to host commands... + // FIXME: after the loop the device doesn't respond to host commands... printf ("Now the SAM is readable for 1 minute from an external reader.\n"); wait_one_minute (); } @@ -207,7 +207,15 @@ main (int argc, const char *argv[]) // FIXME: it does not work as expected...Probably the issue is in "nfc_target_init" // which doesn't provide a way to set custom data for SENS_RES, NFCID1, SEL_RES, etc. - if (!nfc_target_init (pnd, NTM_PICC, abtRx, &szRxLen)) + nfc_target_t nt = { + .ntt = NTT_GENERIC_PASSIVE_106, + .nti.nai.abtAtqa = "\x04\x00", + .nti.nai.abtUid = "\x08\xad\xbe\xaf", + .nti.nai.btSak = 0x20, + .nti.nai.szUidLen = 4, + .nti.nai.szAtsLen = 0, + }; + if (!nfc_target_init (pnd, NTM_PICC, nt, abtRx, &szRxLen)) return EXIT_FAILURE; printf ("Now both the NFC reader and SAM are readable for 1 minute from an external reader.\n"); diff --git a/examples/nfcip-target.c b/examples/nfcip-target.c index d5cd718..e255ecb 100644 --- a/examples/nfcip-target.c +++ b/examples/nfcip-target.c @@ -59,7 +59,17 @@ main (int argc, const char *argv[]) errx (1, "usage: %s", argv[0]); } - if (!pnd || !nfc_target_init (pnd, NTM_DEP, abtRecv, &szRecvBits)) { + // Note: We have to build a "fake" nfc_target_t in order to do exactly the same that was done before the new nfc_target_init() was introduced. + nfc_target_t nt = { + .ntt = NTT_GENERIC_PASSIVE_106, + .nti.nai.abtAtqa = "\x04\x00", + .nti.nai.abtUid = "\xde\xad\xbe\xaf\x62", + .nti.nai.btSak = 0x20, + .nti.nai.szUidLen = 5, + .nti.nai.szAtsLen = 0, + }; + + if (!pnd || !nfc_target_init (pnd, NTM_DEP, nt, abtRecv, &szRecvBits)) { printf ("unable to connect or initialize\n"); return 1; } diff --git a/include/nfc/nfc.h b/include/nfc/nfc.h index ba1923a..4b7fe9b 100644 --- a/include/nfc/nfc.h +++ b/include/nfc/nfc.h @@ -90,7 +90,7 @@ extern "C" { byte_t * pbtRxPar); /* NFC target: act as tag (i.e. MIFARE Classic) or NFC target device. */ - NFC_EXPORT bool nfc_target_init (nfc_device_t * pnd, nfc_target_mode_t ntm, byte_t * pbtRx, size_t * pszRxLen); + NFC_EXPORT bool nfc_target_init (nfc_device_t * pnd, const nfc_target_mode_t ntm, const nfc_target_t nt, byte_t * pbtRx, size_t * pszRxLen); NFC_EXPORT bool nfc_target_send_bytes (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTxLen); NFC_EXPORT bool nfc_target_receive_bytes (nfc_device_t * pnd, byte_t * pbtRx, size_t * pszRxLen); NFC_EXPORT bool nfc_target_send_bits (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTxBits, diff --git a/libnfc/chips/pn53x.c b/libnfc/chips/pn53x.c index 22acf7f..2070fae 100644 --- a/libnfc/chips/pn53x.c +++ b/libnfc/chips/pn53x.c @@ -921,7 +921,7 @@ pn53x_initiator_transceive_bytes (nfc_device_t * pnd, const byte_t * pbtTx, cons } bool -pn53x_target_init (nfc_device_t * pnd, nfc_target_mode_t ntm, byte_t * pbtRx, size_t * pszRxLen) +pn53x_target_init (nfc_device_t * pnd, const nfc_target_mode_t ntm, const nfc_target_t nt, byte_t * pbtRx, size_t * pszRxLen) { // Save the current configuration settings bool bCrc = pnd->bCrc; @@ -965,7 +965,30 @@ pn53x_target_init (nfc_device_t * pnd, nfc_target_mode_t ntm, byte_t * pbtRx, si if (!pn53x_set_reg (pnd, REG_CIU_TX_AUTO, SYMBOL_INITIAL_RF_ON, 0x04)) return false; - if(!pn53x_TgInitAsTarget(pnd, ntm, pbtRx, pszRxLen)) { + byte_t abtMifareParams[6]; + byte_t * pbtMifareParams = NULL; + + switch(nt.ntt) { + case NTT_MIFARE: + case NTT_GENERIC_PASSIVE_106: + case NTT_ISO14443A_106: { + // Set ATQA (SENS_RES) + abtMifareParams[0] = nt.nti.nai.abtAtqa[1]; + abtMifareParams[1] = nt.nti.nai.abtAtqa[0]; + // Set UID + // Note: in this mode we can only emulate a single size (4 bytes) UID where the first is fixed by PN53x as 0x08 + abtMifareParams[2] = nt.nti.nai.abtUid[1]; + abtMifareParams[3] = nt.nti.nai.abtUid[2]; + abtMifareParams[4] = nt.nti.nai.abtUid[3]; + // Set SAK (SEL_RES) + abtMifareParams[5] = nt.nti.nai.btSak; + + pbtMifareParams = abtMifareParams; + } + break; + } + + if(!pn53x_TgInitAsTarget(pnd, ntm, pbtMifareParams, NULL, NULL, pbtRx, pszRxLen)) { return false; } @@ -979,7 +1002,9 @@ pn53x_target_init (nfc_device_t * pnd, nfc_target_mode_t ntm, byte_t * pbtRx, si } bool -pn53x_TgInitAsTarget (nfc_device_t * pnd, nfc_target_mode_t ntm, byte_t * pbtRx, size_t * pszRxLen) +pn53x_TgInitAsTarget (nfc_device_t * pnd, nfc_target_mode_t ntm, + const byte_t * pbtMifareParams, const byte_t * pbtFeliCaParams, const byte_t * pbtNFCID3t, + byte_t * pbtRx, size_t * pszRxLen) { byte_t abtRx[MAX_FRAME_LEN]; size_t szRxLen; @@ -993,26 +1018,27 @@ pn53x_TgInitAsTarget (nfc_device_t * pnd, nfc_target_mode_t ntm, byte_t * pbtRx, // Store the target mode in the initialization params abtCmd[2] = ntm; - // Set ATQA (SENS_RES) - abtCmd[3] = 0x04; - abtCmd[4] = 0x00; - - // Set SAK (SEL_RES) - abtCmd[8] = 0x20; - - // Set UID - abtCmd[5] = 0x00; - abtCmd[6] = 0xb0; - abtCmd[7] = 0x0b; + if (pbtMifareParams) { + memcpy (abtCmd+3, pbtMifareParams, 6); + } + if (pbtFeliCaParams) { + memcpy (abtCmd+9, pbtFeliCaParams, 18); + } + if (pbtNFCID3t) { + memcpy(abtCmd+27, pbtNFCID3t, 10); + } + // TODO Handle General bytes and Tk (Historical bytes) lenght // Request the initialization as a target szRxLen = MAX_FRAME_LEN; if (!pn53x_transceive (pnd, abtCmd, sizeof (pncmd_target_init), abtRx, &szRxLen)) return false; + // Note: the first byte is skip: + // its the "mode" byte which contains baudrate, DEP and Framing type (Mifare, active or FeliCa) datas. + // Save the received byte count *pszRxLen = szRxLen - 1; - // Copy the received bytes memcpy (pbtRx, abtRx + 1, *pszRxLen); diff --git a/libnfc/chips/pn53x.h b/libnfc/chips/pn53x.h index 2183f53..95567ef 100644 --- a/libnfc/chips/pn53x.h +++ b/libnfc/chips/pn53x.h @@ -112,6 +112,7 @@ bool pn53x_decode_target_data (const byte_t * pbtRawData, size_t szDataLen, n bool pn53x_get_firmware_version (nfc_device_t * pnd); bool pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool bEnable); +// NFC device as Initiator functions bool pn53x_initiator_select_dep_target (nfc_device_t * pnd, const nfc_modulation_t nmInitModulation, const byte_t * pbtPidData, const size_t szPidDataLen, const byte_t * pbtNFCID3i, const size_t szNFCID3iDataLen, @@ -122,16 +123,15 @@ bool pn53x_initiator_transceive_bits (nfc_device_t * pnd, const byte_t * pbtT byte_t * pbtRxPar); bool pn53x_initiator_transceive_bytes (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTxLen, byte_t * pbtRx, size_t * pszRxLen); - -bool pn53x_target_init (nfc_device_t * pnd, nfc_target_mode_t tm, byte_t * pbtRx, size_t * pszRxLen); +// NFC device as Target functions +bool pn53x_target_init (nfc_device_t * pnd, const nfc_target_mode_t ntm, const nfc_target_t nt, byte_t * pbtRx, size_t * pszRxLen); bool pn53x_target_receive_bits (nfc_device_t * pnd, byte_t * pbtRx, size_t * pszRxBits, byte_t * pbtRxPar); bool pn53x_target_receive_bytes (nfc_device_t * pnd, byte_t * pbtRx, size_t * pszRxLen); bool pn53x_target_send_bits (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTxBits, const byte_t * pbtTxPar); bool pn53x_target_send_bytes (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTxLen); - +// Error handling functions const char *pn53x_strerror (const nfc_device_t * pnd); - static const struct chip_callbacks pn53x_callbacks_list = { pn53x_strerror }; @@ -145,7 +145,9 @@ bool pn53x_InRelease (nfc_device_t * pnd, const uint8_t ui8Target); bool pn53x_InAutoPoll (nfc_device_t * pnd, const nfc_target_type_t * pnttTargetTypes, const size_t szTargetTypes, const byte_t btPollNr, const byte_t btPeriod, nfc_target_t * pntTargets, size_t * pszTargetFound); -bool pn53x_TgInitAsTarget (nfc_device_t * pnd, nfc_target_mode_t tm, byte_t * pbtRx, size_t * pszRxLen); +bool pn53x_TgInitAsTarget (nfc_device_t * pnd, nfc_target_mode_t ntm, + const byte_t * pbtMifareParams, const byte_t * pbtFeliCaParams, const byte_t * pbtNFCID3t, + byte_t * pbtRx, size_t * pszRxLen); #endif // __NFC_CHIPS_PN53X_H__ diff --git a/libnfc/nfc.c b/libnfc/nfc.c index 1400b56..678f3b1 100644 --- a/libnfc/nfc.c +++ b/libnfc/nfc.c @@ -556,11 +556,11 @@ nfc_initiator_transceive_bits (nfc_device_t * pnd, const byte_t * pbtTx, const s * @warning Be aware that this function will wait (hang) until a command is received that is not part of the anti-collision. The RATS command for example would wake up the emulator. After this is received, the send and receive functions can be used. */ bool -nfc_target_init (nfc_device_t * pnd, nfc_target_mode_t ntm, byte_t * pbtRx, size_t * pszRxLen) +nfc_target_init (nfc_device_t * pnd, const nfc_target_mode_t ntm, const nfc_target_t nt, byte_t * pbtRx, size_t * pszRxLen) { pnd->iLastError = 0; - return pn53x_target_init (pnd, ntm, pbtRx, pszRxLen); + return pn53x_target_init (pnd, ntm, nt, pbtRx, pszRxLen); } /**