0
votes

I try to use an ACR122 USB NFC-Reader on Mac OSX Mojave 10.14.6 with libnfc and I've got a "Unable to write to USB (Result too large)" error when I try to use the command LIBNFC_LOG_LEVEL=3 nfc-list:

info    libnfc.config   Unable to open file: /usr/local/etc/nfc/libnfc.conf
debug   libnfc.config   key: [device.allow_autoscan], value: [false]
info    libnfc.config   Unknown key in config line: device.allow_autoscan = false
debug   libnfc.config   key: [device.allow_intrusive_scan], value: [false]
info    libnfc.config   Unknown key in config line: device.allow_intrusive_scan = false
debug   libnfc.config   key: [device.log_level], value: [3]
info    libnfc.config   Unknown key in config line: device.log_level = 3
debug   libnfc.general  log_level is set to 3
debug   libnfc.general  allow_autoscan is set to true
debug   libnfc.general  allow_intrusive_scan is set to false
debug   libnfc.general  0 device(s) defined by user
nfc-list uses libnfc 1.7.1
debug   libnfc.driver.acr122_usb    device found: Bus 020 Device 020 Name ACS ACR122
debug   libnfc.general  1 device(s) found using acr122_usb driver
debug   libnfc.driver.acr122_usb    3 element(s) have been decoded from "acr122_usb:020:020"
debug   libnfc.driver.acr122_usb    TX: 62 00 00 00 00 00 00 01 00 00
error   libnfc.driver.acr122_usb    Unable to write to USB (Result too large)
debug   libnfc.general  Unable to open "acr122_usb:020:020".
nfc-list: ERROR: Unable to open NFC device: acr122_usb:020:020

When I started troubleshooting I had an "Unable to Claim USB Interface" error, which other people had as well. So I tried the following things from this stackoverflow question and this github issue I found:

  1. install libnfc with brew install libnfc --> Got the "Unable to Claim..." error.
  2. Using sudo -> No change
  3. Disable the PC/SC daemon -> Did not do anything
  4. Editing /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist -> Did not help
  5. Uninstall libnfc, compile the project myself and disable ifreader. I tried to build it with both drivers acr122_usb and acr122_pcsc -> Got now a "Unable to write to USB (Result too large)" error instead.
    • Compile with: autoreconf -iv && ./configure --with-drivers=acr122_usb && make clean && make && make install
    • sudo launchctl remove com.apple.ifdreader
    • sudo launchctl stop com.apple.ifdreader

After troubleshooting now I'm stuck with the error and have no idea how to solve the problem. The readers light is not blinking red anymore, but from the error the device is clearly connected to the computer and available.

As a side node: I connect the reader over a USB Hub, since the reader has no USB C cable, but that shouldn't be a problem. Has anyone had the same problem or another approach I could try?

3

3 Answers

2
votes

Your step 4, editing /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist worked for me and it is the only clean solution I could find.

Here a short description what you need to do:

  • disable 'System Integrity Protection'
  • removes 3 matching lines (with the same array index!) from the the 3 arrays ifdFriendlyName, ifdVendorID and ifdProductID of the plist /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist
  • enable 'System Integrity Protection'

The three lines in my case were the entry number 370:

  • ifdFriendlyName="ACS ACR122U PICC Interface"
  • ifdVendorID=0x072F
  • ifdProductID=0x2200

Detailed step by step description:

  1. unplug your NFC card reader
  2. shut down OSX
  3. hold down the keys <cmd>+<R> on the keyboard while starting your Mac to enter recovery mode
  4. in the recovery mode open a Terminal Window using the 'Utility' menu
  5. execute the command csrutil disable
  6. reboot your Mac normally
  7. open a Terminal window and execute the following commands:

    sudo -i
    cd /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents
    cp Info.plist Info.plist.orig
    patch -l -p0 <<EOF
    --- Info.plist.orig 2019-12-07 20:26:36.000000000 +0100
    +++ Info.plist  2019-12-07 20:26:40.000000000 +0100
    @@ -471,7 +471,6 @@
            <string>0x1050</string>
            <string>0x1050</string>
            <string>0x1050</string>
    -       <string>0x072F</string>
            <string>0x09C3</string>
            <string>0x03EB</string>
            <string>0x0A5C</string>
    @@ -864,7 +863,6 @@
            <string>0x0405</string>
            <string>0x0406</string>
            <string>0x0407</string>
    -       <string>0x2200</string>
            <string>0x0008</string>
            <string>0x6016</string>
            <string>0x5800</string>
    @@ -1257,7 +1255,6 @@
            <string>Yubico Yubikey 4 OTP+CCID</string>
            <string>Yubico Yubikey 4 U2F+CCID</string>
            <string>Yubico Yubikey 4 OTP+U2F+CCID</string>
    -       <string>ACS ACR122U PICC Interface</string>
            <string>ActivCard ActivCard USB Reader V2</string>
            <string>ATMEL VaultIC460</string>
            <string>Broadcom Corp 5880</string>
    EOF
    
  8. reboot your Mac normally

  9. plug in your NFC card reader
  10. test if the nfc utils are now working, e.g. by calling nfc-scan-device
  11. shut down OSX
  12. hold down the keys <cmd>+<R> on the keyboard and then start your Mac to enter recovery mode
  13. open a Terminal Window using the 'Utility' menu
  14. execute the command csrutil enable
  15. reboot your Mac normally

@anderssonjohan was giving the correct answer in his post, but the plist file he posted was inconsistent because he only removed one line instead of three.

0
votes

The original problem is, that the daemon system/com.apple.ifdreader loads the user level driver /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle which is based on pcsc-lite and claims the ownership of the USB device. To make the card reader accessible to libnfc you can either

  • tell ifd-ccid to ignore the USB device (I will tell you how to achieve this)
  • tell libnfc to use pcsc-lite
  • completely disable ifdreader daemon (I consider this risky, especially on system upgrades)

I made two answers to this question:

  1. This one assumes you are a bit more familar with the Terminal and the paths in the recovery environment. Instead of disabling 'System Integrity Protection' and needing multiple reboots like described in my other answer you can also do this with only one reboot
  2. The other answer needs more steps (especially reboots) and I have written it before. It temporarily disables 'System Integrity Protection' which is risky when you forget to enable it again.

Here some commands you can execute to show the status of the service:

launchctl list com.apple.ifdreader
launchctl blame system/com.apple.ifdreader

Just killing the daemon or disabling it will not work, it is automatically (re)started when the system detects a USB device whose ID is listed in its Info.plist, so you need to remove the USB IDs from /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist.

Unfortunately that file is protected by 'System Integrity Protection' in MacOS Mojave 10.14.6, so you can only modify it when you boot to recovery mode and modify it there or disable 'System Integrity Protection' there using csrutil disable to be able to modify it in the normal user environment.

These are the steps you need to do:

  1. prepare the new Info.plist and keep a backup of the original (see below)
  2. shut down OSX
  3. hold down the keys <cmd>+<R> on the keyboard and then start your Mac to enter recovery mode
  4. open a 'Terminal' Window using the 'Utilities' menu
  5. Replace the original /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist with the one you prepared

Before entering the recovery mode you need to know under which paths the files can be found, because the root-filesystem is different and your normal root filesystem will be mounted under /Volumes/<TheNameOfYourSystemDisk>, so look up this name in the Finder before going to recovery mode.

For example my system drive is called Macintosh HD and the paths are:

  • My homedir: /Volumes/Macintosh HD/Users/michael
  • The pinfo file: /Volumes/Macintosh HD/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist

The best way in my example is to chroot '/Volumes/Macintosh HD' to be able to use most of the normal CLI commands.

To create the new Info.plist file you can use the small patch from my other answer. Or you can use the attached python script which is more flexible. Just call the script and it will create the changed Info.plist file in the sub-dir SmartCardService_disable of the current directory:

#!/usr/bin/env python3
import os, re, plistlib
from shutil import copyfile
plistFile = "/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist"
plistFileBak = "Info.plist.orig"
plistFileOut = "Info.plist"
workDir = "SmartCardService_disable"
usbFriendlyNamePattern = ".*ACS.*ACR122.*"

def findDevicesByFriendlyName(pl, usbFriendlyNamePattern) :
        reUsbFriendlyName = re.compile(usbFriendlyNamePattern, re.IGNORECASE)
        indexes = []
        for index, item in enumerate(pl["ifdFriendlyName"]):
                if reUsbFriendlyName.fullmatch(item) :
                        indexes.append(index)
        return indexes

def makePlistCopy() :
        try:
                os.mkdir(workDir)
        except FileExistsError:
                pass
        except:
                raise Exception("Unable to create work directory")
        os.chdir(workDir)
        try:
                os.stat(plistFileBak)
        except FileNotFoundError:
                copyfile(plistFile, plistFileBak)
        except:
                raise Exception("Unable to copy plist file")

makePlistCopy()
pl = plistlib.readPlist(plistFileBak)
indexes = findDevicesByFriendlyName(pl, usbFriendlyNamePattern)
indexes.sort(reverse = True)
for index in indexes:
        del pl["ifdFriendlyName"][index]
        del pl["ifdVendorID"][index]
        del pl["ifdProductID"][index]

plistlib.writePlist(pl, plistFileOut)

The script can easily be adapted to remove other card readers, just change usbFriendlyNamePattern = ".*ACS.*ACR122.*" to any other pattern.

0
votes

The first solution is what I need, but enable SIP, change driver and restore SIP as for me is too much just to disable PC/SC for our reader.

If you are using reader in some macos applications which is PC/SC compliant, this solution will not work for you.

I found solution without enable/disable SIP.

  1. Install non system drivers, in my case it was https://www.acs.com.hk/download-driver-unified/12835/ACS-Unified-INST-MacOSX-1182-P.zip which is acsccid drivers.
  2. Found at local system such folder /usr/local/libexec/SmartCardServices/drivers/ifd-acsccid.bundle/Contents which is not protected by SIP, since it's /usr/local and it's user drivers
  3. Modify file Info.plist how is described in the first answer
  4. Unplug and plug the reader - led is not working (it's expected!)
  5. Make sure lsusb show yours reader in the list
  6. libnfc working with acr122_usb driver

In this case macos system ignore system drivers since installed user drivers and all configuration applied from them even if the device has been ignored in it.

Tested and working well with the latest version of the libnfc from master and macos BigSur 11.6

Note: to be able to work correctly with gen3 fob I would recommend to compile and install libnfc from master, some of new changes have been made but not released yet (