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, June 9, 2023
Sunday, April 16, 2023
FAQ: pcsc-lite and SCARD_E_SERVICE_STOPPED error
One of the most popular search request that bring people on my blog is about
SCARD_E_SERVICE_STOPPED.
The problem
With pcsc-lite the only cause for the error
SCARD_E_SERVICE_STOPPED is that the two sides, pcscd and
libpcsclite, are using a different version of the communication protocol.
See for example the reported issue "SCardEstablishContext: Service was stopped.".
In the logs you have something like:
$ journalctl --unit=pcscd [...] févr. 11 18:55:07 debian pcscd[3715]: 00000006 winscard_svc.c:361:ContextThread() Received command: CMD_VERSION from client 8 févr. 11 18:55:07 debian pcscd[3715]: 00000004 winscard_svc.c:373:ContextThread() Client is protocol version 4:3 févr. 11 18:55:07 debian pcscd[3715]: 00000001 winscard_svc.c:382:ContextThread() Communication protocol mismatch! févr. 11 18:55:07 debian pcscd[3715]: 00000002 winscard_svc.c:384:ContextThread() Client protocol is 4:3 févr. 11 18:55:07 debian pcscd[3715]: 00000001 winscard_svc.c:386:ContextThread() Server protocol is 4:4 févr. 11 18:55:07 debian pcscd[3715]: 00000002 winscard_svc.c:396:ContextThread() CMD_VERSION rv=0x8010001E for client 8Here the server is using version 4.4 but the client is using version 4.3.
The error code
0x8010001E is
SCARD_E_SERVICE_STOPPED.
The cause
This situation can happen if you reinstalled pcsc-lite yourself but in
You may also use an application inside a flatpak container that uses a different version of pcsc-lite. See the limitations listed in "Accessing smart cards from inside a flatpak sandbox".
The solution
Do not mix different versions of pcsc-lite.
Conclusion
This is the second article in the FAQ "section". The first one was "FAQ: wintypes.h or winscard.h not found". I will try to provide other articles about common errors.
Friday, March 17, 2023
FAQ: wintypes.h or winscard.h not found
One of the most popular search requests that bring people on my website
https://pcsclite.apdu.fr/ is about
Problem
For example you try to compile something and get the error:
smartcard/scard/helpers.c:28:10: fatal error: winscard.h: No such file or directory
#include <winscard.h>
^~~~~~~~~~~~
Solution
The PC/SC header files (
- for Debian, Ubuntu or derivatives the package is pcsclite-dev
- for RedHat, Fedora and derivatives the package is pcsc-lite-devel
- for other Unixes, use your favourite search engine 😜
You install the correct package and you try again to build your software.
Conclusion
I hope this blog article will be correctly indexed by search engines to help people find the
solution.
Tuesday, November 29, 2022
PC/SC sample in TypeScript (Deno)
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.
pcsc-deno
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.
Deno
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
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.
Source code
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");
}
Output
$ 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!
Conclusion
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.
Wednesday, November 16, 2022
Share a smart card reader between a host and its guest VM(s)
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.
Problem
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.
Solution
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.
Setup
My demo setup:
- Host: Debian testing system
-
Guest: NetBSD 9.3 running inside
KVM (Kernel Virtual
Machine).
I use 2 very different operating systems, GNU/Linux and NetBSD, on purpose. It is to show it is possible to mix systems.
Host
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
Guest
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:
Limitations
pcsc-lite to pcsc-lite
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.
macOS or Windows host
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.
Conclusion
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?
Friday, October 28, 2022
Ubuntu 22.04 and pcscd auto start failure
Problem
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)
Fix
The fix is easy:
sudo systemctl enable pcscd.socket
And reboot.
No problem on Debian
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.
Conclusion
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.
Sunday, September 11, 2022
New version of pcsc-lite: 1.9.9
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.
Changes:
11 September 2022
-
SCardEstablishContext()may returnSCARD_W_SECURITY_VIOLATIONif refused by Polkit - Fix
SCardReleaseContext()failure on orphan handles - Fix
SCardDisconnect()on orphan handle -
pcsc-spy: log the
pioSendPci&pioRecvPciSCardTransmit()parameters - Improve the log from pcscd: log the return code in text instead of hex
- Some other minor improvements
Sunday, June 12, 2022
PCSC API spy, update
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.
Changes
-
The
pcsc-spy.py command has been renamedpcsc-spy (in 2012) -
The
libpcscspy.so library has been moved from/usr/lib/ to/usr/lib/x86_64-linux-gnu/ (for Intel 64-bits CPU systems) -
opensc-tool can't be used withLD_PRELOAD=any more
Demo
As before we have two cases for the use ofApplications linked with libpcsclite.so.1
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
Application loading libpcsclite.so.1
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
Redirection in a file
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
Remarks
Bugs found
I note that SCardReleaseContext() is not always called by
pcsc_scan before exit. I just fixed this problem in
pcsc-tools.
Install/uninstall
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.
Order of execution
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:
-
if the fifo file
~/pcsc-spy does not yet exist then pcsc-spy will display nothing -
if the fifo file
~/pcsc-spy already exists thenlibpcscspy.so will use it to send logs and will be blocked until something reads the file (pcsc-spyor thecatcommand to redirect the content)
Conclusion
I hope this update is useful.
if you have ideas to improve the logs please contact me.
Saturday, June 11, 2022
New version of pcsc-lite: 1.9.8
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.
Changes:
1.9.8: Ludovic Rousseau
11 June 2022
- Install
install_spy.sh &uninstall_spy.sh scripts in docdir SCardTransmit(): do not fail if receive buffer is "too large"SCardControl(): do not fail if receive buffer is "too large"- fix some memory leaks on shutdown
- use a better random number generator
- Some other minor improvements
Saturday, May 14, 2022
SCardListReaders() and non-initialized pcchReaders parameter
Sample C sample
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:
Makefile
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
Output
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 your friend
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.
SCardListReaders
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.
mszReadersis a pointer to a character string that is allocated by the application. If the application sendsmszGroupsandmszReadersas NULL then this function will return the size of the buffer needed to allocate inpcchReaders.If
*pcchReadersis 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;
Looking for problems
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).
GnuPG
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)".
WinSCard API
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.
Conclusion
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).
Friday, May 13, 2022
New version of pcsc-lite: 1.9.7
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.
Changes
1.9.7: Ludovic Rousseau
13 May 2022
- disable strict compilation by default
- fix 3 warnings
Issues with strict compilation
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.
Wednesday, May 11, 2022
New version of pcsc-lite: 1.9.6
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.
Changes:
1.9.6: Ludovic Rousseau11 May 2022
- do not fail reader removal in some specific cases (USB/Thunderbolt port)
- improve documentation regarding
/etc/reader.conf.d/ -
SCardGetStatusChange: speedup the case
DISABLE_AUTO_POWER_ON - configure:
-
add
--disable-strictoption
By default the compiler arguments are now:-Wall -Wextra -Wno-unused-parameter -Werror ${CFLAGS} - fail if flex is not found
- fix different data races
-
pcscdaemon: -v displays internal constants values:
MAX_READERNAME&PCSCLITE_MAX_READERS_CONTEXTS - Some other minor improvements
Reader removal issue
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:
- 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
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.
Thursday, April 14, 2022
PC/SC sample in Erlang
I use the PC/SC wrapper for Erlang: erlang-pcsc from Alex Wilson. The project description is "libpcsc NIF binding for erlang". The license is BSD 2 clause.
This is the same wrapper I used in the previous blog article "PC/SC sample in Elixir".
The wrapper is available on Hex.pm (The package manager for the Erlang ecosystem) at https://hex.pm/packages/pcsc.
API documentation is available at https://arekinath.github.io/erlang-pcsc/index.html
Create a new application
$ rebar3 new app blog
===> Writing blog/src/blog_app.erl
===> Writing blog/src/blog_sup.erl
===> Writing blog/src/blog.app.src
===> Writing blog/rebar.config
===> Writing blog/.gitignore
===> Writing blog/LICENSE
===> Writing blog/README.md
Install pcsc module
Edit the file
{deps, [pcsc]}.
{erl_opts, [{i, "_build/default/lib/pcsc/include/"}]}.
The erl_opts option is needed because we will include one header
file from the pcsc module. Maybe it is possible to have a less ugly/hardcoded
path.
Upgrade the dependencies:
$ rebar3 upgrade --all ===> Verifying dependencies... ===> Fetching pcsc v1.3.1 ===> Fetching rebar3_hex v7.0.1 ===> Fetching hex_core v0.8.4 ===> Fetching verl v1.1.1 ===> Analyzing applications... ===> Compiling verl ===> Compiling hex_core ===> Compiling rebar3_hex _build/default/plugins/rebar3_hex/src/rebar3_hex_organization.erl:391:5: Warning: public_key:ssh_encode/2 is deprecated and will be removed in OTP 26; use ssh_file:encode/2 instead ===> Fetching lager v3.9.2 ===> Fetching goldrush v0.1.9 ===> No upgrade needed for pcsc ===> No upgrade needed for lager ===> No upgrade needed for goldrush
Build the dependencies:
$ rebar3 compile ===> Verifying dependencies... make : on entre dans le répertoire « /home/rousseau/Documents/blog/erlang/_build/default/lib/pcsc/c_src » cc -Wall -g -O2 -Wextra -pipe -funsigned-char -fstrict-aliasing -Wchar-subscripts -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wunused -Wuninitialized -Wpointer-arith -Wredundant-decls -Winline -Wformat -Wformat-security -Wswitch-enum -Winit-self -Wmissing-include-dirs -Wempty-body -fdiagnostics-color=auto -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Wbad-function-cast -Wnested-externs -Wmissing-declarations -fPIC -I /usr/lib/erlang/erts-12.3.1/include/ -I /usr/lib/erlang/lib/erl_interface-5.2.2/include -pthread -I/usr/include/PCSC -c -o /home/rousseau/Documents/blog/erlang/_build/default/lib/pcsc/c_src/pcsc_nif.o /home/rousseau/Documents/blog/erlang/_build/default/lib/pcsc/c_src/pcsc_nif.c [...] cc /home/rousseau/Documents/blog/erlang/_build/default/lib/pcsc/c_src/pcsc_nif.o -shared -L /usr/lib/erlang/lib/erl_interface-5.2.2/lib -lei -lpcsclite -o /home/rousseau/Documents/blog/erlang/_build/default/lib/pcsc/c_src/../priv/pcsc_nif.so make : on quitte le répertoire « /home/rousseau/Documents/blog/erlang/_build/default/lib/pcsc/c_src » ===> Analyzing applications... ===> Compiling goldrush ===> Compiling lager ===> Compiling pcsc
===> Analyzing applications... ===> Compiling blog
Edit the file
It should look like:
[...]
{applications,
[kernel,
stdlib,
pcsc
]},
[...]
Sample code
Create the source code file
-module(blog).
-export([main/0]).
-include("iso7816.hrl").
main() ->
% get all the available readers
{ok, Readers} = pcsc_card_db:list_readers(),
% use the first reader
[Reader | _] = Readers,
io:fwrite("Using: ~s~n", [Reader]),
% connect
{ok, Card} = pcsc_card:start_link(Reader, shared, [t1, t0]),
% select applet
Aid = << 160, 0, 0, 0, 98, 3, 1, 12, 6, 1 >>,
Select_apdu = #apdu_cmd{cla = iso, ins = select, p1 = 4, p2 = 0, data = Aid},
{ok, Select_replies} = pcsc_card:command(Card, Select_apdu),
io:write(Select_replies),
io:fwrite("~n"),
% command
Command_apdu = #apdu_cmd{ cla = iso, ins = 0, p1 = 0, p2 = 0 },
{ok, Command_replies} = pcsc_card:command(Card, Command_apdu),
io:write(Command_replies),
io:fwrite("~n"),
% extract the answer
[Reply | _] = Command_replies,
case Reply of
{apdu_reply, _, ok, Msg} ->
io:write(binary_to_atom(Msg)),
io:fwrite("~n");
{apdu_reply, _, error, _} ->
io:fwrite("Error~n")
end.
Output
Generating a standalone Erlang application looks complex. But you can test your code using the interactive shell.
$ rebar3 shell ===> Verifying dependencies... ===> Analyzing applications... ===> Compiling blog Erlang/OTP 24 [erts-12.3.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit] Eshell V12.3.1 (abort with ^G) ===> Booted syntax_tools ===> Booted compiler ===> Booted goldrush ===> Booted lager ===> Booted pcsc ===> Booted blog 1> blog:main(). Using: Gemalto PC Twin Reader 00 00 [{apdu_reply,t1,ok,none}] [{apdu_reply,t1,ok,<<72,101,108,108,111,32,119,111,114,108,100,33>>}] 'Hello world!' ok 2>
Comments
ehecatl
An older github project also exist at
https://github.com/zgbjgg/ehecatl
Its description is "An erlang library for read/write nfc smart cards".
I filed 2 issues in 2020: Missing <PCSC/winscard.h>? and More complete PC/SC wrapper? but got no answer.
This project has not seen any commit since 2014.
So I guess this project is dead.
erlang-pcsc
The only problem I have with erlang-pcsc is that, if no smart card reader is connected, I get:
$ rebar3 shell
===> Verifying dependencies...
===> Analyzing applications...
===> Compiling blog
Erlang/OTP 24 [erts-12.3.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit]
Eshell V12.3.1 (abort with ^G)
1> ===> Booted syntax_tools
===> Booted compiler
===> Booted goldrush
===> Booted lager
===> Booted pcsc
===> Booted blog
23:31:49.563 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.622 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.677 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.729 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.782 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.836 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.889 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.941 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.992 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:50.044 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
etc...
The error -2146435026 is SCARD_E_NO_READERS_AVAILABLE and is not really an error for SCardListReaders().
I filed a github issue [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok #4 but with no answer so far.
Conclusion
Thanks Alex for the Erlang PC/SC wrapper. And thanks tofferoma, from the elixir forum, for your help in writing the Erlang sample code.
If you work on a Free Software PC/SC wrapper that is not yet in my list please let me know.
Wednesday, April 13, 2022
PC/SC sample in Elixir
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 Elixir.
Elixir uses the Erlang virtual machine: BEAM. I wanted to start with an example in Erlang but Erlang is more complex (for me) so I have not yet a working sample code in Erlang.
I use the PC/SC wrapper for Erlang: erlang-pcsc from Alex Wilson. The project description is "libpcsc NIF binding for erlang". The license is BSD 2 clause.
The wrapper is available on Hex.pm (The package manager for the Erlang ecosystem) at https://hex.pm/packages/pcsc.
API documentation is available at
https://arekinath.github.io/erlang-pcsc/index.html
Elixir sample project
Create a new Elixir project using mix new ...
$ mix new blog
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/blog.ex
* creating test
* creating test/test_helper.exs
* creating test/blog_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd blog
mix test
Run "mix help" for more commands.
Edit the file
[...]
defp deps do
[
{:pcsc, "~> 1.3"},
]
end
[...]
Install the dependency using mix deps.get
$ mix deps.get Resolving Hex dependencies... Dependency resolution completed: New: goldrush 0.1.9 lager 3.9.2 pcsc 1.3.1 * Getting pcsc (Hex package) * Getting lager (Hex package) * Getting goldrush (Hex package)
Source code
Now we create a file
# list card readers
{:ok, readers} = :pcsc_card_db.list_readers()
# use the fist reader
[reader | _] = readers
IO.puts("Using reader: " <> reader)
# connect to the card
{:ok, card} = :pcsc_card.start_link(reader, :shared, [:t1, :t0])
aid = << 160, 0, 0, 0, 98, 3, 1, 12, 6, 1 >>
select_apdu = {:apdu_cmd, :default, :iso, :select, 4, 0, aid, :none}
# send select APDU
{:ok, replies} = :pcsc_card.command(card, select_apdu)
IO.inspect replies
# send command APDU
command_apdu = {:apdu_cmd, :default, :iso, 0, 0, 0, :none, :none}
{:ok, replies} = :pcsc_card.command(card, command_apdu)
IO.inspect replies
# get the first reply only
[reply | _] = replies
case reply do
{:apdu_reply, _, :ok, msg} -> IO.puts(msg)
{:apdu_reply, _, :error, _} -> IO.puts("Failed")
end
Output
You can now build and run the code using mix run ...
The first time you run mix run the pcsc wrapper will be built
automatically. After that you only get the build & execution of the sample code.
$ mix run blog.exs
17:40:50.239 [error] calling logger:remove_handler(default) failed: :error {:badmatch, {:error, {:not_found, :default}}}
17:40:50.273 [info] Application lager started on node nonode@nohost
17:40:50.280 [info] Application pcsc started on node nonode@nohost
17:40:50.281 [info] Application blog started on node nonode@nohost
Using reader: Gemalto PC Twin Reader 00 00
[{:apdu_reply, :t1, :ok, :none}]
[{:apdu_reply, :t1, :ok, "Hello world!"}]
Hello world!
Remarks
I do not have any complaints for the Erlang PC/SC wrapper. It built fine on the first try. Nice work Alex.
As always my sample code is very minimal with no error handling. It is just a short sample.
Thanks to Stéphane Bortzmeyer for his Elixir training. That gave me the idea to try Elixir.
A big thank to tofferoma for his help on the Elixir forum on "How to access PCSC card readers via erlang/elixir?".
Conclusion
If you work on a Free Software PC/SC wrapper that is not yet in my list please let me know.
Thursday, February 17, 2022
One smart card reader accessible from many computers
In 2010 I wrote the article "PC/SC client and server on two different hosts". At that time OpenSSH was not able to redirect Unix sockets.
I just received a request to (re)do something similar. Of course, I forgot I wrote this article 12 years ago. So I started searching for a solution, again.
Since OpenSSH 6.7 (released in 2014) it is possible to redirect Unix sockets over the network.
Setup
The normal pcsc-lite use case is described in the figure bellow:
The goal is to have 2 computers connected by a network and transfer the pcsc-lite internal connection over the network as described bellow:
Server
On computer1 you have your smart card reader(s) connected and pcscd will run
as usual. You do not need to change your pcsc-lite configuration.
A user on computer1 is able to connect to computer2 using ssh and run something like:
$ ssh -N -R/tmp/pcscd.comm:/run/pcscd/pcscd.comm computer2
Note that the socket on computer2 is
Otherwise I get the error:
Warning: remote port forwarding failed for listen path /run/pcscd/pcscd.comm
So I create the socket on computer2 in
Client
On computer2 you define the pcsc-lite socket path to use.
$ export PCSCLITE_CSOCK_NAME=/tmp/pcscd.comm
And you can run your PC/SC application as usual.
Connection in the other direction
It is also possible to do the SSH connection from the client to the server. On the client you do something like
$ ssh -N -L/tmp/pcscd.comm:/run/pcscd/pcscd.comm computer1
It may be easier this way if the client is light terminal and does not have an
ssh server running for example.
Socket access rights
The socket
$ ls -l /tmp/pcscd.comm srw------- 1 rousseau rousseau 0 17 févr. 12:07 /tmp/pcscd.comm
As you can see the access rights are limited to read & write for "rousseau" and no access for the other users. You may want to share the remote connection to other users in the client computer. You can do something like:
$ chmod a+rw /tmp/pcscd.comm
The administrator of the system is free to configure the access rights to
use.
Cleanup
When you stop the ssh execution, the socket
So if you run ssh again you will get the error:
$ ssh -N -R/tmp/pcscd.comm:/run/pcscd/pcscd.comm computer2 Warning: remote port forwarding failed for listen path /tmp/pcscd.comm
or (if the connection is used in the other direction):
$ ssh -N -L/tmp/pcscd.comm:/run/pcscd/pcscd.comm computer1 unix_listener: cannot bind to path /tmp/pcscd.comm: Address already in use Could not request local forwarding.
One card, multiple computers
The same smart card can also be accessed from different computers. The ssh redirection is not limited to one computer. You can have 1 server and 10 clients all connected to the same server so connected to the same smart card reader(s).
The pcsc-lite daemon pcscd will still play his role of resource manager. So if the applications are correctly written with PC/SC transactions to get exclusive access to the card, no problem is expected. i.e. no more problems than if the 3 applications were all running locally in computer1.
Multi-architecture support
It is possible to run the server on one CPU architecture and run clients on a different CPU architecture.
I tried running the server on a x86-64 CPU (Intel PC) and the client on a
ARM-32 CPU (Raspberry Pi 3 using armv7l). It works like a charm.
Conclusion
This architecture is a generalisation of accessing the pcscd server from the host and also from guests in virtual environments (described in "Accessing smart cards from inside a flatpak sandbox") but, this time, with remote computers.
I am sure people will find many original use cases for an architecture like
this. Please tell me if and how you use it.
Monday, February 14, 2022
Fedora, flatpak and pcsc-lite
The bug "Unable to list readers inside flatpak, when pcscd runs on host." was very strange. It is not like the potential problem I described in "Accessing smart cards from inside a flatpak sandbox" where we have 2 sides (host & flatpak container) using different versions of the pcsc-lite internal protocol.
In the present case both sides are using the same protocol but SCardGetStatusChange() fails with a very strange error: Unknown error: 0x53204253. 0x53204253 is not a (valid) error code returned by any of the PC/SC functions.
Fedora custom build
After some debug I discovered that Fedora provides pcsc-lite packages with a modification.
From
https://fedora.pkgs.org/35/fedora-updates-x86_64/pcsc-lite-libs-1.9.5-1.fc35.x86_64.rpm.html
your can download the
source package
which contains the patch file
diff -up ./src/PCSC/pcsclite.h.in.readers_32 ./src/PCSC/pcsclite.h.in --- ./src/PCSC/pcsclite.h.in.readers_32 2018-08-20 16:02:17.708302410 -0700 +++ ./src/PCSC/pcsclite.h.in 2018-08-20 16:02:49.462500967 -0700 @@ -281,7 +281,7 @@ extern const SCARD_IO_REQUEST g_rgSCardT #define PCSCLITE_VERSION_NUMBER "@VERSION@" /**< Current version */ /** Maximum readers context (a slot is count as a reader) */ -#define PCSCLITE_MAX_READERS_CONTEXTS 16 +#define PCSCLITE_MAX_READERS_CONTEXTS 48 #define MAX_READERNAME 128 diff -up ./src/PCSC/pcsclite.h.readers_32 ./src/PCSC/pcsclite.h --- ./src/PCSC/pcsclite.h.readers_32 2018-08-20 16:02:30.993385481 -0700 +++ ./src/PCSC/pcsclite.h 2018-08-20 16:03:00.061567242 -0700 @@ -281,7 +281,7 @@ extern const SCARD_IO_REQUEST g_rgSCardT #define PCSCLITE_VERSION_NUMBER "1.9.5" /**< Current version */ /** Maximum readers context (a slot is count as a reader) */ -#define PCSCLITE_MAX_READERS_CONTEXTS 16 +#define PCSCLITE_MAX_READERS_CONTEXTS 48 #define MAX_READERNAME 128
This patch redefines PCSCLITE_MAX_READERS_CONTEXTS which is the
maximum number of readers supported by pcsc-lite and update the value from 16
to 48.
pcsc-lite internal protocol
To implement the function SCardGetStatusChange() pcsc-lite exchanges the list of readers between the daemon (pcscd) and the client (libpcsclite.so.1).
pcscd will sent a list of PCSCLITE_MAX_READERS_CONTEXTS readers
and libpcsclite.so.1 is expecting a list of
PCSCLITE_MAX_READERS_CONTEXTS readers.
Flatpak issue
In the case of flatpak the server is running on the host and is provided by Fedora, and the client is running inside the flatpak container and is provided by whoever provides the flatpak so possibly with a pcsc-lite client not from Fedora.
And now we have a problem: the daemon is sending a list of 48 readers while the client is expecting a list of only 16 readers. After that, many bad things can happen, like incorrect return values.
Flatpak solution
The solution is simple: include in the flatpak container a client library that is configured like the server on your host i.e. patch the pcsc-lite included in the container.
The bad news is that the flatpak contained application will not be universal
any-more. You will need 2 different containers for Fedora and for Debian for
example.
pcsc-lite-ccid patch
The pcsc-lite-ccid Fedora package (CCID reader driver) also uses a patch to increase the number of supported readers.
The package source code is available at
https://fedora.pkgs.org/35/fedora-updates-x86_64/pcsc-lite-ccid-1.4.36-2.fc35.x86_64.rpm.html
and contains the file
diff -up ./src/ccid_ifdhandler.h.readers_32 ./src/ccid_ifdhandler.h --- ./src/ccid_ifdhandler.h.readers_32 2018-08-20 16:06:34.080905748 -0700 +++ ./src/ccid_ifdhandler.h 2018-08-20 16:07:04.638097096 -0700 @@ -47,7 +47,7 @@ extern int DriverOptions; * The maximum number of readers is also limited in pcsc-lite (16 by default) * see the definition of PCSCLITE_MAX_READERS_CONTEXTS in src/PCSC/pcsclite.h */ -#define CCID_DRIVER_MAX_READERS 16 +#define CCID_DRIVER_MAX_READERS 48 /* * CCID driver specific functions
According to the spec file
* Fri Jun 25 2021 Jakub Jelen <jjelen@redhat.com> - 1.4.34-2 - Add support for more readers
So less than a year.
Increase the number of readers?
I guess Fedora/RedHat has one (or more) customer(s) with a need to support
more than 16 readers. Maybe that is the case of 0.01% of pcsc-lite users
(rough estimation out of my mind). And for some users 48 readers will not be
enough (See "A reader for 96 smart cards? sysmoSIMBANK").
A long term solution is to move from a hard coded limit of
CCID_DRIVER_MAX_READERS readers to a dynamic (unlimited) list. This is already
planed for pcsc-lite in "use a list instead of a fixed size array for 16 reader states" and for ccid in "use a list instead of a fixed size array for 16 reader states". I had no motivation to implement that so far. If you need this change
please contact me.
Revert the Fedora patches?
One option to solve the issue with Flatpak would be for Fedora/RedHat to revert the patches.
I don't know if they have more customers using more than 16 smart card readers, or more customers using Flatpak applications.
Conclusion
Flatpak applications with a need to access smart cards or tokens (Chrome, Teams) may be difficult to use on Fedora/RedHat.
Friday, February 11, 2022
Accessing smart cards from inside a flatpak sandbox
I received a bug report about "Unable to list readers inside flatpak, when pcscd runs on host." complaining that a smart card reader is not accessible from inside a flatpak sandbox.
I then discovered many other flatpak issues regarding smart cards access in https://github.com/flathub:
- Flatpak Apps and SmartCard or Security Device
- Smart Card Support
- Flatpak support for smart cards (yubikey)
- Help with Smartcards
- opensc support
- Teams cannot access my PIV card to login
I never used flatpak so I start by trying to reproduce the problem.
Environment
- GNU/Linux Debian testing
- flatpak 1.12.4-1
- pcscd 1.9.5-1
Simple test
The idea is to run
Since the daemon (
The important part for that is:
finish-args: - --socket=pcsc
Sources
File
app-id: fr.apdu.pcsc_scan
runtime: org.freedesktop.Platform
runtime-version: '21.08'
sdk: org.freedesktop.Sdk
command: pcsc_scan.sh
finish-args:
- --socket=pcsc
modules:
- name: pcsc-lite
config-opts:
- --disable-libudev
- --disable-libsystemd
- --without-systemdsystemunitdir
- --disable-serial
- --disable-usb
- --disable-documentation
cleanup:
- '/include'
- '/bin/pcsc-spy'
- '/lib/libpcscspy*'
- '/lib/pkg-config'
- '/share/doc'
- '/share/man'
post-install:
- rm /app/sbin/pcscd
- rmdir /app/sbin || true
sources:
- type: archive
url: https://pcsclite.apdu.fr/files/pcsc-lite-1.9.5.tar.bz2
sha256: 9ee3f9b333537562177893559ad4f7b8d5c23ebe828eef53056c02db14049d08
- name: pcsc-tools
cleanup:
- '/bin/gscriptor'
- '/bin/scriptor'
- '/bin/ATR_analysis'
- '/share/pcsc'
- '/share/man'
sources:
- type: archive
url: http://ludovic.rousseau.free.fr/softwares/pcsc-tools/pcsc-tools-1.6.0.tar.bz2
sha256: 651c8dd74bcb33db4c16935ce5d80dd1aa6eb20ba9d5c4b9631a098326ef8b9f
- name: pcsc_scan.sh
buildsystem: simple
build-commands:
- install -D pcsc_scan.sh /app/bin/pcsc_scan.sh
sources:
- type: file
path: pcsc_scan.sh
File
By default -n argument to disable
the use of
#!/bin/sh pcsc_scan -n
Generation
$ flatpak-builder --user --install build-dir fr.apdu.pcsc_scan.yml [...]
Execution
$ flatpak run fr.apdu.pcsc_scan Using reader plug'n play mechanism Scanning present readers... 0: Gemalto PC Twin Reader 00 00 Fri Feb 11 17:55:17 2022 Reader 0: Gemalto PC Twin Reader 00 00 Event number: 6 Card state: Card inserted, Shared Mode, ATR: 3B A7 00 40 18 80 65 A2 08 01 01 52
It works fine. Youpi!
Limitations
You need to use the same protocol version for the pcsc-lite daemon and the pcsc-lite client.
If not then pcscd will complain with something like:
Journalctl : Jan 16 16:24:42 nuc01.lan pcscd[2066]: 99999999 winscard_svc.c:383:ContextThread() Client protocol is 4:4 Jan 16 16:24:42 nuc01.lan pcscd[2066]: 00000040 winscard_svc.c:385:ContextThread() Server protocol is 4:3
The protocol version major & minor is defined in winscard_msg.h.
Protocol history
- 4.4 since pcsc-lite 1.8.24, Oct 2018
- 4.3 since pcsc-lite 1.8.9, Oct 2013
- 4.2 since pcsc-lite 1.6.5, Dec 2010
- 4.1 since pcsc-lite 1.6.5, Dec 2010
- 4.0 since pcsc-lite 1.6.0, May 2010
So if the server side is older than 1.8.24 (Oct 2018) and the client side is newer you have a problem.
For example Ubuntu 18.04 LTS provides pcscd 1.8.23-1. This can be problematic.
Reproducing the problem
To check that I modified the file
The build is successful but the execution fails with:
$ flatpak run fr.apdu.pcsc_scan SCardEstablishContext: Service was stopped.
And in the logs on the host I see:
$ journalctl --unit=pcscd [...] févr. 11 18:55:07 debian pcscd[3715]: 00000006 winscard_svc.c:361:ContextThread() Received command: CMD_VERSION from client 8 févr. 11 18:55:07 debian pcscd[3715]: 00000004 winscard_svc.c:373:ContextThread() Client is protocol version 4:3 févr. 11 18:55:07 debian pcscd[3715]: 00000001 winscard_svc.c:382:ContextThread() Communication protocol mismatch! févr. 11 18:55:07 debian pcscd[3715]: 00000002 winscard_svc.c:384:ContextThread() Client protocol is 4:3 févr. 11 18:55:07 debian pcscd[3715]: 00000001 winscard_svc.c:386:ContextThread() Server protocol is 4:4 févr. 11 18:55:07 debian pcscd[3715]: 00000002 winscard_svc.c:396:ContextThread() CMD_VERSION rv=0x8010001E for client 8
Here the server is using version 4.4 but the client is using version 4.3.
The error code 0x8010001E is SCARD_E_SERVICE_STOPPED.
Solution
The solution is simple: use the same protocol version on both sides.
If your host is using an old pcsc-lite using the internal protocol 4.3 then include an old (between 1.8.9 and 1.8.23) pcsc-lite in your flatpak image.
I know this is not perfect. It is then not possible to provide an application in one flatpak and deploy it everywhere and anywhere.
Conclusion
The protocol between the daemon and the client is internal to pcsc-lite. It has not been designed to be interoperable with something else, including older versions of pcsc-lite itself.
pcsc-lite is free software. So you are free to install whatever version you want.
