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.