diff --git a/.travis.yml b/.travis.yml index 2198598..b331309 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,6 @@ addons: - libusb-dev - doxygen - cmake - - libcutter-dev script: - if [ $BLD == autoconf ]; then autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install; fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ad92d7..576f6e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,14 +18,15 @@ SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") # config.h IF(WIN32) - CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_windows.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_windows.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) SET(LIBNFC_SYSCONFDIR "${CMAKE_INSTALL_PREFIX}/config" CACHE PATH "libnfc configuration directory") INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32) ELSE(WIN32) SET(_XOPEN_SOURCE 600) SET(SYSCONFDIR "/etc" CACHE PATH "System configuration directory") - CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_posix.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_posix.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) ENDIF(WIN32) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) ADD_DEFINITIONS("-DHAVE_CONFIG_H") diff --git a/libnfc/drivers/Makefile.am b/libnfc/drivers/Makefile.am index 1ac65b2..4432c5c 100644 --- a/libnfc/drivers/Makefile.am +++ b/libnfc/drivers/Makefile.am @@ -39,6 +39,11 @@ if DRIVER_PN532_I2C_ENABLED libnfcdrivers_la_SOURCES += pn532_i2c.c pn532_i2c.h endif +if DRIVER_PN71XX_ENABLED +libnfcdrivers_la_LIBADD += -lnfc_nci_linux +libnfcdrivers_la_SOURCES += pn71xx.c pn71xx.h +endif + if PCSC_ENABLED libnfcdrivers_la_CFLAGS += @libpcsclite_CFLAGS@ libnfcdrivers_la_LIBADD += @libpcsclite_LIBS@ diff --git a/libnfc/drivers/pn53x_usb.c b/libnfc/drivers/pn53x_usb.c index 18c51fc..56c6eba 100644 --- a/libnfc/drivers/pn53x_usb.c +++ b/libnfc/drivers/pn53x_usb.c @@ -132,13 +132,13 @@ struct pn53x_usb_supported_device { }; const struct pn53x_usb_supported_device pn53x_usb_supported_devices[] = { - { 0x04CC, 0x0531, NXP_PN531, "Philips / PN531", 0, 0, 0 }, - { 0x04CC, 0x2533, NXP_PN533, "NXP / PN533", 0x04, 0x84, 40 }, - { 0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW", 0x04, 0x84, 40 }, - { 0x04E6, 0x5594, SCM_SCL3712, "SCM Micro / SCL3712-NFC&RW", 0, 0, 0 }, - { 0x054c, 0x0193, SONY_PN531, "Sony / PN531", 0, 0, 0 }, - { 0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO", 0x04, 0x84, 40 }, - { 0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]", 0, 0, 0 } + { 0x04CC, 0x0531, NXP_PN531, "Philips / PN531", 0x84, 0x04, 0x40 }, + { 0x04CC, 0x2533, NXP_PN533, "NXP / PN533", 0x84, 0x04, 0x40 }, + { 0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW", 0x84, 0x04, 0x40 }, + { 0x04E6, 0x5594, SCM_SCL3712, "SCM Micro / SCL3712-NFC&RW", 0, 0, 0 }, // to check on real device + { 0x054c, 0x0193, SONY_PN531, "Sony / PN531", 0x84, 0x04, 0x40 }, + { 0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO", 0x84, 0x04, 0x40 }, + { 0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]", 0x84, 0x04, 0x40 } }; // PN533 USB descriptors backup buffers @@ -421,6 +421,11 @@ pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring) // Open the USB device if ((data.pudh = usb_open(dev)) == NULL) continue; + + //To retrieve real USB endpoints configuration: + //pn53x_usb_get_end_points(dev, &data); + //printf("DEBUG ENDPOINTS In:0x%x Out:0x%x Size:0x%x\n", data.uiEndPointIn, data.uiEndPointOut, data.uiMaxPacketSize); + // Retrieve end points, using hardcoded defaults if available // or using the descriptors otherwise. if (pn53x_usb_get_end_points_default(dev, &data) == false) { diff --git a/libnfc/drivers/pn71xx.c b/libnfc/drivers/pn71xx.c new file mode 100644 index 0000000..8245908 --- /dev/null +++ b/libnfc/drivers/pn71xx.c @@ -0,0 +1,596 @@ + +/** + * @file pn71xx.h + * @brief Driver for PN71XX using libnfc-nci library + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif // HAVE_CONFIG_H + +#include "pn71xx.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "drivers.h" +#include "nfc-internal.h" + +#include "linux_nfc_api.h" + +#define PN71XX_DRIVER_NAME "pn71xx" + +#define LOG_CATEGORY "libnfc.driver.pn71xx" +#define LOG_GROUP NFC_LOG_GROUP_DRIVER + +const nfc_modulation_type pn71xx_supported_modulation_as_target[] = {NMT_ISO14443A, NMT_FELICA, NMT_ISO14443B, NMT_ISO14443BI, NMT_ISO14443B2SR, NMT_ISO14443B2CT, NMT_JEWEL, NMT_DEP, 0}; +const nfc_modulation_type pn71xx_supported_modulation_as_initiator[] = {NMT_ISO14443A, NMT_FELICA, NMT_ISO14443B, NMT_ISO14443BI, NMT_ISO14443B2SR, NMT_ISO14443B2CT, NMT_JEWEL, NMT_DEP, 0}; + +const nfc_baud_rate pn71xx_iso14443a_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 }; +const nfc_baud_rate pn71xx_felica_supported_baud_rates[] = { NBR_424, NBR_212, 0 }; +const nfc_baud_rate pn71xx_dep_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 }; +const nfc_baud_rate pn71xx_jewel_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 }; +const nfc_baud_rate pn71xx_iso14443b_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 }; + +static nfcTagCallback_t TagCB; +static nfc_tag_info_t *TagInfo = NULL; + +static void onTagArrival(nfc_tag_info_t *pTagInfo); +static void onTagDeparture(void); + +/** ------------------------------------------------------------------------ */ +/** ------------------------------------------------------------------------ */ +/** + * @brief Initialize libnfc_nci library to verify presence of PN71xx device. + * + * @param context NFC context. + * @param connstrings array of 'nfc_connstring' buffer (allocated by caller). It is used to store the + * connection info strings of devices found. + * @param connstrings_len length of the connstrings array. + * @return number of devices found. + */ +static size_t +pn71xx_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) +{ + size_t device_found = 0; + + if ((context == NULL) || (connstrings_len == 0)) return 0; + + if (nfcManager_doInitialize() == 0) { + nfc_connstring connstring = "pn71xx"; + memcpy(connstrings[device_found++], connstring, sizeof(nfc_connstring)); + } + + return device_found; +} + +/** + * @brief Close connection to PN71xx by stopping the discovery loop and deinitializing the libnfc_nci library. + * + * @param pnd pointer on the device to close. + */ +static void +pn71xx_close(nfc_device *pnd) +{ + nfcManager_disableDiscovery(); + nfcManager_deregisterTagCallback(); + nfcManager_doDeinitialize(); + nfc_device_free(pnd); + pnd = NULL; +} + +/** + * @brief Open a connection to PN71xx, starting the discovery loop for tag detection. + * + * @param context NFC context. + * @param connstring connection info to the device + * @return pointer to the device, or NULL in case of error. + */ +static nfc_device * +pn71xx_open(const nfc_context *context, const nfc_connstring connstring) +{ + nfc_device *pnd; + + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "open: %s", connstring); + + pnd = nfc_device_new(context, connstring); + if (!pnd) { + perror("malloc"); + return NULL; + } + + pnd->driver = &pn71xx_driver; + strcpy(pnd->name, "pn71xx-device"); + strcpy(pnd->connstring, connstring); + + TagCB.onTagArrival = onTagArrival; + TagCB.onTagDeparture = onTagDeparture; + nfcManager_registerTagCallback(&TagCB); + + nfcManager_enableDiscovery(DEFAULT_NFA_TECH_MASK, 1, 0, 0); + + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "wait 1 seconds for polling"); + sleep(1); + + return pnd; +} + +/** ------------------------------------------------------------------------ */ +/** ------------------------------------------------------------------------ */ +static bool IsTechnology(nfc_tag_info_t *TagInfo, nfc_modulation_type nmt) +{ + switch (nmt) { + case NMT_ISO14443A: + if (TagInfo->technology == TARGET_TYPE_ISO14443_4 + || TagInfo->technology == TARGET_TYPE_ISO14443_3A + || TagInfo->technology == TARGET_TYPE_MIFARE_CLASSIC + || TagInfo->technology == TARGET_TYPE_MIFARE_UL) + return true; + break; + + case NMT_ISO14443B: + case NMT_ISO14443BI: + case NMT_ISO14443B2SR: + case NMT_ISO14443B2CT: + if (TagInfo->technology == TARGET_TYPE_ISO14443_3B) + return true; + break; + + case NMT_FELICA: + if (TagInfo->technology == TARGET_TYPE_FELICA) + return true; + break; + + case NMT_JEWEL: + if (TagInfo->technology == TARGET_TYPE_ISO14443_3A + && TagInfo->protocol == NFA_PROTOCOL_T1T) + return true; + break; + + default: + return false; + } + return false; +} + +static void BufferPrintBytes(char* buffer, unsigned int buflen, const uint8_t *data, unsigned int datalen) +{ + int cx = 0; + for(unsigned int i = 0x00; i < datalen; i++) { + cx += snprintf(buffer + cx, buflen - cx, "%02X ", data[i]); + } +} + +static void PrintTagInfo (nfc_tag_info_t *TagInfo) +{ + switch (TagInfo->technology) + { + case TARGET_TYPE_UNKNOWN: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type Unknown'"); + } break; + case TARGET_TYPE_ISO14443_3A: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 3A'"); + } break; + case TARGET_TYPE_ISO14443_3B: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 3B'"); + } break; + case TARGET_TYPE_ISO14443_4: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 4A'"); + } break; + case TARGET_TYPE_FELICA: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type F'"); + } break; + case TARGET_TYPE_ISO15693: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type V'"); + } break; + case TARGET_TYPE_NDEF: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type NDEF'"); + } break; + case TARGET_TYPE_NDEF_FORMATABLE: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type Formatable'"); + } break; + case TARGET_TYPE_MIFARE_CLASSIC: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Mifare Classic'"); + } break; + case TARGET_TYPE_MIFARE_UL: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Mifare Ul'"); + } break; + case TARGET_TYPE_KOVIO_BARCODE: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Kovio Barcode'"); + } break; + case TARGET_TYPE_ISO14443_3A_3B: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A/B'"); + } break; + default: + { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type %d (Unknown or not supported)'\n", TagInfo->technology); + } break; + } + /*32 is max UID len (Kovio tags)*/ + if((0x00 != TagInfo->uid_length) && (32 >= TagInfo->uid_length)) + { + char buffer [100]; + int cx = 0; + + if(4 == TagInfo->uid_length || 7 == TagInfo->uid_length || 10 == TagInfo->uid_length) + { + cx += snprintf(buffer + cx, sizeof(buffer) - cx, "NFCID1 : \t'"); + } + else if(8 == TagInfo->uid_length) + { + cx += snprintf(buffer + cx, sizeof(buffer) - cx, "NFCID2 : \t'"); + } + else + { + cx += snprintf(buffer + cx, sizeof(buffer) - cx, "UID : \t'"); + } + + BufferPrintBytes(buffer + cx, sizeof(buffer) - cx, (unsigned char*) TagInfo->uid, TagInfo->uid_length); + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s'", buffer); + } +} + +/** ------------------------------------------------------------------------ */ +/** ------------------------------------------------------------------------ */ + +static void onTagArrival(nfc_tag_info_t *pTagInfo) +{ + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "tag found"); + + TagInfo = malloc(sizeof(nfc_tag_info_t)); + memcpy(TagInfo, pTagInfo, sizeof(nfc_tag_info_t)); + + PrintTagInfo(TagInfo); +} + +static void onTagDeparture(void) +{ + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "tag lost"); + + free(TagInfo); + TagInfo = NULL; +} + +static int +pn71xx_initiator_init(struct nfc_device *pnd) +{ + if (pnd == NULL) return NFC_EIO; + return NFC_SUCCESS; +} + +static int +pn71xx_initiator_select_passive_target(struct nfc_device *pnd, + const nfc_modulation nm, + const uint8_t *pbtInitData, const size_t szInitData, + nfc_target *pnt) +{ + if (pnd == NULL) return NFC_EIO; + + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "select_passive_target"); + + if (TagInfo) { + + nfc_target nttmp; + memset(&nttmp, 0x00, sizeof(nfc_target)); + nttmp.nm = nm; + + void* uidPtr = NULL; + unsigned int maxLen = 0; + + switch (nm.nmt) { + case NMT_ISO14443A: + if (IsTechnology(TagInfo, nm.nmt)) { + maxLen = 10; + uidPtr = nttmp.nti.nai.abtUid; + + if (TagInfo->technology == TARGET_TYPE_MIFARE_CLASSIC) { + nttmp.nti.nai.btSak = 0x08; + } else { + // make hardcoded desfire for freefare lib check + nttmp.nti.nai.btSak = 0x20; + nttmp.nti.nai.szAtsLen = 5; + memcpy (nttmp.nti.nai.abtAts, "\x75\x77\x81\x02", 4); + } + } + break; + + case NMT_ISO14443B: + if (IsTechnology(TagInfo, nm.nmt)) { + maxLen = 4; + uidPtr = nttmp.nti.nbi.abtPupi; + } + break; + + case NMT_ISO14443BI: + if (IsTechnology(TagInfo, nm.nmt)) { + maxLen = 4; + uidPtr = nttmp.nti.nii.abtDIV; + } + break; + + case NMT_ISO14443B2SR: + if (IsTechnology(TagInfo, nm.nmt)) { + maxLen = 8; + uidPtr = nttmp.nti.nsi.abtUID; + } + break; + + case NMT_ISO14443B2CT: + if (IsTechnology(TagInfo, nm.nmt)) { + maxLen = 4; + uidPtr = nttmp.nti.nci.abtUID; + } + break; + + case NMT_FELICA: + if (IsTechnology(TagInfo, nm.nmt)) { + maxLen = 8; + uidPtr = nttmp.nti.nfi.abtId; + } + break; + + case NMT_JEWEL: + if (IsTechnology(TagInfo, nm.nmt)) { + maxLen = 4; + uidPtr = nttmp.nti.nji.btId; + } + break; + + default: + return 0; + } + + if (uidPtr && TagInfo->uid_length) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "target found"); + int len = TagInfo->uid_length > maxLen ? maxLen : TagInfo->uid_length; + memcpy(uidPtr, TagInfo->uid, len); + if (nm.nmt == NMT_ISO14443A) + nttmp.nti.nai.szUidLen = len; + + // Is a tag info struct available + if (pnt) { + memcpy(pnt, &nttmp, sizeof(nfc_target)); + } + return 1; + } + } + + return 0; +} + +static int +pn71xx_initiator_deselect_target(struct nfc_device *pnd) +{ + if (pnd == NULL) return NFC_EIO; + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "deselect_passive_target"); + return NFC_SUCCESS; +} + + +static int +pn71xx_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, +const size_t szRx, int timeout) +{ + if (pnd == NULL) return NFC_EIO; + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "transceive_bytes timeout=%d", timeout); + + if (!TagInfo) return NFC_EINVARG; + + char buffer[500]; + BufferPrintBytes(buffer, sizeof(buffer), pbtTx, szTx); + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "===> %s", buffer); + + int received = nfcTag_transceive(TagInfo->handle, (uint8_t *) pbtTx, szTx, pbtRx, szRx, 500); + if (received <= 0) + return NFC_EIO; + + BufferPrintBytes(buffer, sizeof(buffer), pbtRx, received); + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "<=== %s", buffer); + + return received; +} + +static int +pn71xx_initiator_poll_target(struct nfc_device *pnd, + const nfc_modulation *pnmModulations, const size_t szModulations, + const uint8_t uiPollNr, const uint8_t uiPeriod, + nfc_target *pnt) +{ + static int periodFactor = 150000; + int period = uiPeriod * periodFactor; + + if (pnd == NULL) return 0; + + for (int j = 0; j < uiPollNr; j++) { + for (unsigned int i = 0; i < szModulations; i++) { + const nfc_modulation nm = pnmModulations[i]; + + nfc_target nt; + int res = pn71xx_initiator_select_passive_target(pnd, nm, 0, 0, &nt); + if (res > 0 && pnt) { + memcpy(pnt, &nt, sizeof(nfc_target)); + return res; + } + } + usleep(period); + } + + return 0; +} + +static int +pn71xx_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt) +{ + if ((pnd == NULL) || (pnt == NULL)) return 1; + return !TagInfo; +} + + +/** ------------------------------------------------------------------------ */ +/** ------------------------------------------------------------------------ */ +static int +pn71xx_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt) +{ + if (pnd == NULL) return NFC_EIO; + + switch (mode) { + case N_TARGET: + *supported_mt = (nfc_modulation_type *)pn71xx_supported_modulation_as_target; + break; + case N_INITIATOR: + *supported_mt = (nfc_modulation_type *)pn71xx_supported_modulation_as_initiator; + break; + default: + return NFC_EINVARG; + } + return NFC_SUCCESS; +} + +static int +pn71xx_get_supported_baud_rate(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) +{ + if (pnd == NULL) return NFC_EIO; + if (mode) {} + + switch (nmt) { + case NMT_FELICA: + *supported_br = (nfc_baud_rate *)pn71xx_felica_supported_baud_rates; + break; + case NMT_ISO14443A: + *supported_br = (nfc_baud_rate *)pn71xx_iso14443a_supported_baud_rates; + break; + case NMT_ISO14443B: + case NMT_ISO14443BI: + case NMT_ISO14443B2SR: + case NMT_ISO14443B2CT: + *supported_br = (nfc_baud_rate *)pn71xx_iso14443b_supported_baud_rates; + break; + case NMT_JEWEL: + *supported_br = (nfc_baud_rate *)pn71xx_jewel_supported_baud_rates; + break; + case NMT_DEP: + *supported_br = (nfc_baud_rate *)pn71xx_dep_supported_baud_rates; + break; + default: + return NFC_EINVARG; + } + return NFC_SUCCESS; +} + +/** ------------------------------------------------------------------------ */ +/** ------------------------------------------------------------------------ */ + +static int +pn71xx_set_property_bool(struct nfc_device *pnd, const nfc_property property, const bool bEnable) +{ + if (pnd == NULL) return NFC_EIO; + return NFC_SUCCESS; +} + +static int +pn71xx_set_property_int(struct nfc_device *pnd, const nfc_property property, const int value) +{ + if (pnd == NULL) return NFC_EIO; + return NFC_SUCCESS; +} + +static int +pn71xx_get_information_about(nfc_device *pnd, char **pbuf) +{ + static const char* info = "PN71XX nfc driver using libnfc-nci userspace library"; + size_t buflen = strlen(info) + 1; + + if (pnd == NULL) return NFC_EIO; + + *pbuf = malloc(buflen); + memcpy(*pbuf, info, buflen); + + return buflen; +} +/** + * @brief Abort any pending operation + * + * @param pnd pointer on the NFC device. + * @return NFC_SUCCESS + */ +static int +pn71xx_abort_command(nfc_device *pnd) +{ + if (pnd == NULL) return NFC_EIO; + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "abort_command"); + return NFC_SUCCESS; +} + +static int +pn71xx_idle(struct nfc_device *pnd) +{ + if (pnd == NULL) return NFC_EIO; + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "idle"); + return NFC_SUCCESS; +} + +static int +pn71xx_PowerDown(struct nfc_device *pnd) +{ + if (pnd == NULL) return NFC_EIO; + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "PowerDown"); + return NFC_SUCCESS; +} + +/** ------------------------------------------------------------------------ */ +/** ------------------------------------------------------------------------ */ +const struct nfc_driver pn71xx_driver = { + .name = PN71XX_DRIVER_NAME, + .scan_type = NOT_INTRUSIVE, + .scan = pn71xx_scan, + .open = pn71xx_open, + .close = pn71xx_close, + .strerror = NULL, + + .initiator_init = pn71xx_initiator_init, + .initiator_init_secure_element = NULL, + .initiator_select_passive_target = pn71xx_initiator_select_passive_target, + .initiator_poll_target = pn71xx_initiator_poll_target, + .initiator_select_dep_target = NULL, + .initiator_deselect_target = pn71xx_initiator_deselect_target, + .initiator_transceive_bytes = pn71xx_initiator_transceive_bytes, + .initiator_transceive_bits = NULL, + .initiator_transceive_bytes_timed = NULL, + .initiator_transceive_bits_timed = NULL, + .initiator_target_is_present = pn71xx_initiator_target_is_present, + + .target_init = NULL, + .target_send_bytes = NULL, + .target_receive_bytes = NULL, + .target_send_bits = NULL, + .target_receive_bits = NULL, + + .device_set_property_bool = pn71xx_set_property_bool, + .device_set_property_int = pn71xx_set_property_int, + .get_supported_modulation = pn71xx_get_supported_modulation, + .get_supported_baud_rate = pn71xx_get_supported_baud_rate, + .device_get_information_about = pn71xx_get_information_about, + + .abort_command = pn71xx_abort_command, + .idle = pn71xx_idle, + .powerdown = pn71xx_PowerDown, +}; + diff --git a/libnfc/drivers/pn71xx.h b/libnfc/drivers/pn71xx.h new file mode 100644 index 0000000..43c5ff6 --- /dev/null +++ b/libnfc/drivers/pn71xx.h @@ -0,0 +1,14 @@ +/** + * @file pn71xx.h + * @brief Driver for PN71XX using libnfc-nci library + */ + +#ifndef __NFC_DRIVER_PN71XX_H__ +#define __NFC_DRIVER_PN71XX_H__ + +#include + +/* Reference to the driver structure */ +extern const struct nfc_driver pn71xx_driver; + +#endif // ! __NFC_DRIVER_7120_H__ diff --git a/libnfc/nfc.c b/libnfc/nfc.c index 636697d..ce30694 100644 --- a/libnfc/nfc.c +++ b/libnfc/nfc.c @@ -119,6 +119,10 @@ # include "drivers/pn532_i2c.h" #endif /* DRIVER_PN532_I2C_ENABLED */ +#if defined (DRIVER_PN71XX_ENABLED) +# include "drivers/pn71xx.h" +#endif /* DRIVER_PN71XX_ENABLED */ + #define LOG_CATEGORY "libnfc.general" #define LOG_GROUP NFC_LOG_GROUP_GENERAL @@ -130,6 +134,25 @@ struct nfc_driver_list { const struct nfc_driver_list *nfc_drivers = NULL; +// descritions for debugging +const char * nfc_property_name[] = { + "NP_TIMEOUT_COMMAND", + "NP_TIMEOUT_ATR", + "NP_TIMEOUT_COM", + "NP_HANDLE_CRC", + "NP_HANDLE_PARITY", + "NP_ACTIVATE_FIELD", + "NP_ACTIVATE_CRYPTO1", + "NP_INFINITE_SELECT", + "NP_ACCEPT_INVALID_FRAMES", + "NP_ACCEPT_MULTIPLE_FRAMES", + "NP_AUTO_ISO14443_4", + "NP_EASY_FRAMING", + "NP_FORCE_ISO14443_A", + "NP_FORCE_ISO14443_B", + "NP_FORCE_SPEED_106" +}; + static void nfc_drivers_init(void) { @@ -157,6 +180,9 @@ nfc_drivers_init(void) #if defined (DRIVER_ARYGON_ENABLED) nfc_register_driver(&arygon_driver); #endif /* DRIVER_ARYGON_ENABLED */ +#if defined (DRIVER_PN71XX_ENABLED) + nfc_register_driver(&pn71xx_driver); +#endif /* DRIVER_PN71XX_ENABLED */ } static int @@ -409,6 +435,7 @@ nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], const size_ int nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "set_property_int %s %s", nfc_property_name[property], value ? "True" : "False"); HAL(device_set_property_int, pnd, property, value); } @@ -428,6 +455,7 @@ nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "set_property_bool %s %s", nfc_property_name[property], bEnable ? "True" : "False"); HAL(device_set_property_bool, pnd, property, bEnable); } diff --git a/libnfc/target-subr.c b/libnfc/target-subr.c index 97e2882..61cedfd 100644 --- a/libnfc/target-subr.c +++ b/libnfc/target-subr.c @@ -503,7 +503,7 @@ snprint_nfc_barcode_info(char *dst, size_t size, const nfc_barcode_info *pnti, b { (void) verbose; int off = 0; - off += snprintf(dst + off, size - off, " Size (bits): %lu\n", pnti->szDataLen * 8); + off += snprintf(dst + off, size - off, " Size (bits): %lu\n", (unsigned long)(pnti->szDataLen * 8)); off += snprintf(dst + off, size - off, " Content: "); for (uint8_t i = 0; i < pnti->szDataLen; i++) { off += snprintf(dst + off, size - off, "%02X", pnti->abtData[i]); diff --git a/m4/libnfc_drivers.m4 b/m4/libnfc_drivers.m4 index 4672539..54be7e7 100644 --- a/m4/libnfc_drivers.m4 +++ b/m4/libnfc_drivers.m4 @@ -4,7 +4,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS], [ AC_MSG_CHECKING(which drivers to build) AC_ARG_WITH(drivers, - AS_HELP_STRING([--with-drivers=DRIVERS], [Use a custom driver set, where DRIVERS is a coma-separated list of drivers to build support for. Available drivers are: 'acr122_pcsc', 'acr122_usb', 'acr122s', 'arygon', 'pn532_i2c', 'pn532_spi', 'pn532_uart' and 'pn53x_usb'. Default drivers set is 'acr122_usb,acr122s,arygon,pn532_i2c,pn532_spi,pn532_uart,pn53x_usb'. The special driver set 'all' compile all available drivers.]), + AS_HELP_STRING([--with-drivers=DRIVERS], [Use a custom driver set, where DRIVERS is a coma-separated list of drivers to build support for. Available drivers are: 'acr122_pcsc', 'acr122_usb', 'acr122s', 'arygon', 'pn532_i2c', 'pn532_spi', 'pn532_uart', 'pn53x_usb' and 'pn71xx'. Default drivers set is 'acr122_usb,acr122s,arygon,pn532_i2c,pn532_spi,pn532_uart,pn53x_usb'. The special driver set 'all' compile all available drivers.]), [ case "${withval}" in yes | no) dnl ignore calls without any arguments @@ -36,7 +36,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS], fi ;; all) - DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart" + DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart pn71xx" if test x"$spi_available" = x"yes" then DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_spi" @@ -58,6 +58,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS], driver_pn532_uart_enabled="no" driver_pn532_spi_enabled="no" driver_pn532_i2c_enabled="no" + driver_pn71xx_enabled="no" for driver in ${DRIVER_BUILD_LIST} do @@ -102,6 +103,10 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS], driver_pn532_i2c_enabled="yes" DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_I2C_ENABLED" ;; + pn71xx) + driver_pn71xx_enabled="yes" + DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN71XX_ENABLED" + ;; *) AC_MSG_ERROR([Unknow driver: $driver]) ;; @@ -116,6 +121,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS], AM_CONDITIONAL(DRIVER_PN532_UART_ENABLED, [test x"$driver_pn532_uart_enabled" = xyes]) AM_CONDITIONAL(DRIVER_PN532_SPI_ENABLED, [test x"$driver_pn532_spi_enabled" = xyes]) AM_CONDITIONAL(DRIVER_PN532_I2C_ENABLED, [test x"$driver_pn532_i2c_enabled" = xyes]) + AM_CONDITIONAL(DRIVER_PN71XX_ENABLED, [test x"$driver_pn71xx_enabled" = xyes]) ]) AC_DEFUN([LIBNFC_DRIVERS_SUMMARY],[ @@ -129,4 +135,5 @@ echo " pn53x_usb........ $driver_pn53x_usb_enabled" echo " pn532_uart....... $driver_pn532_uart_enabled" echo " pn532_spi....... $driver_pn532_spi_enabled" echo " pn532_i2c........ $driver_pn532_i2c_enabled" +echo " pn71xx........... $driver_pn71xx_enabled" ]) diff --git a/utils/nfc-mfclassic.c b/utils/nfc-mfclassic.c index bc3fe6c..3b12cd8 100644 --- a/utils/nfc-mfclassic.c +++ b/utils/nfc-mfclassic.c @@ -10,6 +10,7 @@ * See AUTHORS file for a more comprehensive list of contributors. * Additional contributors of this file: * Copyright (C) 2011-2013 Adam Laurie + * Copyright (C) 2018-2019 Danielle Bruneo * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -70,7 +71,9 @@ static bool bForceKeyFile; static bool bTolerateFailures; static bool bFormatCard; static bool magic2 = false; +static bool magic3 = false; static bool unlocked = false; +static bool bForceSizeMismatch; static uint8_t uiBlocks; static uint8_t keys[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -208,10 +211,18 @@ authenticate(uint32_t uiBlock) // Try to authenticate for the current sector if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) return true; - } + } else if (magic3) { + //If it's a One Time Write card, we're gonna authenticate with the default keys + memcpy(mp.mpa.abtKey, default_key, sizeof(default_key)); + + + // Try to authenticate for the current sector + if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) { + return true; + } // If formatting or not using key file, try to guess the right key - if (bFormatCard || !bUseKeyFile) { + } else if (bFormatCard || !bUseKeyFile) { for (size_t key_index = 0; key_index < num_keys; key_index++) { memcpy(mp.mpa.abtKey, keys + (key_index * 6), 6); if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) { @@ -352,10 +363,17 @@ read_card(int read_unlocked) if (read_unlocked) { memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, sizeof(mtDump.amb[iBlock].mbd.abtData)); } else { - // Copy the keys over from our key dump and store the retrieved access bits - memcpy(mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, sizeof(mtDump.amb[iBlock].mbt.abtKeyA)); - memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpt.abtAccessBits, sizeof(mtDump.amb[iBlock].mbt.abtAccessBits)); - memcpy(mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, sizeof(mtDump.amb[iBlock].mbt.abtKeyB)); + //If we're using a One Time Write ('Magic 3') Badge - we'll use default keys + ACL + if (magic3) { + memcpy(mtDump.amb[iBlock].mbt.abtKeyA, default_key, sizeof(default_key)); + memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpt.abtAccessBits, sizeof(mtDump.amb[iBlock].mbt.abtAccessBits)); + memcpy(mtDump.amb[iBlock].mbt.abtKeyB, default_key, sizeof(default_key)); + } else { + // Copy the keys over from our key dump and store the retrieved access bits + memcpy(mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, sizeof(mtDump.amb[iBlock].mbt.abtKeyA)); + memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpt.abtAccessBits, sizeof(mtDump.amb[iBlock].mbt.abtAccessBits)); + memcpy(mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, sizeof(mtDump.amb[iBlock].mbt.abtKeyB)); + } } } else { printf("!\nfailed to read trailer block 0x%02x\n", iBlock); @@ -392,6 +410,7 @@ write_card(int write_block_zero) bool bFailure = false; uint32_t uiWriteBlocks = 0; + //Determine if we have to unlock the card if (write_block_zero) { //If the user is attempting an unlocked write, but has a direct-write type magic card, they don't //need to use the W mode. We'll trigger a warning and let them proceed. @@ -407,8 +426,8 @@ write_card(int write_block_zero) } printf("Writing %d blocks |", uiBlocks + 1); - // Write the card from begin to end; - for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) { + // Completely write the card, end to start, but skipping block 0 + for (uiBlock = 4; uiBlock <= uiBlocks; uiBlock++) { // Authenticate everytime we reach the first sector of a new block if (is_first_block(uiBlock)) { if (bFailure) { @@ -423,44 +442,116 @@ write_card(int write_block_zero) fflush(stdout); // Try to authenticate for the current sector - if (!write_block_zero && !authenticate(uiBlock) && !bTolerateFailures) { - printf("!\nError: authentication failed for block %02x\n", uiBlock); - return false; + // If we are are writing to a chinese magic card, we've already unlocked + // If we're writing to a One Time Write card, we need to authenticate + // If we're writing something else, we'll need to authenticate + if ((write_block_zero && magic3) || !write_block_zero) { + if (!authenticate(uiBlock) && !bTolerateFailures) { + printf("!\nError: authentication failed for block %02x\n", uiBlock); + return false; + } + } + + if (is_trailer_block(uiBlock)) { + if (bFormatCard) { + // Copy the default key and reset the access bits + memcpy(mp.mpt.abtKeyA, default_key, sizeof(mp.mpt.abtKeyA)); + memcpy(mp.mpt.abtAccessBits, default_acl, sizeof(mp.mpt.abtAccessBits)); + memcpy(mp.mpt.abtKeyB, default_key, sizeof(mp.mpt.abtKeyB)); + } else { + // Copy the keys over from our key dump and store the retrieved access bits + memcpy(mp.mpt.abtKeyA, mtDump.amb[uiBlock].mbt.abtKeyA, sizeof(mp.mpt.abtKeyA)); + memcpy(mp.mpt.abtAccessBits, mtDump.amb[uiBlock].mbt.abtAccessBits, sizeof(mp.mpt.abtAccessBits)); + memcpy(mp.mpt.abtKeyB, mtDump.amb[uiBlock].mbt.abtKeyB, sizeof(mp.mpt.abtKeyB)); + } + + // Try to write the trailer + if (nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp) == false) { + printf("failed to write trailer block %d \n", uiBlock); + bFailure = true; + } + } else { + // The first block 0x00 is read only, skip this + if (uiBlock == 0 && !write_block_zero && !magic2) + continue; + + // Make sure a earlier write did not fail + if (!bFailure) { + // Try to write the data block + if (bFormatCard && uiBlock) + + memset(mp.mpd.abtData, 0x00, sizeof(mp.mpd.abtData)); + else + memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, sizeof(mp.mpd.abtData)); + // do not write a block 0 with incorrect BCC - card will be made invalid! + if (uiBlock == 0) { + if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00 && !magic2) { + printf("!\nError: incorrect BCC in MFD file!\n"); + printf("Expecting BCC=%02X\n", mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3]); + return false; + } + } + if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp)) { + bFailure = true; + printf("Failure to write to data block %i\n", uiBlock); + } + + } else { + printf("Failure during write process.\n"); + } } } + // Show if the write went well for each block + print_success_or_failure(bFailure, &uiWriteBlocks); + if ((! bTolerateFailures) && bFailure) + return false; + } - if (is_trailer_block(uiBlock)) { - if (bFormatCard) { - // Copy the default key and reset the access bits - memcpy(mp.mpt.abtKeyA, default_key, sizeof(mp.mpt.abtKeyA)); - memcpy(mp.mpt.abtAccessBits, default_acl, sizeof(mp.mpt.abtAccessBits)); - memcpy(mp.mpt.abtKeyB, default_key, sizeof(mp.mpt.abtKeyB)); - } else { - // Copy the keys over from our key dump and store the retrieved access bits - memcpy(mp.mpt.abtKeyA, mtDump.amb[uiBlock].mbt.abtKeyA, sizeof(mp.mpt.abtKeyA)); - memcpy(mp.mpt.abtAccessBits, mtDump.amb[uiBlock].mbt.abtAccessBits, sizeof(mp.mpt.abtAccessBits)); - memcpy(mp.mpt.abtKeyB, mtDump.amb[uiBlock].mbt.abtKeyB, sizeof(mp.mpt.abtKeyB)); + //Write Block 0 if necessary + if (write_block_zero || magic2 || magic3) { + for (uiBlock = 0; uiBlock < 4; uiBlock++) { + + // The first block 0x00 is read only, skip this + if (uiBlock == 0) { + //If the card is not magic, we're gonna skip over + if (write_block_zero || magic2 || magic3) { + //NOP + } else { + continue; + } + } + + if (is_first_block(uiBlock)) { + if (bFailure) { + // When a failure occured we need to redo the anti-collision + if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { + printf("!\nError: tag was removed\n"); + return false; + } + bFailure = false; + } + + fflush(stdout); + // Try to authenticate for the current sector + // If we are are writing to a chinese magic card, we've already unlocked + // If we're writing to a One Time Write, we need to authenticate + // If we're writing something else, we'll need to authenticate + if ((write_block_zero && magic3) || !write_block_zero) { + if (!authenticate(uiBlock) && !bTolerateFailures) { + printf("!\nError: authentication failed for block %02x\n", uiBlock); + return false; + } + } } - // Try to write the trailer - if (nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp) == false) { - printf("failed to write trailer block %d \n", uiBlock); - bFailure = true; - } - } else { - // The first block 0x00 is read only, skip this - if (uiBlock == 0 && !write_block_zero && !magic2) - continue; - - - // Make sure a earlier write did not fail + // Make sure a earlier write did not fail if (!bFailure) { - // Try to write the data block + // Try to write the data block if (bFormatCard && uiBlock) memset(mp.mpd.abtData, 0x00, sizeof(mp.mpd.abtData)); else memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, sizeof(mp.mpd.abtData)); - // do not write a block 0 with incorrect BCC - card will be made invalid! + // do not write a block 0 with incorrect BCC - card will be made invalid! if (uiBlock == 0) { if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00 && !magic2) { printf("!\nError: incorrect BCC in MFD file!\n"); @@ -468,15 +559,24 @@ write_card(int write_block_zero) return false; } } - if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp)) + if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp)) { bFailure = true; + printf("Failure to write to data block %i\n", uiBlock); + } + + } else { + printf("Failure during write process.\n"); } + + // Show if the write went well for each block + print_success_or_failure(bFailure, &uiWriteBlocks); + if ((! bTolerateFailures) && bFailure) + return false; + } - // Show if the write went well for each block - print_success_or_failure(bFailure, &uiWriteBlocks); - if ((!bTolerateFailures) && bFailure) - return false; + } + printf("|\n"); printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1); fflush(stdout); @@ -505,6 +605,7 @@ print_usage(const char *pcProgramName) printf(" - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n"); printf(" - MiFare Dump (MFD) that contain the keys (optional)\n"); printf(" f - Force using the keyfile even if UID does not match (optional)\n"); + printf("Examples: \n\n"); printf(" Read card to file, using key A:\n\n"); printf(" %s r a u mycard.mfd\n\n", pcProgramName); @@ -519,6 +620,54 @@ print_usage(const char *pcProgramName) printf(" %s r a U01ab23cd mycard.mfd\n\n", pcProgramName); } + +bool is_directwrite(){ + printf("Checking if Badge is DirectWrite...\n"); + + // Set default keys + memcpy(mtDump.amb[0].mbt.abtKeyA, default_key, sizeof(default_key)); + memcpy(mtDump.amb[0].mbt.abtAccessBits, default_acl, sizeof(mp.mpt.abtAccessBits)); + memcpy(mtDump.amb[0].mbt.abtKeyB, default_key, sizeof(default_key)); + + // Temporarly override bUseKeyFile + bool orig_bUseKeyFile=bUseKeyFile; + bUseKeyFile=false; + // Try to authenticate for the current sector + if (!authenticate(0)) { + printf("!\nError: authentication failed for block 0x%02x\n", 0); + bUseKeyFile=orig_bUseKeyFile; + return false; + } + // restore bUseKeyFile + bUseKeyFile=orig_bUseKeyFile; + + // Try to read block 0 + uint8_t original_b0[16]; + if (nfc_initiator_mifare_cmd(pnd, MC_READ, 0, &mp)) { + memcpy(original_b0, mp.mpd.abtData, sizeof(mp.mpd.abtData)); + printf(" Original Block 0: "); + for(int i=0;i<16;i++){ + printf("%02x", original_b0[i]); + } + printf("\n"); + printf(" Original UID: %02x%02x%02x%02x\n", + original_b0[0], original_b0[1], original_b0[2], original_b0[3]); + } else { + printf("!\nError: unable to read block 0x%02x\n", 0); + return false; + } + + printf(" Attempt to write Block 0 ...\n"); + memcpy(mp.mpd.abtData, original_b0, sizeof(original_b0)); + if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, 0, &mp)) { + printf("Failure to write to data block %i\n", 0); + return false; + } + printf(" Block 0 written successfully\n"); + + return true; +} + int main(int argc, const char *argv[]) { @@ -683,6 +832,7 @@ main(int argc, const char *argv[]) // Testing RATS int res; if ((res = get_rats()) > 0) { + printf("RATS support: yes\n"); if ((res >= 10) && (abtRx[5] == 0xc1) && (abtRx[6] == 0x05) && (abtRx[7] == 0x2f) && (abtRx[8] == 0x2f) && ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x00)) { @@ -694,8 +844,29 @@ main(int argc, const char *argv[]) && (abtRx[7] == 0x19) && (abtRx[8] == 0x10)) { magic2 = true; } + } else + printf("RATS support: no\n"); + printf("Guessing size: seems to be a %lu-byte card\n", (unsigned long) ((uiBlocks + 1) * sizeof(mifare_classic_block))); + + //If size is 4k check for direct-write card + if (uiBlocks == 0xff) { + if (is_directwrite()){ + printf("Card is DirectWrite\n"); + magic3=true; + unlock=0; + } else { + printf("Card is not DirectWrite\n"); + } } - printf("Guessing size: seems to be a %lu-byte card\n", (uiBlocks + 1) * sizeof(mifare_classic_block)); + + //Check to see if we have a One Time Write badge (magic3) + if (pbtUID[0] == 0xaa && pbtUID[1] == 0x55 && + pbtUID[2] == 0xc3 && pbtUID[3] == 0x96) { + printf("Card appears to be a One Time Write Card..\n"); + magic3 = true; + unlock = 0; + } + if (bUseKeyFile) { FILE *pfKeys = fopen(argv[5], "rb"); diff --git a/utils/nfc-mfultralight.c b/utils/nfc-mfultralight.c index 8c6859a..d115fec 100644 --- a/utils/nfc-mfultralight.c +++ b/utils/nfc-mfultralight.c @@ -10,6 +10,7 @@ * See AUTHORS file for a more comprehensive list of contributors. * Additional contributors of this file: * Copyright (C) 2013-2018 Adam Laurie + * Copyright (C) 2018-2019 Daniele Bruneo * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -292,48 +293,44 @@ unlock_card(void) static bool check_magic(void) { - bool bFailure = false; - int uid_data; - - for (uint32_t page = 0; page <= 1; page++) { - // Show if the readout went well - if (bFailure) { - // When a failure occured we need to redo the anti-collision - if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { - ERR("tag was removed"); - return false; - } - bFailure = false; - } - - uid_data = 0x00000000; - - memcpy(mp.mpd.abtData, &uid_data, sizeof uid_data); - memset(mp.mpd.abtData + 4, 0, 12); - - //Force the write without checking for errors - otherwise the writes to the sector 0 seem to complain - nfc_initiator_mifare_cmd(pnd, MC_WRITE, page, &mp); - } - - //Check that the ID is now set to 0x000000000000 + bool directWrite = true; + // Try to read pages 0, 1, 2 + uint8_t original_b0[12]; + printf("Checking if UL badge is DirectWrite...\n"); if (nfc_initiator_mifare_cmd(pnd, MC_READ, 0, &mp)) { - //printf("%u", mp.mpd.abtData); - bool result = true; - for (int i = 0; i <= 7; i++) { - if (mp.mpd.abtData[i] != 0x00) result = false; + memcpy(original_b0, mp.mpd.abtData, 12); + printf(" Original Block 0 (Pages 0-2): "); + for(int i=0;i<12;i++){ + printf("%02x", original_b0[i]); } - - if (result) { - return true; - } - + printf("\n"); + printf(" Original UID: %02x%02x%02x%02x%02x%02x%02x\n", + original_b0[0], original_b0[1], original_b0[2], original_b0[4], original_b0[5], original_b0[6], original_b0[7]); + } else { + printf("!\nError: unable to read block 0x%02x\n", 0); + directWrite = false; } - - //Initially check if we can unlock via the MF method - if (unlock_card()) { + printf(" Attempt to write Block 0 (pages 0-2) ...\n"); + for (uint32_t page = 0; page <= 2; page++) { + printf(" Writing Page %i:", page); + memcpy(mp.mpd.abtData, original_b0 + page*4, 4); + for(int i=0;i<4;i++){ + printf(" %02x", mp.mpd.abtData[i]); + } + printf("\n"); + if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, page, &mp)) { + printf(" Failure writing Page %i\n", page); + directWrite = false; + break; + } + } + if(directWrite){ + printf(" Block 0 written successfully\n"); + printf("Card is DirectWrite\n"); return true; } else { - return false; + printf("Card is not DirectWrite\n"); + return unlock_card(); } } @@ -383,9 +380,9 @@ write_card(bool write_otp, bool write_lock, bool write_dyn_lock, bool write_uid) write_uid = ((buffer[0] == 'y') || (buffer[0] == 'Y')); } - printf("Writing %d pages |", uiBlocks); /* We may need to skip 2 first pages. */ if (!write_uid) { + printf("Writing %d pages |", uiBlocks); printf("ss"); uiSkippedPages = 2; } else { @@ -393,6 +390,7 @@ write_card(bool write_otp, bool write_lock, bool write_dyn_lock, bool write_uid) printf("\nUnable to unlock card - are you sure the card is magic?\n"); return false; } + printf("Writing %d pages |", uiBlocks); } for (uint32_t page = uiSkippedPages; page < uiBlocks; page++) { @@ -527,7 +525,7 @@ main(int argc, const char *argv[]) bool bFilename = false; FILE *pfDump; - if (argc < 3) { + if (argc == 0) { print_usage(argv); exit(EXIT_FAILURE); } @@ -580,7 +578,7 @@ main(int argc, const char *argv[]) } } } - if (! bFilename) { + if (iAction != 3 && !bFilename) { ERR("Please supply a Mifare Dump filename"); exit(EXIT_FAILURE); } @@ -650,7 +648,7 @@ main(int argc, const char *argv[]) if (get_ev1_version()) { if (!bPWD) printf("WARNING: Tag is EV1 or NTAG - PASSWORD may be required\n"); - if (abtRx[6] == 0x0b) { + if (abtRx[6] == 0x0b || abtRx[6] == 0x00) { printf("EV1 type: MF0UL11 (48 bytes)\n"); uiBlocks = 20; // total number of 4 byte 'pages' iDumpSize = uiBlocks * 4; @@ -714,7 +712,7 @@ main(int argc, const char *argv[]) size_t szDump; if (((szDump = fread(&mtDump, 1, sizeof(mtDump), pfDump)) != iDumpSize && !bPart) || szDump <= 0) { - ERR("Could not read from dump file or size mismatch: %s (read %lu, expected %lu)\n", argv[2], szDump, iDumpSize); + ERR("Could not read from dump file or size mismatch: %s (read %lu, expected %lu)\n", argv[2], (unsigned long)szDump, (unsigned long)iDumpSize); fclose(pfDump); exit(EXIT_FAILURE); }