OS X El Capitan bug: PC/SC not usable after fork()

This is part of the series: "OS X El Capitan and smart cards: known bugs".

PC/SC is not unusable after fork()

SCardEstablishContext() returns SCARD_E_NO_SERVICE if called after fork(2) on El Capitan.

I can agree that if you mix PC/SC calls from before and after the fork(2) call you can have problems, as in OS X Yosemite bug: PC/SC functions crash after a fork(2). But if you start all the PC/SC calls in the same (child) process I expected it to work.

From the fork(2) manpage I read:

CAVEATS
There are limits to what you can do in the child process. To be totally safe you should restrict yourself to only executing async-signal safe operations until such time as one of the exec functions is called. All APIs, including global data symbols, in any framework or library should be assumed to be unsafe after a fork() unless explicitly documented to be safe or async-signal safe. If you need to use these frameworks in the child process, you must exec. In this situation it is reasonable to exec yourself.

I expect Apple to just close this bug as it it the documented behaviour.

It is not a bug but a feature ☹.

See also

Apple bug report #23669488 "PC/SC is not unusable after fork()"

Bug closed by Apple. See Update bellow.

Sample code


#include <stdio.h>
#include <unistd.h>
#ifdef __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#else
#include <winscard.h>
#endif

int main(void)
{
    int pid = fork();
    if (0 == pid)
    {
        /* son process */

        SCARDCONTEXT hContext;
        DWORD err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
            &hContext);
        if (err != SCARD_S_SUCCESS) {
            printf("ScardEstablishedContext: %s (0x%08lx)\n",
                pcsc_stringify_error(err), (long)err);
            return -1;
        }
        else
            printf("OK\n");

        SCardReleaseContext(hContext);
    }
    else
        /* give some time to the son */
        sleep(1);

    return 0;
}


Result (on El Capitan)

$ CFLAGS="-framework PCSC" make main
cc -framework PCSC    main.c   -o main

$ ./main
ScardEstablishedContext: Service not available. (0x8010001d)

Expected result (on Debian)

$ CFLAGS=`pkg-config --cflags libpcsclite` LDFLAGS=`pkg-config --libs libpcsclite` make main
cc -pthread -I/usr/include/PCSC    -lpcsclite    main.c   -o main

$ ./main
OK

Known workaround

None known.

Update 8th December 2015

As expected Apple closed the bug with:
As documented in the quoted fork man page excerpt, it is quite expected that PC/SC does not work in forked child.

OS X El Capitan bug: SCardConnect() returns SCARD_E_PROTO_MISMATCH instead of SCARD_E_SHARING_VIOLATION

This is part of the series: "OS X El Capitan and smart cards: known bugs".

SCardConnect() returns SCARD_E_PROTO_MISMATCH instead of SCARD_E_SHARING_VIOLATION

SCardConnect() returns the wrong error code on El Capitan.

If you use SCardConnect() to connect a reader that is already used by another application in exclusive mode (SCARD_SHARE_EXCLUSIVE) you should get the SCARD_E_SHARING_VIOLATION error. Instead you get a (surprising) SCARD_E_PROTO_MISMATCH error.

See also

Apple bug report #23646838 "SCardConnect() returns SCARD_E_PROTO_MISMATCH instead of SCARD_E_SHARING_VIOLATION".

Bug closed by Apple on 10th Dec 2015 because it is a duplicate of #22575831.

Sample code

The 2 programs are written in Python and use the PySCard wrapper so the code is much shorter than if written in C-language.

File lock.py:
#! /usr/bin/env python

from smartcard.System import readers
from smartcard.scard import SCARD_SHARE_EXCLUSIVE

reader = readers()[0]
print "Using:", reader

connection = reader.createConnection()
connection.connect(mode=SCARD_SHARE_EXCLUSIVE)

import time
time.sleep(10)

File connect.py:
#! /usr/bin/env python

from smartcard.System import readers

reader = readers()[0]
print "Using:", reader

connection = reader.createConnection()
connection.connect()

You need to execute the 2 programs in 2 different terminals. The execution of lock.py will lock the reader for 10 seconds. The execution of connect.py will try to connect, and get the error if lock.py is still running.

Result (on El Capitan)

$ ./lock.py
Using: Gemalto PC Twin Reader

In another terminal:
$ ./connect.py
Using: Gemalto PC Twin Reader
Traceback (most recent call last):
  File "./connect.py", line 9, in 
    connection.connect()
  File "/Library/Python/2.7/site-packages/pyscard-1.9.0-py2.7-macosx-10.10-intel.egg/smartcard/CardConnectionDecorator.py", line 54, in connect
    self.component.connect(protocol, mode, disposition)
  File "/Library/Python/2.7/site-packages/pyscard-1.9.0-py2.7-macosx-10.10-intel.egg/smartcard/pcsc/PCSCCardConnection.py", line 128, in connect
    SCardGetErrorMessage(hresult))
smartcard.Exceptions.CardConnectionException: Unable to connect with protocol: T0 or T1. Card protocol mismatch.

Expected result (on Debian)

$ ./lock.py 
Using: Gemalto PC Twin Reader 00 00

In another terminal:
$ ./connect.py
Using: Gemalto PC Twin Reader 00 00
Traceback (most recent call last):
  File "./connect.py", line 16, in 
    connection.connect()
  File "/usr/lib/python2.7/dist-packages/smartcard/CardConnectionDecorator.py", line 54, in connect
    self.component.connect(protocol, mode, disposition)
  File "/usr/lib/python2.7/dist-packages/smartcard/pcsc/PCSCCardConnection.py", line 128, in connect
    SCardGetErrorMessage(hresult))
smartcard.Exceptions.CardConnectionException: Unable to connect with protocol: T0 or T1. Sharing violation.

Discussion

The correct error code (Sharing violation) is returned if you run a second lock.py in another terminal.

The difference between lock.py and connect.py is that lock.py uses an exclusive connection (SCARD_SHARE_EXCLUSIVE) and connect.py uses a (default value) shared connection (SCARD_SHARE_SHARED).

I also get the correct error code (Sharing violation) if I try to connect in exclusive mode while a PC/SC transaction is running.

Known workaround

None known.

The error SCARD_E_PROTO_MISMATCH returned by SCardConnect() may in fact indicates a SCARD_E_SHARING_VIOLATION in some cases in El Capitan.

Update: 27th September 2016

This bug is fixed in macOS Sierra 10.12.0.

OS X El Capitan bug: Connecting a CT700 Gemalto smart card reader renders PC/SC useless

This is part of the series: "OS X El Capitan and smart cards: known bugs".

Connecting a CT700 Gemalto smart card reader renders PC/SC useless

The CCID driver provided by Apple do not work with the Gemalto CT700 smart card reader. This reader was previously named Gemalto GemPC Pinpad.

This is not really Apple fault since I maintain the CCID diver. So you can say this is my fault.

The problem was not easy to identify since the CCID driver is located in /usr/libexec/SmartCardServices/drivers/ and this directory is protected by System Integrity Protection (SIP) and can't be changed easily.

After I could enable some logs I get:
12/11/2015 15:18:47,192 com.apple.ifdreader[2100]: ifdhandler.c:83:CreateChannelByNameOrChannel() Lun: 0, device: Gemalto USB GemPCPinpad SmartCard Reader
12/11/2015 15:18:47,192 com.apple.ifdreader[2100]: ccid_usb.c:233:OpenUSBByName() Reader index: 0, Device: Gemalto USB GemPCPinpad SmartCard Reader
12/11/2015 15:18:47,192 com.apple.ifdreader[2100]: ccid_usb.c:281:OpenUSBByName() Using: /usr/local/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist
12/11/2015 15:18:47,193 com.apple.ifdreader[2100]: ccid_usb.c:299:OpenUSBByName() ifdManufacturerString: Ludovic Rousseau (ludovic.rousseau@free.fr)
12/11/2015 15:18:47,193 com.apple.ifdreader[2100]: ccid_usb.c:300:OpenUSBByName() ifdProductString: Generic CCID driver
12/11/2015 15:18:47,193 com.apple.ifdreader[2100]: ccid_usb.c:301:OpenUSBByName() Copyright: This driver is protected by terms of the GNU Lesser General Public License version 2.1, or (at your option) any later
12/11/2015 15:18:48,196 com.apple.ifdreader[2100]: ccid_usb.c:426:OpenUSBByName() Checking device: 20/14
12/11/2015 15:18:48,196 com.apple.ifdreader[2100]: ccid_usb.c:488:OpenUSBByName() Trying to open USB bus/device: 20/14
12/11/2015 15:18:48,197 com.apple.ifdreader[2100]: ccid_usb.c:589:OpenUSBByName() Found Vendor/Product: 08E6/3478 (Gemalto USB GemPCPinpad SmartCard Reader)
12/11/2015 15:18:48,197 com.apple.ifdreader[2100]: ccid_usb.c:591:OpenUSBByName() Using USB bus/device: 20/14
12/11/2015 15:18:48,197 com.apple.ifdreader[2100]: ccid_usb.c:1142:ControlUSB() request: 0x03
12/11/2015 15:18:48,200 com.apple.ifdreader[2100]: receive: 01 2A 00 00 01 38 00 00 09 3D 00 00 34 43 00 00 61 51 00 00 01 54 00 00 8E 5B 00 00 CE 64 00 00 02 70 00 00 12 7A 00 00 02 7E 00 00 69 86 00 00 97 98 00 00 C3 A2 00 00 03 A8 00 00 1B B7 00 00 73 CB 00 00 03 D2 00 00 04 E0 00 00 24 F4 00 00 04 FC 00 00 D1 0C 01 00 05 18 01 00 2D 31 01 00 85 45 01 00 06 50 01 00 36 6E 01 00 E7 96 01 00 07 A4 01 00 07 C0 01 00 48 E8 01 00 08 F8 01 00 09 30 02 00 5A 62 02 00 0B 8B 02 00 0B A0 02 00 0E 48 03 00 0F 80 03 00 90 D0 03 00 16 40 05 00 20 A1 07 00 
12/11/2015 15:18:48,200 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 10753 bps
12/11/2015 15:18:48,200 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 14337 bps
12/11/2015 15:18:48,200 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 15625 bps
12/11/2015 15:18:48,200 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 17204 bps
12/11/2015 15:18:48,200 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 20833 bps
12/11/2015 15:18:48,200 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 21505 bps
12/11/2015 15:18:48,200 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 23438 bps
12/11/2015 15:18:48,200 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 25806 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 28674 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 31250 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 32258 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 34409 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 39063 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 41667 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 43011 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 46875 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 52083 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 53763 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 57348 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 62500 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 64516 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 68817 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 71685 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 78125 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 83333 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 86022 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 93750 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 104167 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 107527 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 114695 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 125000 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 129032 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 143369 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 156250 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 166667 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 172043 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 215054 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 229391 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 250000 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 344086 bps
12/11/2015 15:18:48,201 com.apple.ifdreader[2100]: ccid_usb.c:1122:get_data_rates() declared: 500000 bps
12/11/2015 15:18:48,216 com.apple.ifdreader[2100]: NotifySlotChange: 50 02 
12/11/2015 15:18:48,217 com.apple.ifdreader[2100]: -> 000000 65 00 00 00 00 00 00 00 00 00 
12/11/2015 15:18:48,219 com.apple.ifdreader[2100]: <- 000000 81 00 00 00 00 00 00 02 00 00 
12/11/2015 15:18:48,219 com.apple.ifdreader[2100]: -> 000000 65 00 00 00 00 00 01 00 00 00 
12/11/2015 15:18:48,221 com.apple.ifdreader[2100]: <- 000000 81 00 00 00 00 00 01 02 00 00 
12/11/2015 15:18:48,224 com.apple.ifdreader[2100]: ccid.c:383:ccid_open_hack_post() Using lang: (null)
12/11/2015 15:18:49,268 com.apple.ifdreader[2100]: -> 000000 6B A5 00 00 00 00 02 00 00 00 B2 A0 00 4D 4C 45 6E 74 65 72 20 50 49 4E 20 20 20 20 20 20 20 4E 65 77 20 50 49 4E 20 20 20 20 20 20 20 20 20 43 6F 6E 66 69 72 6D 20 50 49 4E 20 20 20 20 20 50 49 4E 20 4F 4B 20 20 20 20 20 20 20 20 20 20 49 6E 63 6F 72 72 65 63 74 20 50 49 4E 21 20 20 54 69 6D 65 20 4F 75 74 20 20 20 20 20 20 20 20 2A 20 72 65 74 72 69 65 73 20 6C 65 66 74 20 20 49 6E 73 65 72 74 20 43 61 72 64 20 20 20 20 20 43 61 72 64 20 45 72 72 6F 72 20 20 20 20 20 20 50 49 4E 20 62 6C 6F 63 6B 65 64 20 20 20 20 20 
12/11/2015 15:18:49,371 com.apple.ifdreader[2100]: ccid_usb.c:784:ReadUSB() read failed (20/14): -7 Operation timed out
12/11/2015 15:18:49,371 com.apple.ifdreader[2100]: ccid.c:436:ccid_open_hack_post() Failed to load l10n strings
12/11/2015 15:18:49,371 com.apple.ifdreader[2100]: -> 000000 6B 01 00 00 00 00 03 00 00 00 6A 
12/11/2015 15:18:54,372 com.apple.ifdreader[2100]: ccid_usb.c:745:WriteUSB() write failed (20/14): -7 Operation timed out
12/11/2015 15:18:54,372 com.apple.ifdreader[2100]: ccid.c:219:set_gemalto_firmware_features() GET_FIRMWARE_FEATURES failed: 612, len=21
12/11/2015 15:18:54,372 com.apple.ifdreader[2100]: ifdhandler.c:167:CreateChannelByNameOrChannel() failed

And on any new CCID reader connected I get:
12/11/2015 15:24:42,414 com.apple.ifdreader[2100]: ifdhandler.c:83:CreateChannelByNameOrChannel() Lun: 0, device: Gemalto PC Twin Reader
12/11/2015 15:24:42,414 com.apple.ifdreader[2100]: ccid_usb.c:233:OpenUSBByName() Reader index: 0, Device: Gemalto PC Twin Reader
12/11/2015 15:24:42,414 com.apple.ifdreader[2100]: ccid_usb.c:274:OpenUSBByName() USB driver with index 0 already in use
12/11/2015 15:24:42,414 com.apple.ifdreader[2100]: ifdhandler.c:117:CreateChannelByNameOrChannel() failed

This is because the initialisation of the CT700 failed but did not correctly reset a reader structure at index 0.

This problem has been fixed upstream in the CCID driver but is not yet available in a stable driver version.

See also

Apple bug report #23515984 "Connecting a CT700 Gemalto smart card reader renders PC/SC useless"

Known workaround

None known.

Do not use this reader on El Capitan until Gemalto or Apple provides a solution.

Update: 27th September 2016

This bugs is fixed upstream in CCID driver version 1.4.22.
So this bug is fixed in macOS Sierra as a side effect of the CCID driver upgrade to version 1.4.24.

OS X El Capitan and smart cards: known bugs

El Capitan: OS X 10.11

In Yosemite (OS X 10.10) Apple rewrote a large part of the smart card infrastructure and introduced many bugs. I made a list in "OS X Yosemite and smart cards: known bugs".

I propose to maintain a similar lists for smart card bugs found in El Capitan10.11.x.

The bugs I find in El Capitan may also be present in Yosemite. The bugs may not be specific to El Capitan.

Bug list

  1. PC/SC is not unusable after fork()
  2. SCardBeginTransaction() returns different error codes than on GNU/Linux and Windows

Fixed in 10.11.5

  1. OS X El Capitan and CCID driver upgrades
    see OS X El Capitan 10.11.5 and CCID driver fix

Fixed in 10.12.0 (Sierra)

  1. Connecting a CT700 Gemalto smart card reader renders PC/SC useless
  2. SCardGetAttrib() returns SCARD_E_NOT_TRANSACTED when it should not
  3. SCardConnect() returns SCARD_E_PROTO_MISMATCH instead of SCARD_E_SHARING_VIOLATION
  4. SCardGetAttrib() returns SCARD_E_NOT_TRANSACTED instead of SCARD_E_INSUFFICIENT_BUFFER

Fixed in 10.13.0 (High Sierra)

  1. SCARD_W_RESET_CARD not returned by SCardTransmit()

Feature list

  1. SCardGetStatusChange() and number of card events
  2. SCardGetStatusChange() and "\\?PnP?\Notification"
  3. add support of TAG_IFD_POLLING_THREAD_WITH_TIMEOUT

Conclusion

Apple still has some PC/SC bugs to fix.

OS X El Capitan bug: SCARD_W_RESET_CARD not returned by SCardTransmit()

This is part of the series: "OS X El Capitan and smart cards: known bugs".

SCARD_W_RESET_CARD not returned by SCardTransmit()

SCardTransmit() do not work correctly on El Capitan (and maybe also on Yosemite but that is untested).

When an application calls SCardTransmit() after the card has been reseted the returned value should be SCARD_W_RESET_CARD to indicate that the card has been reseted.
What happens on El Capitan is that the SCardTransmit() returns SCARD_S_SUCCESS but the card answer will (in general) be incorrect since the card has been reseted.

The error SCARD_W_RESET_CARD is returned from the next SCardTransmit() call.

This behaviour can confuse applications since the SCardTransmit() that should fail just works but with a (possibly) wrong answer from the card.

See also

Apple bug report #23574394 "SCARD_W_RESET_CARD not returned by SCardTransmit()"

Sample code

For the example I used a smart card with a test JavaCard applet loaded. The idea is to send commands to the applet. If the command is send before the applet is selected (after a reset) then the command will fail.

I used my test applet installed in the card.

The 2 programs are written in Python and use the PySCard wrapper so the code is much shorter than if written in C-language.

Looping program


#! /usr/bin/env python

from smartcard.System import readers
from smartcard.util import toBytes

# define the APDUs used in this script
SELECT = toBytes("00 A4 04 00 06 A0 00 00 00 18 FF")
COMMAND = toBytes("80 34 00 0E 0E")

# use the 1st available reader
reader = readers()[0]
print "Using:", reader

connection = reader.createConnection()
connection.connect()

data, sw1, sw2 = connection.transmit(SELECT)

while True:
    data, sw1, sw2 = connection.transmit(COMMAND)
    print data
    print "Command: %02X %02X" % (sw1, sw2)

Reset program


#! /usr/bin/env python

from smartcard.System import readers
from smartcard.scard import SCARD_RESET_CARD

reader = readers()[0]
print "Using:", reader

connection = reader.createConnection()
connection.connect(disposition=SCARD_RESET_CARD)

Expected result (on Debian)

$ ./loop.py
Using: Gemalto PC Twin Reader 00 00
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Command: 90 00
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Command: 90 00
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Command: 90 00
Traceback (most recent call last):
  File "./loop2.py", line 20, in 
    data, sw1, sw2 = connection.transmit(COMMAND)
  File "/usr/lib/python2.7/dist-packages/smartcard/CardConnectionDecorator.py", line 82, in transmit
    return self.component.transmit(bytes, protocol)
  File "/usr/lib/python2.7/dist-packages/smartcard/CardConnection.py", line 144, in transmit
    data, sw1, sw2 = self.doTransmit(bytes, protocol)
  File "/usr/lib/python2.7/dist-packages/smartcard/pcsc/PCSCCardConnection.py", line 198, in doTransmit
    SCardGetErrorMessage(hresult))
smartcard.Exceptions.CardConnectionException: Failed to transmit with protocol T0. Card was reset.

In another terminal I run the reset program:
$ ./reset.py
Using: Gemalto PC Twin Reader

Result (on El Capitan)

$ ./loop.py
Using: Gemalto PC Twin Reader
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Command: 90 00
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Command: 90 00
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Command: 90 00
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Command: 90 00
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Command: 90 00
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Command: 90 00
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Command: 90 00
[]
Command: 69 85
Traceback (most recent call last):
  File "./loop2.py", line 20, in 
    data, sw1, sw2 = connection.transmit(COMMAND)
  File "/Library/Python/2.7/site-packages/pyscard-1.9.0-py2.7-macosx-10.10-intel.egg/smartcard/CardConnectionDecorator.py", line 82, in transmit
    return self.component.transmit(bytes, protocol)
  File "/Library/Python/2.7/site-packages/pyscard-1.9.0-py2.7-macosx-10.10-intel.egg/smartcard/CardConnection.py", line 142, in transmit
    data, sw1, sw2 = self.doTransmit(bytes, protocol)
  File "/Library/Python/2.7/site-packages/pyscard-1.9.0-py2.7-macosx-10.10-intel.egg/smartcard/pcsc/PCSCCardConnection.py", line 205, in doTransmit
    SCardGetErrorMessage(hresult))
smartcard.Exceptions.CardConnectionException: Failed to transmit with protocol T0. Card was reset.

Results interpretation

In the two executions you see mostly the same results. The loop program runs and at one point it fails and returns with the error "Card was reset."

The difference is that on El Capitan, just before returning with the error code, the program returned an error from the card "69 85". This is because the applet is not selected so the command is no more understood by the card. And the applet is no more selected because the card has been reseted.

The last command before the error should never have been sent to the card. That is the problem on El Capitan.

Known workaround

None known.

Update: 26 September 2017

This bug is now fixed in macOS 10.13.0 High Sierra

New version of libccid: 1.4.21

I just released a version 1.4.21 of libccid the Free Software CCID class smart card reader driver.

Direct download here.

Changes:
1.4.21 - 21 October 2015, Ludovic Rousseau

  • Add support of
    • ACS ACR1252 Dual Reader
    • Chicony HP USB Smartcard CCID Keyboard JP
    • Chicony HP USB Smartcard CCID Keyboard KR
    • FT ePass2003Auto
    • Feitian bR301 BLE
    • Feitian iR301 (ProductID 0x0619)
    • Feitian iR301 (ProductID 0x061C)
    • Identiv @MAXX ID-1 Smart Card Reader
    • Identiv @MAXX Light2 token
    • Identiv CLOUD 2980 F Smart Card Reader
    • Identiv Identiv uTrust 4701 F Dual Interface Reader
    • Identiv SCR3500 A Contact Reader
    • Identiv SCR3500 B Contact Reader
    • Identiv SCR35xx USB Smart Card Reader
    • Identiv uTrust 2900 R Smart Card Reader
    • Identiv uTrust 2910 R Smart Card Reader
    • Identiv uTrust 2910 R Taglio SC Reader
    • Identiv uTrust 3512 SAM slot Token
    • Identiv uTrust 3522 embd SE RFID Token
    • Identiv uTrust 3700 F CL Reader
    • Identiv uTrust 3701 F CL Reader
    • Identive Identive CLOUD 4000 F DTC
    • Liteon HP SC Keyboard - Apollo (Liteon)
    • Liteon HP SC Keyboard - Apollo JP (Liteon)
    • Liteon HP SC Keyboard - Apollo KR (Liteon)
    • Nitrokey Nitrokey HSM
    • Nitrokey Nitrokey Pro
    • Nitrokey Nitrokey Start
    • Rocketek RT-SCR1
    • VASCO DIGIPASS 875
    • WatchCNPC USB CCID Key
  • Remove support of
    • Crypto Stick Crypto Stick v1.4 is an old version of Nitrokey Nitrokey Pro
    • Free Software Initiative of Japan Gnuk Token is an old version of Nitrokey Nitrokey Start
    • Add Feitain R502 dual interface (composite) reader on Mac OS X
    • display a human readable version of the error code returned by libusb
    • Mac OS X: wait until libusb/the reader is ready
    • some minor bugs fixed

    My blog Google+ page

    You are now more than 200 to follow my blog Google+ page at https://plus.google.com/u/0/b/105951035108309096272/105951035108309096272/posts



    Comments

    I disabled comments on the blog in 2013. See why at "Comments are now disabled". Technical questions should go on the MUSCLE mailing list.

    The goal of the Google+ page is to allow you to leave comments about my blog articles.

    If you just want to know when a new article is available maybe you should subscribe to my blog RSS feed instead. It looks like many people are doing that because I have much more readers of my blog than subscribers of my blog Google+ page.

    Conclusion

    Feel free to leave comments related to the articles on Google+.

    If you want to contact me directly you should use email instead of comments. You can reach me at ludovic.rousseau@free.fr or ludovic.rousseau@gmail.com.

    Evolution of the number of CCID readers

    Regularly I add support of new smart card readers in the list of CCID devices. I wanted to know how regularly I did that over the lifetime of the project (more than 12 years now).
    So I extracted some numbers from the CCID driver git repository to generate a graphic.

    Graph




    I am really surprised by the linearity of the curve.



    The linear correlation equation is (according to Numbers): y = 1.132e-6 x -159.63
    That is a growth rate of 1.132x10-6 readers per second or 36.7 readers per year.


    The curve is even better approximated by a polynomial equation in x2. The coefficient of determination R2 is then equal to 0.9949 (closer to 1.0) instead of 0.9753 for the linear correlation.



    Accidents

    I note 3 "accidents" or fast evolutions:



    Conclusion

    The number of supported CCID readers continues to grow. I do not expect the growth rate to decrease.

    I guess some very old smart card reader models are no more sold. And are, or not, replaced by new newer models.
    You can list the readers sorted by "seniority" using the Readers sorted by 'release' field page and discover the first 7 readers included in version 0.1.0 of the driver.

    OS X El Capitan and smart cards status

    El Capitan (OS X 10.11) is now out since 30th September, 2015.

    As I did with the previous major versions of Mac OS X Yosemite, Mavericks, Mountain Lion (and Lion) I will list changes in El Capitan regarding the smart card world.


    API Differences between 10.10 and 10.11

    The differences are listed in the developer page OS X El Capitan v10.11. The page only document big changes. The smart card changes are not listed there :-)

    A complete list of API changes is at OS X v10.11 API Diffs. Regarding the smart card world we have:
    The CryptoTokenKit API has changed. Some methods have been modified, some methods have been added.

    I note two sets of new methods: TKSmartCardPIN* and TKSmartCardUserInteractionFor*. It looks like Apple wants to provide a nice User eXperience regarding PIN management.

    I hope Apple will provide more documentation than the .h header file and some code samples.
    I will try to rebuild my Crypto Token Kit Objective-C and Swift examples on El Capitan to check if they still work.

    PC/SC

    Since Yosemite (10.10) the PC/SC layer is no more a fork of pcsc-lite. So comparing versions with pcsc-lite is useless.

    $ cat /System/Library/Frameworks/PCSC.framework/Versions/A/Resources/version.plist 
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
     <key>BuildAliasOf</key>
     <string>CryptoTokenKit</string>
     <key>BuildVersion</key>
     <string>13</string>
     <key>CFBundleShortVersionString</key>
     <string>8.0</string>
     <key>CFBundleVersion</key>
     <string>1</string>
     <key>ProjectName</key>
     <string>SmartCardServices</string>
     <key>SourceVersion</key>
     <string>79001001000000</string>
    </dict>
    </plist>
    


    The BuildVersion changed from 1 on Yosemite to 13 on El Capitan, and SourceVersion changed from 22020004000000 to 79001001000000. I have no idea what the SourceVersion "number" is.

    It looks like Apple made 12 builds of the PC/SC framework since Yosemite 10.10.

    Bugs fixed

    At least one bug remains: PC/SC functions crash after a fork(2). But this bug may be hard to fix.

    I updated my blog article OS X Yosemite and smart cards: known bugs.

    Maybe new bugs will be found on El Capitan. But I have not yet found any after just a few hours of tests.

    CCID driver

    Driver version 1.4.14.
    No change since Yosemite.

    $ grep -A 1 CFBundleShortVersionString /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist
     <key>CFBundleShortVersionString</key>
     <string>1.4.14</string>
    

    New driver location

    The System Integrity Protection (SIP) introduced in El Capitan impose that custom PC/SC drivers are now installed in /usr/local/libexec/SmartCardServices/drivers/.

    Only the CCID driver provided by Apple is still in /usr/libexec/SmartCardServices/drivers/.

    Tokend

    Because of SIP, the tokend needs to be installed in /Library/Security/tokend/ now instead of /System/Library/Security/tokend/.

    The tokend and CDSA are still usable. I just fixed the PKCS11.tokend so that it looks for PKCS#11 libraries in /usr/local/lib/pkcs11/ if /usr/lib/pkcs11/ does not exist (as it is the case on El Capitan because of SIP again).

    Conclusion

    Most of the remaining PC/SC bugs fixed.
    tokend still usable.
    Some new Crypto Token Kit methods.