Wednesday, September 28, 2022

PySCard 2.0.5 released

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.


Changes:

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:

1.9.9: Ludovic Rousseau
11 September 2022
  • SCardEstablishContext() may return SCARD_W_SECURITY_VIOLATION if refused by Polkit
  • Fix SCardReleaseContext() failure on orphan handles
  • Fix SCardDisconnect() on orphan handle
  • pcsc-spy: log the pioSendPci & pioRecvPci SCardTransmit() parameters
  • Improve the log from pcscd: log the return code in text instead of hex
  • Some other minor improvements

Sunday, September 4, 2022

New PyKCS11 1.5.11 available

I just released a new version of PyKCS11, a Python wrapper above the PKCS#11 API.
See "PyKCS11 introduction" or "PyKCS11’s documentation".

The project is registered at Pypi: https://pypi.org/project/PyKCS11/
 

Changes:

1.5.11 - September 2022, Ludovic Rousseau

  • add deriveKey() with CKM_ECDH1_DERIVE and CK_ECDH1_DERIVE_PARAMS
  • support pSourceData in OAEP params
  • remove use of (deprecated) distutils
  • samples: port to Python 3
  • fix code coverage generation

Sunday, August 28, 2022

PySCard 2.0.4 released

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

Changes:

2.0.4 (August 2022)
  • Fix a problem on PCSCCardConnection.disconnect
  • Add support of BaseSCardException(hresult) format
  • Do not use deprecated distutils anymore


Tuesday, July 5, 2022

CCID Windows 10 driver?

Just 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:


Conclusion

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? :-)

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 renamed pcsc-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 with LD_PRELOAD= any more

Demo

As before we have two cases for the use of libpcsclite.so.1.

Applications linked with libpcsclite.so.1

This is the case of the pcsc_scan command for example.

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 libpcsclite.so.1 library. This is done by 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 ldconfig (configure dynamic linker run-time bindings) administration command. ldconfig is used, for example, during the installation of a package.

If you run uninstall_spy.sh after an execution of ldconfig you may get a broken libpcsclite installation with an error like:

$ 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:

  1. if the fifo file ~/pcsc-spy does not yet exist then pcsc-spy will display nothing
  2. if the fifo file ~/pcsc-spy already exists then libpcscspy.so will use it to send logs and will be blocked until something reads the file (pcsc-spy or the cat command 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

Friday, May 20, 2022

ATR parsing in JSON

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. 


JSON

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.

Examples

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)"

 

Card matching

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


Conclusion

If you have ideas how to improve the service just tell me.

Saturday, May 14, 2022

SCardListReaders() and non-initialized pcchReaders parameter

Sample C sample

We start with the following sample.c program:

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.

mszReaders is a pointer to a character string that is allocated by the application. If the application sends mszGroups and mszReaders as NULL then this function will return the size of the buffer needed to allocate in pcchReaders.

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;

 

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 Rousseau
11 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-strict option
      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.

    It looks like the problem occurred with a USB-C + Thunderbolt port and was reported in "pcscd fails to read future yubikeys after removing a yubikey, until restarted #125" and "Yubikey 5c Reader "stuck" #57".

    Wednesday, April 27, 2022

    30 shades of PC/SC

    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:

    1. Ada
    2. C
    3. C#
    4. C for UEFI
    5. Common Lisp
    6. Elixir
    7. Erlang
    8. Flutter/Dart
    9. Free Pascal (Lazarus)
    10. go
    11. Java
    12. JavaScript (Node.js)
    13. Java using intarsys smartcard-io
    14. Kotlin
    15. lua
    16. Objective-C (synchronous)
    17. Objective-C (using Crypto Token Kit)
    18. OCaml
    19. Perl
    20. PHP5
    21. PHP (dead upstream as 11 January 2015)
    22. Prolog
    23. Python
    24. Python (using python-pcsclite)
    25. Ruby
    26. Rust
    27. Scala
    28. scriptor
    29. Smart Card Connector on Chromebook
    30. Swift (using Crypto Token Kit)

    Top Computer Languages

    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


    Comments

    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.

    Not listed

    Some programming languages are not listed in the TIOBE index but do provide a PC/SC wrapper:

    • Elixir
    • Erlang
    • OCaml

    Windows technologies

    Some languages are specific to the Microsoft Windows system. I can't use them since I do not use Windows. They are:

    • Visual Basic
    • Classic Visual Basic
    • VBScript
    • Visual FoxPro.

    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.

    Language I would be surprised to get PC/SC support

    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 .

    Languages that could have a PC/SC wrapper

    What I had not yet found

    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.

    Conclusion

    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.

    Thursday, April 14, 2022

    PC/SC sample in Erlang

    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 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 rebar.config to use:

    {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 src/blog.app.src to declare the pcsc application.

    It should look like:

    [...]
      {applications,
       [kernel,
        stdlib,
        pcsc
       ]},
    [...]

    Sample code

    Create the source code file src/blog.erl with the content:

    -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 mix.exs and add the pcsc dependency. You should have something like:

    [...]
      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 blog.exs that contains (sorry, source-highlight does not provide syntax colorization for Elixir):

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

    Friday, March 18, 2022

    PySCard 2.0.3 released

    I just released a new version 2.0.3 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.

    Changes:

    • PCSCExceptions: include error code in the message
    • getReaderNames(): fix Windows 10 issue when the last reader is disconnected

    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 /tmp/pcscd.comm and not /run/pcscd/pcscd.comm as on computer1. That is because of access rights restriction. Only root is allowed to create files in /run/pcscd/.

    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 /tmp/ instead.

    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 /tmp/pcscd.comm is created as the user running the ssh command. For example in my case it is created as user "rousseau".

    $ 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 /tmp/pcscd.comm created on the client side is not removed.

    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.

    The internal pcsc-lite protocol is not sensible to 32 or 64-bits CPU differences. I have not tested a mix with big-endian and little-endian CPUs. I do not have a computer using a big-endian CPU. I am pretty sure that configuration would fail.

    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 pcsc-lite-1.9.1-maxreaders.patch.

    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 ccid-1.4.34-maxreaders.patch

    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 pcsc-lite-ccid.spec this changes dates from June 2021:

    * 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:

    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 pcsc_scan from a flatpak sandbox using the pcscd daemon on the host. This is possible since the flatpak patch "Add support for PCSC socket".

    Since the daemon (pcscd) and the client library (libpcsclite.so.1) use a socket (/run/pcscd/pcscd.comm by default) to communicate we just have to export the socket in the sandbox to allow the communication.

    The important part for that is:

    finish-args:
      - --socket=pcsc

    Sources

    File fr.apdu.pcsc_scan.yml

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

    By default pscs_scan calls ATR_analysis which is a Perl script. I do not want to include Perl in my sandbox so I create a wrapper to call pcsc_scan with the -n argument to disable the use of ATR_analysis.

    #!/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 fr.apdu.pcsc_scan.yml to build pcsc-lite 1.8.23 instead of the latest version 1.9.5.

    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.