I just released a new version of pcsc-tools, a suite of tools for PC/SC.
Changes:
1.6.1 - 30 December 2022, Ludovic ROUSSEAU
- 196 new ATRs
- use colors on NetBSD ("wsvt25" terminal)
- pcsc_scan: always print the version in verbose mode
I moved my blog from https://ludovicrousseau.blogspot.com/ to https://blog.apdu.fr/ . Why? I wanted to move away from Blogger (owne...
I just released a new version of pcsc-tools, a suite of tools for PC/SC.
1.6.1 - 30 December 2022, Ludovic ROUSSEAU
The documentation for the PySCard API was not updated since 2017 (5 years ago).
The tool used to generate the HTML documentation is epydoc. The latest epydoc version was released in 2008 (14 years ago). This tool is no more available in Debian so I had to move to something else.
The (new) tool to replace epydoc is pydoctor. It is actively maintained and generates nicer HTML pages.
For example, nice changes are:
The old (epydoc) documentation is still available online at
https://pyscard.sourceforge.io/epydoc/
The new API documentation is available at
https://pyscard.sourceforge.io/apidocs/index.html
or from the project main documentation page
https://pyscard.sourceforge.io/index.html
I guess I could improve the documentation. Feel free to report issues or
suggest improvements.
The AlcorMicro AU9560 smart card reader has problems with high speed smart cards.
The same problem is already reported in different places:
The reader is always the same but used with different cards.
The card must have a
TA1
> 0x95. To know the TA1 of your smart card you need to get and
parse the card's ATR, for example using pcsc_scan program from
pcsc-tools.
The reader declares it can support card/reader communication speed up to
688 172 bps.
See
dwMaxDataRate
field in
AlcorMicro_AU9560.txt.
It is fast but I have
4.5 % of readers in my list
that declare to be faster (not including contactless readers).
But speeds above ~200 000 bps are problematic with the AlcorMicro AU9560. It works fine, until an APDU exchange fails with a "Hardware error" (for example) message from the reader:
00000009 APDU: 00 A4 00 00 02 3F 00 00 00000007 ifdhandler.c:1333:IFDHTransmitToICC() usb:058f/9540:libudev:0:/dev/bus/usb/001/002 (lun: 0) 00000006 commands.c:1670:CmdXfrBlockAPDU_extended() T=0 (extended): 8 bytes 00000017 -> 000000 6F 08 00 00 00 00 0E 00 00 00 00 A4 00 00 02 3F 00 00 02734396 <- 000000 80 00 00 00 00 00 0E 41 FB 00 00000025 commands.c:1563:CCID_Receive Hardware error 00000009 APDU: 00 A4 00 00 02 3F 00 00
The AlcorMicro AU9560 is not a stand alone USB reader. It must be integrated
in a laptop. For example it is present in these laptop models:
I guess the same AlcorMicro AU9560 reader is present in a lot of other Lenovo or HP laptops and also laptops from other brands.
I worked on a patch to remove the highest speeds so that the CCID driver will negotiate a lower speed that is still supported by the reader.
My patch works fine with one card I have (NXP JCOP 4). But it generates problems with another card (Acos-ID).
The error occurs when the driver set the communication speed. The Set Parameters commands fails and the driver gets a "Card absent or mute" error.
00000004 [140396399142464] commands.c:2324:SetParameters() length: 7 bytes 00000006 [140396399142464] -> 000000 61 07 00 00 00 00 07 01 00 00 95 10 FF 46 00 FE 00 01646726 [140396415927872] ccid_usb.c:1532:InterruptRead() after (0) (2) 00621370 [140396399142464] <- 000000 82 00 00 00 00 00 07 41 FE 00 00000025 [140396399142464] commands.c:2351:SetParameters Card absent or mute 00000005 [140396399142464] prothandler.c:141:PHSetProtocol() Set PTS failed (612)
I suspect the problem to be specific to this card. But I am not sure. That is why I need your help to test with as much possible combinations as possible.
If your have:
then you can help me.
The AlcorMicro AU9560 and the AlcorMicro AU9540 both use the same USB
idProduct value of 0x9540 even if the two readers are a bit different. So even
if you have a AU9560 the PC/SC name will be "Alcor Micro AU9540 xx yy". If you
do not know what reader you have just suppose you have a AU9560.
You can check the 2 conditions above (AlcorMicro and TA1 value) using the
$ pcsc_scan Using reader plug'n play mechanism Scanning present readers... 0: Alcor Micro AU9540 00 00 Sat Dec 17 11:02:51 2022 Reader 0: Alcor Micro AU9540 00 00 Event number: 0 Card state: Card inserted, Shared Mode, ATR: 3B DC 96 FF 81 11 FE 80 31 C8 54 43 56 35 07 73 FF A1 C0 3C ATR: 3B DC 96 FF 81 11 FE 80 31 C8 54 43 56 35 07 73 FF A1 C0 3C + TS = 3B --> Direct Convention + T0 = DC, Y(1): 1101, K: 12 (historical bytes) TA(1) = 96 --> Fi=512, Di=32, 16 cycles/ETU 250000 bits/s at 4 MHz, fMax for Fi = 5 MHz => 312500 bits/s TC(1) = FF --> Extra guard time: 255 (special value) TD(1) = 81 --> Y(i+1) = 1000, Protocol T = 1 ----- TD(2) = 11 --> Y(i+1) = 0001, Protocol T = 1 ----- TA(3) = FE --> IFSC: 254 + Historical bytes: 80 31 C8 54 43 56 35 07 73 FF A1 C0 [...]
+ TCK = 3C (correct checksum) Possibly identified card (using /home/rousseau/.cache/smartcard_list.txt): 3B DC 96 FF 81 11 FE 80 31 C8 54 43 56 35 07 73 FF A1 C0 3C NXP JCOP 4, J3R200P0X3U/0ZA16CP NXD6.2 (JavaCard)
Please do:
Your help will greatly improve support of this reader commonly found in laptops.
Thank you.
The patch is now included in the CCID driver and will be present in the CCID release 1.5.2 (to be released later).
The CCID driver version 1.5.2 is now available.
Support of the AlcorMicro AU9560 should be better now.
To continue the list of PC/SC wrappers initiated in 2010 with "PC/SC sample in different languages" I now present a new sample code in Deno a modern runtime for JavaScript and TypeScript.
The wrapper is available at https://github.com/cryptographix/pcsc-deno and https://deno.land/x/pcsc
The author is
Sean Michael Wykes.
The license is MIT.
I used version
0.4.
This version includes the fixes I proposed for GNU/Linux.
From Wikipedia Deno article:
Deno is a runtime for JavaScript, TypeScript, and WebAssembly that is based on the V8 JavaScript engine and the Rust programming language. Deno was co-created by Ryan Dahl, who also created Node.js.
Deno explicitly takes on the role of both runtime and package manager within a single executable, rather than requiring a separate package-management program.
Installation is very easy. First install Deno as documented in https://deno.land/#installation
The PC/SC wrapper will be downloaded and installed automatically at run
time.
import { CommandAPDU, ContextProvider, ISO7816, PCSC, } from 'https://deno.land/x/pcsc/mod.ts'; try { // establish a PC/SC context const context = ContextProvider.establishContext(); // get all available readers const readers = context.listReaders(); for (const reader of readers) { console.log(`Using reader: ${reader.name}`); if (reader.isMute) { console.log(`Reader ${reader.name}: MUTE`); } else if (reader.isPresent) { // connect const card = await reader.connect(); // send Select Applet APDU const selectApplet = CommandAPDU .from([ISO7816.CLA.ISO, ISO7816.INS.SelectFile, 0x04, 0x00]) // ISO SELECT .setData([0xA0, 0x00, 0x00, 0x00, 0x62, 0x03, 0x01, 0x0C, 0x06, 0x01]); const resp = await card.transmitAPDU(selectApplet); // check for 0x90 0x00 if (resp.SW == ISO7816.SW.SUCCESS) { // success .. console.log(`Reader ${reader.name}: applet successfully selected`); // send Test APDU const command = CommandAPDU .from([ISO7816.CLA.ISO, 0, 0, 0]); const resp = await card.transmitAPDU(command); if (resp.SW == ISO7816.SW.SUCCESS) { // success .. console.log(`Reader ${reader.name}: Test command successful`); // convert from bytes to string and display console.log(String.fromCharCode.apply(null, resp.data)); } else { // something went wrong .. console.error( `Reader ${reader.name}: error SW=${resp.SW.toString(16)}`, ); } } else { // something went wrong .. console.error( `Reader ${reader.name}: error SW=${resp.SW.toString(16)}`, ); } // unpower and disconnect await card.disconnect(PCSC.Disposition.UnpowerCard); } else { console.log(`Reader ${reader.name}: NO CARD`); } } // release the PC/SC context context.shutdown(); } catch (e: PCSCException) { console.log(e, "error"); }
$ deno run --unstable --allow-ffi blog.ts Using reader: Gemalto PC Twin Reader (F8345B4A) 00 00 Reader Gemalto PC Twin Reader (F8345B4A) 00 00: applet successfully selected Reader Gemalto PC Twin Reader (F8345B4A) 00 00: command successful Hello world!
Nothing special to say. Thanks Sean for the wrapper.
If you work on a Free Software PC/SC wrapper that is not yet in my list please let me know.
As I wrote in "One smart card reader accessible from many computers" it is possible to share a smart card reader between 2 or more systems.
I recently received a bug report about a problem between pcsc-lite and VirtualBox. When the smart card reader is connected to the VM guest then the kernel on the host reports errors like:
2022-11-11T14:25:01.186983-08:00 track pcscd[2474]: 00000001 eventhandler.c:336:EHStatusHandlerThread() Error communicating to: SCM Microsystems Inc. SCR 3310 [CCID Interface] (53311514247933) 00 00
2022-11-11T14:25:01.186993-08:00 track pcscd[2474]: 00000005 ccid_usb.c:1356:InterruptRead() libusb_submit_transfer failed: LIBUSB_ERROR_IO
2022-11-11T14:25:01.188050-08:00 track kernel: [ 1247.705353][ T2521] usb 1-2: usbfs: process 2521 (pcscd) did not claim interface 0 before use
2022-11-11T14:25:01.188053-08:00 track kernel: [ 1247.705386][ T2521] usb 1-2: usbfs: process 2521 (pcscd) did not claim interface 0 before use
2022-11-11T14:25:01.587034-08:00 track pcscd[2474]: 00400173 ccid_usb.c:865:WriteUSB() write failed (1/2): -1 LIBUSB_ERROR_IO
2022-11-11T14:25:01.587076-08:00 track pcscd[2474]: 00000008 ifdwrapper.c:364:IFDStatusICC() Card not transacted: 612
And after some times (in days) the host kernel crashes.
A Linux kernel crash is never a good thing. pcsc-lite may be very powerful but
it can't crash the Linux kernel. Only a bug in the kernel itself can generate
a crash. Here I suspect the VirtualBox Linux kernel module to do something
bad.
Instead of connecting the USB smart card reader in the guest VM (and
disconnecting it from the host) it is possible to share the smart card
reader(s) between the host and guest with some help from pcsc-lite.
My demo setup:
I use 2 very different operating systems, GNU/Linux and NetBSD, on purpose. It is to show it is possible to mix systems.
In the host, no change to the configuration. But we will redirect (inject)
On the Debian host I run:
$ ssh -N -R/tmp/pcscd.comm:/run/pcscd/pcscd.comm VMNetBSD
On the NetBSD VM I use:
$ export PCSCLITE_CSOCK_NAME=/tmp/pcscd.comm
Then I can run any application using pcsc-lite and get access to the smart
card(s) and reader(s) from the host. For example:
$ pcsc_scan -c
Wed Nov 16 17:26:55 2022 Reader 0: Alcor Micro AU9540 00 00 Event number: 0 Card state: Card inserted, ATR: 3B A7 00 40 18 80 65 A2 08 01 01 52
With a screenshot:
As I demonstrated the solution is not limited to GNU/Linux. Any Unix system using pcsc-lite can be used. But you must use the same pcsc-lite protocol on both sides.
For example the current protocol version used by pcsc-lite 1.9.9 (current version) is 4.4. It is the same protocol version since pcsc-lite 1.8.24 released in Oct 2018.
It should be technically possible to use Windows or macOS as the host OS. That would involve a new development. Contact me if you need something like that.
No need to disconnect/reconnect the USB reader in the VM. Just share it with the host.
You will be able to use the same smart card at the same time on the two sides. Isn't it nice?
Ventura (macOS 13.0) is now available since October, 2022.
I will compare this version to the previous one in Monterey I presented in macOS Monterey and smart cards status.
$ grep -A 1 CFBundleShortVersionString /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist
<key>CFBundleShortVersionString</key>
<string>1.5.0</string>
The CCID driver has been upgraded from version 1.4.34 as in Monterey to
version 1.5.0.
ifdLogLevel
from No big changes in Ventura for the smart card world.
I just released version 1.5.1 of libccid the Free Software CCID class smart card reader driver.
PCSCLITE_HP_DROPDIR
--enable-strict
option"%{public}s"
In 2015 (7 years ago) I ported my CCID driver to UEFI (Unified Extensible Firmware Interface). For example read "UEFI Smart Card Reader Protocol implementation" and "PCSC sample in C for UEFI".
I now updated the driver to use:
The driver is no more a patch for edk2 but an independent UEFI driver in its own repository UEFI-SmartCardReader. It should now be easier to build.
I also updated my samples applications in UEFI-SmartCardReader-Samples.
This driver will not be used by a lot of people. The driver is for applications that are run in the UEFI (i.e. before the main operating system is started) and with a need to access smart cards.
If you use it and want to have new features, or just want to discuss, you can contact me. I am curious to know what people can do with it.
Since Ubuntu 22.04 LTS there is a problem with PC/SC daemon automatic start. pcscd is supposed to start when an application makes the first PC/SC call. See "pcscd auto start using systemd". In some cases pcscd will not start and SCardEstablishContext() will receive the error SCARD_E_NO_SERVICE.
A ticket is opened at Ubuntu with bug #1971984:
pcscd 1.9.5-3 do not start automatically, only manual
The problem is present on some configurations only. I have no idea why on some systems it works fine and on some others we have the problem.
For an unknown reason pcscd.socket is inactive.
$ systemctl status pcscd.socket ○ pcscd.socket - PC/SC Smart Card Daemon Activation Socket Loaded: loaded (/lib/systemd/system/pcscd.socket; disabled; vendor preset: enabled) Active: inactive (dead) Triggers: ● pcscd.service Listen: /run/pcscd/pcscd.comm (Stream)
The fix is easy:
sudo systemctl enable pcscd.socket
And reboot.
The same pcscd package has no problem on Debian.
I compared the configuration scripts between the Ubutun and Debian packages and they are the same. I guess the problem comes from systemd or dpkg on Ubuntu and the systemd configuration files are not always installed correctly. Again, no idea why.
The bug is opened since 2022-05-06. I don't know if someone at Ubuntu is working on it.
The pcscd package is in the section Universe (Community-Maintained, Open-Source Software) at Ubuntu. It is not in the section Main (Officially Supported, Open-Source Software) so maybe no engineer from Ubuntu is looking at this issue.
The problem may not be fixed until Ubuntu 24.04, the next LTS version.
I just released a new version 2.0.5 of pyscard. PySCard is a python module adding smart cards support (PC/SC) to Python.
The PySCard project is available at:
This version is a not even a bug fix release. No code has changed.
The problem is that for the previous version, 2.0.4, I uploaded a incorrect source archive to Pypi. I inadvertently included some generated files in the .tar.gz archive. I discovered the problem while creating the Debian package. I removed the incorrect file from Pypi. But then it is not possible to upload a new file with a name that was already present on Pypi.
The source .tar.gz is already present in the pyscard project on sourceforge.net so I thought it was OK.
But then I received bug reports like Missing source release for 2.0.4? or pyscard 2.0.4 not available on linux from pypi so I had to do something.
I just released a new version of
pcsc-lite 1.9.9.
pcsc-lite is a Free Software implementation of the PC/SC (or WinSCard) API for
Unix systems.
SCardEstablishContext()
may return SCARD_W_SECURITY_VIOLATION
if refused
by Polkit
SCardReleaseContext()
failure on orphan handlesSCardDisconnect()
on orphan handlepioSendPci
& pioRecvPci
SCardTransmit()
parameters
I just released a new version of
PyKCS11, a Python
wrapper above the PKCS#11 API.
See "PyKCS11 introduction" or "PyKCS11’s documentation".
1.5.11 - September 2022, Ludovic Rousseau
deriveKey()
with CKM_ECDH1_DERIVE
and
CK_ECDH1_DERIVE_PARAMS
pSourceData
in OAEP paramsI just released a new version 2.0.4 of pyscard. PySCard is a python module adding smart cards support (PC/SC) to Python.
The PySCard project is available at:
This version is a bug fix release.
PCSCCardConnection.disconnect
BaseSCardException(hresult)
formatJust a quick article to talk about something funny.
Google Search Console Team sent me an email with the top most Google searches used to arrive on my website https://ccid.apdu.fr/.
For the month of June 2022 the second top search is: "ccid driver windows 10".
Google "think" someone will find a Windows 10 driver on https://ccid.apdu.fr/?
The Windows CCID is so hard to find or to install or is so buggy that users are searching for an alternative?
On the last 12 months the result is less worrisome. The "ccid driver windows 10" search is only 7th in the list:
Please propose your own explanation of this result.
Maybe I should add "Windows 10" in the web site description metadata to confuse Google search a bit more? :-)
10 years ago I documented in "PCSC API spy, third try" a way to generate PC/SC API traces when using pcsc-lite.
Since then the ecosystem has changed. This article is an update of the previous blog article with more up-to-date information.
LD_PRELOAD=
any
more
This is the case of the
You can use the ldd
command to know what library has been dynamically linked
at build time:
$ ldd /usr/bin/pcsc_scan
linux-vdso.so.1 (0x00007fffac11b000)
libpcsclite.so.1 => /lib/x86_64-linux-gnu/libpcsclite.so.1 (0x00007f85a5f24000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f85a5f03000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f85a5d2a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f85a5f4f000)
You can use the LD_PRELOAD solution by doing:
In on terminal you run the pcsc-spy
program. In another terminal you run:
$ LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libpcscspy.so.0 pcsc_scan -r libpcsclite_nospy.so.1: cannot open shared object file: No such file or directory No reader found.
In the first terminal you get the trace:
$ pcsc-spy SCardEstablishContext i dwScope: SCARD_SCOPE_SYSTEM (0x00000002) o hContext: 0x0E4C693B => Command successful. (SCARD_S_SUCCESS [0x00000000]) [0.002456] SCardGetStatusChange i hContext: 0x0E4C693B i dwTimeout: 0x00000000 (0) i cReaders: 1 i szReader: \\?PnP?\Notification i dwCurrentState: (0x00000000) i dwEventState: SCARD_STATE_IGNORE, SCARD_STATE_UNKNOWN, SCARD_STATE_UNAVAILABLE, SCARD_STATE_EMPTY, SCARD_STATE_INUSE, SCARD_STATE_MUTE (0x55EDE352031D) i Atr length: 0x55EDE352032C (94480209412908) i Atr: NULL o szReader: \\?PnP?\Notification o dwCurrentState: (0x00000000) o dwEventState: (0x00000000) o Atr length: 0x55EDE352032C (94480209412908) o Atr: NULL => Command timeout. (SCARD_E_TIMEOUT [0x8010000A]) [0.007774] SCardListReaders i hContext: 0x0E4C693B i mszGroups: (null) o pcchReaders: 0x00000001 o mszReaders: NULL => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E]) [0.000908] SCardListReaders i hContext: 0x0E4C693B i mszGroups: (null) o pcchReaders: 0x00000001 o mszReaders: NULL => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E]) [0.000531] Thread 1/1 Results sorted by total execution time total time: 0.011769 sec 0.007774 sec ( 1 calls) 66.06% SCardGetStatusChange 0.002456 sec ( 1 calls) 20.87% SCardEstablishContext 0.001439 sec ( 2 calls) 12.23% SCardListReaders
In this case you need to modify the system configuration to replace the
install_spy.sh
script. You only need to run the script once.
$ sudo bash /usr/share/doc/libpcsclite-dev/install_spy.sh Using directory: /lib/x86_64-linux-gnu Spying library is: /lib/x86_64-linux-gnu/libpcscspy.so.0
On Debian (and derivatives like Ubuntu) and with pcsc-lite version 1.9.8 and
more the script is provided by the libpcsclite-dev package.
In on terminal you run the pcsc-spy program. In another terminal you run the program you want to spy. For example:
$ opensc-tool -a No smart card readers found. Failed to connect to reader: No readers found
In the first terminal you get the trace:
SCardEstablishContext i dwScope: SCARD_SCOPE_USER (0x00000000) o hContext: 0x2667F6DA => Command successful. (SCARD_S_SUCCESS [0x00000000]) [0.005316] SCardListReaders i hContext: 0x2667F6DA i mszGroups: (null) o pcchReaders: 0x00000001 o mszReaders: NULL => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E]) [0.000079] SCardReleaseContext i hContext: 0x2667F6DA => Command successful. (SCARD_S_SUCCESS [0x00000000]) [0.000074] Thread 1/1 Results sorted by total execution time total time: 0.007195 sec 0.005316 sec ( 1 calls) 73.88% SCardEstablishContext 0.000079 sec ( 1 calls) 1.10% SCardListReaders 0.000074 sec ( 1 calls) 1.03% SCardReleaseContext
Do not forget to restore the system configuration using the
uninstall_spy.sh
script.
$ sudo bash /usr/share/doc/libpcsclite-dev/uninstall_spy.sh Using directory: /lib/x86_64-linux-gnu
It is still possible to redirect the traces in a file. Instead of running
pcsc-spy
you do:
$ mkfifo ~/pcsc-spy $ cat ~/pcsc-spy > logfile
And in another terminal you start the application as indicated above (i.e.
using LD_PRELOAD=
or after running install_spy.sh
)
You can then analyse the logs later using:
$ pcsc-spy logfile
I note that SCardReleaseContext()
is not always called by
pcsc_scan
before exit. I just fixed this problem in
pcsc-tools.
It is important to run the uninstall_spy.sh
script to undo the
changes made by the install_spy.sh
script.
It is important you undo the changes before any execution of the
If you run uninstall_spy.sh
after an execution of
$ pcsc_scan
pcsc_scan: error while loading shared libraries: libpcsclite.so.1: cannot open shared object file: No such file or directory
To fix te problem you can force reinstall the libpcsclite1 (or equivalent) package.
It is important to start pcsc-spy
before the application
you want to spy. If you start pcsc-spy after the application you have 2
cases:
pcsc-spy
or the cat
command to redirect the
content)
I hope this update is useful.
if you have ideas to improve the logs please contact me.
I just released a new version of
pcsc-lite 1.9.8.
pcsc-lite is a Free Software implementation of the PC/SC (or WinSCard) API for
Unix systems.
1.9.8: Ludovic Rousseau
11 June 2022
SCardTransmit()
: do not fail if receive buffer is "too large"SCardControl()
: do not fail if receive buffer is "too large"I updated my ATR parsing web site at https://smartcard-atr.apdu.fr/ to add the option to get the result not in an HTML page but as a JSON document.
If you do not yet know this service you can read "Parsing an ATR: new web site URL" to get some history.
The URL for the JSON service is https://smartcard-atr.apdu.fr/V1/parse2json?ATR=3BFF9700008131FE4380318065B0846160FB120FFD8290000D.
It is the same as for the HTML output
https://smartcard-atr.apdu.fr/parse?ATR=3BFF9700008131FE4380318065B0846160FB120FFD8290000D
except you replace "parse" by "V1/parse2json" in the URL.
Of course you update the ATR parameter value to use the ATR value you want to parse.
You can use it to get the description of a particular field by piping the result in the jq command.
jq is a lightweight and flexible command-line JSON processor.
For example to get the meaning of the TA1 byte you can use:
$ curl -s https://smartcard-atr.apdu.fr/V1/parse2json?ATR=3B12953606 | jq '.TA."1"' { "description": "Fi=512, Di=16, 32 cycles/ETU (125000 bits/s at 4.00 MHz, 156250 bits/s for fMax=5 MHz)", "value": 149 }
Or for just the TA1 description:
$ curl -s https://smartcard-atr.apdu.fr/V1/parse2json?ATR=3B90160187 | jq '.TA."1".description'
"Fi=372, Di=32, 11.625 cycles/ETU (344086 bits/s at 4.00 MHz, 430107 bits/s for fMax=5 MHz)"
I also added the possibility to get the cards matching a given ATR.
For example: https://smartcard-atr.apdu.fr/V1/match?ATR=3B8F800180318065B0850300EF120FFE82900072
$ curl -s https://smartcard-atr.apdu.fr/V1/match?ATR=3B8F800180318065B0850300EF120FFE82900072 | jq { "3B 8F 80 01 80 31 80 65 B0 .. .. .. .. 12 0F FE 82 90 00 ..": [ "IDPrime MD 3810 T=Contactless (Prox DU)" ], "3B 8F 80 01 80 31 80 65 B0 85 03 00 EF 12 0F FE 82 90 00 72": [ "Gemalto IDPrime MD 3840", "http://www.gemalto.com/dwnld/6891_IDPrimeMD3840_Product_Datasheet_May14.pdf" ] }
Because of the joker mechanism using the character '.' it is possible that one ATR matches
more than one "card".
If you have ideas how to improve the service just tell me.
We start with the following
01: #include <stdio.h> 02: #include <stdlib.h> 03: #include <winscard.h> 04: 05: #define CHECK(f, rv) \ 06: if (SCARD_S_SUCCESS != rv) \ 07: { \ 08: printf(f ": %s\n", pcsc_stringify_error(rv)); \ 09: return -1; \ 10: } 11: 12: int main(void) 13: { 14: LONG rv; 15: 16: SCARDCONTEXT hContext; 17: LPTSTR mszReaders; 18: DWORD dwReaders; 19: 20: rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); 21: CHECK("SCardEstablishContext", rv) 22: 23: rv = SCardListReaders(hContext, NULL, NULL, &dwReaders); 24: CHECK("SCardListReaders", rv) 25: 26: mszReaders = calloc(dwReaders, sizeof(char)); 27: rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders); 28: CHECK("SCardListReaders", rv) 29: printf("1st reader name: %s\n", mszReaders); 30: 31: free(mszReaders); 32: 33: rv = SCardReleaseContext(hContext); 34: CHECK("SCardReleaseContext", rv) 35: 36: return 0; 37: } 38:
I used this Makefile
# Linux PCSC_CFLAGS := $(shell pkg-config --cflags libpcsclite) LDLIBS := $(shell pkg-config --libs libpcsclite) CFLAGS = $(PCSC_CFLAGS) -g sample: sample.c clean: rm -f sample
Compilation and execution give:
$ make cc -pthread -I/usr/include/PCSC -g sample.c -lpcsclite -o sample $ ./sample 1st reader name: Alcor Micro AU9540 00 00
It looks like everything is correct.
But can you find the problem?
valgrind is a very nice tool to debug issues.
Valgrind is an instrumentation framework for building dynamic analysis tools. There are Valgrind tools that can automatically detect many memory management and threading bugs, and profile your programs in detail. You can also use Valgrind to build new tools.
valgrind sees a problem:
$ valgrind --track-origins=yes ./sample
==99878== Memcheck, a memory error detector
==99878== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==99878== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==99878== Command: ./sample
==99878==
==99878== Conditional jump or move depends on uninitialised value(s)
==99878== at 0x486E02E: SCardListReaders (in /usr/lib/x86_64-linux-gnu/libpcsclite.so.1.0.0)
==99878== by 0x109210: main (sample.c:23)
==99878== Uninitialised value was created by a stack allocation
==99878== at 0x109199: main (sample.c:13)
==99878==
1st reader name: Alcor Micro AU9540 00 00
==99878==
==99878== HEAP SUMMARY:
==99878== in use at exit: 112 bytes in 4 blocks
==99878== total heap usage: 10 allocs, 6 frees, 1,434 bytes allocated
==99878==
==99878== LEAK SUMMARY:
==99878== definitely lost: 0 bytes in 0 blocks
==99878== indirectly lost: 0 bytes in 0 blocks
==99878== possibly lost: 0 bytes in 0 blocks
==99878== still reachable: 112 bytes in 4 blocks
==99878== suppressed: 0 bytes in 0 blocks
==99878== Rerun with --leak-check=full to see details of leaked memory
==99878==
==99878== For lists of detected and suppressed errors, rerun with: -s
==99878== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Using uninitialized variables is bad. It creates bugs that declare at random time and are not easy to find.
The problem is at line 23 which is:
23: rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
If we read the documentation for SCardListReaders() we have:
Returns a list of currently available readers on the system.
mszReaders
is a pointer to a character string that is allocated by the application. If the application sendsmszGroups
andmszReaders
as NULL then this function will return the size of the buffer needed to allocate inpcchReaders
.If
*pcchReaders
is equal to SCARD_AUTOALLOCATE then the function will allocate itself the needed memory. Use SCardFreeMemory() to release it.
- Parameters
[in] hContext Connection context to the PC/SC Resource Manager. [in] mszGroups List of groups to list readers (not used). [out] mszReaders Multi-string with list of readers. [in,out] pcchReaders Size of multi-string buffer including NULL's.
You can note that the parameter pcchReaders is in and out. This is because the
value is compared to
SCARD_AUTOALLOCATE. So the value of pcchReaders shall be set before calling
SCardListReaders()
.
The fix is simple. Just update line 18 like this:
18: DWORD dwReaders = 0;
What happens if we initialize dwReaders
to the special value
SCARD_AUTOALLOCATE
instead of 0?
18: DWORD dwReaders = SCARD_AUTOALLOCATE;
We build and run the sample:
$ ./sample SCardListReaders: Invalid parameter given.
The execution of SCardListReaders()
fails.
23: rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
This is because we are asking SCardListReaders()
to allocate and
store the result in the parameter mszReaders
. But in our sample
this parameter is NULL
. pcsc-lite has a check for that and
returns an error code.
Instead of using NULL
we could use something else like
0x1234
.
23: rv = SCardListReaders(hContext, NULL, 0x1234, &dwReaders);
This time we have a nice crash:
$ ./sample Segmentation fault
This is because we asked SCardListReaders()
to write at the
address 0x1234
. This address is, in general, not valid.
This problem could happen if you use something like:
23: rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
And both variables mszReaders
and dwReaders
are
uninitialized, and by a total lack of luck dwReaders
has the
value SCARD_AUTOALLOCATE
(i.e. -1).
The problem was found in by
oddlama and reported to PCSC at "pcscd fails to read future yubikeys after removing a yubikey, until
restarted #125".
The problem is not in pcsc-lite but in GnugPG. So I reported the problem at "SCardListReaders: Conditional jump or move depends on uninitialised value(s)".
macOS does not support (yet) the value SCARD_AUTOALLOCATE
. But
pcsc-lite and Windows WinSCard do.
I agree the API to use SCARD_AUTOALLOCATE
is ugly. We pass the
address of a buffer pointer in a parameter that is a buffer pointer. We have to cast the
variable like I did in the
C sample
like:
dwReaders = SCARD_AUTOALLOCATE; rv = SCardListReaders(hContext, NULL, (LPTSTR)&mszReaders, &dwReaders);
This feature is a Microsoft extension that is not present in the PCSC workgroup specification.
I think the problem is not very known and should be better documented. That
was my motivation for writting this blog article.
Morality: in C language, always initialize your variables to a known/safe
value (like 0).
I just released a new version of
pcsc-lite 1.9.7.
pcsc-lite is a Free Software implementation of the PC/SC (or WinSCard) API for
Unix systems.
1.9.7: Ludovic Rousseau
13 May 2022
In the previous version (1.9.6) I enabled a strict compilation option by
default. The compiler was configured to use the -Werror
argument. The effect is to
transform warnings into errors. The compilation would fail instead of just
displaying a warning.
On my side I had no warnings so I was confident.
But some build systems use a different set of default compilation arguments.
For example Arch Linux or openSUSE Tumbleweed use the argument -flto=auto
to
perform some link-time optimizer.
This option generated 3 warnings. The warnings are minor but since the
compilation used -Werror
they were treated as errors and the compilation
failed.
Sorry for generating the problem. Thanks to Axel Braun and frederik for
reporting the failure.
I just released a new version of
pcsc-lite 1.9.6.
pcsc-lite is a Free Software implementation of the PC/SC (or WinSCard) API for
Unix systems.
DISABLE_AUTO_POWER_ON
--disable-strict
option-Wall -Wextra -Wno-unused-parameter -Werror ${CFLAGS}
MAX_READERNAME
&
PCSCLITE_MAX_READERS_CONTEXTS
The problem with reader removal is that, with some hardware configurations,
the USB bus is removed when the USB device is disconnected. You can see that
using the libusb
command.
Before connecting the device:
Bus 002 Device 002: ID 0bda:0328 Realtek Semiconductor Corp. USB3.0-CRW Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 003: ID 1bcf:2c6b Sunplus Innovation Technology Inc. HD WebCam Bus 001 Device 005: ID 1044:7a39 Chu Yuen Enterprise Co., Ltd USB-HID Keyboard Bus 001 Device 004: ID 8087:0a2b Intel Corp. Bluetooth wireless interface Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
After connecting the Yubikey token
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 003 Device 002: ID 1050:0407 Yubico.com Yubikey 4/5 OTP+U2F+CCID Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 002: ID 0bda:0328 Realtek Semiconductor Corp. USB3.0-CRW Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 003: ID 1bcf:2c6b Sunplus Innovation Technology Inc. HD WebCam Bus 001 Device 005: ID 1044:7a39 Chu Yuen Enterprise Co., Ltd USB-HID Keyboard Bus 001 Device 004: ID 8087:0a2b Intel Corp. Bluetooth wireless interface Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
The new lines are:
2 new USB buses are created 003 & 004. The Yubikey token is connected on the bus 003.
After removing the Yubikey
Bus 002 Device 002: ID 0bda:0328 Realtek Semiconductor Corp. USB3.0-CRW Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 003: ID 1bcf:2c6b Sunplus Innovation Technology Inc. HD WebCam Bus 001 Device 005: ID 1044:7a39 Chu Yuen Enterprise Co., Ltd USB-HID Keyboard Bus 001 Device 004: ID 8087:0a2b Intel Corp. Bluetooth wireless interface Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
The USB buses 3 & 4 have disappeared. This confused pcsc-lite. The token was not removed for pcsc-lite and caused the generation of log errors. This is now fixed.
In 2010 I started to write about the different programming languages you can use to talk to a smart card and a smart card reader.
12 years later I have 30 languages in the list.
They are, in alphabetical order:
Different lists exist for the top computer languages popularity. I will use the TIOBE Index for April 2022.
The "support" column indicates if the language has a smart card API
available.
# |
Language | support |
---|---|---|
1 | Python | Yes |
2 | C | Yes |
3 | Java | Yes |
4 | C++ | Yes |
5 | C# | Yes |
6 | Visual Basic | ? |
7 | JavaScript | Yes |
8 | Assembly | ? |
9 | SQL | ? |
10 | PHP | Yes |
11 | R | ? |
12 | Pascal | Yes |
13 | Go | Yes |
14 | Swift | Yes |
15 | Ruby | Yes |
16 | Classic Visual Basic | ? |
17 | Objective-C | Yes |
18 | Perl | Yes |
19 | Lua | Yes |
20 | Mathlab | ? |
21 | SAS | ? |
22 | Prolog | Yes |
23 | (Visual) FoxPro | ? |
24 | Scratch | ? |
25 | COBOL | ? |
26 | Julia | ? |
27 | Kotlin | Yes |
28 | Rust | Yes |
29 | Ada | Yes |
30 | Lisp | Yes |
31 | Fortran | ? |
32 | Groovy | ? |
33 | VBScript | ? |
34 | PL/SQL | ? |
35 | D | ? |
36 | Scala | Yes |
37 | Haskell | ? |
38 | Dart | Yes |
It should be easy to call the C WinSCard API from assembly language. So the answer could be "yes". I learned assembly language with a Motorola 6809 and then a Motorola 68000. I am not a fan of the Intel x86 assembly language with its very strange register names (to be backward compatible). Yes, I could also use ARM or RISC-V CPUs. I let the exercise to write an example in assembly language to the readers.
Some programming languages are not listed in the TIOBE index but do provide a PC/SC wrapper:
Some languages are specific to the Microsoft Windows system. I can't use them since I do not use Windows. They are:
It looks like Visual Basic is also available for GNU/Linux. But I don't want to invest time in these technologies.
Also note that all the computer languages with PC/SC support exist in a Free Software implementation. I am not sure for the Microsoft languages.
R and SAS are languages used for statistics.
Scratch is used for education.
Mathlab is for numeric computing.
COBOL is very old. I do not
expect any COBOL program needing access to smart cards. Same remark for
Fortran. COBOL and Fortran
are still used and it looks like it is possible to call C functions from
both
of
them. So there is hope ☺.
SQL: (SQL Server) PC/SC List Smart Card Readers (and USB Tokens)
This is for SQL Server, so may be limited to the Microsoft product and not the
SQL language.
It was a lot of fun to discover and write a sample codes for all the 30 languages.
For some (4) of the PC/SC wrappers I am the maintainer so writing a sample code was easy.
The list is not finished and may never be as new programming languages are
created from time to time. If you want me to add a new language please contact me.