Friday, December 25, 2015

New version of pcsc-lite: 1.8.15

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

Changes:
1.8.15: Ludovic Rousseau
25 December 2015
  • Add support of remove and/or customize PC/SC reader names using
    PCSCLITE_FILTER_IGNORE_READER_NAMES and PCSCLITE_FILTER_EXTEND_READER_NAMES
    See "Remove and/or customize PC/SC reader names"
  • Some other minor improvements and bug corrections

Apple PC/SC: blog articles about missing features

You may have noticed that I wrote 3 blog articles about missing features in the PC/SC layer from Apple.
  1. SCardGetStatusChange() and number of card events
  2. SCardGetStatusChange() and "\\?PnP?\Notification"
  3. add support of TAG_IFD_POLLING_THREAD_WITH_TIMEOUT

This is because Apple replaced pcsc-lite by something else in Yosemite (10.10) and improved it in El Capitan (10.11). I imagine that Apple is still working on this software and it is the good time to propose to Apple to implement features that are present in PC/SC on GNU/Linux and Windows but not (yet) on Mac OS X.

If you think these features are useful you should open bug reports at https://bugreport.apple.com. This will indicate that a feature is important for many users, and not just me. If more users create a bug report then priority for Apple to do something will be higher.

Of course, I would be happy to help Apple implement the missing features.

OS X El Capitan missing feature: add support of TAG_IFD_POLLING_THREAD_WITH_TIMEOUT

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

This is not a bug since this feature was never present in any PC/SC from Apple.

com.apple.ifdreader.slotd does not support TAG_IFD_POLLING_THREAD_WITH_TIMEOUT  and friends

The equivalent of pcscd on Mac OS X since Yosemite (10.10) is com.apple.ifdreader.slotd. See "OS X Yosemite and smart cards status". This process is in charge of loading the smart card reader driver. The API between pcscd or com.apple.ifdreader.slotd and the driver is defined in IFDHandler API.

The IFDHandler API evolved during the development of pcsc-lite and the CCID driver to support new features. Apple forked pcsc-lite in 2002 (see "Evolution of Apple pcsc-lite (from Jaguar to Mavericks)") and never merged back the changes I made in pcsc-lite and the IFDHandler API since that time.

Card status polling

In the early versions of pcsc-lite (when the smart card readers where using a RS 232 serial port because USB was not invented yet) the card state (card present or card absent) was checked using a regular polling (every 200 ms) of the reader. Every 200 ms a command is sent to the reader to know if a card is present or not.

The problem is that pcscd is then continuously running (and pcscd was reported by the powertop tool as one of the processes that prevent the CPU to sleep and consume less power)

Another problem is that you have to wait up to 200 ms to detect that a card has been inserted or removed in a reader.

Polling replaced

The CCID specification provides a way to indicate that a card event occurred. This mechanism uses an USB interrupt end point. See "New CCID 1.4.0 and card movement notification mechanism" for more details.

The new mechanism, introduced in the pcsc-lite and the CCID driver 2010, allows to let libusb-1.0 notify the driver that a card event occurred. The change was introduced in the CCID driver version 1.4.0 (with the update from libusb-0.1 to libusb-1.0) and in pcsc-lite 1.6.2 released at the same time.

The mechanism uses the IFDHandler function IFDHGetCapabilities to request the driver about three features:

This allows pcscd to delegate to the driver the cart event management. pcscd will call a function in the driver that will block until a card event occurs or the timeout expires.

Benefits to implement it

If such a mechanism is implemented by Apple in com.apple.ifdreader.slotd we could have, at least, three benefits.
  1. better reactivity when a smart card is inserted (or removed)
  2. lower CPU power consumption
  3. far less log messages when you debug a smart card driver (mostly useful to smart card reader driver developers ☺)

See also

Apple bug report #24009313 "PC/SC: com.apple.ifdreader.slotd does not support TAG_IFD_POLLING_THREAD_WITH_TIMEOUT and friends"

Closed by Apple on 19th January 2016 as a duplicate of 17534485.

Sample code

I do not provide code sample. It is an internal implementation issue with no impact on the PC/SC API.

Known workaround

None known. It is not an PC/SC API issue.

Monday, December 21, 2015

Remove and/or customize PC/SC reader names

The need

In some cases you need to control the smart card reader names reported by PC/SC.

For real examples see some requests sent on the Pcsclite-muscle mailing list: "Possibility to disable Reader Interface?", "Deny card access for one application" and "Dynamically disable/enable specific card reader".

Ignore some readers

For example imagine you have a laptop with 2 integrated smart card readers:
  • Broadcom Corp 5880 [Contacted SmartCard] (0123456789ABCD)
  • Broadcom Corp 5880 [Contactless SmartCard] (0123456789ABCD)
One reader is contactless but you do not use it. The other is a contact reader and should be the only one used but the users of the laptop.
To ease the life of the users you do not want them to have to select the contact reader each time an application has to use a reader and ask the user to select one.

Since the readers are integrated into the laptop you can't easily unplug the reader you don't want to use. You need a solution to ignore unwanted readers at the PC/SC level.

Extend reader names

In this use case you use a remote desktop solution (RDP) to access a Windows server from your GNU/Linux laptop. Your company has equipped users with the same laptop model. So at the PC/SC level all the readers have the same name and this PC/SC name is forwarded to Windows through RDP.

Now imagine a bogus application on the Windows server (not too hard to imagine a bogus application on Windows ☺) that uses the PC/SC reader name to identify a user. Since every user is using the same laptop model they will all have the same PC/SC reader name in Windows. And the bogus Windows application is broken ☹ and can't be used.

The proposed solution

To enable these two features you need to configure pcsc-lite with --enable-filter.

Ignore some readers

If the environment variable PCSCLITE_FILTER_IGNORE_READER_NAMES is defined then it contains a list of patterns separated by the character ":".
If a pattern is found in a PC/SC reader name then this reader is ignored and will not be reported by SCardListReaders() or any other PC/SC calls.

In the example described above you would define PCSCLITE_FILTER_IGNORE_READER_NAMES as: "Contactless".

Extend reader names

To differentiate the PC/SC reader names one idea is to use the host name of the system. If the IT department is doing correctly his job every laptop should have a different host name.

If the environment variable PCSCLITE_FILTER_EXTEND_READER_NAMES is defined then it contains a string that will be added at the end of the PC/SC reader names.
The computer host name is available in the variable $HOSTNAME. If you want to have a space character between the PC/SC reader name and host name you define PCSCLITE_FILTER_EXTEND_READER_NAMES as:
" $HOSTNAME".

Setup

The Debian init script for pcscd contains:

NAME=pcscd
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

You then just have to create a file /etc/default/pcscd containing:
PCSCLITE_FILTER_IGNORE_READER_NAMES="Contactless"
PCSCLITE_FILTER_EXTEND_READER_NAMES=" $HOSTNAME"
And you are good to go.

GNU/Linux systems using systemd will need a different configuration. The systemd configuration is left as an exercise for the reader.

Conclusion

These new features will be provided in the next version of pcsc-lite.

If you have another special feature request for pcsc-lite, please do not hesitate to contact me.

Thanks

Thanks to Sparkasse Pforzheim Calw for the patch.

Saturday, December 19, 2015

OS X El Capitan missing feature: SCardGetStatusChange() and "\\?PnP?\Notification"

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

SCardGetStatusChange() does not support "\\?PnP?\Notification"

SCardGetStatusChange() does not support the special reader name "\\?PnP?\Notification".

This is not a bug since this feature was never present in any PC/SC from Apple.

From the Doxygen documentation of pcsc-lite:
To wait for a reader event (reader added or removed) you may use the special reader name "\\?PnP?\Notification".
If a reader event occurs the state of this reader will change and the bit SCARD_STATE_CHANGED will be set.
With this feature it is possible to detect that a smart card reader has been added or removed to the system without polling with calls to SCardListReaders() in a loop.

This is used by my tools pcsc_scan from the pcsc-tools package.

See also

Apple bug report #23966225 "PC/SC SCardGetStatusChange() and "\\?PnP?\Notification""

Sample code

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

int main(void)
{
    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;
    }

    SCARD_READERSTATE rgReaderStates[1];
    rgReaderStates[0].szReader = "\\\\?PnP?\\Notification";
    rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE;
    rgReaderStates[0].dwEventState = SCARD_STATE_UNKNOWN;

    err = SCardGetStatusChange(hContext, 10, rgReaderStates, 1);
    printf("SCardGetStatusChange: %s (0x%08X)\n", pcsc_stringify_error(err),
        err);
    printf("dwEventState: %X\n", rgReaderStates[0].dwEventState);

    if (rgReaderStates[0].dwEventState & SCARD_STATE_UNKNOWN)
        printf("\\\\?PnP?\\Notification is NOT supported\n");
    else
        printf("\\\\?PnP?\\Notification IS supported\n");

    SCardReleaseContext(hContext);

    return 0;
}

Result (on El Capitan)

$ CFLAGS="-framework PCSC" make main
cc -framework PCSC    main.c   -o main
$ ./main
SCardGetStatusChange: Command successful. (0x00000000)
dwEventState: 6
\\?PnP?\Notification is NOT supported
The returned value for dwEventState is 6 and correspond to SCARD_STATE_CHANGED (2) + SCARD_STATE_UNKNOWN (4). PC/SC indicates that the reader "\\?PnP?\Notification" is unknown.

Note that SCardGetStatusChange() returns SCARD_S_SUCCESS and also waited for the indicated time, here 10 ms but you can increase the value to make the test more explicit.
The command should have returned immediately (or have returned SCARD_E_TIMEOUT). Yes, it is a bug in the PC/SC layer.

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
SCardGetStatusChange: Command timeout. (0x8010000A)
dwEventState: 0
\\?PnP?\Notification IS supported
Here the command returns after the delay has expired because no reader has been connected or removed. The returned value is SCARD_E_TIMEOUT.
If a reader is connected or removed during the delay (here 10 ms) the command would have indicated SCARD_STATE_CHANGED for this reader.

Known workaround

None known.
Maybe Apple will add support of "\\?PnP?\Notification" one day.

Thursday, December 17, 2015

OS X El Capitan missing feature: SCardGetStatusChange() and number of card events

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

SCardGetStatusChange() and number of card events

SCardGetStatusChange() does not return the number of card events in the upper word of dwEventState.

This is not a bug since I don't think this feature was every present in the PC/SC from Apple. It is a feature request and not a bug report.

From the Doxygen documentation of pcsc-lite:
dwEventState also contains a number of events in the upper 16 bits (dwEventState & 0xFFFF0000). This number of events is incremented for each card insertion or removal in the specified reader. This can be used to detect a card removal/insertion between two calls to SCardGetStatusChange().
This behaviour is also present in PC/SC on Windows.

It is the only way to know that the card has been removed from a reader and inserted again while no call to SCardGetStatusChange() was running. Potentially the inserted card is not the same as the removed card so the PC/SC application may have to build a new applicative context for the new card.

See also

Apple bug report #23937633 "PC/SC SCardGetStatusChange() and number of card events"

Sample code

Using the Python PC/SC wrapper PySCard to have a shorter code.

#! /usr/bin/env python

from smartcard.scard import *
from smartcard.pcsc.PCSCExceptions import *


def parseEventState(eventstate):
    stateList = list()
    states = {SCARD_STATE_IGNORE: "Ignore",
              SCARD_STATE_CHANGED: "Changed",
              SCARD_STATE_UNKNOWN: "Unknown",
              SCARD_STATE_UNAVAILABLE: "Unavailable",
              SCARD_STATE_EMPTY: "Empty",
              SCARD_STATE_PRESENT: "Present",
              SCARD_STATE_ATRMATCH: "ATR match",
              SCARD_STATE_EXCLUSIVE: "Exclusive",
              SCARD_STATE_INUSE: "In use",
              SCARD_STATE_MUTE: "Mute"}
    for state in states:
        if eventstate & state:
            stateList.append(states[state])
    return stateList

hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER)
if hresult != SCARD_S_SUCCESS:
    raise EstablishContextException(hresult)

hresult, readers = SCardListReaders(hcontext, [])
if hresult != SCARD_S_SUCCESS:
    raise ListReadersException(hresult)
print 'PC/SC Readers:', readers

readerstates = {}
for reader in readers:
    readerstates[reader] = (reader, SCARD_STATE_UNAWARE)
hresult, newstates = SCardGetStatusChange(hcontext, 0, readerstates.values())
if hresult != SCARD_S_SUCCESS:
    raise BaseSCardException(hresult)
print newstates
for readerState in newstates:
    readername, eventstate, atr = readerState
    readerstates[readername] = (readername, eventstate)

print "Move the smart card"

ok = True
while ok:
    try:
        hresult, newstates = SCardGetStatusChange(hcontext, INFINITE, newstates)
        if hresult != SCARD_S_SUCCESS and hresult != SCARD_E_TIMEOUT:
            raise BaseSCardException(hresult)
    except KeyboardInterrupt:
        ok = False
    for readerState in newstates:
        readername, eventstate, atr = readerState
        states = parseEventState(eventstate)
        print states, hex(eventstate)

hresult = SCardReleaseContext(hcontext)
print "SCardReleaseContext()", SCardGetErrorMessage(hresult)
if hresult != SCARD_S_SUCCESS:
    raise ReleaseContextException(hresult)

Result (on El Capitan)

$ ./SCardGetStatusChange.py
PC/SC Readers: ['Gemalto PC Twin Reader']
[('Gemalto PC Twin Reader', 18, [])]
Move the smart card
['Changed', 'Present'] 0x22
['Empty', 'Changed'] 0x12
['Changed', 'Present'] 0x22
['Empty', 'Changed'] 0x12
^C['Empty', 'Changed'] 0x12
SCardReleaseContext() Command successful.

For the tests I insert and remove the card 2 times.

Then press Control-C and insert the card to quit the program.

Expected result (on Debian)

$ ./SCardGetStatusChange.py 
PC/SC Readers: ['Gemalto PC Twin Reader 00 00']
[('Gemalto PC Twin Reader 00 00', 18, [])]
Move the smart card
['Changed', 'Present'] 0x10022
['Empty', 'Changed'] 0x20012
['Changed', 'Present'] 0x30022
['Empty', 'Changed'] 0x40012
^C['Empty', 'Changed'] 0x40012
SCardReleaseContext() Command successful.

The change is the value eventstate displayed (in hexadecimal).

On Debian the high word (upper 16 bits) takes the values 1, 2, 3 and 4.

If the value change from 0x10022 to 0x30022, the reader state is the same (SCARD_STATE_CHANGED and SCARD_STATE_PRESENT) but you know that the card has been removed and inserted.

Known workaround

None known.

Tuesday, December 15, 2015

OS X El Capitan bug: SCardBeginTransaction() returns different error codes than on GNU/Linux and Windows

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

SCardBeginTransaction() returns different error codes than on GNU/Linux and Windows

I found 2 cases in which SCardBeginTransaction() on El Capitan returns error codes that are different than on GNU/Linux and Windows.

SCardBeginTransaction() returns SCARD_W_RESET_CARD after a card change

On El Capitan SCardBeginTransaction() returns SCARD_W_RESET_CARD if the card has been removed and inserted again in the reader.

On GNU/Linux and Windows SCardBeginTransaction() returns SCARD_W_REMOVED_CARD instead.

SCardBeginTransaction() returns SCARD_W_UNPOWERED_CARD after a card is unpowered

The same function SCardBeginTransaction() returns SCARD_W_UNPOWERED_CARD on Mac OS X El Capitan if the card has been powered off by another application.

On GNU/Linux and Windows SCardBeginTransaction() returns SCARD_W_RESET_CARD instead.

See also

Apple bug report #23900844 "PC/SC SCardBeginTransaction() returns different error codes than on GNU/Linux and Windows"

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 pcsc_error(fct) printf(fct ": %s 0x%08lX\n", pcsc_stringify_error(err), (long)err)

int main(void)
{
 LPSTR mszReaders;
 DWORD err, cchReaders = 0;
 SCARDCONTEXT hContext = 0;
 SCARDHANDLE hCard = 0;

 err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
 if (err != SCARD_S_SUCCESS) {
  pcsc_error("ScardEstablishedContext");
  return -1;
 }

 err = SCardListReaders(hContext, NULL, NULL, &cchReaders);
 if (err != 0) {
  pcsc_error("ScardListReaders");
  return -1;
 }
 mszReaders = calloc(cchReaders, sizeof(char));
 if (!mszReaders) {
  printf("calloc\n");
  return -1;
 }
 err = SCardListReaders(hContext,NULL, mszReaders, &cchReaders);
 if (err != SCARD_S_SUCCESS) {
  pcsc_error("ScardListReaders");
  return -1;
 }

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

 DWORD dwActiveProtocol;
 err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
    if (err != SCARD_S_SUCCESS) {
        pcsc_error("SCardConnect");
        return 0;
    }

 printf("Remove and insert the card. Then press enter\n");
 getchar();

 err = SCardBeginTransaction(hCard);
 if (err != SCARD_S_SUCCESS)
  pcsc_error("SCardBeginTransaction");

 err = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
 if (err != SCARD_S_SUCCESS)
  pcsc_error("SCardDisconnect");

 SCardReleaseContext(hContext);

 return 0;
}

Reset program

Using the Python PC/SC wrapper PySCard to have a shorter code.

#! /usr/bin/env python

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

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

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

If you modify the reset program to use disposition=SCARD_RESET_CARD then SCardBeginTransaction() will return SCARD_W_RESET_CARD as is also the case on GNU/Linux and Windows.

Result (on El Capitan)

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

$ ./main
Using reader: Gemalto PC Twin Reader
Remove and insert the card. Then press enter

SCardBeginTransaction: Card was reset. 0x80100068

In case of unpower (instead of card removal) by a second application:
$ ./main
Using reader: Gemalto PC Twin Reader
Remove and insert the card. Then press enter

SCardBeginTransaction: Card is unpowered. 0x80100067

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
Using reader: Gemalto PC Twin Reader 00 00
Remove and insert the card. Then press enter

SCardBeginTransaction: Card was removed. 0x80100069

In case of unpower:
$ ./main
Using reader: Gemalto PC Twin Reader 00 00
Remove and insert the card. Then press enter

SCardBeginTransaction: Card was reset. 0x80100068

Known workaround

None known.

I have not checked the same code on Mavericks (OS X 10.9) to see if it is a regression or not.
I guess the behaviour changed in Yosemite with the rewrite of PC/SC (see OS X Yosemite and smart cards status)

Wednesday, December 9, 2015

OS X El Capitan and smart card source code

Apple released the source code of the open source components they use in El Capitan (OS X 10.11 released in September 2015). The components are available at OS X 10.11 Source.



As I did for Yosemite in "OS X Yosemite and smart card source code" I will document what I found.

The smart card related components are:

See "OS X El Capitan and smart cards status" for a general discussion of the changes in El Capitan.

General remark

Apple published the source code at the same time they published the 2nd minor version of El Capitan: 10.11.2. Maybe Apple wanted to fix the most serious bugs before publishing the source code. Or maybe they had not enough free time before today?

SecurityTokend

The version did not changed from 55108 in Yosemite to 55108 in El Capitan.

It is surprising to see a Tokend related component. CDSA (and then tokend) has been deprecated in 2011.

Maybe Apple forgot to remove this component?

SmartcardCCID

The version did not changed from 55008 in Yosemite to 55008 in El Capitan.

The CCID driver has not changed between Yosemite and El Capitan. This is what I already found in "OS X El Capitan and smart cards status".

SmartCardServices

The version did not changed from 55111 in Yosemite to 55111 in El Capitan.

SmartCardServices is the component providing pcsc-lite. For Yosemite Apple rewrote the complete PC/SC stack and replaced pcsc-lite by something else. So this component is not used in El Capitan.

Maybe Apple forgot to remove this component?

Conclusion

No change at all since Yosemite in the Open Source components related to smart card.

The PC/SC layer changed. Apple fixed some bugs between Yosemite and El Capitan, see "OS X Yosemite and smart cards: known bugs". But Apple still does not provide the source code of this component.

Components not used any more in El Capitan are still provided in OS X 10.11 Source. It looks like Apple forgot to clean the list of the components used in El Capitan.