OS X El Capitan 10.11.5 and CCID driver fix

As explained in my previous article "OS X El Capitan 10.11.5 and CCID driver still broken" the upgrade to 10.11.5 did not fix the CCID driver issue.

To fix the issue you have to download and install the "OS X El Capitan 10.11.5 Combo Update".

The file size is 1.5 GB. You can install it even if you already upgraded your system to 10.11.5.

Fixed CCID driver

Now I have:
$ pwd
/usr/libexec/SmartCardServices/drivers
$ ls -lR ifd-ccid.bundle/
total 0
drwxr-xr-x  5 root  wheel  170 23 mai 18:54 Contents

ifd-ccid.bundle//Contents:
total 24
-rw-r--r--  1 root  wheel  36860 21 déc 06:05 Info.plist
drwxr-xr-x  6 root  wheel    204 23 mai 18:54 MacOS
-rw-r--r--  1 root  wheel    470 21 déc 06:05 version.plist

ifd-ccid.bundle//Contents/MacOS:
total 512
lrwxr-xr-x  1 root  wheel      20 23 mai 18:52 libccid.dylib -> libccid.dylib.1.4.21
-rwxr-xr-x  1 root  wheel  165888 17 sep  2015 libccid.dylib.1.4.14
-rwxr-xr-x  1 root  wheel  166096  3 déc 07:33 libccid.dylib.1.4.20
-rwxr-xr-x  1 root  wheel  166096  5 mai 08:02 libccid.dylib.1.4.21

Note that the symbolic link libccid.dylib now points to the latest driver version.

The files libccid.dylib.1.4.14 and libccid.dylib.1.4.20 are now useless and could be removed. But because of System Integrity Protection it is not easy and I think I will not remove them.

Conclusion

The problem should now be fixed.

If you installed a copy of the CCID driver in /usr/local/libexec/SmartCardServices/drivers/ as suggested by some people you may want to remove it now to avoid conflicts with the Apple provided CCID driver.

New version of libccid: 1.4.24

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

Changes:
1.4.24 - 22 May 2016, Ludovic Rousseau

  • Add support of
    • Generic USB Smart Card Reader
    • Giesecke & Devrient GmbH StarSign CUT S
    • HID AVIATOR Generic
  • better support of Elatec TWN4 SmartCard NFC
  • better support of SCM SCL011
  • betetr support of HID Aviator generic
  • fix SCARD_ATTR_VENDOR_IFD_SERIAL_NO attribute size
  • fix a race condition on card events with multiple readers
  • Some minor improvements

OS X El Capitan 10.11.5 and CCID driver still broken

Mac OS X El Capitan version 10.11.5 is now available. The Apple documentation "About the OS X El Capitan v10.11.5 Update" does not mention the CCID driver. But I am not surprised since many bugs have been fixed but are not listed in the upgrade message.

Unfortunately the problem reported in "OS X El Capitan and CCID driver upgrades" is still not fixed.

OS X 10.11.5

On Mac OS X 10.11.5 I have:

$ pwd
/usr/libexec/SmartCardServices/drivers

$ ls -lR ifd-ccid.bundle/
total 0
drwxr-xr-x  5 root  wheel  170 23 mar 09:30 Contents

ifd-ccid.bundle//Contents:
total 24
-rw-r--r--  1 root  wheel  36860 21 déc 06:05 Info.plist
drwxr-xr-x  6 root  wheel    204 23 mar 09:30 MacOS
-rw-r--r--  1 root  wheel    470 21 déc 06:05 version.plist

ifd-ccid.bundle//Contents/MacOS:
total 512
lrwxr-xr-x  1 root  wheel      20  4 nov  2015 libccid.dylib -> libccid.dylib.1.4.14
-rwxr-xr-x  1 root  wheel  165888 17 sep  2015 libccid.dylib.1.4.14
-rwxr-xr-x  1 root  wheel  166096  3 déc 07:33 libccid.dylib.1.4.20
-rwxr-xr-x  1 root  wheel  166096 12 mar 09:30 libccid.dylib.1.4.21

In my case the CCID driver is working but the driver binary is still wrong. I still have an half upgrade with the Info.plist file from CCID version 1.4.21 but the libccid.dylib binary is from CCID version 1.4.14.

Broken upgrade

If you had a broken upgrade with a file libccid.dylib either missing or pointing to a non existing file you may still have the same problem.

Proposed solution

The solution I proposed is still valid. See "OS X El Capitan and CCID driver upgrades".

I don't like the idea to install another CCID driver in /usr/local/ since that will/may create new problems when Apple fixes the original problem.

Conclusion

I reported a new bug at Apple as bug #26396810 "CCID smart card reader driver update not fixed in 10.11.5".

Update

On 24th May 2016, Apple closed my bug report as a duplicate:
Engineering has determined that your bug report (26396810) is a duplicate of another issue (26328490) and will be closed.

OS X El Capitan and CCID driver upgrades

Silent upgrade of the CCID driver

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

The first version of El Capitan 10.11 in September, 2015 was provided with the CCID driver version 1.4.14. See "OS X El Capitan and smart cards status" for more details.

I recently discovered that Apple upgraded the CCID driver in the minor upgrades (also thanks to Martin P. for the notice):
  • Mac OS X 10.11.3 provides the CCID driver version 1.4.20 (driver released 5 August 2015)
  • Mac OS X 10.11.4 provides the CCID driver version 1.4.21 (driver released 21 October 2015)

OS X 10.11

On Mac OS X 10.11 (or 10.11.0) I have:
$ ls -lR /usr/libexec/SmartCardServices/drivers
total 0
drwxr-xr-x  3 root  wheel  102 23 aoû  2015 ifd-ccid.bundle

/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle:
total 0
drwxr-xr-x  5 root  wheel  170  5 oct  2015 Contents

/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents:
total 56
-rw-r--r--  1 root  wheel  27616  5 oct  2015 Info.plist
drwxr-xr-x  4 root  wheel    136  2 oct  2015 MacOS
-rw-r--r--  1 root  wheel    471 23 aoû  2015 version.plist

/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/MacOS:
total 176
lrwxr-xr-x  1 root  wheel      20  2 oct  2015 libccid.dylib -> libccid.dylib.1.4.14
-rwxr-xr-x  1 root  wheel  165888 17 sep  2015 libccid.dylib.1.4.14

OS X 10.11.3

On Mac OS X 10.11.3 I have:

$ ls -lR /usr/libexec/SmartCardServices/drivers
total 0
drwxr-xr-x  3 root  wheel  102 Aug 23  2015 ifd-ccid.bundle

/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle:
total 0
drwxr-xr-x  5 root  wheel  170 Jan 28 10:05 Contents

/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents:
total 24
-rw-r--r--  1 root  wheel  33873 Sep 23  2015 Info.plist
drwxr-xr-x  5 root  wheel    170 Jan 28 10:05 MacOS
-rw-r--r--  1 root  wheel    469 Sep 23  2015 version.plist

/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/MacOS:
total 344
lrwxr-xr-x  1 root  wheel      20 Dec  9 15:06 libccid.dylib -> libccid.dylib.1.4.14
-rwxr-xr-x  1 root  wheel  165888 Oct 18  2015 libccid.dylib.1.4.14
-rwxr-xr-x  1 root  wheel  166096 Jan 14 03:06 libccid.dylib.1.4.20


OS X 10.11.4

On Mac OS X 10.11.4 I have:

$ pwd
/Volumes/ElCapitan/usr/libexec/SmartCardServices/drivers

$ ls -lR ifd-ccid.bundle/
total 0
drwxr-xr-x  5 root  wheel  170 Mar 22 13:23 Contents

ifd-ccid.bundle//Contents:
total 24
-rw-r--r--  1 root  wheel  36860 Dec 21 06:05 Info.plist
drwxr-xr-x  5 root  wheel    170 Mar 22 13:23 MacOS
-rw-r--r--  1 root  wheel    470 Dec 21 06:05 version.plist

ifd-ccid.bundle//Contents/MacOS:
total 344
lrwxr-xr-x  1 root  wheel      20 Sep 16  2015 libccid.dylib -> libccid.dylib.1.4.14
-rwxr-xr-x  1 root  wheel  165888 Sep  3  2015 libccid.dylib.1.4.14
-rwxr-xr-x  1 root  wheel  166096 Mar 12 09:30 libccid.dylib.1.4.21

Half upgrade

What is strange is that only the driver Info.plist file has been updated. A new binary driver is installed (libccid.dylib.1.4.20 or libccid.dylib.1.4.21) but not used.

The driver Info.plist file contains:

<key>CFBundleExecutable</key>
 <string>libccid.dylib</string>

So the driver binary is always the file libccid.dylib. And, as you can see from the previous commands libccid.dylib is just a symbolic link to the same libccid.dylib.1.4.14 file.

It looks like the upgrade is not complete:
  • New readers present in the driver Info.plist file will be recognized
  • Bugs fixes and new code from versions 1.4.15 to 1.4.21 are not used since the driver binary used is still at version 1.4.14.

Broken upgrade

Some/many people reported that the CCID driver was not working any more after the 10.11.4 upgrade. I have not (yet) reproduce this problem myself.

The driver configuration looks like this:

/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/MacOS:
lrwxr-xr-x 1 root wheel         20    3 déc 08:37   libccid.dylib -> libccid.dylib.1.4.20
-rwxr-xr-x 1 root wheel     166096   12 mar 09:30   libccid.dylib.1.4.21

The symbolic link points to a non-existent libccid.dylib.1.4.20 file. So, of course, the driver is not loaded and the support of CCID readers is broken.

Error message in the system log file:
com.apple.ifdreader[219]: Failed to load IFD bundle executable:
'file:///usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/' with error: Error Domain=NSCocoaErrorDomain Code=4 "The bundle “CCIDCLASSDRIVER” couldn’t be loaded because its executable couldn’t be located." UserInfo={NSLocalizedFailureReason=The bundle’s executable couldn’t be located., NSLocalizedRecoverySuggestion=Try reinstalling the bundle., NSBundlePath=/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle, NSLocalizedDescription=The bundle “CCIDCLASSDRIVER” couldn’t be loaded because its executable couldn’t be located.}

Proposed solution

Because of System Integrity Protection [or wikipedia], it is forbidden to change/remove/add files in the /usr/ directory.

My proposal to fix the issue, until Apple provides a fix, is to:
  1. disable SIP
  2. fix the symbolic link using some think like
    cd /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/MacOS
    ln -sf libccid.dylib.1.4.21 libccid.dylib
  3. enable SIP

Another solution

In the Apple developer forums "gtall" reported the same problem in "el capitan 10.11.4 unable to see smartcard" and "Metsma" posted a different workaround.

Maybe Apple will publish a Technical Note to give a better solution or, better, provide a version 10.11.5 with a fix for the CCID driver.

Conclusion

I reported the problem to Apple as bug #25873806 "CCID smart card reader driver update failed in 10.11.4".

That is the first time that Apple updates a smart card component (instead of just fixing bugs) with minor revisions of Mac OS X. Maybe it is a sign that Apple cares about smart cards?

My list of El Capitan known smart card bugs contains 7 unfixed bugs and 3 wanted features. There is still Apple work to do for the next (minor or major) release of Mac OS X.

Update

On 26th April 2016, Apple closed my bug report as a duplicate:
"Engineering has determined that your bug report (25873806) is a duplicate of another issue (25416818) and will be closed."

New version of libccid: 1.4.23

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

Changes:
1.4.23 - 20 April 2016, Ludovic Rousseau

  • Add support of
    • ACS ACR3901U ICC Reader
    • Alcor Micro AU9560
    • Cherry SmartTerminal XX44
    • HID Global OMNIKEY 3x21 Smart Card Reader
    • HID Global OMNIKEY 5022 Smart Card Reader
    • HID Global OMNIKEY 6121 Smart Card Reader
    • IonIDe Smartcard Reader reader
    • KACST HSID Reader
    • KACST HSID Reader Dual Storage
    • KACST HSID Reader Single Storage
  • Remove support of
    • VMware Virtual USB CCID
  • Do NOT add support of
    • DUALi DE-ABCM6
  • Fix a busy loop consuming 100% of CPU for some composite USB devices
    impacted readers: Yubico Yubikey NEO U2F+CCID and Broadcom BCM5880
  • Remove support of (unused) option DRIVER_OPTION_RESET_ON_CLOSE
  • log libusb error name instead of decimal value
  • Some minor improvements

OS X El Capitan bug: SCardGetAttrib() returns SCARD_E_NOT_TRANSACTED when it should not

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

SCardGetAttrib() returns SCARD_E_NOT_TRANSACTED when it should not

SCardGetAttrib() does not work correctly any more on El Capitan. SCardGetAttrib() is used to get an attribute value from the IFD Handler (the smart card reader driver).

One idea of SCardGetAttrib() is to use a double call:
  • 1st call to get the correct buffer size to store the attribute
  • 2nd call to fill the allocated buffer with the requested attribute value

The program then looks like:
rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, NULL, &attrLen);
  attr = malloc(attrLen);
  rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, attr, &attrLen);

  1. On the first call the pbAttr pointer is NULL because no buffer is used. This call will just but the correct buffer size in the pcbAttrLen parameter (named attrLen here).
  2. A big enough buffer is allocated to store the attribute value.
  3. On the second call the buffer is passed as argument and is filled by the SCardGetAttrib() call.

I discovered that the first call to SCardGetAttrib() fails and returns SCARD_E_NOT_TRANSACTED if the value in attrLen (given to the function) is lower than the needed buffer size.

This input value (buffer size) should just be ignored by PC/SC since the buffer pointer is NULL (no buffer is used). The parameter is used to get a value from the function, not to give a value to the function.

See also

Apple bug report #25802143 "PCSC SCardGetAttrib() returns SCARD_E_NOT_TRANSACTED when it should not"

Sample code


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

#define SCARD_ATTR_VALUE(Class, Tag) ((((ULONG)(Class)) << 16) | ((ULONG)(Tag)))
#define SCARD_CLASS_ICC_STATE       9   /**< ICC State specific definitions */
#define SCARD_ATTR_ATR_STRING SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0303) /**< Answer to reset (ATR) string. */

#define RED "\33[01;31m"
#define NORMAL "\33[0m"
#define pcsc_error(fct) printf(RED fct ": %s 0x%08X\n" NORMAL, pcsc_stringify_error(err), err)

int main(void)
{
    SCARDCONTEXT hContext;
    LPSTR mszReaders;
    DWORD err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
    if (err != SCARD_S_SUCCESS) {
        pcsc_error("ScardEstablishedContext");
        return -1;
    }
    DWORD cchReaders = 0;
    err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders);
    if (err != 0) {
        pcsc_error("ScardListReaders");
        return -1;
    }
    mszReaders = calloc(cchReaders, sizeof(char));
    if (!mszReaders) {
        pcsc_error("calloc\n");
        return -1;
    }
    err = SCardListReaders(hContext,"SCard$AllReaders", mszReaders, &cchReaders);
    if (err != SCARD_S_SUCCESS) {
        pcsc_error("ScardListReaders");
        return -1;
    }

    printf("Reader: %s\n", mszReaders);

    SCARDHANDLE hCard;
    DWORD dwActiveProtocol;
    err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_RAW, &hCard, &dwActiveProtocol);
    if (err != SCARD_S_SUCCESS) {
        pcsc_error("ScardConnect");
    } else {
        unsigned char attr[33] = { 0 };
        unsigned int i;
        DWORD attrLen;

        attrLen = 22;
        err = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, NULL, &attrLen);
        printf("attrLen: %d\n", attrLen);
        if (err != SCARD_S_SUCCESS) {
            pcsc_error("SCardGetAttrib");
        }

        attrLen = 123456;
        err = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, NULL, &attrLen);
        printf("attrLen: %d\n", attrLen);
        if (err != SCARD_S_SUCCESS) {
            pcsc_error("SCardGetAttrib");
        }

        attrLen = sizeof attr;
        err = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, attr, &attrLen);
        printf("attrLen: %d\n", attrLen);
        if (err != SCARD_S_SUCCESS) {
            pcsc_error("SCardGetAttrib");
        } else {
            for (i=0; i<attrLen; i++)
                printf("%02X ", attr[i]);
            printf("\n");
        }
    }
    SCardDisconnect(hCard, SCARD_LEAVE_CARD);
    SCardReleaseContext(hContext);
    return 0;
}


Result (on El Capitan)

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

Reader: Gemalto PC Twin Reader
attrLen: 22
SCardGetAttrib: Transaction failed. 0x80100016
attrLen: 23
attrLen: 23
3B FD 94 00 00 81 31 20 43 80 31 80 65 B0 83 02 04 7E 83 00 90 00 B6 

Here the requested attribute is the card ATR (dwAttrId = SCARD_ATTR_ATR_STRING) with a size of 23 bytes. If the first call to SCardGetAttrib() uses a value of 22 (or less) then the function returns with the error SCARD_E_NOT_TRANSACTED (0x80100016)

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

Reader: Gemalto PC Twin Reader (70D7E2EE) 00 00
attrLen: 23
attrLen: 23
attrLen: 23
3B FD 94 00 00 81 31 20 43 80 31 80 65 B0 83 02 04 7E 83 00 90 00 B6 

Known workaround

Do not use a random value for attrLen on the first call (or you will get random results). But initialize the variable to a big enough value. A value of 65535 should be good enough in most cases.

Update: 27th September 2016

This bugs is fixed in macOS Sierra 10.12.0.

ATR statistics: TA1 - Global, encodes Fi and Di

Article from the series "ATR statistics"

TA1 - Global, encodes Fi and Di

The ISO 7816-3 specification is not public. So I can't copy/paste part of the text. I will use Wikipedia instead.

From Wikipedia https://en.wikipedia.org/wiki/Answer_to_reset#Interface_byte_TA1 (with some edition to remove extra details):
Interface byte TA1, if present, is global, and encodes the maximum clock frequency fmax supported by the card, and the number of clock periods per ETU that it suggests to use after the ATR, expressed as the ratio Fi/Di of two integers. When TA1 is absent, it's assumed default value is ‘11’, corresponding to fmax = 5 MHz, Fi = 372, Di = 1.

The 4 low-order bits of TA1 (4th MSbit to 1st LSbit) encode Di as:
4th to 1st bits 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
Di RFU 1 2 4 8 16 32 64 12 20 RFU RFU RFU RFU RFU RFU

The 4 high-order bits of TA1 (8th MSbit to 5th LSbit) encode fmax and Fi as:
8th to 5th bits 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
Fi 372 372 558 744 1 116 1 488 1 860 RFU RFU 512 768 1 024 1 536 2 048 RFU RFU
fmax (MHz) 4 5 6 8 12 16 20 5 7.5 10 15 20

TA1 # %
932 44.98 %
0x18 241 11.63 %
0x96 202 9.75 %
0x94 167 8.06 %
0x95 158 7.63 %
0x13 136 6.56 %
0x11 124 5.98 %
0x00 18 0.87 %
0x91 16 0.77 %
0x12 15 0.72 %
0x98 15 0.72 %
0x14 14 0.68 %
0x21 8 0.39 %
0x15 7 0.34 %
0x97 6 0.29 %
0x38 4 0.19 %
0x01 1 0.05 %
0x04 1 0.05 %
0x16 1 0.05 %
0x32 1 0.05 %
0x36 1 0.05 %
0x3F 1 0.05 %
0xA8 1 0.05 %
0xD6 1 0.05 %
0xFF 1 0.05 %


The TA1 value indicates the maximal communication speed between the card and the reader supported by the card. The reader may not support such a high speed. A lower speed will then be used (negotiated by the reader itself or by the reader driver).

Data rate (communication speed)

To know the speed value we need to convert the TA1 value in Fi/Di into a speed value in bit/s.

TA1 Fi Di cycles/ETU bits/s at 4 Mhz Fmax Mhz bits/s at Fmax
0x01 372 1 372 10752 4 10752
0x04 372 8 46 86956 4 86956
0x16 372 32 11 363636 5 454545
0x32 744 2 372 10752 8 21505
0x36 744 32 23 173913 8 347826
0x3F 744 RFU RFU RFU RFU RFU
0xA8 768 12 64 62500 7.5 117187.5
0xD6 2048 32 64 62500 20 312500
0xFF RFU RFU RFU RFU RFU RFU
0x38 744 12 62 64516 8 129032
0x97 512 64 8 500000 5 625000
0x15 372 16 23 173913 5 217391
0x21 558 1 558 7168 6 10752
0x14 372 8 46 86956 5 108695
0x12 372 2 186 21505 5 26881
0x98 512 12 42 95238 5 119047
0x91 512 1 512 7812 5 9765
0x00 372 RFU RFU RFU RFU RFU
0x11 372 1 372 10752 5 13440
0x13 372 4 93 43010 5 53763
0x95 512 16 32 125000 5 156250
0x94 512 8 64 62500 5 78125
0x96 512 32 16 250000 5 312500
0x18 372 12 31 129032 5 161290
0x11 372 1 372 10752 5 13440

The table provides the data rate value for a clock of 4 Mhz. We have seen in "CCID descriptor statistics: dwDefaultClock" that 4 Mhz is the default clock of 48% of the CCID readers in my list.

You can note that there is different values of Fi and Di that give the same data rate. For example TA1=0xA8 and TA1=0xD6 both give a data rate of 62500 bits/s when using a clock at 4 MHz.

Population

We can count the number of ATR for each value of TA1. We get the table bellow:
TA1 bits/s at 4 Mhz bits/s at Fmax #
0x01 10752 10752 1
0x04 86956 86956 1
0x16 363636 454545 1
0x32 10752 21505 1
0x36 173913 347826 1
0x3F RFU RFU 1
0xA8 62500 117187.5 1
0xD6 62500 312500 1
0xFF RFU RFU 1
0x38 64516 129032 4
0x97 500000 625000 6
0x15 173913 217391 7
0x21 7168 10752 8
0x14 86956 108695 14
0x12 21505 26881 15
0x98 95238 119047 15
0x91 7812 9765 16
0x00 RFU RFU 18
0x11 10752 13440 124
0x13 43010 53763 136
0x95 125000 156250 158
0x94 62500 78125 167
0x96 250000 312500 202
0x18 129032 161290 241
10752 13440 932

We can draw a graph of the number of ATR for a given data rates to get an idea of the repartition:

In the graph I merged the results for a same data rate. So for the value 10 752 bits/s we get the sum of TA1=0x11 and no TA1 so the default value of 0x11. The total is then 932+124=1056.

We can also compute and display the median value:

Half of the cards have a data rate below 86 956 bits/s and the other half has a data rate above 86 956 bits/s.

Using Fmax

The Fi value also gives the maximal clock speed supported by the smart card. The value goes from 4 Mhz to 20 MHz. If we reuse the same examples the maximal clock speed for TA1=0xA8 is 7.5 Mhz and for TA1=0xD6 it is 20 Mhz. The data rates using the maximal clock speed are then quite different: we have 11 7187.5 bits/s for TA1=0xA8 and 312 500 bits/s for TA1=0xD6.

So we get another distribution graph:

And another median:

This time the median value is 113 871 bits/s.

Reader max clock speed

Note that only 4 readers have a clock that can go up to 20 Mhz (or more). But I guess they are bogus readers.
The highest "common" clock speed is more likely 16 Mhz with 16 readers (3.95%).

OS X El Capitan bug: SCardGetAttrib() returns SCARD_E_NOT_TRANSACTED instead of SCARD_E_INSUFFICIENT_BUFFER

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

SCardGetAttrib() returns SCARD_E_NOT_TRANSACTED instead of SCARD_E_INSUFFICIENT_BUFFER

SCardGetAttrib() does not work correctly on El Capitan 10.11.4 (on Yosemite the function was not usable at all. See "OS X Yosemite bug: SCardGetAttrib").

When the buffer is too small to store the result the function may return SCARD_E_NOT_TRANSACTED instead of the expected SCARD_E_INSUFFICIENT_BUFFER.

The problem is not present for all the attributes. For example it is the case for SCARD_ATTR_ATR_STRING (Answer to reset (ATR) string) but not for SCARD_ATTR_VENDOR_IFD_SERIAL_NO (Vendor-supplied interface device serial number). This is because for SCARD_ATTR_ATR_STRING the CCID diver checks the buffer size and returns IFD_ERROR_INSUFFICIENT_BUFFER to the PC/SC middleware. In the case of SCARD_ATTR_VENDOR_IFD_SERIAL_NO the buffer size is not checked by the CCID driver and the CCID returns IFD_SUCCESS (the buffer between pcscd and the driver is 264 bytes long and is enough to store a serial number).

It should be the job of the PC/SC middleware to check the user provided buffer is large enough and return SCARD_E_INSUFFICIENT_BUFFER to the application when needed.

See also

Apple bug report #25463286 "PCSC SCardGetAttrib() returns SCARD_E_NOT_TRANSACTED instead of SCARD_E_INSUFFICIENT_BUFFER"

Sample code


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

#define SCARD_ATTR_VALUE(Class, Tag) ((((ULONG)(Class)) << 16) | ((ULONG)(Tag)))
#define SCARD_CLASS_ICC_STATE       9   /**< ICC State specific definitions */
#define SCARD_ATTR_ATR_STRING SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0303) /**< Answer to reset (ATR) string. */

#define RED "\33[01;31m"
#define NORMAL "\33[0m"
#define pcsc_error(fct) printf(RED fct ": %s 0x%08X\n" NORMAL, pcsc_stringify_error(err), err)

int main(int argc, const char * argv[])
{
    SCARDCONTEXT hContext;
    LPSTR mszReaders;
    DWORD err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
    if (err != SCARD_S_SUCCESS) {
        pcsc_error("ScardEstablishedContext");
        return -1;
    }
    DWORD cchReaders = 0;
    err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders);
    if (err != 0) {
        pcsc_error("ScardListReaders");
        return -1;
    }
    mszReaders = calloc(cchReaders, sizeof(char));
    if (!mszReaders) {
        pcsc_error("calloc\n");
        return -1;
    }
    err = SCardListReaders(hContext,"SCard$AllReaders", mszReaders, &cchReaders);
    if (err != SCARD_S_SUCCESS) {
        pcsc_error("ScardListReaders");
        return -1;
    }

    printf("Reader: %s\n", mszReaders);

    SCARDHANDLE hCard;
    DWORD dwActiveProtocol;
    err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_RAW, &hCard, &dwActiveProtocol);
    if (err != SCARD_S_SUCCESS) {
        pcsc_error("ScardConnect");
    } else {
        DWORD attrLen = 33;
        unsigned char attr[attrLen];
        unsigned int i;
        err = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, attr, &attrLen);
        printf("attrLen: %d\n", attrLen);
        if (err != SCARD_S_SUCCESS) {
            pcsc_error("SCardGetAttrib");
        } else {
            printf("SCARD_ATTR_ATR_STRING: %d\n", attrLen);
            for (i=0; i<attrLen; i++)
                printf("%02X ", attr[i]);
            printf("\n");
        }

        attrLen = 2;
        err = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, attr, &attrLen);
        printf("attrLen: %d\n", attrLen);
        if (err != SCARD_S_SUCCESS) {
            pcsc_error("SCardGetAttrib");
        } else {
            printf("SCARD_ATTR_ATR_STRING: %d\n", attrLen);
            for (i=0; i<attrLen; i++)
                printf("%02X ", attr[i]);
            printf("\n");
        }
    }
    SCardDisconnect(hCard, SCARD_LEAVE_CARD);
    SCardReleaseContext(hContext);
    return 0;
}

The sample code performs 2 calls to SCardGetAttrib() with 2 different buffer sizes.
  • The first time the size is 33 bytes and is big enough to contain the ATR.
  • The second time the size is 2 bytes and is obviously too short.

Result (on El Capitan 10.11.4)

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

$ ./main
Reader: Gemalto PC Twin Reader
attrLen: 23
SCARD_ATTR_ATR_STRING: 23
3B FD 94 00 00 81 31 20 43 80 31 80 65 B0 83 02 04 7E 83 00 90 00 B6 
attrLen: 2
SCardGetAttrib: Transaction failed. 0x80100016

As expected the first SCardGetAttrib() call succeeds and returns the card ATR value.

The second call with pcbAttrLen set to 2 fails and returns the unexpected error SCARD_E_NOT_TRANSACTED.

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 
Reader: Gemalto PC Twin Reader (70D7E2EE) 00 00
attrLen: 23
SCARD_ATTR_ATR_STRING: 23
3B FD 94 00 00 81 31 20 43 80 31 80 65 B0 83 02 04 7E 83 00 90 00 B6 
attrLen: 2
SCardGetAttrib: Insufficient buffer. 0x80100008

On GNU/Linux we have the expected behavior: SCARD_E_INSUFFICIENT_BUFFER is returned on the second call.

Known workaround

None known.
Be sure to always use big enough buffers.

Update: 27th September 2016

This bug is fixed in macOS Sierra 10.12.0.

New version of pcsc-lite: 1.8.16

I just released a new version of pcsc-lite 1.8.16.
pcsc-lite is a Free Software implementation of the PC/SC (or WinSCard) API for Unix systems.

Changes:
1.8.16: Ludovic Rousseau
20 March 2016

  • SCardCancel() was not correctly handled
    When a SCardGetStatusChange() was cancelled then a next PC/SC call after the SCardGetStatusChange() may fail with a strange error code if the event waited in SCardGetStatusChange() occurs.
  • Doxygen: fix different documentation issues
  • SCARD_SCOPE_GLOBAL is now defined in a public header (even if never used)
  • Enable Trace and Profile features using compiler flags and without modifying the source code
  • Some other minor improvements and bug corrections

New version of pcsc-tools: 1.4.26

I just released a new version of pcsc-tools, a suite of tools for PC/SC.

Changes:
1.4.26 - 19 March 2016, Ludovic ROUSSEAU

  • 77 new ATRs
  • ATR_analysis: fix display the submission message
  • fix typos in pcsc_scan.1 and scriptor.1p man pages