From 75e5e23c8194a016dabe0876361e1b3db65eed10 Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Mon, 2 Sep 2019 11:05:48 +0200 Subject: [PATCH 1/4] Added driver for contactless PC/SC readers - only initiator mode is supported - properties are choosen as they are available via PC/SC, the rest of the defaults are chosen to be compatible with Mifare DESFire - This commit allows reading Mifare DESFire via PC/SC with libfreefare --- libnfc/drivers/Makefile.am | 4 + libnfc/drivers/acr122_pcsc.c | 2 +- libnfc/drivers/pcsc.c | 751 +++++++++++++++++++++++++++++++++++ libnfc/drivers/pcsc.h | 35 ++ libnfc/nfc.c | 7 + m4/libnfc_drivers.m4 | 12 +- 6 files changed, 808 insertions(+), 3 deletions(-) create mode 100644 libnfc/drivers/pcsc.c create mode 100644 libnfc/drivers/pcsc.h diff --git a/libnfc/drivers/Makefile.am b/libnfc/drivers/Makefile.am index 1ac65b2..6550af2 100644 --- a/libnfc/drivers/Makefile.am +++ b/libnfc/drivers/Makefile.am @@ -7,6 +7,10 @@ libnfcdrivers_la_SOURCES = libnfcdrivers_la_CFLAGS = @DRIVERS_CFLAGS@ -I$(top_srcdir)/libnfc -I$(top_srcdir)/libnfc/buses libnfcdrivers_la_LIBADD = +if DRIVER_PCSC_ENABLED +libnfcdrivers_la_SOURCES += pcsc.c pcsc.h +endif + if DRIVER_ACR122_PCSC_ENABLED libnfcdrivers_la_SOURCES += acr122_pcsc.c acr122_pcsc.h endif diff --git a/libnfc/drivers/acr122_pcsc.c b/libnfc/drivers/acr122_pcsc.c index 1875166..f5cc02e 100644 --- a/libnfc/drivers/acr122_pcsc.c +++ b/libnfc/drivers/acr122_pcsc.c @@ -93,7 +93,7 @@ const struct pn53x_io acr122_pcsc_io; // Prototypes char *acr122_pcsc_firmware(nfc_device *pnd); -const char *supported_devices[] = { +static const char *supported_devices[] = { "ACS ACR122", // ACR122U & Touchatag, last version "ACS ACR 38U-CCID", // Touchatag, early version "ACS ACR38U-CCID", // Touchatag, early version, under MacOSX diff --git a/libnfc/drivers/pcsc.c b/libnfc/drivers/pcsc.c new file mode 100644 index 0000000..06480a9 --- /dev/null +++ b/libnfc/drivers/pcsc.c @@ -0,0 +1,751 @@ +/*- + * Free/Libre Near Field Communication (NFC) library + * + * Libnfc historical contributors: + * Copyright (C) 2019 Frank Morgner + * See AUTHORS file for a more comprehensive list of contributors. + * Additional contributors of this file: + * + * 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 pcsc.c + * @brief Driver for non-ACR122 devices behind PC/SC + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif // HAVE_CONFIG_H + +#include +#include +#include +#include +#include + +#include + +#include "drivers/pcsc.h" +#include "nfc-internal.h" + +// Bus +#ifdef __APPLE__ +#include +#include +#else +#ifndef _Win32 +#include +#endif +#include +#endif + +#define PCSC_DRIVER_NAME "pcsc" + +#include + +#define LOG_GROUP NFC_LOG_GROUP_DRIVER +#define LOG_CATEGORY "libnfc.driver.pcsc" + +static const char *supported_devices[] = { + "ACS ACR122", // ACR122U & Touchatag, last version + "ACS ACR 38U-CCID", // Touchatag, early version + "ACS ACR38U-CCID", // Touchatag, early version, under MacOSX + "ACS AET65", // Touchatag using CCID driver version >= 1.4.6 + " CCID USB", // ?? + NULL +}; + +struct pcsc_data { + SCARDHANDLE hCard; + SCARD_IO_REQUEST ioCard; + DWORD dwShareMode; + DWORD last_error; +}; + +#define DRIVER_DATA(pnd) ((struct pcsc_data*)(pnd->driver_data)) + +static SCARDCONTEXT _SCardContext; +static int _iSCardContextRefCount = 0; + +const nfc_baud_rate pcsc_supported_brs[] = {NBR_106, NBR_424, 0}; +const nfc_modulation_type pcsc_supported_mts[] = {NMT_ISO14443A, NMT_ISO14443B, 0}; + +SCARDCONTEXT * +pcsc_get_scardcontext(void) +{ + if (_iSCardContextRefCount == 0) { + if (SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &_SCardContext) != SCARD_S_SUCCESS) + return NULL; + } + _iSCardContextRefCount++; + + return &_SCardContext; +} + +void +pcsc_free_scardcontext(void) +{ + if (_iSCardContextRefCount) { + _iSCardContextRefCount--; + if (!_iSCardContextRefCount) { + SCardReleaseContext(_SCardContext); + } + } +} + +#define ICC_TYPE_UNKNOWN 0 +#define ICC_TYPE_14443A 5 +#define ICC_TYPE_14443B 6 + +uint8_t pcsc_get_icc_type(struct nfc_device *pnd) +{ + uint8_t it = 0; + DWORD dwItLen = sizeof it; + DRIVER_DATA(pnd)->last_error = SCardGetAttrib(DRIVER_DATA(pnd)->hCard, SCARD_ATTR_ICC_TYPE_PER_ATR, &it, &dwItLen); + return it; +} + +int pcsc_get_uid(struct nfc_device *pnd, uint8_t *puid, size_t szuid) +{ + uint8_t get_data[] = {0xFF, 0xCA, 0x00, 0x00, 0x00}, data[256 + 2]; + DWORD dwRxLen = sizeof data; + + LOG_HEX(NFC_LOG_GROUP_COM, "TX", get_data, sizeof get_data); + DRIVER_DATA(pnd)->last_error = SCardTransmit(DRIVER_DATA(pnd)->hCard, &(DRIVER_DATA(pnd)->ioCard), get_data, sizeof get_data, NULL, data, &dwRxLen); + if ((DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS) + || dwRxLen < 2) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reader doesn't support request for UID"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + LOG_HEX(NFC_LOG_GROUP_COM, "RX", data, dwRxLen); + if (szuid < (size_t) dwRxLen - 2) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Malformed response code"); + pnd->last_error = NFC_EINVARG; + return pnd->last_error; + } + memcpy(puid, data, dwRxLen - 2); + return dwRxLen - 2; +} + +int pcsc_props_to_target(uint8_t it, const uint8_t *patr, size_t szatr, const uint8_t *puid, int szuid, const nfc_modulation_type nmt, nfc_target *pnt) +{ + if (NULL != pnt) { + switch (nmt) { + case NMT_ISO14443A: + if ((it == ICC_TYPE_UNKNOWN || it == ICC_TYPE_14443A) + && (szuid <= 0 || szuid == 4 || szuid == 7 || szuid == 10) + && NULL != patr && szatr >= 5 + && patr[0] == 0x3B + && patr[1] == (0x80 | ((uint8_t)(szatr - 5))) + && patr[2] == 0x80 + && patr[3] == 0x01) { + memset(pnt, 0, sizeof * pnt); + pnt->nm.nmt = NMT_ISO14443A; + pnt->nm.nbr = pcsc_supported_brs[0]; + if (szuid > 0) { + memcpy(pnt->nti.nai.abtUid, puid, szuid); + pnt->nti.nai.szUidLen = szuid; + } + /* SAK_ISO14443_4_COMPLIANT */ + pnt->nti.nai.btSak = 0x20; + /* Choose TL, TA, TB, TC according to Mifare DESFire */ + memcpy(pnt->nti.nai.abtAts, "\x75\x77\x81\x02", 4); + /* copy historical bytes */ + memcpy(pnt->nti.nai.abtAts + 4, patr + 4, (uint8_t)(szatr - 5)); + pnt->nti.nai.szAtsLen = 4 + (uint8_t)(szatr - 5); + return NFC_SUCCESS; + } + break; + case NMT_ISO14443B: + if ((ICC_TYPE_UNKNOWN == 0 || ICC_TYPE_14443B == 6) + && (szuid <= 0 || szuid == 8) + && NULL != patr && szatr == 5 + 8 + && patr[0] == 0x3B + && patr[1] == (0x80 | 0x08) + && patr[2] == 0x80 + && patr[3] == 0x01) { + memset(pnt, 0, sizeof * pnt); + pnt->nm.nmt = NMT_ISO14443B; + pnt->nm.nbr = pcsc_supported_brs[0]; + memcpy(pnt->nti.nbi.abtApplicationData, patr + 4, 4); + memcpy(pnt->nti.nbi.abtProtocolInfo, patr + 8, 3); + /* PI_ISO14443_4_SUPPORTED */ + pnt->nti.nbi.abtProtocolInfo[1] = 0x01; + return NFC_SUCCESS; + } + break; + default: + break; + } + } + return NFC_EINVARG; +} + +#define PCSC_MAX_DEVICES 16 +/** + * @brief List opened devices + * + * Probe PCSC to find any reader but the ACR122 devices (ACR122U and Touchatag/Tikitag). + * + * @param connstring array of nfc_connstring where found device's connection strings will be stored. + * @param connstrings_len size of connstrings array. + * @return number of devices found. + */ +static size_t +pcsc_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) +{ + (void) context; + size_t szPos = 0; + char acDeviceNames[256 + 64 * PCSC_MAX_DEVICES]; + size_t szDeviceNamesLen = sizeof(acDeviceNames); + SCARDCONTEXT *pscc; + int i; + + // Clear the reader list + memset(acDeviceNames, '\0', szDeviceNamesLen); + + // Test if context succeeded + if (!(pscc = pcsc_get_scardcontext())) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Warning: %s", "PCSC context not found (make sure PCSC daemon is running)."); + return 0; + } + // Retrieve the string array of all available pcsc readers + DWORD dwDeviceNamesLen = szDeviceNamesLen; + if (SCardListReaders(*pscc, NULL, acDeviceNames, &dwDeviceNamesLen) != SCARD_S_SUCCESS) + return 0; + + size_t device_found = 0; + while ((acDeviceNames[szPos] != '\0') && (device_found < connstrings_len)) { + bool bSupported = false; + for (i = 0; supported_devices[i] && !bSupported; i++) { + int l = strlen(supported_devices[i]); + bSupported = 0 == !strncmp(supported_devices[i], acDeviceNames + szPos, l); + } + + if (bSupported) { + // Supported non-ACR122 device found + snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s", PCSC_DRIVER_NAME, acDeviceNames + szPos); + device_found++; + } else { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Skipping PCSC device [%s] as it is supported by acr122_pcsc driver.", acDeviceNames + szPos); + } + + // Find next device name position + while (acDeviceNames[szPos++] != '\0'); + } + pcsc_free_scardcontext(); + + return device_found; +} + +struct pcsc_descriptor { + char *pcsc_device_name; +}; + +static nfc_device * +pcsc_open(const nfc_context *context, const nfc_connstring connstring) +{ + struct pcsc_descriptor ndd; + int connstring_decode_level = connstring_decode(connstring, PCSC_DRIVER_NAME, "pcsc", &ndd.pcsc_device_name, NULL); + + if (connstring_decode_level < 1) { + return NULL; + } + + nfc_connstring fullconnstring; + if (connstring_decode_level == 1) { + // Device was not specified, take the first one we can find + size_t szDeviceFound = pcsc_scan(context, &fullconnstring, 1); + if (szDeviceFound < 1) + return NULL; + connstring_decode_level = connstring_decode(fullconnstring, PCSC_DRIVER_NAME, "pcsc", &ndd.pcsc_device_name, NULL); + if (connstring_decode_level < 2) { + return NULL; + } + } else { + memcpy(fullconnstring, connstring, sizeof(nfc_connstring)); + } + if (strlen(ndd.pcsc_device_name) < 5) { // We can assume it's a reader ID as pcsc_name always ends with "NN NN" + // Device was not specified, only ID, retrieve it + size_t index; + if (sscanf(ndd.pcsc_device_name, "%4" SCNuPTR, &index) != 1) { + free(ndd.pcsc_device_name); + return NULL; + } + nfc_connstring *ncs = malloc(sizeof(nfc_connstring) * (index + 1)); + if (!ncs) { + perror("malloc"); + free(ndd.pcsc_device_name); + return NULL; + } + size_t szDeviceFound = pcsc_scan(context, ncs, index + 1); + if (szDeviceFound < index + 1) { + free(ncs); + free(ndd.pcsc_device_name); + return NULL; + } + strncpy(fullconnstring, ncs[index], sizeof(nfc_connstring)); + fullconnstring[sizeof(nfc_connstring) - 1] = '\0'; + free(ncs); + connstring_decode_level = connstring_decode(fullconnstring, PCSC_DRIVER_NAME, "pcsc", &ndd.pcsc_device_name, NULL); + + if (connstring_decode_level < 2) { + free(ndd.pcsc_device_name); + return NULL; + } + } + + nfc_device *pnd = nfc_device_new(context, fullconnstring); + if (!pnd) { + perror("malloc"); + goto error; + } + pnd->driver_data = malloc(sizeof(struct pcsc_data)); + if (!pnd->driver_data) { + perror("malloc"); + goto error; + } + + SCARDCONTEXT *pscc; + + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open %s", ndd.pcsc_device_name); + // Test if context succeeded + if (!(pscc = pcsc_get_scardcontext())) + goto error; + DRIVER_DATA(pnd)->last_error = SCardConnect(*pscc, ndd.pcsc_device_name, SCARD_SHARE_DIRECT, 0, &(DRIVER_DATA(pnd)->hCard), (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol)); + if (DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS) { + // We can not connect to this device. + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC connect failed"); + goto error; + } + // Configure I/O settings for card communication + DRIVER_DATA(pnd)->ioCard.cbPciLength = sizeof(SCARD_IO_REQUEST); + DRIVER_DATA(pnd)->dwShareMode = SCARD_SHARE_DIRECT; + + // Done, we found the reader we are looking for + snprintf(pnd->name, sizeof(pnd->name), "%s", ndd.pcsc_device_name); + + pnd->driver = &pcsc_driver; + + free(ndd.pcsc_device_name); + return pnd; + +error: + free(ndd.pcsc_device_name); + nfc_device_free(pnd); + return NULL; +} + +static void +pcsc_close(nfc_device *pnd) +{ + SCardDisconnect(DRIVER_DATA(pnd)->hCard, SCARD_LEAVE_CARD); + pcsc_free_scardcontext(); + + nfc_device_free(pnd); +} + +static const char *stringify_error(const LONG pcscError) +{ + static char strError[75]; + const char *msg = NULL; + + switch (pcscError) { + case SCARD_S_SUCCESS: + msg = "Command successful."; + break; + case SCARD_F_INTERNAL_ERROR: + msg = "Internal error."; + break; + case SCARD_E_CANCELLED: + msg = "Command cancelled."; + break; + case SCARD_E_INVALID_HANDLE: + msg = "Invalid handle."; + break; + case SCARD_E_INVALID_PARAMETER: + msg = "Invalid parameter given."; + break; + case SCARD_E_INVALID_TARGET: + msg = "Invalid target given."; + break; + case SCARD_E_NO_MEMORY: + msg = "Not enough memory."; + break; + case SCARD_F_WAITED_TOO_LONG: + msg = "Waited too long."; + break; + case SCARD_E_INSUFFICIENT_BUFFER: + msg = "Insufficient buffer."; + break; + case SCARD_E_UNKNOWN_READER: + msg = "Unknown reader specified."; + break; + case SCARD_E_TIMEOUT: + msg = "Command timeout."; + break; + case SCARD_E_SHARING_VIOLATION: + msg = "Sharing violation."; + break; + case SCARD_E_NO_SMARTCARD: + msg = "No smart card inserted."; + break; + case SCARD_E_UNKNOWN_CARD: + msg = "Unknown card."; + break; + case SCARD_E_CANT_DISPOSE: + msg = "Cannot dispose handle."; + break; + case SCARD_E_PROTO_MISMATCH: + msg = "Card protocol mismatch."; + break; + case SCARD_E_NOT_READY: + msg = "Subsystem not ready."; + break; + case SCARD_E_INVALID_VALUE: + msg = "Invalid value given."; + break; + case SCARD_E_SYSTEM_CANCELLED: + msg = "System cancelled."; + break; + case SCARD_F_COMM_ERROR: + msg = "RPC transport error."; + break; + case SCARD_F_UNKNOWN_ERROR: + msg = "Unknown error."; + break; + case SCARD_E_INVALID_ATR: + msg = "Invalid ATR."; + break; + case SCARD_E_NOT_TRANSACTED: + msg = "Transaction failed."; + break; + case SCARD_E_READER_UNAVAILABLE: + msg = "Reader is unavailable."; + break; + /* case SCARD_P_SHUTDOWN: */ + case SCARD_E_PCI_TOO_SMALL: + msg = "PCI struct too small."; + break; + case SCARD_E_READER_UNSUPPORTED: + msg = "Reader is unsupported."; + break; + case SCARD_E_DUPLICATE_READER: + msg = "Reader already exists."; + break; + case SCARD_E_CARD_UNSUPPORTED: + msg = "Card is unsupported."; + break; + case SCARD_E_NO_SERVICE: + msg = "Service not available."; + break; + case SCARD_E_SERVICE_STOPPED: + msg = "Service was stopped."; + break; + /* case SCARD_E_UNEXPECTED: */ + /* case SCARD_E_ICC_CREATEORDER: */ + /* case SCARD_E_UNSUPPORTED_FEATURE: */ + /* case SCARD_E_DIR_NOT_FOUND: */ + /* case SCARD_E_NO_DIR: */ + /* case SCARD_E_NO_FILE: */ + /* case SCARD_E_NO_ACCESS: */ + /* case SCARD_E_WRITE_TOO_MANY: */ + /* case SCARD_E_BAD_SEEK: */ + /* case SCARD_E_INVALID_CHV: */ + /* case SCARD_E_UNKNOWN_RES_MNG: */ + /* case SCARD_E_NO_SUCH_CERTIFICATE: */ + /* case SCARD_E_CERTIFICATE_UNAVAILABLE: */ + case SCARD_E_NO_READERS_AVAILABLE: + msg = "Cannot find a smart card reader."; + break; + /* case SCARD_E_COMM_DATA_LOST: */ + /* case SCARD_E_NO_KEY_CONTAINER: */ + /* case SCARD_E_SERVER_TOO_BUSY: */ + case SCARD_W_UNSUPPORTED_CARD: + msg = "Card is not supported."; + break; + case SCARD_W_UNRESPONSIVE_CARD: + msg = "Card is unresponsive."; + break; + case SCARD_W_UNPOWERED_CARD: + msg = "Card is unpowered."; + break; + case SCARD_W_RESET_CARD: + msg = "Card was reset."; + break; + case SCARD_W_REMOVED_CARD: + msg = "Card was removed."; + break; + /* case SCARD_W_SECURITY_VIOLATION: */ + /* case SCARD_W_WRONG_CHV: */ + /* case SCARD_W_CHV_BLOCKED: */ + /* case SCARD_W_EOF: */ + /* case SCARD_W_CANCELLED_BY_USER: */ + /* case SCARD_W_CARD_NOT_AUTHENTICATED: */ + + case SCARD_E_UNSUPPORTED_FEATURE: + msg = "Feature not supported."; + break; + default: + (void)snprintf(strError, sizeof(strError) - 1, "Unknown error: 0x%08lX", + pcscError); + }; + + if (msg) + (void)strncpy(strError, msg, sizeof(strError)); + else + (void)snprintf(strError, sizeof(strError) - 1, "Unknown error: 0x%08lX", + pcscError); + + /* add a null byte */ + strError[sizeof(strError) - 1] = '\0'; + + return strError; +} + +const char * +pcsc_strerror(const struct nfc_device *pnd) +{ + return stringify_error(DRIVER_DATA(pnd)->last_error); +} + +int pcsc_initiator_init(struct nfc_device *pnd) +{ + (void) pnd; + return NFC_SUCCESS; +} + +int pcsc_initiator_select_passive_target(struct nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt) +{ + uint8_t pbAtr[MAX_ATR_SIZE]; + uint8_t uid[10]; + DWORD dwState, dwProtocol, dwReaderLen, dwAtrLen = sizeof pbAtr; + + (void) pbtInitData; + (void) szInitData; + + if (nm.nbr != pcsc_supported_brs[0] && nm.nbr != pcsc_supported_brs[1]) + return NFC_EINVARG; + DRIVER_DATA(pnd)->last_error = SCardStatus(DRIVER_DATA(pnd)->hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen); + if ((DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS + && DRIVER_DATA(pnd)->last_error != SCARD_W_RESET_CARD) + || !(dwState & SCARD_PRESENT)) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "No target present"); + return NFC_ENOTSUCHDEV; + } + uint8_t it = pcsc_get_icc_type(pnd); + int szuid = pcsc_get_uid(pnd, uid, sizeof uid); + if (pcsc_props_to_target(it, pbAtr, dwAtrLen, uid, szuid, nm.nmt, pnt) != NFC_SUCCESS + || (DRIVER_DATA(pnd)->last_error = SCardReconnect((DRIVER_DATA(pnd)->hCard), SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_LEAVE_CARD, (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol))) != SCARD_S_SUCCESS) { + // We can not reconnect to this device. + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC reconnect failed"); + return NFC_EIO; + } + DRIVER_DATA(pnd)->dwShareMode = SCARD_SHARE_SHARED; + return 1; +} + +int pcsc_initiator_deselect_target(struct nfc_device *pnd) +{ + DRIVER_DATA(pnd)->last_error = SCardReconnect((DRIVER_DATA(pnd)->hCard), SCARD_SHARE_DIRECT, 0, SCARD_LEAVE_CARD, (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol)); + if (DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS + && DRIVER_DATA(pnd)->last_error != SCARD_W_RESET_CARD) { + // We can not reconnect to this device. + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC reconnect failed"); + return NFC_EIO; + } + DRIVER_DATA(pnd)->dwShareMode = SCARD_SHARE_DIRECT; + return NFC_SUCCESS; +} + +int pcsc_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout) +{ + // FIXME: timeout is not handled + (void) timeout; + + DWORD dwRxLen = szRx; + + LOG_HEX(NFC_LOG_GROUP_COM, "TX", pbtTx, szTx); + DRIVER_DATA(pnd)->last_error = SCardTransmit(DRIVER_DATA(pnd)->hCard, &(DRIVER_DATA(pnd)->ioCard), pbtTx, szTx, NULL, pbtRx, &dwRxLen); + if (DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC transmit failed"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + LOG_HEX(NFC_LOG_GROUP_COM, "RX", pbtRx, dwRxLen); + + return dwRxLen; +} + +int pcsc_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt) +{ + uint8_t pbAtr[MAX_ATR_SIZE]; + DWORD dwState, dwProtocol, dwReaderLen, dwAtrLen = sizeof pbAtr; + nfc_target nt; + + DRIVER_DATA(pnd)->last_error = SCardStatus(DRIVER_DATA(pnd)->hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen); + if ((DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS + && DRIVER_DATA(pnd)->last_error != SCARD_W_RESET_CARD) + || !(dwState & SCARD_PRESENT)) { + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + if (pnt) { + if (pcsc_props_to_target(ICC_TYPE_UNKNOWN, pbAtr, dwAtrLen, NULL, 0, pnt->nm.nmt, &nt) != NFC_SUCCESS + || pnt->nm.nmt != nt.nm.nmt || pnt->nm.nbr != nt.nm.nbr) { + pnd->last_error = NFC_EINVARG; + return pnd->last_error; + } + } + return NFC_SUCCESS; +} + +int pcsc_device_set_property_bool(struct nfc_device *pnd, const nfc_property property, const bool bEnable) +{ + (void) pnd; + switch (property) { + case NP_INFINITE_SELECT: + // ignore + return NFC_SUCCESS; + case NP_AUTO_ISO14443_4: + case NP_EASY_FRAMING: + case NP_FORCE_ISO14443_A: + case NP_HANDLE_CRC: + case NP_HANDLE_PARITY: + case NP_FORCE_SPEED_106: + if (bEnable == true) + return NFC_SUCCESS; + break; + case NP_ACCEPT_INVALID_FRAMES: + case NP_ACCEPT_MULTIPLE_FRAMES: + if (bEnable == false) + return NFC_SUCCESS; + break; + case NP_ACTIVATE_FIELD: + if (bEnable == false) { + SCardReconnect(DRIVER_DATA(pnd)->hCard, DRIVER_DATA(pnd)->dwShareMode, DRIVER_DATA(pnd)->ioCard.dwProtocol, SCARD_RESET_CARD, (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol)); + } + return NFC_SUCCESS; + default: + break; + } + return NFC_EDEVNOTSUPP; +} + +int pcsc_get_supported_modulation(struct nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt) +{ + (void) pnd; + if (mode == N_TARGET || NULL == supported_mt) + return NFC_EINVARG; + *supported_mt = pcsc_supported_mts; + return NFC_SUCCESS; +} + +int pcsc_get_supported_baud_rate(struct nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) +{ + (void) pnd; + (void) nmt; + if (mode == N_TARGET || NULL == supported_br) + return NFC_EINVARG; + *supported_br = pcsc_supported_brs; + return NFC_SUCCESS; +} + +int +pcsc_get_information_about(nfc_device *pnd, char **pbuf) +{ + LPBYTE name = NULL, version = NULL, type = NULL, serial = NULL; + DWORD name_len = SCARD_AUTOALLOCATE, version_len = SCARD_AUTOALLOCATE, + type_len = SCARD_AUTOALLOCATE, serial_len = SCARD_AUTOALLOCATE; + int res = NFC_SUCCESS; + SCARDCONTEXT *pscc; + + if (!(pscc = pcsc_get_scardcontext())) { + pnd->last_error = NFC_ESOFT; + return pnd->last_error; + } + + SCardGetAttrib(DRIVER_DATA(pnd)->hCard, SCARD_ATTR_VENDOR_NAME, (LPBYTE)&name, &name_len); + SCardGetAttrib(DRIVER_DATA(pnd)->hCard, SCARD_ATTR_VENDOR_IFD_TYPE, (LPBYTE)&type, &type_len); + SCardGetAttrib(DRIVER_DATA(pnd)->hCard, SCARD_ATTR_VENDOR_IFD_VERSION, (LPBYTE)&version, &version_len); + SCardGetAttrib(DRIVER_DATA(pnd)->hCard, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, (LPBYTE)&serial, &serial_len); + + *pbuf = malloc(name_len + type_len + version_len + serial_len + 30); + if (! *pbuf) { + res = NFC_ESOFT; + goto error; + } + sprintf((char *) *pbuf, + "%s" // model + "%s%s" // version + " (%s)" // vendor + "%s%s\n" // serial + , + name && name_len > 0 && name[0] != '\0' + ? (char *)name : "unknown model", + version && version_len > 0 && version[0] != '\0' + ? " " : "", version_len > 0 ? (char *)version : "", + type && type_len > 0 && type[0] != '\0' + ? (char *)type : "unknown vendor", + serial && serial_len > 0 && serial[0] != '\0' + ? "\nserial: " : "", serial_len > 0 ? (char *)serial : ""); + +error: + SCardFreeMemory(*pscc, name); + SCardFreeMemory(*pscc, type); + SCardFreeMemory(*pscc, version); + SCardFreeMemory(*pscc, serial); + + pnd->last_error = res; + return pnd->last_error; +} + +const struct nfc_driver pcsc_driver = { + .name = PCSC_DRIVER_NAME, + .scan = pcsc_scan, + .open = pcsc_open, + .close = pcsc_close, + .strerror = pcsc_strerror, + + .initiator_init = pcsc_initiator_init, + .initiator_init_secure_element = NULL, // No secure-element support + .initiator_select_passive_target = pcsc_initiator_select_passive_target, + .initiator_poll_target = NULL, + .initiator_select_dep_target = NULL, + .initiator_deselect_target = NULL, + .initiator_transceive_bytes = pcsc_initiator_transceive_bytes, + .initiator_transceive_bits = NULL, + .initiator_transceive_bytes_timed = NULL, + .initiator_transceive_bits_timed = NULL, + .initiator_target_is_present = pcsc_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 = pcsc_device_set_property_bool, + .device_set_property_int = NULL, + .get_supported_modulation = pcsc_get_supported_modulation, + .get_supported_baud_rate = pcsc_get_supported_baud_rate, + .device_get_information_about = pcsc_get_information_about, + + .abort_command = NULL, // Abort is not supported in this driver + .idle = NULL, + .powerdown = NULL, +}; + diff --git a/libnfc/drivers/pcsc.h b/libnfc/drivers/pcsc.h new file mode 100644 index 0000000..f96030d --- /dev/null +++ b/libnfc/drivers/pcsc.h @@ -0,0 +1,35 @@ +/*- + * Free/Libre Near Field Communication (NFC) library + * + * Libnfc historical contributors: + * Copyright (C) 2019 Frank Morgner + * See AUTHORS file for a more comprehensive list of contributors. + * Additional contributors of this file: + * + * 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 pcsc.h + * @brief Driver for non-ACR122 devices (behind PC/SC daemon) + */ + +#ifndef __NFC_DRIVER_PCSC_H__ +#define __NFC_DRIVER_PCSC_H__ + +#include + +extern const struct nfc_driver pcsc_driver; + +#endif // ! __NFC_DRIVER_PCSC_H__ diff --git a/libnfc/nfc.c b/libnfc/nfc.c index 636697d..46d49c0 100644 --- a/libnfc/nfc.c +++ b/libnfc/nfc.c @@ -87,6 +87,10 @@ #include "target-subr.h" #include "drivers.h" +#if defined (DRIVER_PCSC_ENABLED) +# include "drivers/pcsc.h" +#endif /* DRIVER_PCSC_ENABLED */ + #if defined (DRIVER_ACR122_PCSC_ENABLED) # include "drivers/acr122_pcsc.h" #endif /* DRIVER_ACR122_PCSC_ENABLED */ @@ -136,6 +140,9 @@ nfc_drivers_init(void) #if defined (DRIVER_PN53X_USB_ENABLED) nfc_register_driver(&pn53x_usb_driver); #endif /* DRIVER_PN53X_USB_ENABLED */ +#if defined (DRIVER_PCSC_ENABLED) + nfc_register_driver(&pcsc_driver); +#endif /* DRIVER_ACR122_PCSC_ENABLED */ #if defined (DRIVER_ACR122_PCSC_ENABLED) nfc_register_driver(&acr122_pcsc_driver); #endif /* DRIVER_ACR122_PCSC_ENABLED */ diff --git a/m4/libnfc_drivers.m4 b/m4/libnfc_drivers.m4 index 4672539..a7219b9 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: 'pcsc', '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.]), [ 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="pcsc acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart" if test x"$spi_available" = x"yes" then DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_spi" @@ -50,6 +50,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS], DRIVERS_CFLAGS="" + driver_pcsc_enabled="no" driver_acr122_pcsc_enabled="no" driver_acr122_usb_enabled="no" driver_acr122s_enabled="no" @@ -62,6 +63,11 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS], for driver in ${DRIVER_BUILD_LIST} do case "${driver}" in + pcsc) + pcsc_required="yes" + driver_pcsc_enabled="yes" + DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PCSC_ENABLED" + ;; acr122_pcsc) pcsc_required="yes" driver_acr122_pcsc_enabled="yes" @@ -109,6 +115,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS], done AC_SUBST(DRIVERS_CFLAGS) AM_CONDITIONAL(DRIVER_ACR122_PCSC_ENABLED, [test x"$driver_acr122_pcsc_enabled" = xyes]) + AM_CONDITIONAL(DRIVER_PCSC_ENABLED, [test x"$driver_pcsc_enabled" = xyes]) AM_CONDITIONAL(DRIVER_ACR122_USB_ENABLED, [test x"$driver_acr122_usb_enabled" = xyes]) AM_CONDITIONAL(DRIVER_ACR122S_ENABLED, [test x"$driver_acr122s_enabled" = xyes]) AM_CONDITIONAL(DRIVER_PN53X_USB_ENABLED, [test x"$driver_pn53x_usb_enabled" = xyes]) @@ -121,6 +128,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS], AC_DEFUN([LIBNFC_DRIVERS_SUMMARY],[ echo echo "Selected drivers:" +echo " pcsc............. $driver_pcsc_enabled" echo " acr122_pcsc...... $driver_acr122_pcsc_enabled" echo " acr122_usb....... $driver_acr122_usb_enabled" echo " acr122s.......... $driver_acr122s_enabled" From 959a992a81c48112e6e0df5fcf9a38eadeb15cd1 Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Tue, 3 Sep 2019 15:50:28 +0200 Subject: [PATCH 2/4] added PC/SC driver to cmake --- CMakeLists.txt | 3 +++ cmake/modules/LibnfcDrivers.cmake | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 576f6e7..03097ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,6 +138,9 @@ IF(NOT WIN32) IF(LIBNFC_DRIVER_PN53X_USB) SET(PKG_REQ ${PKG_REQ} "libusb") ENDIF(LIBNFC_DRIVER_PN53X_USB) + IF(LIBNFC_DRIVER_PCSC) + SET(PKG_REQ ${PKG_REQ} "libpcsclite") + ENDIF(LIBNFC_DRIVER_ACR122) IF(LIBNFC_DRIVER_ACR122) SET(PKG_REQ ${PKG_REQ} "libpcsclite") ENDIF(LIBNFC_DRIVER_ACR122) diff --git a/cmake/modules/LibnfcDrivers.cmake b/cmake/modules/LibnfcDrivers.cmake index a79c229..e3806d4 100644 --- a/cmake/modules/LibnfcDrivers.cmake +++ b/cmake/modules/LibnfcDrivers.cmake @@ -1,3 +1,4 @@ +SET(LIBNFC_DRIVER_PCSC OFF CACHE BOOL "Enable PC/SC reader support (Depends on PC/SC)") SET(LIBNFC_DRIVER_ACR122_PCSC OFF CACHE BOOL "Enable ACR122 support (Depends on PC/SC)") SET(LIBNFC_DRIVER_ACR122_USB ON CACHE BOOL "Enable ACR122 support (Direct USB connection)") SET(LIBNFC_DRIVER_ACR122S ON CACHE BOOL "Enable ACR122S support (Use serial port)") @@ -12,6 +13,12 @@ ENDIF(WIN32) SET(LIBNFC_DRIVER_PN532_UART ON CACHE BOOL "Enable PN532 UART support (Use serial port)") SET(LIBNFC_DRIVER_PN53X_USB ON CACHE BOOL "Enable PN531 and PN531 USB support (Depends on libusb)") +IF(LIBNFC_DRIVER_PCSC) + FIND_PACKAGE(PCSC REQUIRED) + ADD_DEFINITIONS("-DDRIVER_PCSC_ENABLED") + SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pcsc") +ENDIF(LIBNFC_DRIVER_PCSC) + IF(LIBNFC_DRIVER_ACR122_PCSC) FIND_PACKAGE(PCSC REQUIRED) ADD_DEFINITIONS("-DDRIVER_ACR122_PCSC_ENABLED") From 8e7a8e1b61c72a19e5d0d70ef43a16919bbdf3ca Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Tue, 3 Sep 2019 15:51:38 +0200 Subject: [PATCH 3/4] cmake: fixed pcsc requirement for acr122_pcsc --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 03097ea..5d8b5a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,9 +141,9 @@ IF(NOT WIN32) IF(LIBNFC_DRIVER_PCSC) SET(PKG_REQ ${PKG_REQ} "libpcsclite") ENDIF(LIBNFC_DRIVER_ACR122) - IF(LIBNFC_DRIVER_ACR122) + IF(LIBNFC_DRIVER_ACR122_PCSC) SET(PKG_REQ ${PKG_REQ} "libpcsclite") - ENDIF(LIBNFC_DRIVER_ACR122) + ENDIF(LIBNFC_DRIVER_ACR122_PCSC) # CMake lists are separated by a semi colon, replace with colon STRING(REPLACE ";" "," PKG_CONFIG_REQUIRES "${PKG_REQ}") CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libnfc.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libnfc.pc @ONLY) From 6f793da1c139fb71c483fefad036a189c76369dc Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Tue, 3 Sep 2019 22:44:44 +0200 Subject: [PATCH 4/4] cleanup --- libnfc/drivers/pcsc.c | 182 +++++++++++++++++++++++++++--------------- 1 file changed, 119 insertions(+), 63 deletions(-) diff --git a/libnfc/drivers/pcsc.c b/libnfc/drivers/pcsc.c index 06480a9..d89ae7e 100644 --- a/libnfc/drivers/pcsc.c +++ b/libnfc/drivers/pcsc.c @@ -109,35 +109,92 @@ pcsc_free_scardcontext(void) #define ICC_TYPE_14443A 5 #define ICC_TYPE_14443B 6 +int pcsc_transmit(struct nfc_device *pnd, const uint8_t *tx, const size_t tx_len, uint8_t *rx, size_t *rx_len) +{ + struct pcsc_data *data = pnd->driver_data; + DWORD dw_rx_len = *rx_len; + + LOG_HEX(NFC_LOG_GROUP_COM, "TX", tx, tx_len); + + data->last_error = SCardTransmit(data->hCard, &data->ioCard, tx, tx_len, + NULL, rx, &dw_rx_len); + if (data->last_error != SCARD_S_SUCCESS) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC transmit failed"); + return NFC_EIO; + } + *rx_len = dw_rx_len; + + LOG_HEX(NFC_LOG_GROUP_COM, "RX", rx, *rx_len); + + return NFC_SUCCESS; +} + +int pcsc_get_status(struct nfc_device *pnd, int *target_present, uint8_t *atr, size_t *atr_len) +{ + struct pcsc_data *data = pnd->driver_data; + DWORD dw_atr_len = *atr_len, reader_len, state, protocol; + + data->last_error = SCardStatus(data->hCard, NULL, &reader_len, &state, &protocol, atr, &dw_atr_len); + if (data->last_error != SCARD_S_SUCCESS + && data->last_error != SCARD_W_RESET_CARD) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Get status failed"); + return NFC_EIO; + } + + *target_present = state & SCARD_PRESENT; + *atr_len = dw_atr_len; + + return NFC_SUCCESS; +} + +int pcsc_reconnect(struct nfc_device *pnd, DWORD share_mode, DWORD protocol, DWORD disposition) +{ + struct pcsc_data *data = pnd->driver_data; + + data->last_error = SCardReconnect(data->hCard, share_mode, protocol, disposition, &data->ioCard.dwProtocol); + if (data->last_error != SCARD_S_SUCCESS + && data->last_error != SCARD_W_RESET_CARD) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reconnect failed"); + return NFC_EIO; + } + + data->dwShareMode = share_mode; + + return NFC_SUCCESS; +} + uint8_t pcsc_get_icc_type(struct nfc_device *pnd) { + struct pcsc_data *data = pnd->driver_data; uint8_t it = 0; DWORD dwItLen = sizeof it; - DRIVER_DATA(pnd)->last_error = SCardGetAttrib(DRIVER_DATA(pnd)->hCard, SCARD_ATTR_ICC_TYPE_PER_ATR, &it, &dwItLen); + data->last_error = SCardGetAttrib(data->hCard, SCARD_ATTR_ICC_TYPE_PER_ATR, &it, &dwItLen); return it; } -int pcsc_get_uid(struct nfc_device *pnd, uint8_t *puid, size_t szuid) +int pcsc_get_uid(struct nfc_device *pnd, uint8_t *uid, size_t uid_len) { - uint8_t get_data[] = {0xFF, 0xCA, 0x00, 0x00, 0x00}, data[256 + 2]; - DWORD dwRxLen = sizeof data; + const uint8_t get_data[] = {0xFF, 0xCA, 0x00, 0x00, 0x00}; + uint8_t resp[256 + 2]; + size_t resp_len = sizeof resp; - LOG_HEX(NFC_LOG_GROUP_COM, "TX", get_data, sizeof get_data); - DRIVER_DATA(pnd)->last_error = SCardTransmit(DRIVER_DATA(pnd)->hCard, &(DRIVER_DATA(pnd)->ioCard), get_data, sizeof get_data, NULL, data, &dwRxLen); - if ((DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS) - || dwRxLen < 2) { + pnd->last_error = pcsc_transmit(pnd, get_data, sizeof get_data, resp, &resp_len); + if (pnd->last_error != NFC_SUCCESS) + return pnd->last_error; + + if (resp_len < 2) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reader doesn't support request for UID"); - pnd->last_error = NFC_EIO; + pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } - LOG_HEX(NFC_LOG_GROUP_COM, "RX", data, dwRxLen); - if (szuid < (size_t) dwRxLen - 2) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Malformed response code"); - pnd->last_error = NFC_EINVARG; + if (uid_len < resp_len - 2) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "UID too big"); + pnd->last_error = NFC_ESOFT; return pnd->last_error; } - memcpy(puid, data, dwRxLen - 2); - return dwRxLen - 2; + + memcpy(uid, resp, resp_len - 2); + return resp_len - 2; } int pcsc_props_to_target(uint8_t it, const uint8_t *patr, size_t szatr, const uint8_t *puid, int szuid, const nfc_modulation_type nmt, nfc_target *pnt) @@ -530,84 +587,81 @@ int pcsc_initiator_init(struct nfc_device *pnd) int pcsc_initiator_select_passive_target(struct nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt) { - uint8_t pbAtr[MAX_ATR_SIZE]; + uint8_t atr[MAX_ATR_SIZE]; uint8_t uid[10]; - DWORD dwState, dwProtocol, dwReaderLen, dwAtrLen = sizeof pbAtr; + int target_present; + size_t atr_len = sizeof atr; (void) pbtInitData; (void) szInitData; if (nm.nbr != pcsc_supported_brs[0] && nm.nbr != pcsc_supported_brs[1]) return NFC_EINVARG; - DRIVER_DATA(pnd)->last_error = SCardStatus(DRIVER_DATA(pnd)->hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen); - if ((DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS - && DRIVER_DATA(pnd)->last_error != SCARD_W_RESET_CARD) - || !(dwState & SCARD_PRESENT)) { + + pnd->last_error = pcsc_get_status(pnd, &target_present, atr, &atr_len); + if (pnd->last_error != NFC_SUCCESS) + return pnd->last_error; + + if (!target_present) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "No target present"); return NFC_ENOTSUCHDEV; } - uint8_t it = pcsc_get_icc_type(pnd); - int szuid = pcsc_get_uid(pnd, uid, sizeof uid); - if (pcsc_props_to_target(it, pbAtr, dwAtrLen, uid, szuid, nm.nmt, pnt) != NFC_SUCCESS - || (DRIVER_DATA(pnd)->last_error = SCardReconnect((DRIVER_DATA(pnd)->hCard), SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_LEAVE_CARD, (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol))) != SCARD_S_SUCCESS) { - // We can not reconnect to this device. - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC reconnect failed"); - return NFC_EIO; + + uint8_t icc_type = pcsc_get_icc_type(pnd); + int uid_len = pcsc_get_uid(pnd, uid, sizeof uid); + if (pcsc_props_to_target(icc_type, atr, atr_len, uid, uid_len, nm.nmt, pnt) != NFC_SUCCESS) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Type of target not supported"); + return NFC_EDEVNOTSUPP; } - DRIVER_DATA(pnd)->dwShareMode = SCARD_SHARE_SHARED; + + pnd->last_error = pcsc_reconnect(pnd, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_LEAVE_CARD); + if (pnd->last_error != NFC_SUCCESS) + return pnd->last_error; + return 1; } int pcsc_initiator_deselect_target(struct nfc_device *pnd) { - DRIVER_DATA(pnd)->last_error = SCardReconnect((DRIVER_DATA(pnd)->hCard), SCARD_SHARE_DIRECT, 0, SCARD_LEAVE_CARD, (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol)); - if (DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS - && DRIVER_DATA(pnd)->last_error != SCARD_W_RESET_CARD) { - // We can not reconnect to this device. - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC reconnect failed"); - return NFC_EIO; - } - DRIVER_DATA(pnd)->dwShareMode = SCARD_SHARE_DIRECT; - return NFC_SUCCESS; + pnd->last_error = pcsc_reconnect(pnd, SCARD_SHARE_DIRECT, 0, SCARD_LEAVE_CARD); + return pnd->last_error; } int pcsc_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout) { + size_t resp_len = szRx; + // FIXME: timeout is not handled (void) timeout; - DWORD dwRxLen = szRx; - - LOG_HEX(NFC_LOG_GROUP_COM, "TX", pbtTx, szTx); - DRIVER_DATA(pnd)->last_error = SCardTransmit(DRIVER_DATA(pnd)->hCard, &(DRIVER_DATA(pnd)->ioCard), pbtTx, szTx, NULL, pbtRx, &dwRxLen); - if (DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC transmit failed"); - pnd->last_error = NFC_EIO; + pnd->last_error = pcsc_transmit(pnd, pbtTx, szTx, pbtRx, &resp_len); + if (pnd->last_error != NFC_SUCCESS) return pnd->last_error; - } - LOG_HEX(NFC_LOG_GROUP_COM, "RX", pbtRx, dwRxLen); - return dwRxLen; + return resp_len; } int pcsc_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt) { - uint8_t pbAtr[MAX_ATR_SIZE]; - DWORD dwState, dwProtocol, dwReaderLen, dwAtrLen = sizeof pbAtr; + uint8_t atr[MAX_ATR_SIZE]; + int target_present; + size_t atr_len = sizeof atr; nfc_target nt; - DRIVER_DATA(pnd)->last_error = SCardStatus(DRIVER_DATA(pnd)->hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen); - if ((DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS - && DRIVER_DATA(pnd)->last_error != SCARD_W_RESET_CARD) - || !(dwState & SCARD_PRESENT)) { - pnd->last_error = NFC_EIO; + pnd->last_error = pcsc_get_status(pnd, &target_present, atr, &atr_len); + if (pnd->last_error != NFC_SUCCESS) return pnd->last_error; + + if (!target_present) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "No target present"); + return NFC_ENOTSUCHDEV; } + if (pnt) { - if (pcsc_props_to_target(ICC_TYPE_UNKNOWN, pbAtr, dwAtrLen, NULL, 0, pnt->nm.nmt, &nt) != NFC_SUCCESS + if (pcsc_props_to_target(ICC_TYPE_UNKNOWN, atr, atr_len, NULL, 0, pnt->nm.nmt, &nt) != NFC_SUCCESS || pnt->nm.nmt != nt.nm.nmt || pnt->nm.nbr != nt.nm.nbr) { - pnd->last_error = NFC_EINVARG; - return pnd->last_error; + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Target doesn't meet requirements"); + return NFC_ENOTSUCHDEV; } } return NFC_SUCCESS; @@ -636,7 +690,8 @@ int pcsc_device_set_property_bool(struct nfc_device *pnd, const nfc_property pro break; case NP_ACTIVATE_FIELD: if (bEnable == false) { - SCardReconnect(DRIVER_DATA(pnd)->hCard, DRIVER_DATA(pnd)->dwShareMode, DRIVER_DATA(pnd)->ioCard.dwProtocol, SCARD_RESET_CARD, (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol)); + struct pcsc_data *data = pnd->driver_data; + pcsc_reconnect(pnd, data->dwShareMode, data->ioCard.dwProtocol, SCARD_RESET_CARD); } return NFC_SUCCESS; default: @@ -667,6 +722,7 @@ int pcsc_get_supported_baud_rate(struct nfc_device *pnd, const nfc_mode mode, co int pcsc_get_information_about(nfc_device *pnd, char **pbuf) { + struct pcsc_data *data = pnd->driver_data; LPBYTE name = NULL, version = NULL, type = NULL, serial = NULL; DWORD name_len = SCARD_AUTOALLOCATE, version_len = SCARD_AUTOALLOCATE, type_len = SCARD_AUTOALLOCATE, serial_len = SCARD_AUTOALLOCATE; @@ -678,10 +734,10 @@ pcsc_get_information_about(nfc_device *pnd, char **pbuf) return pnd->last_error; } - SCardGetAttrib(DRIVER_DATA(pnd)->hCard, SCARD_ATTR_VENDOR_NAME, (LPBYTE)&name, &name_len); - SCardGetAttrib(DRIVER_DATA(pnd)->hCard, SCARD_ATTR_VENDOR_IFD_TYPE, (LPBYTE)&type, &type_len); - SCardGetAttrib(DRIVER_DATA(pnd)->hCard, SCARD_ATTR_VENDOR_IFD_VERSION, (LPBYTE)&version, &version_len); - SCardGetAttrib(DRIVER_DATA(pnd)->hCard, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, (LPBYTE)&serial, &serial_len); + SCardGetAttrib(data->hCard, SCARD_ATTR_VENDOR_NAME, (LPBYTE)&name, &name_len); + SCardGetAttrib(data->hCard, SCARD_ATTR_VENDOR_IFD_TYPE, (LPBYTE)&type, &type_len); + SCardGetAttrib(data->hCard, SCARD_ATTR_VENDOR_IFD_VERSION, (LPBYTE)&version, &version_len); + SCardGetAttrib(data->hCard, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, (LPBYTE)&serial, &serial_len); *pbuf = malloc(name_len + type_len + version_len + serial_len + 30); if (! *pbuf) {