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

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

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"

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.