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

Monday, December 17, 2018

macOS Mojave and smart card source code

Apple released the source code of the open source components they use in Mojave (macOS 10.14, released in September 2018). The components are available at macOS X 10.14 Source.


Many smart card components are now closed source and maintained by Apple for its different OSes. I can cite:

CCID driver

Apple provides my Free Software CCID driver. The source code from Apple is available at:
Version 55017 corresponds to CCID version 1.4.27 and was already present in macOS High Sierra as noted in "macOS High Sierra and smart cards status".

    Tokend

    Apple still provides "support" of the tokend technology even if it is deprecated since OS X Lion (2011). The source code is provided at:
    The version 55111 has not changed since macOS Sierra. see "macOS Sierra and smart card source code".

    Conclusion

    No change in the free software component binaries so also no change in the corresponding component source codes.

    Wednesday, December 12, 2018

    New version of pcsc-tools: 1.5.4

    I just released a new version of pcsc-tools, a suite of tools for PC/SC.

    A big thank you to Lionel Victor, original author of gscriptor, for the port of gscriptor to Gtk+3. My level of Perl programming has diminished since I do not use this language any more.

    Changes:
    1.5.4 - 12 December 2018, Ludovic ROUSSEAU
    • 213 new ATRs
    • pcsc_scan: display the number of events
    • gscriptor: port from Gtk+2 to Gtk+3

    Friday, October 12, 2018

    New PyKCS11 1.5.3 available

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

    Changes:

    1.5.3 - October 2018, Ludovic Rousseau
    • Do not fail when converting a UTF-8 string
    • Documentation: convert from Epydoc to Sphinx
    • some minor improvements

    New version of pcsc-lite: 1.8.24

    I just released a new version of pcsc-lite 1.8.24.
    pcsc-lite is a Free Software implementation of the PC/SC (or WinSCard) API for Unix systems.

    Changes
    1.8.24: Ludovic Rousseau
    12 October 2018
    • the project moved to https://pcsclite.apdu.fr/
    • SCardGetStatusChange(): Fix a rare race condition
    • SCardReleaseContext(): do not release a lock owned by another context
    • SCardReconnect(): suspend card auto power off
    • Allow "=" in serial driver filenames
    • Add the thread id in the pcscd log lines
    • pcsc-spy: correctly handle incomplete log file
    • Simclist: avoid to divide by zero in list_findpos()
    • Some other minor improvements

    Tuesday, September 25, 2018

    macOS Mojave and smart cards status

    macOS Mojave (macOS 10.14) is now available since 24th September, 2018.


    API Differences between 10.13 and 10.14

    The differences should be listed in the developer page macOS Mojave 10.14.
    The changes for Mojave are not yet available.

    PC/SC

    Since Yosemite (10.10) the PC/SC layer is no more a fork of pcsc-lite. So comparing versions with pcsc-lite is useless.

    $ cat /System/Library/Frameworks/PCSC.framework/Versions/A/Resources/version.plist
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
     <key>BuildAliasOf</key>
     <string>CryptoTokenKit</string>
     <key>BuildVersion</key>
     <string>163</string>
     <key>CFBundleShortVersionString</key>
     <string>8.0</string>
     <key>CFBundleVersion</key>
     <string>1</string>
     <key>ProjectName</key>
     <string>SmartCardServices</string>
     <key>SourceVersion</key>
     <string>281200021000000</string>
    </dict>
    </plist>
    

    The BuildVersion moved from 10 in Sierra 10.13.6 to 163 in Mojave 10.14.0. Maybe Apple made 163 - 10 = 153 internal/alpha/beta releases?

    The SourceVersion moved from 281050022000000 in High Sierra 10.13.6 to 281200021000000 in Mojave 10.14.0. I have no idea how to parse or use this information.

    PC/SC Bugs fixed

    These bugs were found in High Sierra are now fixed in Mojave:
    • Typo in error message from PC/SC call pcsc_stringify_error(), bug #40995115.
      pcsc_stringify_error() returned "Unkown error" instead of ""UnkNown error" for unknown error codes.
    Maybe some other PC/SC bugs (unknown by me) have been fixed.

    CryptoTokenKit

    CryptoTokenKit is the native smart card API since the complete rewrite in macOS Yosemite 10.10 (OS X Yosemite BETA and smart cards status).

    $ strings /System/Library/Frameworks/CryptoTokenKit.framework/CryptoTokenKit | grep BuildRoot
    /BuildRoot/Library/Caches/com.apple.xbs/Sources/CryptoTokenKit/CryptoTokenKit-281.200.21/CryptoTokenKit/TKToken.m
    /BuildRoot/Library/Caches/com.apple.xbs/Sources/CryptoTokenKit/CryptoTokenKit-281.200.21/CryptoTokenKit/TKSmartCard.m
    /BuildRoot/Library/Caches/com.apple.xbs/Sources/CryptoTokenKit/CryptoTokenKit-281.200.21/CryptoTokenKit/TKTokenSession.m

    In Mojave CryptoTokenKit source code is at version 281.200.21. It was at version 281.1.1 in High Sierra 10.13.0 and 281.50.22 in High Sierra 10.13.6.
    Since the source code is not available I can't write much more than that.

    CCID driver

    Driver version: 1.4.27.

    $ grep -A 1 CFBundleShortVersionString /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist
     <key>CFBundleShortVersionString</key>
     <string>1.4.27</string>
    

    This is the exact same version as in Hight Sierra 10.13.0.

    Note that the CCID version 1.4.28 was released in October 2017 and version 1.4.29 in February 2018. Apple had plenty of time to upgrade the CCID driver. This is surprising.

    The current version of the CCID driver is 1.4.30. This version was released 5 days before Mojave so I was not expecting to see this version included in Mojave.

    Conclusion

    No much visible changes in the smart card layer in macOS Mojave.

    It is surprising Apple has not upgraded the CCID driver since the previous major version of macOS. I understand this major version of macOS is not a revolution but more a stabilisation of macOS.

    Saturday, September 22, 2018

    Better CCID suport in FreeBSD

    My CCID driver had some problems when used on a FreeBSD system. I used FreeBSD 10.4 (stable) but the problem should also be present in more recent or older versions of FreeBSD.

    The problem

    The problem was that the removal a USB reader was not reported to the PC/SC application. The removal was detected by the PC/SC daemon (pcscd) but something failed in the removal process.

    The same problem also prevented the PC/SC daemon to exit correctly when stopped using the keyboard combination Control+C.

    After some debugging the cause of the problem was identified. When the CCID driver is stopped (because a reader is removed or pcscd is exited) the driver tries to cancel all the unfinished USB transfers. When the reader provides an interrupt end point to notify card events the CCID driver initiates a USB transfer reading from this end point with a long timeout (10 minutes).

    libUSB issues

    I reported the problem using the FreeBSD bug report tool: https://bugs.freebsd.org/

    I worked with Hans Petter Selasky (libUSB co-maintainer) to fix the problems. I would like to thank Hans Petter for his availability. That is great to have problems fixed in just a few days.

    libusb_cancel_transfer() does NOT cancel a transfer after the USB device is removed

    Bug reported at: libusb_cancel_transfer() does NOT cancel a transfer after the USB device is removed

    Patch applied in FreeBSD: Revision 338616

    Debug is not working correctly

    Use of DPRINTF() to print debug message was not working in some functions.

    Bug reported at: libusb DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done"); does not work in libusb10_do_transfer_cb()

    Patch applied in FreeBSD: Revision 338679

    Bogus management after a device removal

    Bug reported at: libusb_bulk_transfer() does not fail (with LIBUSB_ERROR_NO_DEVICE) if the device is not more present

    This bug is solved by the patch also solving the libusb_cancel_transfer() problem.

    Fixed in FreeBSD stable versions

    The problems have also been fixed in FreeBSD stable versions 9, 10, 11.

    Conclusion

    My CCID driver should now work better on FreeBSD.

    Friday, September 21, 2018

    macOS HighSierra bug: SCardEndTransaction() returns SCARD_W_RESET_CARD instead of SCARD_W_REMOVED_CARD

    This is part of the series: "macOS High Sierra and smart cards: known bugs"

    SCardEndTransaction() returns different error codes than on GNU/Linux and Windows

    SCardEndTransaction() on High Sierra returns error codes that are different than on GNU/Linux and Windows.

    SCardEndTransaction() returns SCARD_W_RESET_CARD after a card change

    On High Sierra SCardEndTransaction() returns SCARD_W_RESET_CARD if the card has been removed and inserted again in the reader.

    On GNU/Linux and Windows SCardEndTransaction() returns SCARD_W_REMOVED_CARD instead.

    This behaviour can be very confusing for an application. The application has started a PC/SC transaction so it has an exclusive access to the card. No other application can reset the card during a transaction.

    See also

    Apple bug report #44672548 "PCSC SCardEndTransaction() returns SCARD_W_RESET_CARD instead of SCARD_W_REMOVED_CARD". Marked as duplicate of #23900844.

    This bug is very similar to previous bugs for other PC/SC functions:

    Sample code

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    
    #ifdef __APPLE__
    #include <PCSC/winscard.h>
    #include <PCSC/wintypes.h>
    #else
    #include <winscard.h>
    #endif
    
    #define CHECK_RV(fct) if (SCARD_S_SUCCESS != rv) { printf(fct"() failed: %s (0x%08X)\n", pcsc_stringify_error(rv), rv); ret = 0; goto error; } else { printf(fct"(): OK\n"); }
    
    int main(void)
    {
        int ret = 1;
        SCARDCONTEXT hContext;
        SCARDHANDLE hCard;
        DWORD dwActiveProtocol;
        LONG rv;
        char mszReaders[1024];
        DWORD dwReaders = sizeof(mszReaders);
    
        rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
        CHECK_RV("SCardEstablishContext");
    
        rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
        CHECK_RV("SCardListReaders");
    
        rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED,
            SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard,
            &dwActiveProtocol);
        CHECK_RV("SCardConnect");
    
        rv = SCardBeginTransaction(hCard);
        CHECK_RV("SCardBeginTransaction");
    
        printf("Remove and insert the card. Then press Enter");
        getchar();
    
        rv = SCardEndTransaction(hCard, SCARD_LEAVE_CARD);
        CHECK_RV("SCardEndTransaction");
    
        rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
        CHECK_RV("SCardDisconnect")
    
        rv = SCardReleaseContext(hContext);
        CHECK_RV("SCardReleaseContext")
    
    error:
        return ret;
    }
    

    Result (on High Sierra)

    $ ./main_Mac 
    SCardEstablishContext(): OK
    SCardListReaders(): OK
    SCardConnect(): OK
    SCardBeginTransaction(): OK
    Remove and insert the card. Then press Enter
    SCardEndTransaction() failed: Card was reset. (0x80100068)

    Expected result (on Debian)

    $ ./main_Linux 
    SCardEstablishContext(): OK
    SCardListReaders(): OK
    SCardConnect(): OK
    SCardBeginTransaction(): OK
    Remove and insert the card. Then press Enter
    SCardEndTransaction() failed: Card was removed. (0x80100069)

    Known workaround

    None known.

    macOS HighSierra bug: SCardStatus() returns SCARD_W_RESET_CARD instead of SCARD_W_REMOVED_CARD

    This is part of the series: "macOS High Sierra and smart cards: known bugs"

    SCardStatus() returns different error codes than on GNU/Linux and Windows

    SCardStatus() on High Sierra returns error codes that are different than on GNU/Linux and Windows.

    SCardStatus() returns SCARD_W_RESET_CARD after a card change

    On High Sierra SCardStatus() returns SCARD_W_RESET_CARD if the card has been removed and inserted again in the reader.

    On GNU/Linux and Windows SCardStatus() returns SCARD_W_REMOVED_CARD instead.

    See also

    Apple bug report #44672224 "PC/SC SCardStatus() returns SCARD_W_RESET_CARD instead of SCARD_W_REMOVED_CARD". Marked as duplicate of #23900844.

    This bug is very similar to previous bugs about SCardTransmit() ("macOS HighSierra bug: SCardTransmit() returns different error codes than on GNU/Linux and Windows") and SCardBeginTransaction() ("OS X El Capitan bug: SCardBeginTransaction() returns different error codes than on GNU/Linux and Windows").

    Sample code

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    
    #ifdef __APPLE__
    #include <PCSC/winscard.h>
    #include <PCSC/wintypes.h>
    #else
    #include <winscard.h>
    #endif
    
    #define CHECK_RV(fct) if (SCARD_S_SUCCESS != rv) { printf(fct"() failed: %s (0x%08X)\n", pcsc_stringify_error(rv), rv); ret = 0; goto error; } else { printf(fct"(): OK\n"); }
    
    int main(void)
    {
        int ret = 1;
        SCARDCONTEXT hContext;
        SCARDHANDLE hCard;
        DWORD dwActiveProtocol;
        LONG rv;
        char mszReaders[1024];
        DWORD dwReaders = sizeof(mszReaders);
    
        rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
        CHECK_RV("SCardEstablishContext");
    
        rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
        CHECK_RV("SCardListReaders");
    
        rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED,
            SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard,
            &dwActiveProtocol);
        CHECK_RV("SCardConnect");
    
        printf("Remove and insert the card. Then press Enter");
        getchar();
    
        DWORD chReaderLen = 100;
        DWORD dwState;
        DWORD dwProtocol;
        BYTE bAtr[33];
        DWORD cbAtrLen = sizeof bAtr;
        rv = SCardStatus(hCard, mszReaders, &chReaderLen, &dwState, &dwProtocol,
            bAtr, &cbAtrLen);
        CHECK_RV("SCardStatus");
    
        rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
        CHECK_RV("SCardDisconnect")
    
        rv = SCardReleaseContext(hContext);
        CHECK_RV("SCardReleaseContext")
    
    error:
        return ret;
    }
    

    Result (on High Sierra)

    $ ./main_Mac 
    SCardEstablishContext(): OK
    SCardListReaders(): OK
    SCardConnect(): OK
    Remove and insert the card. Then press Enter
    SCardStatus() failed: Card was reset. (0x80100068)

    Expected result (on Debian)

    $ ./main_Linux 
    SCardEstablishContext(): OK
    SCardListReaders(): OK
    SCardConnect(): OK
    Remove and insert the card. Then press Enter
    SCardStatus() failed: Card was removed. (0x80100069)

    Known workaround

    None known.

    macOS High Sierra and smart cards: known bugs

    High Sierra: macOS 10.13

    As I did for Yosemite 10.10 ("OS X Yosemite and smart cards: known bugs") and El Capitan 10.11 ("OS X El Capitan and smart cards: known bugs") I propose to maintain a list of know issues in PC/SC on macOS High Sierra 10.13.

    The native API to use smart card on macOS is CryptoTokenKit since Yosemite 10.10 (see "PCSC sample in Objective-C" or "PCSC sample in Swift") but many applications need to be portable to Windows, macOS and GNU/Linux and the common PC/SC API is used instead. So it is important to have a correctly working PC/SC API on macOS.

    Bug list

    I will list known (by me) bugs and will try to maintain the list in the future if/when the bugs are fixed.

    Some of the bugs have been reported a few years ago but are still present in High Sierra.
    1. OS X El Capitan bug: PC/SC is not unusable after fork() (reported in November 2015)
    2. OS X El Capitan bug: SCardBeginTransaction() returns different error codes than on GNU/Linux and Windows (reported in December 2015)
    3. macOS HighSierra bug: SCardTransmit() returns different error codes than on GNU/Linux and Windows (reported in September 2018)
    4. macOS HighSierra bug: SCardStatus() returns SCARD_W_RESET_CARD instead of SCARD_W_REMOVED_CARD (reported in September 2018)
    5. macOS HighSierra bug: SCardEndTransaction() returns SCARD_W_RESET_CARD instead of SCARD_W_REMOVED_CARD (reported in September 2018)

    Missing features

    The missing features are not bugs but services provided but the PC/SC API on Windows and GNU/Linux that would be nice to also have on macOS.
    1. OS X El Capitan missing feature: SCardGetStatusChange() and number of card events (reported in December 2015)
    2. OS X El Capitan missing feature: SCardGetStatusChange() and "\\?PnP?\Notification" (reported in December 2015)
    3. OS X El Capitan missing feature: add support of TAG_IFD_POLLING_THREAD_WITH_TIMEOUT (reported in December 2015)

    Conclusion

    The bugs listed above are not critical for many users. But they may surprise some developers when they try to understand why their code is working fine on GNU/Linux but has a strange behaviour when executed on macOS.

    Thursday, September 20, 2018

    macOS HighSierra bug: SCardTransmit() returns different error codes than on GNU/Linux and Windows

    This is part of the series: "macOS High Sierra and smart cards: known bugs"

    SCardTransmit() returns different error codes than on GNU/Linux and Windows

    SCardTransmit() on High Sierra returns error codes that are different than on GNU/Linux and Windows.

    SCardTransmit() returns SCARD_W_RESET_CARD after a card change

    On High Sierra SCardTransmit() returns SCARD_W_RESET_CARD if the card has been removed and inserted again in the reader.

    On GNU/Linux and Windows SCardTransmit() returns SCARD_W_REMOVED_CARD instead.

    See also

    Apple bug report #44638067 "PC/SC SCardTransmit() returns different error codes than on GNU/Linux and Windows". Marked as duplicate of #23900844.

    This bug is very similar to a previous bug I found in El Capitan in 2015 "OS X El Capitan bug: SCardBeginTransaction() returns different error codes than on GNU/Linux and Windows". It is the same effects for the same behaviour but now with SCardTransmit() instead of SCardBeginTransaction().

    The previous bug has been reported to Apple as bug report #23900844 and is still not closed (or fixed or discussed).

    Sample code

    #! /usr/bin/env python3
    
    from smartcard.System import readers
    from smartcard.util import toBytes
    
    import sys
    try:
        r = int(sys.argv[1])
    except IndexError as e:
        r = 0
    
    reader = readers()[r]
    print("Using:", reader)
    
    connection = reader.createConnection()
    connection.connect()
    
    input("Remove and insert the card. Then press Enter")
    
    # Any APDU will work
    apdu = toBytes("00 00 00 00 00")
    response = connection.transmit(apdu)
    print(response)
    

    Result (on High Sierra)

    $ ./transmit_remove_card.py 
    Using: Gemalto PC Twin Reader
    Remove and insert the card. Then press Enter
    Traceback (most recent call last):
      File "./transmit_remove_card.py", line 22, in 
        response = connection.transmit(apdu)
      File "/usr/local/lib/python3.7/site-packages/pyscard-1.9.7-py3.7-macosx-10.13-x86_64.egg/smartcard/CardConnectionDecorator.py", line 82, in transmit
        return self.component.transmit(bytes, protocol)
      File "/usr/local/lib/python3.7/site-packages/pyscard-1.9.7-py3.7-macosx-10.13-x86_64.egg/smartcard/CardConnection.py", line 146, in transmit
        data, sw1, sw2 = self.doTransmit(bytes, protocol)
      File "/usr/local/lib/python3.7/site-packages/pyscard-1.9.7-py3.7-macosx-10.13-x86_64.egg/smartcard/pcsc/PCSCCardConnection.py", line 203, in doTransmit
        SCardGetErrorMessage(hresult))
    smartcard.Exceptions.CardConnectionException: Failed to transmit with protocol T0. Card was reset.

    Expected result (on Debian)


    $ ./transmit_remove_card.py
    Using: Gemalto PC Twin Reader (70D7E2EE) 00 00
    Remove and insert the card. Then press Enter
    Traceback (most recent call last):
      File "./transmit_remove_card.py", line 22, in 
        response = connection.transmit(apdu)
      File "/usr/lib/python3/dist-packages/smartcard/CardConnectionDecorator.py", line 82, in transmit
        return self.component.transmit(bytes, protocol)
      File "/usr/lib/python3/dist-packages/smartcard/CardConnection.py", line 146, in transmit
        data, sw1, sw2 = self.doTransmit(bytes, protocol)
      File "/usr/lib/python3/dist-packages/smartcard/pcsc/PCSCCardConnection.py", line 205, in doTransmit
        SCardGetErrorMessage(hresult))
    smartcard.Exceptions.CardConnectionException: Failed to transmit with protocol T0. Card was removed.

    Why is it important

    A card reset error can happen while the card is still in the reader. This is a normal PC/SC behaviour in case of multiple PC/SC applications running at the same time. One application may reset the card after using it.
    When an application receive the error SCARD_W_RESET_CARD it can assume that the same card is still present in the reader.

    A card removed error SCARD_W_REMOVED_CARD indicates that the card was removed. The same card or a different card may now be present in the reader. The application must assume that a different card has been inserted and that any cached information or application internal state should be refreshed by reading the newly inserted card.

    Known workaround

    None known.

    An idea would be to use the dwEventState field of SCardGetStatusChange(). From the pcsc-lite documentation:
    dwEventState also contains a number of events in the upper 16 bits (dwEventState & 0xFFFF0000). This number of events is incremented for each card insertion or removal in the specified reader. This can be used to detect a card removal/insertion between two calls to SCardGetStatusChange()

    Unfortunately Apple PC/SC does not support this feature. I reported the missing feature to Apple in bug report #23937633 and "OS X El Capitan missing feature: SCardGetStatusChange() and number of card events" in 2015. But nothing moved since then.

    Wednesday, September 19, 2018

    New version of libccid: 1.4.30

    I just released a version 1.4.30 of libccid the Free Software CCID class smart card reader driver.

    Changes:
    1.4.30 - 19 September 2018, Ludovic Rousseau
    • The project moved to https://ccid.apdu.fr/
    • Add support of
      • ACS ACR33 ICC Reader
      • BIFIT ANGARA
      • Broadcom Corp 58200
      • Certgate GmbH AirID 2 USB
      • DC.Ltd DC4 5CCID READER
      • Genesys Logic CCID Card Reader
      • Genesys Logic Combo Card Reader
      • InfoThink IT-500U Reader
      • Spyrus Inc WorkSafe Pro (ProductID 0x3117)
    • Disabled readers
      • REINER SCT cyberJack RFID standard
    • Update reader names for
      • Fujitsu Keyboard KB100 SCR
      • Fujitsu Keyboard KB100 SCR eSIG
      • FujitsuTechnologySolutions GmbH Keyboard KB SCR2
      • Yubico YubiKey CCID
      • Yubico YubiKey FIDO+CCID
      • Yubico YubiKey OTP+CCID
      • Yubico YubiKey OTP+FIDO+CCID
    • Fix libusb config descriptor leak
    • Fix leaking an allocated bundle in case no matching reader was found

    Wednesday, September 12, 2018

    Smart card integration in macOS Sierra: CryptoTokenKit plugin

    Crypto Token Kit

    In macOS Sierra (v10.12) Apple introduced the CryptoTokenKit plugin mechanism. This new mechanism is used to replace the tokend mechanism that was deprecated since OS X Lion (v10.7) in 2011.

    The CryptoTokenKit API was introduced in OS X Yosemite (v10.10). What is new with macOS Sierra is that a smart card manufacturer can provide a plugin to use the smart card through the Crypto Token Kit API.

    By default, macOS provides a Crypto Token Kit plugin to use a PIV card.

    Implementation of a CryptoTokenKit plugin

    I will not document here how to write a CryptoTokenKit plugin. Refer to Apple documentation for that and in particular the PIVtoken source code. See my article "macOS Sierra and PIVToken source code".

    OpenSC plugin

    The OpenSC project provides a PKCS#11 library for different smart cards.

    OpenSCToken: Use OpenSC in CryptoTokenKit by Frank Morgner is a CryptoTokenKit plugin that works with OpenSC.

    Fetch OpenSCToken-1.0.dmg, open the .dmg image, copy the application OpenSCTokenApp.app in your /Applications/ directory.
    You need to start the OpenSCTokenApp application at least one time to register the CryptoTokenKit plugin provided by the application. The application does nothing and you can quit it now.

    Comparison with OpenSC.tokend

    From the website project:
    • OpenSCToken supports multiple certificates, keys and PINs
    • OpenSCToken has proper support for PIN pad on reader or token
    • OpenSCToken offers easy login with smart card and automatically unlocks the login keychain
    • Tokens are not visible in Keychain Access any more (use sc_auth/security from command line instead)
    • Most non-Apple applications do not yet support CryptoTokenKit. If OpenSCToken is used together with OpenSC.tokend, your token will appear twice in Safari and other Apple-apps.

    Check installation

    To check if the plugin is installed you can use the pluginkit command line tool.

    Before installation:
    $ pluginkit -m -p com.apple.ctk-tokens
         com.apple.CryptoTokenKit.setoken(1.0)
         com.apple.CryptoTokenKit.pivtoken(1.0)

    After installation:
    $ pluginkit -m -p com.apple.ctk-tokens
         org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken(1.0)
         com.apple.CryptoTokenKit.pivtoken(1.0)
         com.apple.CryptoTokenKit.setoken(1.0)

    Verbose

    You can have more verbose output.

    Before installation:
    $ pluginkit -v -m -p com.apple.ctk-tokens
         com.apple.CryptoTokenKit.setoken(1.0) 4D0E5BB3-D45E-42A1-A0AE-24E0D71A6149 2018-07-12 16:37:44 +0000 /System/Library/Frameworks/CryptoTokenKit.framework/PlugIns/setoken.appex
         com.apple.CryptoTokenKit.pivtoken(1.0) A0B7E31C-443B-4B89-9D57-98D6A3736B86 2018-07-12 16:37:44 +0000 /System/Library/Frameworks/CryptoTokenKit.framework/PlugIns/pivtoken.appex
     (2 plug-ins)

    After installation:
    $ pluginkit -v -m -p com.apple.ctk-tokens
         org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken(1.0) 327C0A2C-4A43-4BB6-B858-73594115DCFA 2018-09-09 14:58:30 +0000 /Applications/OpenSCTokenApp.app/Contents/PlugIns/OpenSCToken.appex
         com.apple.CryptoTokenKit.pivtoken(1.0) A0B7E31C-443B-4B89-9D57-98D6A3736B86 2018-07-12 16:37:44 +0000 /System/Library/Frameworks/CryptoTokenKit.framework/PlugIns/pivtoken.appex
         com.apple.CryptoTokenKit.setoken(1.0) 4D0E5BB3-D45E-42A1-A0AE-24E0D71A6149 2018-07-12 16:37:44 +0000 /System/Library/Frameworks/CryptoTokenKit.framework/PlugIns/setoken.appex
     (3 plug-ins)

    This more verbose output allows you to know where on disk the plugin is found.
    To remove/uninstall the plugin you just have to delete the application containing/providing the plugin.

    Verbose + +

    Or an even more verbose output:

    Before installation:
    $ pluginkit -vv -m -p com.apple.ctk-tokens
         com.apple.CryptoTokenKit.setoken(1.0)
                 Path = /System/Library/Frameworks/CryptoTokenKit.framework/PlugIns/setoken.appex
                 UUID = 4D0E5BB3-D45E-42A1-A0AE-24E0D71A6149
            Timestamp = 2018-07-12 16:37:44 +0000
                  SDK = com.apple.ctk-tokens
         Display Name = Secure Enclave Private Key Storage
           Short Name = setoken
    
         com.apple.CryptoTokenKit.pivtoken(1.0)
                 Path = /System/Library/Frameworks/CryptoTokenKit.framework/PlugIns/pivtoken.appex
                 UUID = A0B7E31C-443B-4B89-9D57-98D6A3736B86
            Timestamp = 2018-07-12 16:37:44 +0000
                  SDK = com.apple.ctk-tokens
         Display Name = Personal Identity Verification token driver
           Short Name = pivtoken
    
     (2 plug-ins)

    After installation:
    $ pluginkit -vv -m -p com.apple.ctk-tokens
         org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken(1.0)
                 Path = /Applications/OpenSCTokenApp.app/Contents/PlugIns/OpenSCToken.appex
                 UUID = 327C0A2C-4A43-4BB6-B858-73594115DCFA
            Timestamp = 2018-09-09 14:58:30 +0000
                  SDK = com.apple.ctk-tokens
        Parent Bundle = /Applications/OpenSCTokenApp.app
         Display Name = OpenSC token driver
           Short Name = OpenSCToken
          Parent Name = OpenSCTokenApp
    
         com.apple.CryptoTokenKit.pivtoken(1.0)
                 Path = /System/Library/Frameworks/CryptoTokenKit.framework/PlugIns/pivtoken.appex
                 UUID = A0B7E31C-443B-4B89-9D57-98D6A3736B86
            Timestamp = 2018-07-12 16:37:44 +0000
                  SDK = com.apple.ctk-tokens
         Display Name = Personal Identity Verification token driver
           Short Name = pivtoken
    
         com.apple.CryptoTokenKit.setoken(1.0)
                 Path = /System/Library/Frameworks/CryptoTokenKit.framework/PlugIns/setoken.appex
                 UUID = 4D0E5BB3-D45E-42A1-A0AE-24E0D71A6149
            Timestamp = 2018-07-12 16:37:44 +0000
                  SDK = com.apple.ctk-tokens
         Display Name = Secure Enclave Private Key Storage
           Short Name = setoken
    
     (3 plug-ins)

    List inserted token

    If your smart card is supported by one of the installed CryptoTokenKit plugin you will see it using the command "security list-smartcards".

    $ security list-smartcards
    org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken:3015061316010310

    Card content

    There is different ways to display the content of the card.

    system_profiler SPSmartCardsDataType

    $ system_profiler SPSmartCardsDataType
    
        Readers:
    
          #01: Cherry KC 1000 SC Z (ATR:<3b9f9581 00000081="" 300671df="" 31fe9f00="" 6112c4="" 65465305="">)
    
        Reader Drivers:
    
          #01: org.debian.alioth.pcsclite.smartcardccid:1.4.27 (/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle)
    
        Tokend Drivers:
    
          #01: com.apple.tokend.opensc:1.0 (/Library/Security/tokend/OpenSC.tokend)
    
        SmartCard Drivers:
    
          #01: org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken:1.0 (/Applications/OpenSCTokenApp.app/Contents/PlugIns/OpenSCToken.appex)
          #02: com.apple.CryptoTokenKit.pivtoken:1.0 (/System/Library/Frameworks/CryptoTokenKit.framework/PlugIns/pivtoken.appex)
    
        Available SmartCards (keychain):
    
            org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken:3015061316010310:
    
              #01: Kind: private RSA 2048-bit, Certificate: <0b1bea81 4ee563aa="" ab26c4c8="" c7f82472="" d70c33d5="">, Usage: Sign Decrypt Unwrap 
    Valid from: 2018-09-09 19:50:20 +0000 to: 2019-03-08 19:50:20 +0000, SSL trust: NO, X509 trust: YES 
    
    -----BEGIN CERTIFICATE-----
    MIIFlTCCA32gAwIBAgIDE8gaMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9ydEBjYWNlcnQub3JnMB4XDTE4MDkwOTE5NTAyMFoXDTE5MDMwODE5NTAyMFowTDEYMBYGA1UEAxMPQ0FjZXJ0IFdvVCBVc2VyMTAwLgYJKoZIhvcNAQkBFiFsdWRvdmljLnJvdXNzZWF1K2NhY2VydEBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCcW791p4I7wPdDTpHFzSNQwGvDlbOT5zYqSGTU1EeUNMewgj0KaGGcA9tEPD5B6U089/28QpJDU7LJb1bZygasl5VJxznXofZYP4GLerw8SMKfGPB5M3Yq9Wtxq8A282uzzfH9evvpQDoPxc03FZTyESeF1pr2y1oCNO4tvyd6hQc90zPdmzuXY2I/JwfhF6lJR/NaIFtpUqLJoRgN+pNwWjxvtQx5sjdWnFHW7R1/x+enp2eLTPTt2FRaSOdnCZVx9CNJw0BGTrzjHewp9kbdvLS3/A23ZPa4z+WUxNj4p3AgxJ3vh/VoRD3EhPpyvcfEgS7PWPHWHhKV5Z1CNFz5AgMBAAGjggFRMIIBTTAMBgNVHRMBAf8EAjAAMFYGCWCGSAGG+EIBDQRJFkdUbyBnZXQgeW91ciBvd24gY2VydGlmaWNhdGUgZm9yIEZSRUUgaGVhZCBvdmVyIHRvIGh0dHA6Ly93d3cuQ0FjZXJ0Lm9yZzAOBgNVHQ8BAf8EBAMCA6gwQAYDVR0lBDkwNwYIKwYBBQUHAwQGCCsGAQUFBwMCBgorBgEEAYI3CgMEBgorBgEEAYI3CgMDBglghkgBhvhCBAEwMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC5jYWNlcnQub3JnMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwuY2FjZXJ0Lm9yZy9yZXZva2UuY3JsMCwGA1UdEQQlMCOBIWx1ZG92aWMucm91c3NlYXUrY2FjZXJ0QGdtYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEAAsGk23KL8OmpUmnS+rAQOEuHhcJ2gBNgR8Au83QmJKlpmyJD190UIJARd0QPp7583bt3c0iOMw2qtXSDkiFmo/ngyed02UYFSxWRUsoi8RmF8Rjv/xw797vVlO1zbiMcra91Ftf53ylCtGhhoNxyso4lkwXKCJuKUD4+8f02QvpNgG/WE3YtZ2WWiTa2RaXtoTWY3gU1TZVuW1CV7aHbA/xx+Gv/YK/WtMZYvHNmcppfuRsmw4hIGWyibZ073Nsn7DglictRTrNGI4+yJSR8MV53mkhBJHmXRtOJNvLV9vEcnF6qpxd5kMJiTFr6RzQJb86lIebhXlb6RjtbhNZSR0WESnRYzxjgNIkVtwUBamm94JoY1SUJDqS/totB147oRGzD+ha3scq+ZbM5MMniZM2qUbk6nnbiswPBFYo45nQcMGx++q9WoYGsf0euDzhVMKC7uHaIUHcaI1xlJpSoxR6GIOqqcoNRvPSJQy6DSosewBqhnRps6eSUTuqAD5cen9o16zba1T8iiIch5PeI/GbteokSpwSCH/21wjzMdCc8Q2/WHPWfrbyPuB5ymVmXbYZAD3sGcNh0ukzeEFJ2tuTGavtDil3Yka3C0EfLqKdykDPZtwXg9maCV8i6IQUBW3ty10ms5HRc/U2UaG0j+xx53dMxjl3idZmJN/FVOOM=
    -----END CERTIFICATE-----
    
    
        Available SmartCards (token):
    
            org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken:3015061316010310:
    
              #01: Kind: private RSA 2048-bit, Certificate: <0b1bea81 4ee563aa="" ab26c4c8="" c7f82472="" d70c33d5="">, Usage: Sign Decrypt Unwrap 
    Valid from: 2018-09-09 19:50:20 +0000 to: 2019-03-08 19:50:20 +0000, SSL trust: NO, X509 trust: YES 
    
    -----BEGIN CERTIFICATE-----
    MIIFlTCCA32gAwIBAgIDE8gaMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9ydEBjYWNlcnQub3JnMB4XDTE4MDkwOTE5NTAyMFoXDTE5MDMwODE5NTAyMFowTDEYMBYGA1UEAxMPQ0FjZXJ0IFdvVCBVc2VyMTAwLgYJKoZIhvcNAQkBFiFsdWRvdmljLnJvdXNzZWF1K2NhY2VydEBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCcW791p4I7wPdDTpHFzSNQwGvDlbOT5zYqSGTU1EeUNMewgj0KaGGcA9tEPD5B6U089/28QpJDU7LJb1bZygasl5VJxznXofZYP4GLerw8SMKfGPB5M3Yq9Wtxq8A282uzzfH9evvpQDoPxc03FZTyESeF1pr2y1oCNO4tvyd6hQc90zPdmzuXY2I/JwfhF6lJR/NaIFtpUqLJoRgN+pNwWjxvtQx5sjdWnFHW7R1/x+enp2eLTPTt2FRaSOdnCZVx9CNJw0BGTrzjHewp9kbdvLS3/A23ZPa4z+WUxNj4p3AgxJ3vh/VoRD3EhPpyvcfEgS7PWPHWHhKV5Z1CNFz5AgMBAAGjggFRMIIBTTAMBgNVHRMBAf8EAjAAMFYGCWCGSAGG+EIBDQRJFkdUbyBnZXQgeW91ciBvd24gY2VydGlmaWNhdGUgZm9yIEZSRUUgaGVhZCBvdmVyIHRvIGh0dHA6Ly93d3cuQ0FjZXJ0Lm9yZzAOBgNVHQ8BAf8EBAMCA6gwQAYDVR0lBDkwNwYIKwYBBQUHAwQGCCsGAQUFBwMCBgorBgEEAYI3CgMEBgorBgEEAYI3CgMDBglghkgBhvhCBAEwMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC5jYWNlcnQub3JnMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwuY2FjZXJ0Lm9yZy9yZXZva2UuY3JsMCwGA1UdEQQlMCOBIWx1ZG92aWMucm91c3NlYXUrY2FjZXJ0QGdtYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEAAsGk23KL8OmpUmnS+rAQOEuHhcJ2gBNgR8Au83QmJKlpmyJD190UIJARd0QPp7583bt3c0iOMw2qtXSDkiFmo/ngyed02UYFSxWRUsoi8RmF8Rjv/xw797vVlO1zbiMcra91Ftf53ylCtGhhoNxyso4lkwXKCJuKUD4+8f02QvpNgG/WE3YtZ2WWiTa2RaXtoTWY3gU1TZVuW1CV7aHbA/xx+Gv/YK/WtMZYvHNmcppfuRsmw4hIGWyibZ073Nsn7DglictRTrNGI4+yJSR8MV53mkhBJHmXRtOJNvLV9vEcnF6qpxd5kMJiTFr6RzQJb86lIebhXlb6RjtbhNZSR0WESnRYzxjgNIkVtwUBamm94JoY1SUJDqS/totB147oRGzD+ha3scq+ZbM5MMniZM2qUbk6nnbiswPBFYo45nQcMGx++q9WoYGsf0euDzhVMKC7uHaIUHcaI1xlJpSoxR6GIOqqcoNRvPSJQy6DSosewBqhnRps6eSUTuqAD5cen9o16zba1T8iiIch5PeI/GbteokSpwSCH/21wjzMdCc8Q2/WHPWfrbyPuB5ymVmXbYZAD3sGcNh0ukzeEFJ2tuTGavtDil3Yka3C0EfLqKdykDPZtwXg9maCV8i6IQUBW3ty10ms5HRc/U2UaG0j+xx53dMxjl3idZmJN/FVOOM=
    -----END CERTIFICATE-----

    I also installed the OpenSC_0.18.dmg package so the OpenSC tokend (using the deprecated API) is also installed.

    security export-smartcard

    $ security export-smartcard
    
    ==== certificate #1
     class : "cert"
     subj : <31 18 30 16 06 03 55 04 03 13 0f 43 41 43 45 52 54 20 57 4f 54 20 55 53 45 52 31 30 30 2e 06 09 2a 86 48 86 f7 0d 01 09 01 16 21 6c 75 64 6f 76 69 63 2e 72 6f 75 73 73 65 61 75 2b 63 61 63 65 72 74 40 67 6d 61 69 6c 2e 63 6f 6d>
     cenc : 3
     ctyp : 3
     pkhh : <0b 1b ea 81 4e e5 63 aa d7 0c 33 d5 c7 f8 24 72 ab 26 c4 c8>
     persistref : <>
     agrp : "com.apple.token"
     pdmn : "dk"
     labl : "User PIN (Ludovic Rousseau):ID Root CA de CAcert WoT User (CAcert WoT User)"
     UUID : "B997A93B-052E-4DB0-80B8-46A23A455085"
     mdat : 2018-09-09 19:55:07 +0000
     slnr : <13 c8 1a>
     sync : 0
     sha1 : <04 df f6 71 9e ad 56 97 96 81 6c b5 8b 46 a4 08 cd e0 65 35>
     tkid : "org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken:3015061316010310"
     musr : <>
     cdat : 2018-09-09 19:55:07 +0000
     tomb : 0
     issr : <31 10 30 0e 06 03 55 04 0a 13 07 52 4f 4f 54 20 43 41 31 1e 30 1c 06 03 55 04 0b 13 15 48 54 54 50 3a 2f 2f 57 57 57 2e 43 41 43 45 52 54 2e 4f 52 47 31 22 30 20 06 03 55 04 03 13 19 43 41 20 43 45 52 54 20 53 49 47 4e 49 4e 47 20 41 55 54 48 4f 52 49 54 59 31 21 30 1f 06 09 2a 86 48 86 f7 0d 01 09 01 16 12 73 75 70 70 6f 72 74 40 63 61 63 65 72 74 2e 6f 72 67>
     accc : constraints: {
       ord : true
      }
      protection: {
       tkid : "org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken:3015061316010310"
      }
    ====
    
    ==== private key #1
     crtr : 0
     esiz : 0
     decr : 1
     persistref : <>
     atag : ""
     kcls : 1
     agrp : "com.apple.token"
     pdmn : "dk"
     bsiz : 2 048
     type : 42
     klbl : <0b 1b ea 81 4e e5 63 aa d7 0c 33 d5 c7 f8 24 72 ab 26 c4 c8>
     edat : 2001-01-01 00:00:00 +0000
     sign : 1
     mdat : 2018-09-09 19:55:07 +0000
     drve : 0
     labl : "User PIN (Ludovic Rousseau):ID Root CA de CAcert WoT User (CAcert WoT User)"
     sync : 0
     musr : <>
     sha1 : <ed 9c 0f 96 fd e3 e0 ee 30 b9 d3 b1 23 13 8b 3c b0 8e 9c ad>
     cdat : 2018-09-09 19:55:07 +0000
     tkid : "org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken:3015061316010310"
     sdat : 2001-01-01 00:00:00 +0000
     tomb : 0
     priv : 1
     accc : constraints: {
       od : <ff>,
       osgn : <ff>
      }
      protection: {
       tkid : "org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken:3015061316010310"
      }
     unwp : 1
    ====
    
    ==== identity #1
     class : "idnt"
     slnr : <13 c8 1a>
     certdata : <CFData 0x7fdbb2007c00 [0x7fffa8c23af0]>{length = 1433, capacity = 1433, bytes = 0x308205953082037da003020102020313 ... 75998937f15538e3}
     certtkid : "org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken:3015061316010310"
     priv : 1
     ctyp : 3
     mdat : 2018-09-09 19:55:07 +0000
     sdat : 2001-01-01 00:00:00 +0000
     bsiz : 2 048
     type : 42
     sha1 : <04 df f6 71 9e ad 56 97 96 81 6c b5 8b 46 a4 08 cd e0 65 35>
     pkhh : <0b 1b ea 81 4e e5 63 aa d7 0c 33 d5 c7 f8 24 72 ab 26 c4 c8>
     cdat : 2018-09-09 19:55:07 +0000
     tomb : 0
     UUID : "B997A93B-052E-4DB0-80B8-46A23A455085"
     persistref : <>
     accc : constraints: {
       od : <ff>,
       osgn : <ff>
      }
      protection: {
       tkid : "org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken:3015061316010310"
      }
     sync : 0
     tkid : "org.opensc-project.mac.opensctoken.OpenSCTokenApp.OpenSCToken:3015061316010310"
     subj : <31 18 30 16 06 03 55 04 03 13 0f 43 41 43 45 52 54 20 57 4f 54 20 55 53 45 52 31 30 30 2e 06 09 2a 86 48 86 f7 0d 01 09 01 16 21 6c 75 64 6f 76 69 63 2e 72 6f 75 73 73 65 61 75 2b 63 61 63 65 72 74 40 67 6d 61 69 6c 2e 63 6f 6d>
     pdmn : "dk"
     musr : <>
     sign : 1
     esiz : 0
     decr : 1
     atag : ""
     edat : 2001-01-01 00:00:00 +0000
     klbl : <0b 1b ea 81 4e e5 63 aa d7 0c 33 d5 c7 f8 24 72 ab 26 c4 c8>
     crtr : 0
     unwp : 1
     issr : <31 10 30 0e 06 03 55 04 0a 13 07 52 4f 4f 54 20 43 41 31 1e 30 1c 06 03 55 04 0b 13 15 48 54 54 50 3a 2f 2f 57 57 57 2e 43 41 43 45 52 54 2e 4f 52 47 31 22 30 20 06 03 55 04 03 13 19 43 41 20 43 45 52 54 20 53 49 47 4e 49 4e 47 20 41 55 54 48 4f 52 49 54 59 31 21 30 1f 06 09 2a 86 48 86 f7 0d 01 09 01 16 12 73 75 70 70 6f 72 74 40 63 61 63 65 72 74 2e 6f 72 67>
     cenc : 3
     kcls : 1
     agrp : "com.apple.token"
     labl : "User PIN (Ludovic Rousseau):ID Root CA de CAcert WoT User (CAcert WoT User)"
     drve : 0
    ====

    Keychain Access application

    The Keychain Access application displays objects returned by the tokend.

    If you install only the CryptoTokenKit plugin then you will not see a new keychain in Keychain Access. For me it is a regression. The graphical application was a good tool to display the content of a smart card.

    Pairing a card to a user account


    After inserting the card you should see a dialog window like the one bellow.



    Click on "Pair" to associate the card private key to the user account.

    You will need to enter your account password:


    Then enter the card PIN code:


    And the user account again:


    The pairing is now done.

    Untrusted Certification Authority

    Note that you can pair a card certificate to a user even if the certificate is not trusted. In my case the certificate is issued and signed by CAcert. This Certification Authority is not trusted by macOS (you can see that in the Keychain Access screen copy) but you can still use the untrusted certificate to login.

    Check pairing

    You can now check that your account is paired to card
    $ sc_auth list
    Hash: 0B1BEA814EE563AAD70C33D5C7F82472AB26C4C8

    You can note that the hash 0B1BEA814EE563AAD70C33D5C7F82472AB26C4C8 correspond to the "certificate #1" "pkhh", the "private key #1" "klbl", the "identity #1" "pkhh" and "klbl" fields from the security export-smartcard output.

    Unparing a user

    You can unpair a user

    $ sc_auth unpair
    $ sc_auth list
    $

    You will get the pairing dialog again after removing and inserting the card again. So it is easy to play with the pairing process.

    Pairing dialog status

    Disable

    If you click on the "Do not show again" on the pairing dialog box the dialog will not be displayed again. You can check the pairing dialog status using:

    $ sc_auth pairing_ui -s status
    SmartCard Pairing dialog is disabled.

    Enable

    You can re-enable the pairing dialog using:
    $ sc_auth pairing_ui -s enable

    $ sc_auth pairing_ui -s status 
    SmartCard Pairing dialog is enabled.

    Usage


    Screen unlock

    You can lock your screen and unlock it using your smart card and PIN.


    sudo(8)

    As already seen in "macOS Sierra and pam_smartcard" some services are configured to use a PAM module for smart card.
    In macOS Sierra only authorization_ctk and screensaver_ctk were configred to use the pam_smartcard.so module.

    In macOS High Sierra the sudo command is also configured to use smart card authentication.

    $ sudo id
    Enter PIN for 'User PIN (Ludovic Rousseau):ID Root CA de CAcert WoT User (CAcert WoT User)': 
    uid=0(root) gid=0(wheel) groups=0(wheel),1(daemon),2(kmem),3(sys),4(tty),5(operator),8(procview),9(procmod),12(everyone),20(staff),29(certusers),61(localaccounts),80(admin),702(2),705(5),703(3),701(1),33(_appstore),98(_lpadmin),100(_lpoperator),204(_developer),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing),399(com.apple.access_ssh),704(4)

    User login

    The CryptoTokenKit plugin is enabled only for the user that has started the OpenSCTokenApp application.
    Since the login screen is not executed as my user (I am not yet logged) so the plugin is not available at this step.

    The OpenSCToken web site indicates a way to enable smart card use for the login screen. But this involves to disable the System Integrity Protection (SIP) and I think that is a bad idea.

    There is a way (maybe more) to enable a CryptoTokenKit plugin for the login screen without disabling SIP. I may write about it in another blog article.

    Conclusion

    I wanted to write about CryptoTokenKit plugin since a long time. There is still a lot to write regarding the development and use of a CryptoTokenKit plugin.

    If implemented and integrated correctly a CryptoTokenKit plugin should be very easy to use.

    Wednesday, June 20, 2018

    PySCard 1.9.7 released

    I just released a new official version 1.9.7 of pyscard. PySCard is a python module adding smart cards support (PC/SC) to Python.

    The PySCard project is available at:

    Changes

    1.9.7 (June 2018)


    • Modify CardMonitoring's deleteObserver method to cleanly remove threads
    • Python 3: fix smartcard/Synchronization.py
    • Python 3: Fix SCardGetErrorMessage() on Windows
    • PCSCPart10: add parseFeatureRequest(), parseTlvProperties()
    • Fix PEP8 warnings
    • Minor documentation improvements

    1.9.6 (August 2017)


    • include test/__init__.py in the archive tarball.
      "make test" now works. That fixes build using Python 3.6

    Sunday, May 13, 2018

    ATR statistics: TB3 - Global after T=15 in TDi–1

    Article from the series "ATR statistics".

    TB3 - Global after T=15 in TDi–1


    For T=1 protocol the first TBi encodes Block Waiting Integer and Character Waiting Integer. The high nibble encodes BWI. The low nibble encodes CWI.

    For T=15 protocol TBi the coding is defined in the document ETSI TS 102 221 V10.0.0 (2011-12) chapter "6.3.3 Global Interface byte"

    TB3#%
    156575.53 %
    0x4528813.90 %
    0x55381.83 %
    0x47231.11 %
    0x5D211.01 %
    0x43180.87 %
    0x40170.82 %
    0x75140.68 %
    0x65110.53 %
    0x4290.43 %
    0x5890.43 %
    0x7D80.39 %
    0x4D70.34 %
    0x9F70.34 %
    0xA050.24 %
    0x3540.19 %
    0x1530.14 %
    0x3430.14 %
    0x5730.14 %
    0x3720.10 %
    0x4420.10 %
    0x4920.10 %
    0x5220.10 %
    0x6720.10 %
    0x2410.05 %
    0x4110.05 %
    0x5310.05 %
    0x5910.05 %
    0x6310.05 %
    0x6910.05 %
    0x6D10.05 %
    0x7310.05 %
    0x9E10.05 %

    T=1 protocol

    The list above is not really informative since both BWI and CWI are coded in the same byte.

    BWI


    BWI#%
    434973,01 %
    57315,27 %
    7224,60 %
    6163,35 %
    391,88 %
    961,26 %
    120,42 %
    210,21 %


    CWI


    CWI#%
    5 343 72 %
    1336 8 %
    7 30 6 %
    3 18 4 %
    0 15 3 %
    2 10 2 %
    8 9 2 %
    4 6 1 %
    155 1 %
    9 4 1 %
    1 1 0 %
    141 0 %


    T=15 protocol

    I my list I have only 5 cards with a TB3 for T=15. They all have the value TB3 = 0xA0 for "UICC-CLF interface supported as defined in TS 102 613".

    Sunday, April 15, 2018

    New version of pcsc-tools: 1.5.3

    I just released a new version of pcsc-tools, a suite of tools for PC/SC.

    The main changes are for the pcsc_scan command.

    Changes:
    1.5.3 - 15 April 2018, Ludovic ROUSSEAU
    • 253 new ATRs
    • pcsc_scan (thanks to Pascal J. Bourguignon):
      • add -v argument (default) for verbose
      • add -q argument for quiet
      • add -r argument to display the reader list
      • allow to use Control-C to break execution

    Thursday, April 12, 2018

    New PyKCS11 1.5.2 available

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

    Changes:

    1.5.2 - April 2018, Ludovic Rousseau
    • Fix initPin()
    • add tests for initPin(), setPin(), initToken()

    Friday, March 30, 2018

    New PyKCS11 1.5.1 available

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

    Changes:

    1.5.1 - March 2018, Ludovic Rousseau
    • Fix "pip install"

    Monday, March 26, 2018

    New PyKCS11 1.5.0 available

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

    Changes:

    1.5.0 - March 2018, Ludovic Rousseau
    • Python 3: use strings instead of binary buffers for CK_UTF8CHAR PKCS#11 types. The behaviour is now the same as with Python 2
    • allow non string PIN values (binary PIN) for login(), initToken(), initPin(), setPin()
    • fix support of RSA PKCS PSS mechanism
      The mechanism object now uses a parameter "mechanism" instead of hard coding the mechanism value to CKM_RSA_PKCS_PSS.
    • add support of Python 2.7 on Windows
    • add AppVeyor configuration (automatic Windows builds)
    • ckbytelist: remove possibility to give a initial size
    • samples/getinfo: do not list the mechanisms by default
    • samples/events:
      • do not list the mechanisms by default
      • add support of pinpad readers
    • some minor improvements

    Windows

    If you are a Windows user and you want binary packages then please work on the AppVeyor configuration:

    Sunday, March 18, 2018

    MUSCLE web sites moved to .apdu.fr

    With the decommissioning of alioth.debian.org I had to move the web site to a new place.


    Update your bookmarks.

    I also upgraded the HTML pages to Boostrap 4.0.

    Please report any issue you may find.

    Thursday, March 1, 2018

    Level 1.5 smart card support on macOS

    In a previous article "Level 1 smart card support on Mac OS X" I described some simple commands to check if the smart card stack is working correctly on a macOS system.

    By re-reading the presentation "Working with Smart Cards: macOS and Security" by Richard Purves I discovered a new command.

    I already knew "system_profiler SPUSBDataType" to list the USB devices. I mentioned it in "Level 1 smart card support on Mac OS X" to check the USB reader is seen by the system. But system_profiler provides a better command for smart cards.

    SPSmartCardsDataType

    system_profiler has another very interesting command: system_profiler SPSmartCardsDataType

    Clean macOS installation

    Example 1:
    $ system_profiler SPSmartCardsDataType
    SmartCards:
    
        Readers:
    
          #01: Cherry KC 1000 SC (ATR:<3b7f9600 00803180 65b08441 3df612ff fe829000>)
    
        Reader Drivers:
    
          #01: org.debian.alioth.pcsclite.smartcardccid:1.4.27 (/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle)
    
        Tokend Drivers:
    
        SmartCard Drivers:
    
          #01: com.apple.CryptoTokenKit.pivtoken:1.0 (/System/Library/Frameworks/CryptoTokenKit.framework/PlugIns/pivtoken.appex)
    
        Available SmartCards (keychain):
    
        Available SmartCards (token):
    
    

    You get a lot of useful information:
    1. list of smart card readers
    2. list of installed reader drivers
    3. list of tokend drivers
    4. list of smart card drivers
    5. available smart cards (keychain)
    6. available smart cards (token)

    What you can see in my example:
    • I use a Cherry KC 1000 SC reader. A card is inserted in the reader and you see the ATR.
    • by default Apple provides a CCID driver
    • by default Apple provides a PIV CryptoTokenKit token to support Personal Identity Verification cards

    Using SafeNet Authentication Client

    Example 2:
    $ system_profiler SPSmartCardsDataType 
    SmartCards:
    
        Readers:
    
          #01: Gemalto PC Twin Reader (ATR:<3b7f9600 00803180 65b08503 00ef120f fe829000>)
    
        Reader Drivers:
    
          #01: org.debian.alioth.pcsclite.smartcardccid:1.4.27 (/usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle)
          #02: com.SafeNet.eTokenIfdh:9.0.0.0 (/Library/Frameworks/eToken.framework/Versions/A/aks-ifdh.bundle)
          #03: com.gemalto.ifd-bccid:1.0 (/usr/local/libexec/SmartCardServices/drivers/ifd-bccid.bundle)
          #04: org.debian.alioth.pcsclite.smartcardccid:1.4.27 (/usr/local/libexec/SmartCardServices/drivers/ifd-ccid-SafeNet-eToken5300.bundle)
          #05: (null):(null) (/Library/Frameworks/eToken.framework/Versions/A/ikey-ifdh.bundle)
    
        Tokend Drivers:
    
          #01: com.Safenet.eTokend:9.0 (/Library/Frameworks/eToken.framework/Versions/A/eTokend.tokend)
    
        SmartCard Drivers:
    
          #01: com.apple.CryptoTokenKit.pivtoken:1.0 (/System/Library/Frameworks/CryptoTokenKit.framework/PlugIns/pivtoken.appex)
          #02: com.gemalto.Gemalto-Smart-Card-Token.PKCS11-Token:1.0 (/Library/Frameworks/eToken.framework/Versions/A/SafeNet Authentication Client.app/Contents/PlugIns/PKCS11 Token.appex)
    
        Available SmartCards (keychain):
    
            com.gemalto.Gemalto-Smart-Card-Token.PKCS11-Token:9A522A4489DFA3DE:
    
              #01: Kind: private RSA 2048-bit, Certificate: <1cc4a99c 25e2b4eb 381850d2 e8e7a9a8 8d258b31>, Usage: Sign Decrypt Unwrap 
              #02: Kind: private RSA 2048-bit, Certificate: <425fa8c1 27ad75a1 aec73183 2b053b41 38befe7f>, Usage: Sign Decrypt Unwrap 
              #03: Kind: private RSA 4096-bit, Certificate: <16b5321b d4c7f3e0 e68ef3bd d2b03aee b23918d1>, Usage: Sign Decrypt Unwrap 
              #04: Kind: private RSA 4096-bit, Certificate: <16b5321b d4c7f3e0 e68ef3bd d2b03aee b23918d1>, Usage: Sign Decrypt Unwrap 
              #05: Kind: private RSA 2048-bit, Certificate: <31fde547 b4ca58d4 7b6231c2 62730efd 8c7538a1>, Usage: Sign Derive Decrypt Unwrap 
    
        Available SmartCards (token):
    
            com.gemalto.Gemalto-Smart-Card-Token.PKCS11-Token:9A522A4489DFA3DE:
    
              #01: Kind: private RSA 2048-bit, Certificate: <1cc4a99c 25e2b4eb 381850d2 e8e7a9a8 8d258b31>, Usage: Sign Decrypt Unwrap 
              #02: Kind: private RSA 2048-bit, Certificate: <425fa8c1 27ad75a1 aec73183 2b053b41 38befe7f>, Usage: Sign Decrypt Unwrap 
              #03: Kind: private RSA 4096-bit, Certificate: <16b5321b d4c7f3e0 e68ef3bd d2b03aee b23918d1>, Usage: Sign Decrypt Unwrap 
              #04: Kind: private RSA 2048-bit, Certificate: <31fde547 b4ca58d4 7b6231c2 62730efd 8c7538a1>, Usage: Sign Derive Decrypt Unwrap 
              #05: Certificate <1a222d8f 7458d082 d413fbdb 40c85f56 f48def63>
    
    

    In this second example I installed SAC (SafeNet Authentication Client) from Gemalto. You can see some differences:
    • more reader drivers are installed
    • a tokend driver is installed
    • another SmartCard (Crypto Token Kit or CTK) driver is installed 
    • the card inserted in the reader is available in the keychain

    Conclusion

    This command provides information of a higher level that pcsctest.
    You know what drivers (for readers and for cards) are installed.

    Wednesday, February 21, 2018

    New version of libccid: 1.4.29

    I just released a version 1.4.29 of libccid the Free Software CCID class smart card reader driver.

    Changes:
    1.4.29 - 21 February 2018, Ludovic Rousseau
    • Add support of
      • Access IS NFC Smart Module (With idProduct 0x0164)
      • Bit4id Digital-DNA Key
      • Bit4id Digital-DNA Key BT
      • Bluink Ltd. Bluink CCID
      • Chicony HP Skylab USB Smartcard Keyboard
      • HID Global OMNIKEY 5023 Smart Card Reader
      • HID Global OMNIKEY 5027CK CCID CONFIG IF
      • KeyXentic Inc. KX906 Smart Card Reader
      • Spyrus Inc Rosetta USB
      • Spyrus Inc WorkSafe Pro
      • Watchdata USB Key (idProduct: 0x0418)
    • The C3PO LTC31 v2 wrongly declares PIN support
    • Remove extra EGT patch because if has bad side effects

    Monday, February 5, 2018

    How to use SCardGetStatusChange()?

    Some smart card applications need to detect when a card is inserted or a reader is added to the system. One way to solve the problem is to call SCardListReaders() and SCardGetStatusChange() in a loop.

    SCardListReaders()

    SCardListReaders() is a function to list the smart card reader(s) connected to the system.

    The function API is:

    LONG SCardListReaders(
      SCARDCONTEXT  hContext,
      LPCSTR   mszGroups,
      LPSTR   mszReaders,
      LPDWORD   pcchReaders
    )

    The result in mszReaders is a multi-string containing the list of readers.

    SCardGetStatusChange()

    SCardGetStatusChange() is a function to get the status of a list of readers and wait for events.

    The function API is:

    LONG SCardGetStatusChange(
      SCARDCONTEXT        hContext,
      DWORD               dwTimeout,
      SCARD_READERSTATE * rgReaderStates,
      DWORD               cReaders 
    )

    The function will return any change from the reader(s) listed in the parameter rgReaderStates. See the function documentation for more details.

    dwTimeout is a timeout in milliseconds. The function will block until the timeout expires or a change is reported.

    Real world (bad) application

    Here is a PC/SC log trace (see "PCSC API spy, third try") of an real world (non Free Software) application:

    SCardEstablishContext
     i dwScope: SCARD_SCOPE_SYSTEM (0x00000002)
     o hContext: 0x40DB4852
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000189]
    SCardListReaders
     i hContext: 0x40DB4852
     i mszGroups: (null)
     o pcchReaders: 0x00000001
     o mszReaders: 
     => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000090]
    SCardReleaseContext
     i hContext: 0x40DB4852
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000032]
        SCardEstablishContext
         i dwScope: SCARD_SCOPE_SYSTEM (0x00000002)
         o hContext: 0x21793B9A
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000294]
        SCardListReaders
         i hContext: 0x21793B9A
         i mszGroups: (null)
         o pcchReaders: 0x00000001
         o mszReaders: 
         => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000124]
        SCardGetStatusChange
         i hContext: 0x21793B9A
         i dwTimeout: 0x000000C8 (200)
         i cReaders: 0
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000014]
        SCardGetStatusChange
         i hContext: 0x21793B9A
         i dwTimeout: 0x000000C8 (200)
         i cReaders: 0
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000047]
        SCardGetStatusChange
         i hContext: 0x21793B9A
         i dwTimeout: 0x000000C8 (200)
         i cReaders: 0
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000035]
        SCardGetStatusChange
         i hContext: 0x21793B9A
         i dwTimeout: 0x000000C8 (200)
         i cReaders: 0
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000037]
        SCardListReaders
         i hContext: 0x21793B9A
         i mszGroups: (null)
         o pcchReaders: 0x00000001
         o mszReaders: 
         => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000186]
    
    [... lots of similar lines removed...]
    
        SCardGetStatusChange
         i hContext: 0x21793B9A
         i dwTimeout: 0x000000C8 (200)
         i cReaders: 0
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000014]
        SCardGetStatusChange
         i hContext: 0x21793B9A
         i dwTimeout: 0x000000C8 (200)
         i cReaders: 0
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000034]
        SCardGetStatusChange
         i hContext: 0x21793B9A
         i dwTimeout: 0x000000C8 (200)
         i cReaders: 0
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000046]
        SCardGetStatusChange
         i hContext: 0x21793B9A
         i dwTimeout: 0x000000C8 (200)
         i cReaders: 0
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000035]
        SCardListReaders
         i hContext: 0x21793B9A
         i mszGroups: (null)
         o pcchReaders: 0x00000001
         o mszReaders: 
         => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000160]
        SCardGetStatusChange
         i hContext: 0x21793B9A
         i dwTimeout: 0x000000C8 (200)
         i cReaders: 0
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000014]
        SCardGetStatusChange
         i hContext: 0x21793B9A
         i dwTimeout: 0x000000C8 (200)
         i cReaders: 0
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000036]
        SCardGetStatusChange
         i hContext: 0x21793B9A
         i dwTimeout: 0x000000C8 (200)
         i cReaders: 0
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000035]
        SCardGetStatusChange
         i hContext: 0x21793B9A
         i dwTimeout: 0x000000C8 (200)
         i cReaders: 0
         => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000037]
    
    Thread 1/2
    Results sorted by total execution time
    total time: 10.209201 sec
    0.000189 sec (  1 calls)  0.00% SCardEstablishContext
    0.000090 sec (  1 calls)  0.00% SCardListReaders
    0.000032 sec (  1 calls)  0.00% SCardReleaseContext
    
    Thread 2/2
    Results sorted by total execution time
    total time: 10.209201 sec
    0.002053 sec ( 13 calls)  0.02% SCardListReaders
    0.001655 sec ( 52 calls)  0.02% SCardGetStatusChange
    0.000294 sec (  1 calls)  0.00% SCardEstablishContext
    

    The application was executed during 10 seconds. The application made 14 calls to SCardListReaders() and 52 calls to SCardGetStatusChange().

    No reader was connected at the beginning and nothing happened during the 10 seconds. So all the PC/SC calls were made to detect... nothing.

    Real world (good) application

    For this second example I will use my pcsc_scan application (from pcsc-tools):

    SCardEstablishContext
     i dwScope: SCARD_SCOPE_SYSTEM (0x00000002)
     o hContext: 0x4D0F7F8C
     => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000321]
    SCardGetStatusChange
     i hContext: 0x4D0F7F8C
     i dwTimeout: 0x00000000 (0)
     i cReaders: 1
     i szReader: \\?PnP?\Notification
     i  dwCurrentState:  (0x00000000)
     i  dwEventState: SCARD_STATE_UNKNOWN, SCARD_STATE_UNAVAILABLE, SCARD_STATE_EXCLUSIVE, SCARD_STATE_INUSE, SCARD_STATE_MUTE, SCARD_STATE_PRESENT, SCARD_STATE_ATRMATCH (0x55FD66A4FBEC)
     i  Atr length: 0x55FD66A4FBF2 (94546837175282)
     i  Atr: NULL
     o szReader: \\?PnP?\Notification
     o  dwCurrentState:  (0x00000000)
     o  dwEventState:  (0x00000000)
     o  Atr length: 0x55FD66A4FBF2 (94546837175282)
     o  Atr: NULL
     => Command timeout. (SCARD_E_TIMEOUT [0x8010000A])  [0.000379]
    SCardListReaders
     i hContext: 0x4D0F7F8C
     i mszGroups: (null)
     o pcchReaders: 0x00000001
     o mszReaders: NULL
     => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000129]
    SCardListReaders
     i hContext: 0x4D0F7F8C
     i mszGroups: (null)
     o pcchReaders: 0x00000001
     o mszReaders: 
     => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000098]
    SCardGetStatusChange
     i hContext: 0x4D0F7F8C
     i dwTimeout: 0xFFFFFFFF (4294967295)
     i cReaders: 1
     i szReader: \\?PnP?\Notification
     i  dwCurrentState:  (0x00000000)
     i  dwEventState:  (0x00000000)
     i  Atr length: 0x55FD66A4FBF2 (94546837175282)
     i  Atr: NULL
    
    Thread 1/1
    Results sorted by total execution time
    total time: -1.000000 sec
    0.000379 sec (  1 calls) -0.04% SCardGetStatusChange
    0.000321 sec (  1 calls) -0.03% SCardEstablishContext
    0.000227 sec (  2 calls) -0.02% SCardListReaders
    

    The execution conditions are the same as in the previous case: no reader connected at the beginning and no change during 10 seconds.

    pcsc_scan made 2 initial calls to SCardListReaders() and 2 calls to SCardGetStatusChange(). The second SCardGetStatusChange() call was interrupted after 10 seconds of execution (using Control-C). That is why the returned values of SCardGetStatusChange() are not logged.

    \\?PnP?\Notification reader name

    The difference between the 2 applications is the use of the special reader name \\?PnP?\Notification by pcsc_scan.

    SCardGetStatusChange() is perfect to detect card events in the selected readers. But how to know when a new reader has been connected? When PC/SC was designed (PC/SC specification 1.0 released in 1996) most smart card readers were (mostly) serial readers. USB was not yet deployed (USB 1.0 specification were also released in 1996). (Serial) reader hotplug was not a use case at that time. So it is not surprising this use case is not handled by PC/SC.

    To solve this problem a special reader name is used. This is (still) NOT documented in the PC/SC workgroup specification, even in the version 2 (PC/SC v2 part 5 page 18), and I guess it is a Microsoft invention.

    The special reader name will tell SCardGetStatusChange() to generate associated events when a reader is added or removed. So no need to continuously call SCardListReaders() as it is the case with the first application.

    macOS case

    Windows WinSCard does support \\?PnP?\Notification since a long time.

    pcsc-lite (WinSCard for Unix) does support \\?PnP?\Notification since version 1.6.0 released in May 2010.

    Apple has no support of \\?PnP?\Notification reader name. I opened a bug for that in 2015 (see "OS X El Capitan missing feature: SCardGetStatusChange() and "\\?PnP?\Notification"") but nothing changed since then.

    So on macOS you have to regularly call SCardListReaders() to detect a reader connection or disconnection.

    CPU consumption

    To reduce the CPU and battery usage an efficient PC/SC application should always use \\?PnP?\Notification when possible (so on Windows and Unix except macOS).

    pcsc-tools 1.5.0

    Since its version 1.5.0 pcsc_scan provides a graphical animation when nothing happens. To update the animation every second a timeout of 1 second is used in SCardGetStatusChange(). So if you redo the experiment with a recent pcsc_scan you will see one SCardGetStatusChange() call every second.

    Since a new reader connection is detected using SCardGetStatusChange() no need to also call SCardListReaders() every second.

    SCardCancel()

    To force SCardGetStatusChange() to return before the end of the timeout you must use SCardCancel() from another thread of the application.

    You can use a very long timeout (or even the special value INFINITE) and use SCardCancel() when needed.

    Conclusion

    PC/SC provides functions to be notified of events. I invested a lot of time and work to make pcsc-lite efficient regarding events management. Every pcsc-lite internal polling has been removed.

    Please use \\?PnP?\Notification in your applications. You may not save the world but you will save a few CPU cycles.