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...

Friday, December 19, 2014

Great OpenPGP smart card article (in French)

gouttegd published a very good article about the configuration and use of an OpenPGP smart card. The article is "“OpenPGP card“, une application cryptographique pour carte à puce" and is written in French (sorry).

Sommaire

OS X Yosemite bug: SCardStatus returns SCARD_E_INSUFFICIENT_BUFFER

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

SCardStatus returns SCARD_E_INSUFFICIENT_BUFFER

SCardStatus() does not correctly report the reader name length. The terminating NUL character of the reader name is not counted. So a second call to SCardStatus() using the size returned by the first SCardStatus() call will fail with 0x80100008 (that is SCARD_E_INSUFFICIENT_BUFFER).

It is a really stupid bug and very easy to fix for Apple.

See also

"Problem with SCardStatus on MAC OS X 10.10 (Yosemite)" at https://smartcardservices.macosforge.org/trac/ticket/140.

Apple bug report #19306215 "PC/SC SCardStatus returns SCARD_E_INSUFFICIENT_BUFFER". Closed by Apple, 9th January 2015, as a duplicated of #18890042.

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

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) {
  printf("ScardEstablishedContext: 0x%08x\n",err);
  return -1;
 }

 DWORD cchReaders = 0;
 err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders);
 if (err != 0) {
  printf("ScardListReaders: 0x%08x\n",err);
  return -1;
 }
 mszReaders = calloc(cchReaders, sizeof(char));
 if (!mszReaders) {
  printf("calloc\n");
  return -1;
 }
 err = SCardListReaders(hContext,"SCard$AllReaders", mszReaders, &cchReaders);
 if (err != SCARD_S_SUCCESS) {
  printf("ScardListReaders: 0x%08x\n",err);
  return -1;
 }
 printf("Reader: %s\n", mszReaders);

 SCARDHANDLE hCard;
 DWORD dwActiveProtocol;
 err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
 if (err != SCARD_S_SUCCESS) {
  printf("ScardConnect: 0x%08x\n",err);
  return -1;
 }

 /* 1st SCardStatus call to get the reader name length */
 char name[100];
 DWORD len;
 err = SCardStatus(hCard, NULL, &len, NULL, NULL, NULL, NULL);
 if (err != SCARD_S_SUCCESS) {
  printf("SCardStatus: 0x%08x\n",err);
  return -1;
 }
 printf("reader name length: %d\n", len);
 //len += 1;

 /* 2nd SCardStatus call to get the reader name value */
 err = SCardStatus(hCard, name, &len, NULL, NULL, NULL, NULL);
 if (err != SCARD_S_SUCCESS) {
  printf("SCardStatus: 0x%08x\n",err);
  return -1;
 }
 printf("Reader name: %s (%ld)\n", name, strlen(name));

 SCardDisconnect(hCard, SCARD_LEAVE_CARD);
 SCardReleaseContext(hContext);

 return 0;
}

Result (on Yosemite)

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

$ ./main
Reader: Gemalto PC Twin Reader
reader name length: 22
SCardStatus: 0x80100008

If I uncomment the line: len += 1; I get:
$ ./main
Reader: Gemalto PC Twin Reader
reader name length: 22
Reader name: Gemalto PC Twin Reader (22)

Note that the reader length returned by the first SCardStatus() call is identical to the value returned by strlen(name). And strlen() does NOT includes the terminating NUL character.

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 00 00
reader length: 29
Reader name: Gemalto PC Twin Reader 00 00 (28)

Note that the length returned by the first SCardStatus() call is strlen(name) + 1.

Known workaround

Add 1 to the reader length returned by SCardStatus().

Update

This bug is now fixed in Mac OS X Yosemite 10.10.2.

Tuesday, December 16, 2014

OS X Yosemite bug: SCardStatus() after a card reset

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

SCardStatus() after a card reset

SCardStatus() does not corectly detect card reset any more on OS X 10.10 Yosemite.

If a card has been reseted using another PC/SC context then SCardStatus() will not fail with 0x80100068 (for SCARD_W_RESET_CARD) as before but will succeed instead.
The problem will be detected later by, for example, the next SCardTransmit() returning SCARD_W_RESET_CARD.

The problem is similar to the one described in OS X Yosemite bug: SCardBeginTransaction() after a card reset.

What is strange is that SCardTransmit() erroneously returns SCARD_W_RESET_CARD after a SCardReconnect(..., SCARD_RESET_CARD, ...) (see OS X Yosemite bug: SCardReconnect) but SCardStatus() do not return SCARD_W_RESET_CARD in the same case. The card reset (or not) state is managed in a "funny" way inside PC/SC on Yosemite.

See also

Apple bug report #19264087 "PC/SC function SCardStatus() fails to fail after a card reset"
#19264087 closed as a duplicate of #18689292.

Sample code

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

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) {
  printf("ScardEstablishedContext: 0x%08x\n",err);
  return -1;
 }

 DWORD cchReaders = 0;
 err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders);
 if (err != 0) {
  printf("ScardListReaders: 0x%08x\n",err);
  return -1;
 }
 mszReaders = calloc(cchReaders, sizeof(char));
 if (!mszReaders) {
  printf("calloc\n");
  return -1;
 }
 err = SCardListReaders(hContext,"SCard$AllReaders", mszReaders, &cchReaders);
 if (err != SCARD_S_SUCCESS) {
  printf("ScardListReaders: 0x%08x\n",err);
  return -1;
 }
 printf("Reader: %s\n", mszReaders);

 SCARDHANDLE hCard;
 DWORD dwActiveProtocol;
 err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
 if (err != SCARD_S_SUCCESS) {
  printf("ScardConnect: 0x%08x\n",err);
  return -1;
 }

 /* create a second PC/SC handle and reset the card */
 SCARDHANDLE hCard2;
 err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard2, &dwActiveProtocol);
 if (err != SCARD_S_SUCCESS) {
  printf("ScardConnect: 0x%08x\n",err);
  return -1;
 }
 err = SCardDisconnect(hCard2, SCARD_RESET_CARD);
 if (err != SCARD_S_SUCCESS) {
  printf("SCardDisconnect: 0x%08x\n",err);
 }

 /* SCardStatus should fail with SCARD_W_RESET_CARD */
 char name[100];
 DWORD len = sizeof name;
 DWORD dwState, dwProtocol;
 unsigned char atr[MAX_ATR_SIZE];
 DWORD atr_len = sizeof atr;
 err = SCardStatus(hCard, name, &len, &dwState, &dwProtocol, atr, &atr_len);
 if (err != SCARD_S_SUCCESS) {
  printf("SCardStatus: 0x%08x\n",err);
  return -1;
 }
 SCardDisconnect(hCard, SCARD_LEAVE_CARD);
 SCardReleaseContext(hContext);

 return 0;
}

Result (on Yosemite)

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

An error 0x80100068 (for SCARD_W_RESET_CARD) is expected here.
$ ./main 
Reader: Gemalto PC Twin Reader

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 00 00
SCardStatus: 0x80100068

Known workaround

None known.

Modify your code to check for  SCARD_W_RESET_CARD returned by SCardTransmit() even after a successful SCardStatus().

Update

This bug is now fixed in Mac OS X Yosemite 10.10.2.

OS X Yosemite bug: SCardBeginTransaction() after a card reset

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

SCardBeginTransaction() after a card reset

SCardBeginTransaction() does not corectly detect card reset any more on OS X 10.10 Yosemite.

If a card has been reseted using another PC/SC context then SCardBeginTransaction() will not fail with 0x80100068 (for SCARD_W_RESET_CARD) as before but will succeed instead.
The problem will be detected later by, for example, the next SCardTransmit() returning SCARD_W_RESET_CARD.

The goal of a PC/SC transaction was to guarantee that you have an exclusive and successful access to the card. This mechanism is broken on Yosemite.

See also

Apple bug report #19263926 "PC/SC SCardBeginTransaction() fails after a card reset"
#19263926 closed as a duplicate of #18689292.

Sample code

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

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) {
  printf("ScardEstablishedContext: 0x%08x\n",err);
  return -1;
 }

 DWORD cchReaders = 0;
 err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders);
 if (err != 0) {
  printf("ScardListReaders: 0x%08x\n",err);
  return -1;
 }
 mszReaders = calloc(cchReaders, sizeof(char));
 if (!mszReaders) {
  printf("calloc\n");
  return -1;
 }
 err = SCardListReaders(hContext,"SCard$AllReaders", mszReaders, &cchReaders);
 if (err != SCARD_S_SUCCESS) {
  printf("ScardListReaders: 0x%08x\n",err);
  return -1;
 }
 printf("Reader: %s\n", mszReaders);

 SCARDHANDLE hCard;
 DWORD dwActiveProtocol;
 err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
 if (err != SCARD_S_SUCCESS) {
  printf("ScardConnect: 0x%08x\n",err);
  return -1;
 }

 /* create a second PC/SC handle and reset the card */
 SCARDHANDLE hCard2;
 err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard2, &dwActiveProtocol);
 if (err != SCARD_S_SUCCESS) {
  printf("ScardConnect: 0x%08x\n",err);
  return -1;
 }
 err = SCardDisconnect(hCard2, SCARD_RESET_CARD);
 if (err != SCARD_S_SUCCESS) {
  printf("SCardReconnect: 0x%08x\n",err);
 }

 /* SCardBeginTransaction should fail with SCARD_W_RESET_CARD */
 err = SCardBeginTransaction(hCard);
 if (err != SCARD_S_SUCCESS) {
  printf("SCardBeginTransaction: 0x%08x\n",err);
  return -1;
 }
 SCardDisconnect(hCard, SCARD_LEAVE_CARD);
 SCardReleaseContext(hContext);

 return 0;
}

Result (on Yosemite)

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

An error 0x80100068 (for SCARD_W_RESET_CARD) is expected here.
$ ./main 
Reader: Gemalto PC Twin Reader

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 00 00
SCardBeginTransaction: 0x80100068

Known workaround

None known.

Modify your code to check for  SCARD_W_RESET_CARD returned by SCardTransmit() even inside a PC/SC transaction.

Update

This bug is now fixed in Mac OS X Yosemite 10.10.2.

OS X Yosemite bug: SCardReconnect

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

SCardReconnect

SCardReconnect() has a bad side effect on Yosemite.
After a SCardReconnect(..., SCARD_RESET_CARD, ...) the next SCardTransmit() will fail with the error code 0x80100068 that is SCARD_W_RESET_CARD.

This should not happen since SCardReconnect() should reconnect (sic) to the card after the card has been reseted.

See also

"[OSX 10.10] After connect and SCardReconnect, SCardTransmit raises card reset" https://smartcardservices.macosforge.org/trac/ticket/136

Apple bug report #19262854 "PC/SC function SCardReconnect does not work as expected". Closed by Apple, 6th January 2015, as a duplicated of #18689292.

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

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) {
        printf("ScardEstablishedContext: 0x%08x\n",err);
        return -1;
    }

    DWORD cchReaders = 0;
    err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders);
    if (err != 0) {
        printf("ScardListReaders: 0x%08x\n",err);
        return -1;
    }
    mszReaders = calloc(cchReaders, sizeof(char));
    if (!mszReaders) {
        printf("calloc\n");
        return -1;
    }
    err = SCardListReaders(hContext,"SCard$AllReaders", mszReaders, &cchReaders);
    if (err != SCARD_S_SUCCESS) {
        printf("ScardListReaders: 0x%08x\n",err);
        return -1;
    }
    printf("Reader: %s\n", mszReaders);

    SCARDHANDLE hCard;
    DWORD dwActiveProtocol;
    err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
    if (err != SCARD_S_SUCCESS) {
        printf("ScardConnect: 0x%08x\n",err);
        return -1;
    }

    unsigned char cmd[] = {0, 0, 0, 0};
    unsigned char resp[255];
    DWORD resp_len = sizeof resp;
    SCARD_IO_REQUEST * pci;

    err = SCardReconnect(hCard, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &dwActiveProtocol);
    if (err != SCARD_S_SUCCESS) {
        printf("SCardReconnect: 0x%08x\n",err);
    }

    if (SCARD_PROTOCOL_T0 == dwActiveProtocol)
        pci = SCARD_PCI_T0;
    else
        pci = SCARD_PCI_T1;
    err = SCardTransmit(hCard, pci, cmd, sizeof cmd, pci, resp, &resp_len);
    if (err != SCARD_S_SUCCESS) {
        printf("SCardTransmit: 0x%08x\n",err);
    }
    SCardDisconnect(hCard, SCARD_LEAVE_CARD);
    SCardReleaseContext(hContext);

    return 0;
}


Result (on Yosemite)

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

$ ./main 
Reader: Gemalto PC Twin Reader
SCardTransmit: 0x80100068

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.c: In function ‘main’:
main.c:57:7: warning: assignment discards ‘const’ qualifier from pointer target type [enabled by default]
main.c:59:7: warning: assignment discards ‘const’ qualifier from pointer target type [enabled by default]

No error expected:
$ ./main 
Reader: Gemalto PC Twin Reader 00 00

Known workaround

You can add an second call to SCardReconnect(..., SCARD_LEAVE_CARD, ...) after the first one to force a card reconnection.

Or you can replace the bogus SCardReconnect() by the sequence:
SCardDisconnect(..., SCARD_RESET_CARD);
SCardConnect(...);

I could not find an elegant way to write a macro to automate the code change. The problem is that SCardConnect() needs parameters (PC/SC context and reader name) that are not available from the SCardReconnect() call.

Update

This bug is now fixed in Mac OS X Yosemite 10.10.2.

Monday, December 15, 2014

Feitian bR301 driver for iOS now Free Software

Bluetooth reader

Feitian sells the bR301 smart card reader. This reader uses Blutooth to communicate with a host. The idea is to be able to "connect" the reader to a smart phone (iOS and Android).

The reader can also be connected using a USB cable. In that case the reader is a normal CCID reader and is already listed by my CCID driver in the "Should work but untested by me" list.


Software Development Kit (SDK)

The SDK (containing the reader drivers) is not directly available from Feitian web site. But you can get it from a reseller web site at http://cartesapuce-discount.com/en/smart-card-reader-usb/74-lecteur-de-cartes-a-puce-usb-cardman-3121.html. The SDK URL is http://download.ftsafe.com/files/reade/bR301_UB_V2.19_20141008.zip.

After I had a look inside the SDK I discovered that the iOS driver bR301_UB_V2.19_20141008/SDK/iOS/Library/NON-PCSC API/lib/libiRockey301_ccid_debug_NPCSC_V1.29.0.a is in fact a derivated work from my CCID driver.

It is perfectly fine to modify my CCID driver and provide a derivated work. The only condition is to respect the GNU LGPL v2.1+ license used by my CCID driver. This was not the case with the Feitian driver.

Free Software version

After some email exchanges with Feitian to explain the situation they decided to release their iOS driver under the same license as my CCID driver: the GNU LGPL v2.1+ license. The Feitian iOS driver is hosted at github: https://github.com/entersafe/bR301_iOS.

Conclusion

I am happy the issue ended that way.
  • The license of my CCID driver is respected by this Feitian driver
  • One more Free Software smart card reader driver is available for users

Saturday, December 13, 2014

PySCard 1.6.16 released

As explained in "PySCard: unofficial version 1.6.16 available" the PySCard software was no more actively maintained. After discussing with Jean-Daniel Aussel, previous maintainer, I got the admin rights to manage the sourceforge project. I was already an active code contributor since 2007.


Release 1.6.16

I just released a new official pyscard version 1.6.16.

Changes:
1.6.16 (December 2014)
  • added support for windows 64bit amd64 (Jean-Daniel Aussel)
  • support python "new" classes (derive classes from object) (Ludovic Rousseau from chrysn feature request ID 3110077)
  • fixed Reader.__eq__() (Ludovic Rousseau from Bernard Paulus bug ID 3418113)
  • fixed extended APDU transmit buffer too short by 2 (Jean-Daniel Aussel from bugs ID 2914636 and 3106761)
  • make Card and Reader objects hashable (Jean-Daniel Aussel from Hans-Peter Jansen feature request and patch)
  • convert the user guide to python-Sphinx

Documentation in Sphinx

I also changed the project web pages to use Sphinx (Python document generator) and generate a nice and modern user's guide from ReStructured text instead of manually edited HTML pages.

The API documentation is still using epydoc. Maybe I will switch it to Sphinx if I find the time and motivation. Help appreciated.

Provided software

The source code archive pyscard-1.6.16.tar.gz is of course provided.

I also provide a binary installer pyscard-1.6.16.macosx-10.9-x86_64.tar.gz for Mac OS X 10.9 and Python 2.7.

I do not use Windows so no installer is provided for this platform. Help appreciated.

Debian packages and Ubuntu packages are already provided in Debian and Ubuntu. The other GNU distribution should also provide packages but I have not checked.

Friday, December 12, 2014

OS X Yosemite bug: SCardTransmit (pioSendPci not checked)

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

SCardTransmit

SCardTransmit() fails to detect wrong value for pioSendPci parameter.

If you use NULL for pioSendPci parameter then you get a crash (Segmentation fault: 11) of the application instead of getting the error 0x80100004 that is SCARD_E_INVALID_PARAMETER.

See also

Apple bug report #19231406 "PC/SC function SCardTransmit: pioSendPci not checked".

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

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) {
        printf("ScardEstablishedContext : %08x\n",err);
  return -1;
    }

 DWORD cchReaders = 0;
 err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders);
 if (err != 0) {
  printf("ScardListReaders : %08x\n",err);
  return -1;
 }
 mszReaders = calloc(cchReaders, sizeof(char));
 if (!mszReaders) {
  printf("calloc\n");
  return -1;
 }
 err = SCardListReaders(hContext,"SCard$AllReaders", mszReaders, &cchReaders);
 if (err != SCARD_S_SUCCESS) {
  printf("ScardListReaders : %08x\n",err);
  return -1;
 }

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

 SCARDHANDLE hCard;
 DWORD dwActiveProtocol;
 err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
 unsigned char cmd[] = {0, 0, 0, 0, 0};
 unsigned char resp[255];
 DWORD resp_len = sizeof resp;

 err = SCardTransmit(hCard, NULL, cmd, sizeof cmd, NULL, resp, &resp_len);
 if (err != SCARD_S_SUCCESS) {
  printf("ScardTransmit : %08x\n",err);
  return -1;
 }

 SCardDisconnect(hCard, SCARD_LEAVE_CARD);
 SCardReleaseContext(hContext);

    return 0;
}

Result (on Yosemite)

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

$ ./main
Reader : Gemalto PC Twin Reader
Segmentation fault: 11

$ lldb ./main
(lldb) target create "./main"
Current executable set to './main' (x86_64).
(lldb) r
Process 6169 launched: './main' (x86_64)
Reader : Gemalto PC Twin Reader
Process 6169 stopped
* thread #1: tid = 0x7472a, 0x0000000100004b6d PCSC`__SCardTransmit_block_invoke + 17, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
    frame #0: 0x0000000100004b6d PCSC`__SCardTransmit_block_invoke + 17
PCSC`__SCardTransmit_block_invoke + 17:
-> 0x100004b6d:  movl   (%rax), %edx
   0x100004b6f:  leaq   0x6901(%rip), %rsi        ; "proto"
   0x100004b76:  movq   %r14, %rdi
   0x100004b79:  callq  0x10000b0c2               ; symbol stub for: xpc_dictionary_set_uint64

Expected result (on Debian)

CFLAGS=`pkg-config --cflags libpcsclite` LDFLAGS=`pkg-config --libs libpcsclite` make main

$ ./main
Reader : Gemalto PC Twin Reader (70D7E2EE) 00 00
ScardTransmit : 80100004

Known workaround

Do not use NULL for pioSendPci. It is a wrong value.

Update

This bug is now fixed in Mac OS X El Capitan 10.11.0.

OS X Yosemite bug: SCardGetAttrib

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

SCardGetAttrib

SCardGetAttrib() do not work any more on Yosemite.

The function returns with 8010000c that is SCARD_F_INTERNAL_ERROR.

See also

"Problem With SCardGetAttrib on Mac OS X 10.10 (Yosemite)" at https://smartcardservices.macosforge.org/trac/ticket/139.

Apple bug report #19231112 "PC/SC function SCardGetAttrib is broken on Yosemite".
#19231112 closed as duplicate of #16366962.

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. */

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) {
        printf("ScardEstablishedContext : %08x\n",err);
    } else {
        DWORD cchReaders = 0;
        err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders);
        if (err != 0) {
            printf("ScardListReaders : %08x\n",err);
            return -1;
        }
        mszReaders = calloc(cchReaders, sizeof(char));
        if (!mszReaders) {
            printf("calloc\n");
            return -1;
        }
        err = SCardListReaders(hContext,"SCard$AllReaders", mszReaders, &cchReaders);
        if (err != SCARD_S_SUCCESS) {
            printf("ScardListReaders : %08x\n",err);
            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) {
            printf("ScardConnect : %08x\n",err);
        } else {
            DWORD dwAtrLen = 32;
            err = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, NULL, &dwAtrLen);
            printf("ATR LENGTH : %1d\n", dwAtrLen);
            if (err != SCARD_S_SUCCESS) {
                printf("SCardGetAttrib : %08x\n",err);
            } else {
                printf("ATR LENGTH %d\n", dwAtrLen);
                SCardDisconnect(hCard, SCARD_LEAVE_CARD);
                SCardReleaseContext(hContext);
            }
        }
    }
    return 0;
}

Result (on Yosemite)

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

$ ./main
Reader : Gemalto PC Twin Reader
ATR LENGTH : 32
SCardGetAttrib : 80100001

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
ATR LENGTH : 20
ATR LENGTH 20

Known workaround

None known.

Update

This bug is now fixed in Mac OS X El Capitan 10.11.0.

OS X Yosemite and smart cards: known bugs

Yosemite: OS X 10.10

Yosemite contains a rewrite of pcsc-lite. See "OS X Yosemite and smart cards status". The problem is that the rewrite introduced (many) bugs.

Bug list

I will list known (by me) bugs and will try to maintain the list in the future if/when the bugs are fixed.

  1. SCardDisconnect

Fixed in OS X 10.10.2

  1. SCardReconnect(..., SCARD_RESET_CARD, ...)
  2. SCardBeginTransaction() after a card reset
  3. SCardStatus() after a card reset
  4. SCardStatus returns SCARD_E_INSUFFICIENT_BUFFER
  5. SCARD_E_PROTO_MISMATCH not returned
  6. T=0 is used instead of T=1 on dual protocol cards

Fixed in OS X 10.10.3

  1. SCardTransmit returns SCARD_W_UNPOWERED_CARD

Fixed in El Capitan 10.11.0

  1. SCardGetAttrib
  2. SCardTransmit (pioSendPci not checked)
  3. SCardGetStatusChange blocks forever
  4. OS X Yosemite bug: SCardConnect blocks in SCARD_SHARE_SHARED mode

Bugs that will not be fixed

  1. PC/SC functions crash after a fork(2)

Conclusion

I hope the bugs will be fixed during Yosemite lifetime. But I am afraid it will not happen before the next major version of OS X (OS X 10.11) is out.

This reminds me when Mac OS X 10.5 Leopard has been released in 2007 with lots of important bugs like ATR corruption. At that time it was also a major deviation from pcsc-lite. See "Evolution of Apple pcsc-lite (from Jaguar to Mavericks)".

Friday, December 5, 2014

PCSC sample in Python using python-pcsclite

Here is a new PCSC sample in Python language for the series PC/SC sample in different languages.

I already presented, pyscard, a Python wrapper in "PCSC sample in Python". This wrapper is a different implementation and API.

Installation

The installation is easy on a Debian system. A .deb package is provided (but the project is not part of Debian).
Or you can rebuild the software from the source code. The current version is 0.13.

The web site is http://python-pcsclite.sourceforge.net/. The license is GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Source code

#!/usr/bin/env python

import pcsclite
import binascii

SELECT = "\x00\xA4\x04\x00\x0A\xA0\x00\x00\x00\x62\x03\x01\x0C\x06\x01"
COMMAND = "\x00\x00\x00\x00"

try:
    context = pcsclite.Context()
    readers = context.list_readers()
    print "PCSC readers:", readers
    reader = readers[0]
    print "Using reader:", reader

    card = context.connect(reader)

    data = card.transmit(SELECT)
    print binascii.b2a_hex(data)

    data = card.transmit(COMMAND)
    print data
    print binascii.b2a_hex(data)

    card.disconnect()

    del card
    del context

except Exception, message:
    print "Exception:", message

Output

$ ./sample_pcsclite.py 
PCSC readers: ('Gemalto PC Twin Reader 00 00',)
Using reader: Gemalto PC Twin Reader 00 00
9000
Hello world!?
48656c6c6f20776f726c64219000

Comments

The python-pcsclite project started in 2007 according to the ChangeLog.txt file. I discovered the project only very recently and open some bugs to make it build on my Debian system. Russell Stuart, the maintainer, was very fast to fix the issues.

Compared to pyscard

python-pcsclite does not build on Mac OS X (see bug #5). I guess it also does not build on Windows but I have not tested it myself. So if you want a Python wrapper for GNU/Linux, Mac OS X and Windows you should use pyscard instead.

python-pcsclite may provide good ideas that I could reuse in pyscard :-)

As for pyscard, Python3 is not yet supported.

History

The python-pcsclite project started in 2007. At the same time the pyscard project is made public (according to the dates in the subversion repository but I guess the pyscard project was already developed since some time).

According to the python-pcsclite web site:
The obvious question is why use python-pcsclite instead of the official one. Python-pcsclite is a fairly direct implementation of C API provided by pcsclite, so direct the documentation for pcsclite applies to python-pcsclite. Pyscard on the other hand builds on pcsclite to provide it's own abstractions. I suspect the choice is more a matter of taste, and being an old C programmer I prefer the directness of the C API, which python-pcsclite emulates.
You have the freedom to select the wrapper you want to use. Compare the sample code above with the 2 examples at my previous article PCSC sample in Python to select the implementation you prefer.

Conclusion

I have not seen any advertising of this project on the Muscle mailing list. The project works fine (as far as I tested) and may benefit to be used by more users.