Important!

Blog moved to https://blog.apdu.fr/

I moved my blog from https://ludovicrousseau.blogspot.com/ to https://blog.apdu.fr/ . Why? I wanted to move away from Blogger (owne...

Thursday, March 31, 2016

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.

Sunday, March 20, 2016

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

Monday, March 7, 2016

ATR statistics: T0 - Format byte

Article from the series "ATR statistics"

T0 - Format byte

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#Format_byte_T0:

Format byte T0

The Format byte T0 encodes in its 4 low-order bits (4th MSbit to 1st LSbit) the number K of historical bytes Ti, in range [0..15].
It also encodes in its 4 high-order bits the presence of at most 4 other interface bytes: TA1 (resp. TB1, TC1, TD1) follow, in that order, if the 5th (resp. 6th, 7th, 8th) bit of T0 is 1.

T0#%
0xFF1607.72 %
0x9F1457.00 %
0x8F1085.21 %
0x6F1014.87 %
0x7F874.20 %
0x6E823.96 %
0x65582.80 %
0x9E512.46 %
0x7D452.17 %
0x67432.08 %
0xEF401.93 %
0x88371.79 %
0x6D311.50 %
0xFD281.35 %
0x3F251.21 %
0xFA251.21 %
0x68241.16 %
0x04231.11 %
0x3B221.06 %
0x85221.06 %
0xF7221.06 %
0xDB211.01 %
0xBE200.97 %
0xBF200.97 %
0x16190.92 %
0x6B190.92 %
0x8C190.92 %
0xDF190.92 %
0xFB190.92 %
0x8A180.87 %
0xF9170.82 %
0x1F160.77 %
0x66160.77 %
0x69160.77 %
0x7E160.77 %
0x89160.77 %
0x78150.72 %
0x95150.72 %
0xFE150.72 %
0x17130.63 %
0x77130.63 %
0x8E130.63 %
0xDD130.63 %
0xF8130.63 %
0x2F120.58 %
0x6A120.58 %
0x6C120.58 %
0x86120.58 %
0x8B120.58 %
0xE9120.58 %
0x7A110.53 %
0x98110.53 %
0x9A100.48 %
0x9D100.48 %
0xBA100.48 %
0x2790.43 %
0x8290.43 %
0x8790.43 %
0xBC90.43 %
0xE690.43 %
0x0680.39 %
0x1980.39 %
0x2A80.39 %
0x7B80.39 %
0x8480.39 %
0xF280.39 %
0xFC80.39 %
0x0F70.34 %
0x2670.34 %
0x3D70.34 %
0x7570.34 %
0x7970.34 %
0xB770.34 %
0xD570.34 %
0xEA70.34 %
0xF570.34 %
0x1560.29 %
0x2360.29 %
0x3C60.29 %
0x7660.29 %
0xA760.29 %
0x0250.24 %
0x2450.24 %
0x8D50.24 %
0xB250.24 %
0xE250.24 %
0xE850.24 %
0xEE50.24 %
0x0540.19 %
0x1840.19 %
0x7C40.19 %
0x9C40.19 %
0xB340.19 %
0xD940.19 %
0xDC40.19 %
0xDE40.19 %
0xE740.19 %
0xF040.19 %
0xF640.19 %
0x0730.14 %
0x1230.14 %
0x1B30.14 %
0x1D30.14 %
0x2930.14 %
0x3730.14 %
0x3E30.14 %
0x5F30.14 %
0x6430.14 %
0x9730.14 %
0x9930.14 %
0x9B30.14 %
0xB930.14 %
0xBB30.14 %
0xBD30.14 %
0xD230.14 %
0xD630.14 %
0xEC30.14 %
0xED30.14 %
0xF430.14 %
0x0A20.10 %
0x3220.10 %
0x3420.10 %
0x5B20.10 %
0x8120.10 %
0x8320.10 %
0x9020.10 %
0x9620.10 %
0xA820.10 %
0xAA20.10 %
0xAC20.10 %
0xB020.10 %
0xB820.10 %
0xD820.10 %
0xDA20.10 %
0xE020.10 %
0xE520.10 %
0xEB20.10 %
0x0010.05 %
0x0910.05 %
0x0E10.05 %
0x1C10.05 %
0x1E10.05 %
0x2810.05 %
0x2D10.05 %
0x5710.05 %
0x5E10.05 %
0x6310.05 %
0x7410.05 %
0x8010.05 %
0x9110.05 %
0x9410.05 %
0xAB10.05 %
0xAD10.05 %
0xD010.05 %
0xE310.05 %
0xF310.05 %


Doing statistics on the complete T0 byte is not really informative.

Interface nibble

format#%
130.14 %
0130.63 %
3150.72 %
2401.93 %
4462.22 %
12723.47 %
6864.15 %
9904.34 %
101075.16 %
111155.55 %
81165.60 %
51286.18 %
71366.56 %
131507.24 %
1421210.23 %
1574335.86 %


Interpretation

In 36% of the ATRs the LSB is equal to 15 (or 1111b in binary) indicating that TA1, TB1, TC1, TD1 are present.

For 10% of ATRs the LSB is equal to 14 (or 1110b in binary) indicating that TB1, TC1, TD1 are present, and TA1 is not present.

For 0.63% of ATRs the LSB is equal to 0 (or 0000b in binary) indicate that TA1, TB1, TC1, TD1 are all absent.

A better way to display the result is to isolate TA1, TB1, TC1, TD1 and count them independently.
interface#%
TA199648.07 %
TB1135565.40 %
TC1138166.65 %
TD151925.05 %


Historic nibble

historic#%
400.00 %
570.34 %
10140.68 %
2522.51 %
0552.65 %
3703.38 %
1773.72 %
13834.01 %
11884.25 %
141004.83 %
722010.62 %
926112.60 %
829314.14 %
1533416.12 %
641820.17 %


The number of historic bytes is not equally distributed between 0 and 15 bytes. I guess that is because the historic bytes are coded using a TLV format so some sizes are more frequent than others.



Update: 22th March 2020

It looks like the data for the Historic nibble are wrong. You can get correct values in the article "ATR statistics: Historical bytes - Historical bytes Ti (optional)".
Sorry for that mistake.

Tuesday, February 23, 2016

PCSC framework spy: broken since Mac OS X Yosemite

In "PCSC API spy, on Mac OS X" I proposed a way to spy on all PC/SC calls of an application.

A few months later Yosemite was available and my spying library does not work any more ☹.

PCSC framework replacement: fails

Example of failure:
$ DYLD_FRAMEWORK_PATH=/tmp pcsc_scan
PC/SC device scanner
V /Users/lroussea/Documents/sc/costa/pcsc-tools (c) 2001-2011, Ludovic Rousseau 
Compiled with PC/SC lite version: 1.4.0
SCardEstablishContext: Service not available.

Spy output (in a second terminal window):
$ ./pcsc-spy
SCardEstablishContext
 i dwScope: SCARD_SCOPE_SYSTEM (0x00000002)
 o hContext: 0x00000000
 => Service not available. (SCARD_E_NO_SERVICE [0x8010001D])  [0.000001109]
SCardReleaseContext
 i hContext: 0x00000000
 => Invalid handle. (SCARD_E_INVALID_HANDLE [0x80100003])  [0.000000006]

Results sorted by total execution time
total time: 0.001138 sec
0.001109 sec (  1 calls) 97.45% SCardEstablishContext
0.000006 sec (  1 calls)  0.53% SCardReleaseContext

If I run pcsc_scan alone, with no PC/SC spy, then the command runs as expected.

Something detects the usage of a new PCSC framework and rejects the first call. I guess the culprit is the original PCSC framework itself and this is a new security feature from Yosemite.

Running the application as root (using sudo) does not help.

SIP: System Integrity Protection

A new change since El Capitan is that the use of DYLD_FRAMEWORK_PATH does not work for programs in protected directories, like /usr/bin/.
$ type pcsctest
pcsctest is hashed (/usr/bin/pcsctest)

$ DYLD_FRAMEWORK_PATH=/tmp pcsctest

MUSCLE PC/SC Lite Test Program

Testing SCardEstablishContext    : Command successful.
Testing SCardGetStatusChange 
Please insert a working reader   : Command successful.
Testing SCardListReaders         : Command successful.
Reader 01: Gemalto PC Twin Reader
Enter the reader number          : ^C

Here the command succeeds but nothing is sent over the spy pipe.

In Yosemite I could use DYLD_FRAMEWORK_PATH=/tmp but with the same results as described above. On El Capitan the dynamic linker dyld just ignores DYLD_FRAMEWORK_PATH.

Another way to check that is to use lldb, the debugger provided with Xcode.

$ lldb pcsctest
(lldb) target create "pcsctest"
Current executable set to 'pcsctest' (x86_64).
(lldb) run
error: process exited with status -1 (cannot attach to process due to System Integrity Protection)
(lldb) quit

Conclusion

I know no way to spy the PC/SC calls done by an application on Mac OS X (with version >= 10.10).

This is problematic because PC/SC is still unstable on El Capitan. See "OS X El Capitan and smart cards: known bugs" for example. In some cases it would really help to know what PC/SC call returns an error to be able to:
  • Report the error to Apple if it is a bug in PC/SC
  • Tell the customer that it is a bug on Apple side
  • Try to find a way to avoid the problem, if possible

Friday, February 5, 2016

PySCard 1.9.2 released

I just released a new official version 1.9.2 of pyscard. PySCard is a python module adding smart cards support (PC/SC) to Python.

The PySCard project is available at:

Changes

1.9.2 (February 2016)
  • Fix toBytes regression
  • Fix installation using pip
  • improve pydoc documentation
  • user-guide.rst: use real sample codes
  • minor improvements

I forgot to announce the previous version 1.9.1 on the blog.

1.9.1 (September 2015)
  • Create a new version so that the upload to Pypi does _not_ contain the swig generated files.

Remaining problem

The versions 1.9.1 and 1.9.2 were supposed to fix  a problem when the software is installed using pip. But the problem is still present ☹.

The best way, for now, to install the software from source code is to use:
$ cd pyscard-1.9.2
$ python setup.py install

Wednesday, February 3, 2016

ATR statistics: TS, initial character

Article from the series "ATR statistics"

TS: initial character

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#Initial_character_TS:

Initial character TS

The initial character TS encodes the convention used for encoding of the ATR, and further communications until the next reset. In direct [resp. inverse] convention, bits with logic value ‘1’ are transferred as a High voltage (H) [resp. a Low voltage (L)]; bits with logic value ‘0’ are transferred as L [resp. H]; and least-significant bit of each data byte is first (resp. last) in the physical transmission by the card.
For  direct   convention, TS is (H) L H H L H H H L L H (H) and encodes the byte ‘3B’.
For inverse convention, TS is (H) L H H L L L L L L H (H) and encodes the byte ‘3F’.
[ (H) represents the idle (High, Mark) state of the I/O line. The 8 data bits are shown in italic. ]
Bits in bytes following TS in the ATR, and further communications until the next reset, are numbered 1st to 8th from low-order to high-order, and their value noted 0 or 1, regardless of the chronological order and electrical representation, defined by TS. The bit following the 8 data bits in these bytes is an even parity bit, that is such that there's an even number of ‘1’ bits (H or L according to the direct or inverse convention defined by TS) among the 8 data bits and the parity bit.
TS also allows the card reader to confirm or determine the ETU, as one third of the delay between the first and second H-to-L transition in TS. This is optional, and the principal definition of ETU in the ATR of standard-compliant asynchronous Smart Cards is 372 periods of the clock received by the card

This first byte is used to indicate how bits and bytes are encoded at the electrical level: direct or inverse convention.

This choice has no impact on performances. As you can see, the vast majority of cards (94%) are using the direct convention (0x3B).

TS#%
0x3B194593.87 %
0x3F1276.13 %