GnuPG and PC/SC conflicts, episode 3
After GnuPG and PC/SC conflicts and GnuPG and PC/SC conflicts, episode 2 we now have a 3rd episode.
Executive summary
Your file ~/.gnupg/scdaemon.conf
should contain:
PC/SC access sharing
More and more applications are using smart cards. So they all need to behave cooperatively to share the access to the card.
PC/SC provides a way to connect to a smart card and get an exclusive
access to it. That is the parameter dwShareMode
of SCardConnect(). It
can take 3 values:
SCARD_SHARE_SHARED
- This application will allow others to share the reader.SCARD_SHARE_EXCLUSIVE
- This application will NOT allow others to share the reader.SCARD_SHARE_DIRECT
- Direct control of the reader, even without a card.SCARD_SHARE_DIRECT
can be used before using SCardControl() to send control commands to the reader even if a card is not present in the reader. Contrary to Windows winscard behavior, the reader is accessed in shared mode and not exclusive mode.
If you use SCARD_SHARE_EXCLUSIVE
then no other application can use the
reader, and the card inserted in the reader, until the application calls
SCardDisconnect().
If you try to use SCARD_SHARE_EXCLUSIVE
while another application already
has a connection to the reader then your own call fails with
SCARD_E_SHARING_VIOLATION
. Only one application can connect to the
reader when SCARD_SHARE_EXCLUSIVE
is used.
Problem with GnuPG
A user reported an issue on PC/SC because he was not able to use GnuPG2 in Yubikey 5 with gpg2 only initialized properly after restarting pcscd #215.
He gets the output:
$ gpg2 --card-status gpg: selecting card failed: No such device gpg: OpenPGP card not available: No such device
I tried to reproduce the problem and log the GnuPG PC/SC calls as
described in PCSC API spy using LIBPCSCLITE_DELEGATE.
Unfortunately the environment variable LIBPCSCLITE_DELEGATE
is
ignored by scdaemon (GnuPG program used to access the smart card). I
guess that is because scdaemon sanitizes its environment to limit
attacks.
I had to slightly modify pcsc-lite to force the use of the spying library:
diff --git a/src/libredirect.c b/src/libredirect.c index ac023f4..e40d7f6 100644 --- a/src/libredirect.c +++ b/src/libredirect.c @@ -127,7 +127,7 @@ static void log_line(const char *fmt, ...) static LONG load_lib(void) { -#define LIBPCSC "libpcsclite_real.so.1" +#define LIBPCSC "libpcscspy.so.0" const char *lib;
From the PC/SC calls the problem is obvious:
SCardEstablishContext i dwScope: SCARD_SCOPE_SYSTEM (0x00000002) o hContext: 0x43293756 => SCARD_S_SUCCESS [0x00000000] [0.010792] SCardListReaders i hContext: 0x43293756 i mszGroups: (null) o pcchReaders: 0x0000001A o mszReaders: NULL => SCARD_S_SUCCESS [0x00000000] [0.000161] SCardListReaders i hContext: 0x43293756 i mszGroups: (null) o pcchReaders: 0x0000001A o mszReaders: Alcor Micro AU9540 00 00 o mszReaders: => SCARD_S_SUCCESS [0x00000000] [0.000287] SCardConnect i hContext: 0x43293756 i szReader Alcor Micro AU9540 00 00 i dwShareMode: SCARD_SHARE_EXCLUSIVE (0x00000001) i dwPreferredProtocols: 0x00000003 (T=0, T=1) i phCard 0x00000000 (0) i pdwActiveProtocol 0x00000000 (0) o phCard 0x00000000 (0) o dwActiveProtocol: T=1 (0x00000002) => SCARD_E_SHARING_VIOLATION [0x8010000B] [0.007124] SCardReleaseContext i hContext: 0x43293756 => SCARD_S_SUCCESS [0x00000000] [0.000101]
The call to SCardConnect()
fails with SCARD_E_SHARING_VIOLATION
.
Werner Koch (GnuPG author & maintainer) added a comment in the issue:
I then modified my ~/.gnupg/scdaemon.conf
file to contain:
And it now works better:
SCardEstablishContext i dwScope: SCARD_SCOPE_SYSTEM (0x00000002) o hContext: 0x4EFB8700 => SCARD_S_SUCCESS [0x00000000] [0.011911] SCardListReaders i hContext: 0x4EFB8700 i mszGroups: (null) o pcchReaders: 0x0000001A o mszReaders: NULL => SCARD_S_SUCCESS [0x00000000] [0.000177] SCardListReaders i hContext: 0x4EFB8700 i mszGroups: (null) o pcchReaders: 0x0000001A o mszReaders: Alcor Micro AU9540 00 00 o mszReaders: => SCARD_S_SUCCESS [0x00000000] [0.000162] SCardConnect i hContext: 0x4EFB8700 i szReader Alcor Micro AU9540 00 00 i dwShareMode: SCARD_SHARE_SHARED (0x00000002) i dwPreferredProtocols: 0x00000003 (T=0, T=1) i phCard 0x00000000 (0) i pdwActiveProtocol 0x00000000 (0) o phCard 0x1EF6C421 (519488545) o dwActiveProtocol: T=1 (0x00000002) => SCARD_S_SUCCESS [0x00000000] [0.009658] SCarControl i hCard: 0x1EF6C421 i dwControlCode: CM_IOCTL_GET_FEATURE_REQUEST (0x42000D48) i bSendLength 0x00000000 (0) i bSendBuffer i NULL o bRecvLength 0x00000006 (6) o bRecvBuffer o 0000 12 04 42 33 00 12 ..B3.. => SCARD_S_SUCCESS [0x00000000] [0.000267] parsing CM_IOCTL_GET_FEATURE_REQUEST results: Tag FEATURE_GET_TLV_PROPERTIES is 0x42330012 [...]
The call to SCardConnect()
now works ang GnuPG continues with
SCarControl()
, etc.
GnuPG history
The GnuPG code uses PCSC_SHARE_EXCLUSIVE
since the first version supporting
PC/SC in commit 1bcf8ef9dea1a9b171c27ef48cadb79df6201e33.
Author: Werner Koch <wk@gnupg.org> Date: Tue Aug 5 17:11:04 2003 +0000 Cleanups, fixes and PC/SC support + err = pcsc_connect (reader_table[slot].pcsc.context, + portstr? portstr : list, + PCSC_SHARE_EXCLUSIVE, + PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1, + &reader_table[slot].pcsc.card, + &reader_table[slot].pcsc.protocol);
The option to use PCSC_SHARE_SHARED
was introduced in 2021 with
commit 5732e7a8e97cebf8e850c472e644e2a9b040836f.
Author: Werner Koch <wk@gnupg.org> Date: Fri Mar 12 09:21:57 2021 +0100 scd: New option --pcsc-shared. * scd/scdaemon.h (opt): Add field opcsc_shared. * scd/scdaemon.c (opcscShared): New. (opts): Add "--pcsc-shared". (main): Set flag. * scd/apdu.c (connect_pcsc_card): Use it. (pcsc_get_status): Take flag in account. * scd/app-openpgp.c (cache_pin): Bypass in shared mode. (verify_chv2: Do not auto verify chv1 in shared mode. * scd/app-piv.c (cache_pin): By pass caceh in shared mode. -- This option should in general not be used. The patch tries to limit bad effects but using shared mode is somewhat dangerous depending on the other PC/SC users. err = pcsc_connect (pcsc.context, reader_table[slot].rdrname, - PCSC_SHARE_EXCLUSIVE, + opt.pcsc_shared? PCSC_SHARE_SHARED:PCSC_SHARE_EXCLUSIVE, PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1, &reader_table[slot].pcsc.card, &reader_table[slot].pcsc.protocol);
Temporary exclusive access
It is possible to get an exclusive access to a card but still share the reader with other applications.
The idea is to request an exclusive access for a short time, only when needed, using PC/SC transactions.
- SCardBeginTransaction()
Establishes a temporary exclusive access mode for doing a series of commands in a transaction.
You might want to use this when you are selecting a few files and then writing a large file so you can make sure that another application will not change the current file. If another application has a lock on this reader or this application is in SCARD_SHARE_EXCLUSIVE the function will block until it can continue.
- SCardEndTransaction()
Ends a previously begun transaction.
The calling application must be the owner of the previously begun transaction or an error will occur.
The application connects to the reader using SCARD_SHARE_SHARED
. And
then uses SCardBeginTransaction()/SCardEndTransaction()
to send a list of APDU without any interruption. Typically the
application does something like:
start a transaction
submit the user PIN code
perform a protected operation like signing
invalidate the user PIN code
end the transaction
With this algorithm another application cannot inject a command between steps 1 and 5 and benefit from the verified user PIN.
GnuPG and transactions
I had a look at the GnuPG source code and no PC/SC transaction is ever used.
Conclusion
Using an exclusive access at SCardConnect()
is problematic in a multi
applications system.
Use PC/SC transactions instead.
April 2025: Update
You can also find other sources of information
SmartCard stopped working in 2.4 on GnuPG bug tracker
gnupg: fails to interact with HSM after upgrade from 2.2.46 on Debian bug tracker
Yubikey stopped working after noble upgrade on Ubuntu bug tracker
Smartcards on archinux wiki
Resolving GPG's CCID conflicts on yubico support web site