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, November 25, 2011

New version of pcsc-lite: 1.8.1


I just released new version of pcsc-lite 1.8.1.
This version fixes a stupid mistake I made: I forgot to include some files in the source code archive.

Changes:
pcsc-lite-1.8.1: Ludovic Rousseau
25 November 2011
  • Distribute missing files from src/spy/

Saturday, November 19, 2011

New version of pcsc-lite: 1.8.0

I just released new version of pcsc-lite 1.8.0.

Changes:
pcsc-lite-1.8.0: Ludovic Rousseau
19 November 2011
  • PC/SC spy tool. See "PCSC API spy, third try"
  • Support systemd socket activation (the auto start of pcscd from the library has been removed. Use systemd instead). See "pcscd auto start using systemd"
  • SCardGetStatusChange(): check all the readers are already known and return SCARD_E_UNKNOWN_READER if a reader name is not present. Windows XP has this behavior.
  • SCardEstablishContext(): Invalidate all the handles in the son after a fork
  • Add define of FEATURE_EXECUTE_PACE from PCSC v2 Part 10 Amendment 1 2011-06-03
  • Fix some memory leaks reported by Coverity
  • Enable silent build by default
  • log_line(): correctly calculate delta time when no color is used The update of last_time was only done in case of colorization (LogDoColor). So on unsupported consoles the time was wrong.
  • log_xxd_always(): Use a variable-length array The debug message buffer is no more with a fixed size (around 600
    bytes of buffer to log) but uses a variable-length array. It is now possible to log extended APDU of 64kB.
    The variable-length array feature is available in GCC in C90 mode and is mandatory in C99 standard.
  • Some other minor improvements and bug corrections

Friday, November 18, 2011

PCSC API spy, third try

[UPDATE from 2022]: see also "PCSC API spy, update".

I already blogged about how to spy the PCSC API in PCSC API spy for GNU systems and PCSC API spy, another way. But I am still not happy with the limitations and side effects.

Limitations of previous solutions

ltrace

ltrace is able to trace the calls to any library (including libpcsclite.so.1). But one major limitation is that it does not work if the library is not linked to the executable. It does not work when:
  • libpcsclite.so.1 is used by a library used by the executable (like a PKCS#11 library)
  • libpcsclite.so.1 is dynamically loaded using dlopen() as is done by OpenSC

Internal tracing

Internal tracing do not have the limitations of ltrace. But one major drawback is the need to rebuild pcsc-lite with a specific configuration. This may be very difficult or impossible to do on a production system.

Use an independent library

The new idea is to not need to rebuild pcsc-lite. Instead we will use a new library that will be placed between the PC/SC client and the PC/SC library. This new library will spy all the calls and send them to a pretty displayer.

+------------------+
|  PC/SC client    |
+------------------+
        |
+------------------+    +-------------+
| libpcscspy.so.0  | -> | pcsc-spy.py |
+------------------+    +-------------+
        |
+------------------+
| libpcsclite.so.1 |
+------------------+

Two configurations are available


To be able to spy the PC/SC layer the application flow must be modified so that all PC/SC calls are redirected.

Applications linked with libpcsclite.so.1


We will use the standard LD_PRELOAD loader option to load our spying library.

Example:
LD_PRELOAD=/usr/lib/libpcscspy.so opensc-tool -a

Application loading libpcsclite.so.1


This is the case for the PC/SC wrappers like pyscard (for Python) and pcsc-perl (for Perl). The LD_PRELOAD mechanism can't be used. Instead we replace the libpcsclite.so.1 library by the spying one.

Use install_spy.sh and uninstall_spy.sh to install and uninstall the spying library.

Using the spying library without pcsc-spy.py is not a problem but has side effects:
  • a line "libpcsclite_nospy.so.1: cannot open shared object file: No such file or directory" will be displayed
  • some CPU time will be lost because of the PC/SC calls redirection

Starting the spy tool


Direct output

$ pcsc-spy.py

Store for later use

If a command argument is passed we use it instead of the default ~/pcsc-spy FIFO file. It is then possible to record an execution log and use pcsc-spy.py multiple times on the same log.

To create the log file just do:

$ mkfifo ~/pcsc-spy
$ cat ~/pcsc-spy > logfile

and run your PC/SC application. The API trace is stored in the file logfile. It is displayed using:
$ pcsc-spy.py logfile

Example using OpenSC


Executed command

$ LD_PRELOAD=/usr/lib/libpcscspy.so opensc-tool -a
Using reader with a card: Gemalto GemPC Twin 00 00
3b:9f:95:81:31:fe:9f:00:65:46:53:05:30:06:71:df:00:00:00:81:61:0f:d9

API log

$ pcsc-spy.py
SCardEstablishContext
 i dwScope: SCARD_SCOPE_USER (0x00000000)
 o hContext: 0x0103E68C
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000219919]
SCardListReaders
 i hContext: 0x0103E68C
 i mszGroups: (null)
 o pcchReaders: 0x0000001A
 o mszReaders: NULL
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000000128]
SCardListReaders
 i hContext: 0x0103E68C
 i mszGroups: (null)
 o pcchReaders: 0x0000001A
 o mszReaders: Gemalto GemPC Twin 00 00
 o mszReaders: 
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000000101]
SCardGetStatusChange
 i hContext: 0x0103E68C
 i dwTimeout: 0x00000000 (0)
 i cReaders: 1
 i szReader: Gemalto GemPC Twin 00 00
 i  dwCurrentState:  (0x00000000)
 i  dwEventState:  (0x00000000)
 i  Atr length: 0x00000000 (0)
 i  Atr: 
 o szReader: Gemalto GemPC Twin 00 00
 o  dwCurrentState:  (0x00000000)
 o  dwEventState: SCARD_STATE_CHANGED, SCARD_STATE_PRESENT (0x00000022)
 o  Atr length: 0x00000017 (23)
 o  Atr: 3B 9F 95 81 31 FE 9F 00 65 46 53 05 30 06 71 DF 00 00 00 81 61 0F D9
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000000184]
SCardConnect
 i hContext: 0x0103E68C
 i szReader Gemalto GemPC Twin 00 00
 i dwShareMode: SCARD_SHARE_SHARED (0x00000002)
 i dwPreferredProtocols: 0x00000003 (T=0, T=1)
 i phCard 0x02432010 (37953552)
 i pdwActiveProtocol 0x00000020 (32)
 o phCard 0x00015425 (87077)
 o dwActiveProtocol: T=1 (0x00000002)
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000020242]
SCarControl
 i hCard: 0x00015425
 i dwControlCode: CM_IOCTL_GET_FEATURE_REQUEST (0x42000D48)
 i bSendLength 0x00000000 (0)
 i bSendBuffer
 i  NULL
 o bRecvLength 0x00000012 (18)
 o bRecvBuffer
 o  0000 0A 04 42 33 00 0A 12 04 42 33 00 12 13 04 42 00 ..B3....B3....B.
 o  0010 00 01                                           ..
  parsing CM_IOCTL_GET_FEATURE_REQUEST results:
  Tag FEATURE_IFD_PIN_PROPERTIES is 0x4233000A
  Tag FEATURE_GET_TLV_PROPERTIES is 0x42330012
  Tag FEATURE_CCID_ESC_COMMAND is 0x42000001
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000000130]
SCarControl
 i bSendBuffer
 i  NULL
 o bRecvLength 0x00000004 (4)
 o bRecvBuffer
 o  0000 00 00 07 00                                     ....
  parsing FEATURE_IFD_PIN_PROPERTIES results:
  wLcdLayout: 0 0
  bEntryValidationCondition: 7
  bTimeOut2: 0
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000000334]
SCardDisconnect
 i hCard: 0x00015425
 i dwDisposition: SCARD_LEAVE_CARD (0x00000000)
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000000362]
SCardGetStatusChange
 i hContext: 0x0103E68C
 i dwTimeout: 0x00000000 (0)
 i cReaders: 1
 i szReader: Gemalto GemPC Twin 00 00
 i  dwCurrentState: SCARD_STATE_CHANGED, SCARD_STATE_PRESENT (0x00000022)
 i  dwEventState: SCARD_STATE_CHANGED, SCARD_STATE_PRESENT (0x00000022)
 i  Atr length: 0x00000017 (23)
 i  Atr: 3B 9F 95 81 31 FE 9F 00 65 46 53 05 30 06 71 DF 00 00 00 81 61 0F D9
 o szReader: Gemalto GemPC Twin 00 00
 o  dwCurrentState: SCARD_STATE_CHANGED, SCARD_STATE_PRESENT (0x00000022)
 o  dwEventState: SCARD_STATE_PRESENT (0x00000020)
 o  Atr length: 0x00000017 (23)
 o  Atr: 3B 9F 95 81 31 FE 9F 00 65 46 53 05 30 06 71 DF 00 00 00 81 61 0F D9
 => Command timeout. (SCARD_E_TIMEOUT [0x8010000A])  [0.000000352]
SCardGetStatusChange
 i hContext: 0x0103E68C
 i dwTimeout: 0x00000000 (0)
 i cReaders: 1
 i szReader: Gemalto GemPC Twin 00 00
 i  dwCurrentState: SCARD_STATE_PRESENT (0x00000020)
 i  dwEventState: SCARD_STATE_PRESENT (0x00000020)
 i  Atr length: 0x00000017 (23)
 i  Atr: 3B 9F 95 81 31 FE 9F 00 65 46 53 05 30 06 71 DF 00 00 00 81 61 0F D9
 o szReader: Gemalto GemPC Twin 00 00
 o  dwCurrentState: SCARD_STATE_PRESENT (0x00000020)
 o  dwEventState: SCARD_STATE_PRESENT (0x00000020)
 o  Atr length: 0x00000017 (23)
 o  Atr: 3B 9F 95 81 31 FE 9F 00 65 46 53 05 30 06 71 DF 00 00 00 81 61 0F D9
 => Command timeout. (SCARD_E_TIMEOUT [0x8010000A])  [0.000000303]
SCardGetStatusChange
 i hContext: 0x0103E68C
 i dwTimeout: 0x00000000 (0)
 i cReaders: 1
 i szReader: Gemalto GemPC Twin 00 00
 i  dwCurrentState: SCARD_STATE_PRESENT (0x00000020)
 i  dwEventState: SCARD_STATE_PRESENT (0x00000020)
 i  Atr length: 0x00000017 (23)
 i  Atr: 3B 9F 95 81 31 FE 9F 00 65 46 53 05 30 06 71 DF 00 00 00 81 61 0F D9
 o szReader: Gemalto GemPC Twin 00 00
 o  dwCurrentState: SCARD_STATE_PRESENT (0x00000020)
 o  dwEventState: SCARD_STATE_PRESENT (0x00000020)
 o  Atr length: 0x00000017 (23)
 o  Atr: 3B 9F 95 81 31 FE 9F 00 65 46 53 05 30 06 71 DF 00 00 00 81 61 0F D9
 => Command timeout. (SCARD_E_TIMEOUT [0x8010000A])  [0.000000215]
SCardConnect
 i hContext: 0x0103E68C
 i szReader Gemalto GemPC Twin 00 00
 i dwShareMode: SCARD_SHARE_SHARED (0x00000002)
 i dwPreferredProtocols: 0x00000003 (T=0, T=1)
 i phCard 0x0243EA80 (38005376)
 i pdwActiveProtocol 0x7FFEE90B2420 (140732808242208)
 o phCard 0x000104C4 (66756)
 o dwActiveProtocol: T=1 (0x00000002)
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000000142]
SCardBeginTransaction
 i hCard: 0x000104C4
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000000070]
SCardEndTransaction
 i hCard: 0x000104C4
 i dwDisposition: SCARD_LEAVE_CARD (0x00000000)
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000002802]
SCardDisconnect
 i hCard: 0x000104C4
 i dwDisposition: SCARD_RESET_CARD (0x00000001)
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000058724]
SCardReleaseContext
 i hContext: 0x0103E68C
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000000204]

Results sorted by total execution time
total time: 0.304753 sec
0.219919 sec (  1 calls) 72.16% SCardEstablishContext
0.059086 sec (  2 calls) 19.39% SCardDisconnect
0.020384 sec (  2 calls)  6.69% SCardConnect
0.002802 sec (  1 calls)  0.92% SCardEndTransaction
0.001054 sec (  4 calls)  0.35% SCardGetStatusChange
0.000464 sec (  2 calls)  0.15% SCardControl
0.000229 sec (  2 calls)  0.08% SCardListReaders
0.000204 sec (  1 calls)  0.07% SCardReleaseContext
0.000070 sec (  1 calls)  0.02% SCardBeginTransaction

Analysis


  • PC/SC commands are in blue
  • Input arguments are in green
  • Output arguments are in mangenta
  • Errors are in bold red
  • The last part of the log contains some statistics about: functions called and times consumed by each of them

Next steps

Some ideas for the future:

Parse the APDU

For now the APDUs are displayed as a buffer of bytes. It would be great to display the command name corresponding to an INS byte. For example "SELECT FILE" is easier to read than "A4".

Smart card activity live monitoring

I often run pcscd in debug mode to know if something is happening at the PC/SC layer. I then know if the application is doing a lot of smart card accesses and I will just wait or if the application is locked somewhere and I should kill/debug it.

The idea is to send the PC/SC API log stream to a "live monitor" able to display a status using colors for example. The GUI still has to be designed. Please propose ideas.

PC/SC calls correctness

With all the PC/SC API calls you can check your application is using the API correctly. For example you should have the same number of SCardEstablishContext() and SCardReleaseContext() calls.

Mac OS X support

Logs from pcscd are very difficult to read. See pcscd debug output on Mac OS X. A clear PCSC API spy tool would be a real plus.

I do plan to work on porting the spying layer but I don't know when I will work on it. You can work on it and provide patches and ideas.

Windows support?

I do not plan to work on a Windows port myself. At least not without a very big amount of money :-).

If you want to work on this please do. I may integrate your changes if they do not break GNU/Linux and Mac OS X supports.

[UPDATE] Petr Svenda wrote a PC/SC API spy for Windows: PC/SC APDU inspection and manipulation tool (APDUPlay)

Conclusion

I hope this API spy feature will work in the long term. It is already the 3rd iteration of API log.

The displayer program (pcsc-spy.py) is written in Python. It should be easy to extend and make it do some complex tasks.

Tuesday, November 15, 2011

pcscd auto start using systemd

In pcsc-lite version 1.6.0 (5 May 2010) I introduced a mechanism to start the pcscd daemon only when an application called SCardstablishContext() to get a PC/SC context. Read "Configuring your system for pcscd auto-start" for more information.

Old way: start by the libpcsclite library

One of the problem is that pcscd is then started as the user running the application. The pcscd process has to be setgid to get special privileges to get access to the USB devices (the smart card readers). Some people (and I understand) do not like files with special access right (like setgid).

New way: systemd

Around the same time (23 Aug 2010) the first article about systemd was posted by systemd author: Lennart Poettering

Socket activation

I will not describe systemd in details. But one of the services of systemd is to start a process when an application tries to communicate to a socket. The good news is that libpcsclite and pcscd are communicating through a UNIX (local) socket. So systemd provides a way to start pcscd when libpcsclite starts the communication.

The good news is that the changes are really minimal. libpcsclite has not changed and only the initialisation of pcscd has been updated a bit to use systemd services.

systemd configuration

pcsc-lite now use 2 systemd configuration files: pcscd.service and pcscd.socket

File pcscd.service:
[Unit]
Description=PC/SC Smart Card Daemon
Requires=pcscd.socket

[Service]
ExecStart=/usr/sbin/pcscd --foreground --auto-exit
ExecReload=/usr/sbin/pcscd --hotplug
StandardOutput=syslog

[Install]
Also=pcscd.socket

File pcscd.socket:
[Unit]
Description=PC/SC Smart Card Daemon Activation Socket

[Socket]
ListenStream=/var/run/pcscd/pcscd.comm

[Install]
WantedBy=sockets.target

These two files are installed in /lib/systemd/system/ on my Debian (testing) system.

systemd main comands


Status

$ systemctl status pcscd.service
pcscd.service - PC/SC Smart Card Daemon
   Loaded: loaded (/lib/systemd/system/pcscd.service)
   Active: inactive (dead) since Mon, 14 Nov 2011 16:33:40 +0100; 17h ago
  Process: 15489 ExecStart=/usr/sbin/pcscd --foreground --auto-exit (code=exited, status=0/SUCCESS)
   CGroup: name=systemd:/system/pcscd.service

$ systemctl status pcscd.socket
pcscd.socket - PC/SC Smart Card Daemon Activation Socket
   Loaded: loaded (/lib/systemd/system/pcscd.socket)
   Active: active (listening) since Mon, 14 Nov 2011 14:49:45 +0100; 19h ago
   CGroup: name=systemd:/system/pcscd.socket

The pcscd socket is configured and active but the pcscd process is not running. After starting a PC/SC application we get:

$ systemctl status pcscd.service
pcscd.service - PC/SC Smart Card Daemon
   Loaded: loaded (/lib/systemd/system/pcscd.service)
   Active: active (running) since Tue, 15 Nov 2011 10:27:39 +0100; 9s ago
 Main PID: 26929 (pcscd)
   CGroup: name=systemd:/system/pcscd.service
    └ 26929 /usr/sbin/pcscd --foreground --auto-exit

Stop

It is possible to stop the running pcscd process.

$ sudo systemctl stop pcscd.service
$ systemctl status pcscd.service
pcscd.service - PC/SC Smart Card Daemon
   Loaded: loaded (/lib/systemd/system/pcscd.service)
   Active: failed since Tue, 15 Nov 2011 10:30:13 +0100; 1s ago
  Process: 26965 ExecStart=/usr/sbin/pcscd --foreground --auto-exit (code=exited, status=1/FAILURE)
   CGroup: name=systemd:/system/pcscd.service

But in general I just kill(1) the pcscd process.

Start

If you start pcscd by hand, for example in debug and foreground mode, the daemon will remove the socket /var/run/pcscd/pcscd.comm on exit. This socket is not recreated automatically by systemd. You need to stop and start the pcscd.socket, using just start is not enough.

$ ls /var/run/pcscd/pcscd.comm 
ls: cannot access /var/run/pcscd/pcscd.comm: No such file or directory
$ sudo systemctl stop pcscd.socket
$ sudo systemctl start pcscd.socket
$ ls /var/run/pcscd/pcscd.comm 
/var/run/pcscd/pcscd.comm

The pcscd process is not started but the socket is now listening.

Migration

I removed the old autostart code in revision 6105. If you have systemd installed on your system I recommend using it to start pcscd. If you do not have systemd installed (maybe you do not use a Linux kernel) then you have to start pcscd at boot (as before version 1.6.0).

systemd availability

systemd is only available with a Linux kernel. systemd is now installed by default in Fedora 14. systemd is provided by Debian but Debian is not just limited to a Linux kernel. Debian also provides Hurd and FreeBSD kernel based Debian systems and systemd is not (yet) available for these kernels.

Major GNU/Linux distributions should provide systemd now. If your distribution do not have systemd you can still use the old way of starting pcscd at boot.

For non-Linux systems I have no auto-start solution. Just start pcscd at boot.

Conclusion

systemd is a nice new system to replace init and a lot more. It is a good piece of code to implement auto start for pcsc-lite.

Thanks to Kalev Lember for pushing the systemd patches.

Saturday, November 5, 2011

Identifying a reader model

This is another proposition I submitted to the PC/SC workgroup for the November 2011 meeting.

I removed the people names from the document and used XXX instead.

Please send/add comments if you have some.

Identifying a reader model




Identifying a reader model

Authors: Ludovic ROUSSEAU
XXX, Xiring
XXX, Gemalto
Version: 1.0, October 2011

The problem

PC/SC v2 Part 10 now allows to use FEATURE_CCID_ESC_COMMAND to send a proprietary command to a reader using the CCID command PC_to_RDR_Escape.

This is fine, but before sending a CCID escape command the application should be sure it is using the correct reader. A command foobar sent to reader A may return the firmware release but if sent to reader B the same command may erase its firmware or may do many other bad things.

PC/SC should provide a way to uniquely identify a reader so that an application will not send commands to readers not designed to support them.

Proposed solution

The USB protocol already provides a way to identify a device: idVendor and idProduct.

We propose to include these 2 fields in the FEATURE_GET_TLV_PROPERTIES TLV response.

Tag name and value

Vendor ID

Tag value:
0x0B
Length:
2 bytes
Value
idVendor USB idVendor

Product ID

Tag value:
0x0C
Length:
2 bytes
Value
idProduct USB idProduct

Code sample

Here is a sample code written in Python using pyscard PC/SC wrapper http://pyscard.sourceforge.net/
#! /usr/bin/env python

from smartcard.System import readers
from smartcard.pcsc.PCSCPart10 import (getFeatureRequest, hasFeature,
    getTlvProperties, FEATURE_CCID_ESC_COMMAND)

# use the first reader
card_connection = readers()[0].createConnection()
card_connection.connect()

# get CCID Escape control code
feature_list = getFeatureRequest(card_connection)

ccid_esc_command = hasFeature(feature_list, FEATURE_CCID_ESC_COMMAND)
if ccid_esc_command is None:
    raise Exception("The reader does not support FEATURE_CCID_ESC_COMMAND")

# get the TLV PROPERTIES
tlv = getTlvProperties(card_connection)

# check we are using a Xiring Leo reader
if tlv['PCSCv2_PART10_PROPERTY_idVendor'] == 0x0F14 \
    and tlv['PCSCv2_PART10_PROPERTY_idProduct'] == 0x0037:

    # proprietary commands for Xiring readers
    version = [ord(c) for c in "VERSION"]
    res = card_connection.control(ccid_esc_command, version)
    print res
    print ''.join([chr(x) for x in res])
else:
    print "Xiring Leo reader not found"
Execution with a Xiring Leo reader:
[86, 69, 82, 32, 32, 80, 75, 48, 50, 46, 49, 49, 0]
VER  PK02.11
Execution with a non Xiring Leo reader:
Xiring Leo reader not found

Questions & Answers

USB readers

For USB devices the idVendor and idProduct are the values from the USB layer.

Non-USB readers

For serial, PCMCIA, ExpressCard, etc. readers the idVendor can be the manufacturer USB ID (if any), and idProduct a product ID managed by the manufacturer.

But non-USB readers may not support the FEATURE_CCID_ESC_COMMAND command. So a non-USB reader may return no value for idVendor and idProduct tags.

Why not use the PC/SC reader name?

Using the PC/SC name is a fragile method. For example the name of a reader may change over time if the manufacturer name changes ("Gemplus" became "Gemalto" for example) and a new driver updates the reader name.

My CCID driver (http://pcsclite.alioth.debian.org/ccid.html) updated reader names from Gemplus to Gemalto a few years ago. This is a real case.

Why not use SCARD_ATTR_VENDOR_NAME?

PC/SC v2 part 3 defines the tag 0x100 "Vendor Name" as "ASCII string".

MSDN documentation for SCardGetAttrib() defines SCARD_ATTR_VENDOR_NAME as "Vendor name."

It looks like the Windows CCID driver uses the USB iManufacturer text field as SCARD_ATTR_VENDOR_NAME. Other drivers may return something else. For example up to release 1.4.5 my CCID driver returned the name of the driver author not the name of the reader manufacturer (because of a misunderstanding of the PC/SC specification).

The content of field is not specified, only its format: ASCII string.

Another problem is that some USB CCID readers use a strange value for the iManufacturer field.

Here is a list of all the iManufacturer values Ludovic has in his reader list: http://pcsclite.alioth.debian.org/ccid/section.html The first column is the number of occurrences of the name in the second column.
Nb iManufacturer value
1
1
6 ACS
1 ASK-RFID
6 ATMEL
1 ActivCard
2 ActivIdentity
2 Aktiv
1 Aktiv Co., ProgramPark
1 Aladdin
1 Athena
2 Athena
2 Atmel
1 Axalto
2 BIFIT
1 BLUTRONICS
5 Broadcom Corp
6 C3PO
3 COVADIS
7 Cherry GmbH
1 Dell
6 Eutron
1 FS
1 FT SCR301
1 Feitian Technologies
1 Free Software Initiative of Japan
2 Fujitsu Siemens Computers
1 GEMPLUS
8 Gemalto
2 Gemalto
1 Gemalto*
12 Gemplus
7 Generic
1 German Privacy Foundation
2 Giesecke & Devrient GmbH
1 GoldKey Security
1 HDZB
1 Hewlett Packard
2 Hewlett-Packard Company
1 KEBTechnology
3 KOBIL
9 KOBIL Systems
1 Kingtrust
1 Lenovo
1 MYSMART
4 Neowave
2 O2
1 OBERTHUR TECHNOLOGIES
2 OCS ID-One Cosmo Card
4 OMNIKEY
9 OMNIKEY AG
1 Panasonic
2 Philips Semiconductors
2 Precise Biometrics
1 REINER SCT
1 RSA
1 Raritan
1 Reiner-SCT
18 SCM Microsystems Inc.
1 SMART
1 SYNNIX
1 Samsung ElectronicsCo., Ltd
1 SchlumbergerSema
1 Secure Device Solutions
1 Sitecom
7 SpringCard
1 THRC
1 TianYu CCID Key
1 Tianyu
3 Todos
1 USB
8 VASCO
1 VMware
1 Validy
1 Winbond
4 XIRING
1 charismathics
3 id3 Semiconductors
1 jNet Technology inc.
1 ubisys

Remarks

The first name is just 3 space characters for ACS ACR 122U reader.

The second name is just 1 space character for the Gemalto Ezio CB+ reader.

The same company uses "ActivCard" and "ActivIdentity".

The same company uses "Aktiv" and "Aktiv Co., ProgramPark".

The ASEDrive IIIe KB reader uses "Athena " with an extra space at the end of the name. But the other readers from the same manufacturer use "Athena" without the extra space.

Feitian uses the product name "FT SCR301" as iManufacturer.

Gemplus uses "GEMPLUS" (all caps) for the GemPC433 SL reader.

Gemplus has been renamed Gemalto. So the new readers now use "Gemalto", but also "Gemalto " (with an extra space character) and even "Gemalto*".

We have 7 "Generic" for 2 different idVendor (0x0BDA and 0x058F).

We have 1 "Hewlett Packard" and 2 "Hewlett-Packard Company".

We have 3 "KOBIL" and 9 "KOBIL Systems".

We have 4 "OMNIKEY" and 9 "OMNIKEY AG".

We have 1 "REINER SCT" and 1 "Reiner-SCT"

Results

The iManufacturer field is not constant for all devices from the same manufacturer.

The iManufacturer is not uniq since the same name "Generic" is used by (at least) 2 manufacturers.

Only the idVendor USB field is correctly specified and uniq.

Why not use SCARD_ATTR_VENDOR_IFD_TYPE?

PC/SC v2 part 3 defines the tag 0x101 "Vendor- specified IFD Type" as "ASCII string".

MSDN for SCardGetAttrib() defines SCARD_ATTR_VENDOR_IFD_TYPE as "Vendor-supplied interface device type (model designation of reader)."

It looks like the Windows CCID driver uses the USB iProduct text field. Other drivers may return something else.

The content of the field is not specified, only its format (ASCII string).

Another problem is that some USB CCID readers use a strange value for the iProduct field.

Here is a list of all the iProduct values Ludovic has in his reader list. The first column is the number of occurrences of the name in the second column.
Nb Name
13 Smart Card Reader USB
5 mIDentity 4smart
5 5880
4 Weneo
4 CCID USB Reader
3 USB SmartCard Reader
3 USB Smart Card Reader
3 USB SMART CARD READER
3 Contactless Reader
2 XI-SIGN USB V2
2 USB2.0-CRW
2 USB Smart Chip Device
2 USB SMART CARD KEYBOARD
2 USB GemPCPinpad SmartCard Reader
2 Smart Enterprise Guardian Secure USB Device
2 Smart Card Reader
2 SCR33x USB Smart Card Reader
2 SCR3310 USB Smart Card Reader
2 SCR331-DI USB Smart Card Reader
2 SCL01x Contactless Reader
2 Prox SU USB PC LinkReader
2 Prox Dual USB PC LinkReader
2 PCSC Smartcard Reader
2 O2Micro CCID SC Reader
2 ICCD Smartcard
2 Ezio Shield
2 EMV Smartcard Reader
2 DIGIPASS KEY 860
2 DIGIPASS KEY 200
2 CryptoIdentity CCID
2 Connectable
2 Card Reader
2 CCID Smart Card Reader
2 ASEDrive CCID
1 uKeyCI800-K18
1 plug'n'crypt CCID token
1 mIDentity XL
1 mIDentity M
1 jToken s1
1 iBank2Key
1 cyberJack pinpad(a)
1 cyberJack RFID basis
1 Virtual USB CCID
1 VaultIC460
1 VaultIC440
1 VaultIC420 Smart Object
1 VEGA-ALPHA
1 USB-Token iBank2key
1 USB Token
1 USB Reader V3
1 TokenA sl vt
1 Token JC
1 Token GEM USB COMBI-M
1 Token GEM USB COMBI
1 TianYu CCID SmartKey
1 SmartTerminal XX7X
1 SmartTerminal XX44
1 SmartTerminal XX1X
1 SmartTerminal ST-2xxx
1 SmartMX Sample
1 SmartCard USB 2A
1 SmartCard Keyboard USB 2A
1 SmartBoard XX44
1 SmartBoard XX33
1 SmartBoard XX1X
1 Smart Token
1 Smart Card Reader Interface
1 Sitecom USB simcard reader MD-010
1 SchlumbergerSema Cyberflex Access
1 STD200
1 SPRx32 USB Smart Card Reader
1 SIM Reader
1 SDI010 Smart Card Reader
1 SCRx31 USB Smart Card Reader
1 SCR35xx v2.0 USB SC Reader
1 SCR35xx USB Smart Card Reader
1 SCR3340 - ExpressCard54 Smart Card Reader
1 SCR3320 - Smart Card Reader
1 SCR3311 USB Smart Card Reader
1 SCL010 Contactless Reader
1 SBV280
1 SA .NET Dual
1 S3FC9UB USB Smart Card II
1 Rutoken lite
1 Rutoken Magistra
1 Rutoken ECP
1 Reflex USB v3
1 RSA SecurID (R) Authenticator
1 Prox'N'Roll
1 Precise 250 MC
1 Precise 200 MC
1 Panasonic USB Smart Card Reader 7A-Smart
1 PIV Token
1 PDT
1 MySMART PAD V2.0
1 Multi-Reader
1 MFP Smart Card Reader
1 LTC3x USB
1 KONA USB SmartCard
1 KOBIL Class 3 Reader
1 KAAN SIM III
1 KAAN Base
1 KAAN Advanced
1 JCOP41V221
1 Integrated Smart Card Reader
1 IDProtect Key v2
1 ID-ONE TOKEN SLIM v2
1 Hybrid Smartcard Reader
1 HP USB Smartcard Reader
1 HP USB Smart Card Keyboard
1 HP USB CCID Smartcard Keyboard
1 Gemplus USB SmartCard Reader 433-Swap
1 GemPC Express
1 GemCore SIM Pro Smart Card Reader
1 GemCore POS Pro Smart Card Reader
1 Gem e-Seal Pro USB Token
1 GEN5XX CCID
1 FT SCR310
1 FSIJ USB Token
1 EasyFinger Ultimate
1 EasyFinger Standard
1 EZIO CB+
1 Digipass 860
1 Dell USB Smartcard Keyboard
1 Dell Smart Card Reader Keyboard
1 DP905
1 DP865
1 DP855
1 DOMINO-Key TWIN
1 DIGIPASS 920
1 D2CIM-DVUSB VM/CCID
1 Crypto Stick v1.2
1 CrazyWriter
1 CSB6 Ultimate
1 CSB6 Secure
1 CSB6 Basic
1 CCID SmartCard Controller
1 CCID Smart Card 301
1 BLUDRIVE II CCID
1 Auriga
1 Activkey Sim
1 ActivCard USB Reader V2
1
1
AT98SC032CT-USB
AT91SO CCID Smart Card Reader
1 AT91SC192192CT-USB ICCD reader
1 APG8201 USB Reader
1 ALYA
1 AGM2 CCID
1 ACR38 USB Reader
1 ACR122U PICC Interface
1 13.56MHz RFID (CCID)

Remarks

We have 13 readers defined as "Smart Card Reader USB". All these readers are from Omnikey.

Kobil uses the same name "mIDentity 4smart" for 5 readers with different idProduct.

Broadcom uses 5880 for 3 different idProduct.

Neowave uses Weneo for 4 readers with different idProduct.

ACS uses "CCID USB Reader" for 4 different readers (with the same idProduct: 0x90CC).

Gemplus/Gemalto uses "USB SmartCard Reader" for 3 readers with different idProduct.

"USB Smart Card Reader" is used by 2 Atmel readers and 1 THRC reader.

C3PO uses "USB SMART CARD READER" for 3 readers with different idProduct and "USB SMART CARD KEYBOARD" for 2 readers with different idProduct.

Oberthur uses "USB Smart Chip Device" for 2 readers with different idProduct.

Gemalto and Tianyu share the same "Smart Card Reader" name.

Results

Some names are too common and not specific to a product. How can we tell what reader is behind the name "USB SmartCard Reader" or "Smart Card Reader USB"?

The iProduct field is not uniq.

Only the idProduct USB field is correctly specified and (often) uniq.

Why an integer and not an string?

An integer is much more easy to compare to a know value than an string in a low level language like C.


Extended APDU support reported by PC/SC

This is a proposition I submitted to the PC/SC workgroup for the November 2011 meeting.

I removed the people names from the document and used XXX instead.

Please send/add comments if you have some.



Extended APDU support reported by PC/SC




Extended APDU support reported by PC/SC

Authors: Ludovic ROUSSEAU
XXX, Xiring
Version: 1.0, October 2011

The problem

More and more cards do support extended APDU. Some card commands may be available only using an extended APDU.

It is not possible for a PC/SC application to know if the connected reader (+ driver) does or does not support extended APDU. The only way is to use SCardTransmit() to send an extended APDU and try to analyze the error code. Analysing an error code is difficult since PC/SC does nor define an error to indicate that the reader does not support extended APDU. So an already existing error code will be returned instead.

It is then hard or impossible for an application to report a clear error to a user like: "your reader does not support extended APDU. Please use another reader model." The error returned by PC/SC may be caused by another problem.

CCID

At the CCID level it is easy to know if a CCID reader does support extended APDU or not by interpreting the dwFeatures field in the USB CCID descriptor. Readers defined as "Short APDU level exchange with CCID" are not able to manage extended APDU. See http://pcsclite.alioth.debian.org/ccid_extended_apdu.html for more details and a list of readers in each categories.

The current proposal is to allow a PC/SC application to access this information at the PC/SC level.

Proposed solution using SCardControl()

Provide a new tag for FEATURE_GET_TLV_PROPERTIES to return the maximal size of data the reader (+ driver) can support.

For a reader supporting the full extended APDU size the value would be 0x10000 (64 kB). This size does not include the APDU header.

Tag name and value

Name:
dwMaxAPDUDataSize
Tag value:
0x0A
Length:
4 bytes
Coding:
as the other multi-bytes values returned by FEATURE_GET_TLV_PROPERTIES
Values:
  • 0: short APDU only
  • 0 < X <= 256: invalid values (RFU)
  • 256 < X <= 0x10000: short and extended APDU of up to X bytes of data
  • 0x10000 < X: invalid values (RFU)

Proposed solution using SCardGetAttrib()


As suggested by XXX I also propose to add a new entry in the table 3-1 in PC/SC part 3, chapter 3.1.1.2 'Enumeration of Device Capabilities'

I think the correct Information class is "Communications" so the tag should be the next free one: 0x0111.

The table should be updated to add a new line containing:
Information Class Data Element Tag Max Length Data Encoding
Communications Max APDU data size 0x0111 4 bytes DWORD

The PC/SC specification does not define the C macro name. But I propose to use:
#define SCARD_ATTR_MAX_APDU_DATA_SIZE
  SCARD_ATTR_VALUE(SCARD_CLASS_COMMUNICATIONS, 0x0111)
XXX from YYY commented this idea with, November 11 2010:
I fully agree that we should find this information in part 3.

However, it is not so nice to do this on Windows as the driver would have to intercept the IOCTL_SMARTCARD_GET_ATTRIBUTE request and treat it locally instead of forward it to SMCLIB via SmartcardDeviceControl (see http://msdn.microsoft.com/en-us/library/ff548899%28v=VS.85%29.aspx). Note that the driver cannot rely on error code returned by SmartcardDeviceControl to process the request as the IRP has already been completed.

That's why I would prefer using a PC/SC V2 feature for that. PC/SC V2 features such as IFD_PIN_PROPERTIES and IFD_DISPLAY_PROPERTIES are also reader capabilities and should be returned via part 3 but PC/SC structures are restricted in Windows to known fields without possibility to extend them easily.

So we have 2 choices:
  • Add this information in part 3 (and be quite inconsistent with IFD_PIN_PROPERTIES and IFD_DISPLAY_PROPERTIES) and do not strictly respect MS rules on PC/SC drivers
  • Add this information to part 10 as a PC/SC V2 feature
What is Microsoft point of view on that?

AFAIK Microsoft never commented on this remark.

This solution would work just fine using pcsc-lite (and without changing pcsc-lite, just the driver).

Since this solution may be difficult to implement on Windows it may not be a so good solution after all and FEATURE_GET_TLV_PROPERTIES should be used instead.

Sample in pseudo code

If an application need to use extended APDU for a card it should first check support of extended APDU and inform the user in case of problem.

if (get dwMaxAPDUDataSize failed)
{
    /* we don't know if extended APDU is supported */
    Shall we continue or abort? Maybe it is safer to continue (as before).
}
else
{
    if (dwMaxAPDUDataSize == 0)
    {
        error("your reader does not support extended APDU.")
        return
    }

    if (dwMaxAPDUDataSize < needed_size)
    {
        error("your reader supports too short extended APDU.")
        error("We need at least %d bytes", dwMaxAPDUDataSize)
        return
    }
}
continue execution

Questions & Answers

On/off state

It is not enough to have a on/off bit to indicate extended APDU support. Some reader may not support a full length extended APDU (64kB) but only a limited length (1kB or 4kB). So the feature must report the maximal size.

Short APDU

This proposal does not try to define what a "short APDU" or an "extended APDU" are. Short and extended APDU are already defined in ISO 7813-3 chapter 12.1.3 (page 33) "Decoding conventions for command APDUs" where cases 1, 2S, 2E, 3S, 3E, 4S and 4E are defined.

Test suite

This proposal does not plan to provide (or extend) a test suite for extended APDU.

Adding extended APDU support in the Microsoft test suite is another subject. I don't think Microsoft is interested in improving the test suite.

Case 4 APDU

The PC/SC specification does not specify if a case 4 APDU is supported or not by PC/SC.

Extended APDU are not restricted to case 4 APDU. But also exist for case 2 and 3. It is another matter to define the behavior of PC/SC with a case 4 APDU (4S or 4E).

Driver support of extended APDU

The driver must also support extended APDU.

Of course the reader and the driver (and the PC/SC middleware) must support extended APDU. The driver will report support of extended APDU only if the reader and the driver both do support extended APDU.

CCID does report extended APDU support

Yes, a CCID reader will report support (or not) of extended APDU. But a PC/SC application do not have access to this information. The purpose of this proposal is to allow a PC/SC application to get this information from the PC/SC layer.

Some non-CCID readers may also support extended APDU. The same mechanism can be used for non-CCID readers. The driver just need to implement the support of dwMaxAPDUDataSize in FEATURE_GET_TLV_PROPERTIES.

Switch the reader in TPDU mode

" In case your reader does not support extended APDU your driver can switch into TPDU mode and provide the APDU to the reader in several TPDUs. "

I do not know any documented/official CCID command to switch a reader from APDU to TPDU. Most readers can't be switched from APDU to TPDU. So this is not an option in most of the cases.

If a reader can be switched from APDU to TPDU and then support extended APDU this should be transparent for the application. It is the job of the driver to do whatever is needed and use dwMaxAPDUDataSize in FEATURE_GET_TLV_PROPERTIES to inform the application that extended APDU are available for this reader.

Use block chaining at the CCID level

" If the reader were a CCID-APDU styled reader, it is the task for the CCID driver to limit the buffers to: dwMaxCCIDMessageLength

All these single buffers can be chained in the CCID protocol, by using the chaining byte. "

CCID block chaining is available only for readers in "Short and Extended APDU level" mode. For readers in "Short APDU level" mode the wLevelParameter parameter of PC_to_RDR_XfrBlock in bChainParameter parameter of RDR_to_PC_DataBlock are RFU and must be 0 (according to CCID v1.1 section 6.1.4 PC_to_RDR_XfrBlock page 30 and 6.2.1 RDR_to_PC_DataBlock page 49).

Maybe the Microsoft CCID driver do use wLevelParameter/bChainParameter even for a "Short APDU level" reader. But this is not CCID compliant.

CCID block chaining is not available for "Short APDU level" readers.