macOS Sonoma bug: Race condition in SCardGetStatusChange()?

This is part of the series: "macOS Sonoma and smart cards: known bugs".

I found a problem when using a composite reader i.e. a reader with 2 (or more) smart card reader interfaces.

The PC/SC layer reports a smart card is present when no smart card is inserted.

See also

I reported this problem as FB13184685 "race condition in pcsctest or the PC/SC function used to wait for a smart card reader or smart card".

Details

For my tests I use the Gemalto Prox DU reader. This reader is a single USB device with 2 CCID interfaces: one contact and one contactless interface.

I run the command: echo 1 | pcsctest. The idea is to select the reader 1 just after it is found.

I get the output:

% echo 1 | pcsctest

MUSCLE PC/SC Lite Test Program

Testing SCardEstablishContext    : Command successful.
Testing SCardGetStatusChange
Please insert a working reader   :

Then I connect a composite reader (2 CCID interfaces) with or without a card inserted and I get:

[...]
Please insert a working reader   : Command successful.
Testing SCardListReaders         : Command successful.
Reader 01: Gemalto Prox Dual USB PC Link Reader
Enter the reader number          : Waiting for card insertion
                                                                 : Command successful.
Testing SCardConnect             : No smart card inserted.
  • The command is waiting after displaying Please insert a working reader :.

  • Then I connect my smart card reader. The reader is found.

  • Pcsctest displays Waiting for card insertion : Command successful.

  • But then the SCardConnect fails with No smart card inserted.

I note that NO smart card was inserted in the reader. So the Waiting for card insertion reported as a success but that is an error.

I have the same result if a smart card is inserted in the reader.

If I run again the same command I get the expected result:

% echo 1 | pcsctest

MUSCLE PC/SC Lite Test Program

Testing SCardEstablishContext    : Command successful.
Testing SCardGetStatusChange
Please insert a working reader   : Command successful.
Testing SCardListReaders         : Command successful.
Reader 01: Gemalto Prox Dual USB PC Link Reader
Reader 02: Gemalto Prox Dual USB PC Link Reader 01
Enter the reader number          : Waiting for card insertion
                                                                 : Command successful.
Testing SCardConnect             : Command successful.
Testing SCardStatus              : Command successful.
Current Reader Name              : Gemalto Prox Dual USB PC Link Reader
Current Reader State             : 0x54
Current Reader Protocol          : 0x1
Current Reader ATR Size          : 13 (0xd)
Current Reader ATR Value         : 3B 88 80 01 00 00 00 00 33 71 71 00 3A
Testing SCardDisconnect          : Command successful.
Testing SCardReleaseContext      : Command successful.
Testing SCardEstablishContext    : Command successful.
Testing SCardGetStatusChange
Please insert a working reader   : Command successful.
Testing SCardListReaders         : Command successful.
Reader 01: Gemalto Prox Dual USB PC Link Reader
Reader 02: Gemalto Prox Dual USB PC Link Reader 01
Enter the reader number          : %

I do NOT have the problem with a reader with only 1 smart card slot. It looks like the problem is only with multi-slots and composite readers. It looks like a race condition somewhere in the PC/SC layer (or in the CryptoTokenKit layer bellow PC/SC) of macOS Sonoma.

I do not have the problem if I connect 2 "simple" smart card readers on a USB hub and then connect the hub to the Mac.

pcsc_scan

I note I do not have this problem if I use pcsc_scan from pcsc-tools.

With no reader connected I get:

% ./pcsc_scan
PC/SC device scanner
V 1.6.2 (c) 2001-2022, Ludovic Rousseau <ludovic.rousseau@free.fr>
Plug'n play reader name not supported. Using polling every 3600000 ms.
Scanning present readers...
Waiting for the first reader...

Then I connect the dual interface reader and I get the expected value:

[...]
Waiting for the first reader... found one
Scanning present readers...
0: Gemalto Prox Dual USB PC Link Reader
1: Gemalto Prox Dual USB PC Link Reader 01

Wed Oct  4 09:47:47 2023
 Reader 0: Gemalto Prox Dual USB PC Link Reader
  Event number: 0
  Card state: Card removed,
 Reader 1: Gemalto Prox Dual USB PC Link Reader 01
  Event number: 0
  Card state: Card removed,
  • Both interfaces are listed.

  • No card is wrongly found inserted.

Know workaround

None.

Just wait a bit after you detect a new reader is connected.

macOS Sonoma bug: SCardControl() returns SCARD_E_NOT_TRANSACTED

This is part of the series: "macOS Sonoma and smart cards: known bugs".

SCardControl() fails and returns SCARD_E_NOT_TRANSACTED (i.e. 0x80100016).

See also

I reported this bug as FB12779458 "SCardControl() fails on Sonoma beta 4 and returns SCARD_E_NOT_TRANSACTED (0x80100016)".

Update February 2024: The issue FB12779458 is fixed in macOS Sonoma 14.3.

Sample code

If you use the sample code:

2023_09_macOS_Sonoma_bug_SCardControl.c (Source)

//
//  main.c
//  scardcontrol
//
//  Created by Ludovic Rousseau on 28/07/2023.
//

#include <stdio.h>
#include <stdlib.h>
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>

#define SCARD_CTL_CODE(code) (0x42000000 + (code))
#define CM_IOCTL_GET_FEATURE_REQUEST SCARD_CTL_CODE(3400)
#define PCSC_ERROR_EXIT(rv, text) \
if (rv != SCARD_S_SUCCESS) \
{ \
        printf(text ": %s (0x%8X)\n", pcsc_stringify_error(rv), rv); \
        goto end; \
} \
else \
        printf(text ": OK\n");

int main(int argc, const char * argv[]) {
        LONG rv;
        SCARDCONTEXT hContext;
        DWORD dwReaders;
        LPSTR mszReaders = NULL;
        SCARDHANDLE hCard;
        unsigned char bRecvBuffer[MAX_BUFFER_SIZE];
        DWORD length;
        DWORD dwActiveProtocol;

        rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
        if (rv != SCARD_S_SUCCESS)
        {
                printf("SCardEstablishContext: Cannot Connect to Resource Manager %s\n", pcsc_stringify_error(rv));
                return 1;
        }

        /* Retrieve the available readers list */
        rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
        PCSC_ERROR_EXIT(rv, "SCardListReaders")

        mszReaders = malloc(sizeof(char)*dwReaders);
        if (mszReaders == NULL)
        {
                printf("malloc: not enough memory\n");
                goto end;
        }

        rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
        if (rv != SCARD_S_SUCCESS)
                printf("SCardListReader: %8X\n", rv);

        /* connect to a reader (even without a card) */
        dwActiveProtocol = -1;
        printf("Using reader: %s\n", mszReaders);
        rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_DIRECT,
                SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
        PCSC_ERROR_EXIT(rv, "SCardConnect")

        /* get features */
        rv = SCardControl(hCard, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0,
                bRecvBuffer, sizeof(bRecvBuffer), &length);
        PCSC_ERROR_EXIT(rv, "SCardControl")

        printf("Received buffer (%d bytes)\n", length);
        for (int i=0; i<length; i++)
                printf("%02X ", bRecvBuffer[i]);
        printf("\n");

        /* disconnect */
        rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
        PCSC_ERROR_EXIT(rv, "SCardDisconnect")

end:
        /* We try to leave things as clean as possible */
        rv = SCardReleaseContext(hContext);
        if (rv != SCARD_S_SUCCESS)
                printf("SCardReleaseContext: %s (0x%8X)\n", pcsc_stringify_error(rv),
                        rv);

        /* free allocated memory */
        if (mszReaders)
                free(mszReaders);

        return 0;
}

you will get:

 SCardListReaders: OK
 Using reader: Gemplus USB GemPCPinpad SmartCard Reader
 SCardConnect: OK
 SCardControl: Transaction failed. (0x80100016)
 Program ended with exit code: 0

Instead of the expected output (I get it on macOS Ventura 13.5):

 SCardListReaders: OK
 Using reader: Gemalto USB GemPCPinpad SmartCard Reader
 SCardConnect: OK
 SCardControl: OK
 Received buffer (24 bytes)
 06 04 42 33 00 06 07 04 42 33 00 07 0A 04 42 33 00 0A 12 04 42 33 00 12
 SCardDisconnect: OK
 Program ended with exit code: 0

Why is it important

This bug is important because if SCardControl() can't be used then you can't use the secure verify command of a pinpad reader for example (i.e. enter the PIN code on the pinpad keyboard and not on the PC keyboard).

Other commands are using SCardControl(). They are documented in PC/SC specification version 2 part 10 "Interoperability Specification for ICCs and Personal Computer Systems Part 10 IFDs with Secure PIN Entry Capabilities" from the PC/SC workgroup.

See List of SCardControl() commands supported by the CCID driver.

  • GET_FEATURE_REQUEST

  • secure PIN verify (FEATURE_VERIFY_PIN_DIRECT)

  • modify PIN entry (FEATURE_MODIFY_PIN_DIRECT)

  • reader PIN properties (FEATURE_IFD_PIN_PROPERTIES)

  • Multifunctional Card Terminal reader direct (FEATURE_MCT_READER_DIRECT)

  • retrieve reader properties in TLV form (FEATURE_GET_TLV_PROPERTIES)

Know workaround

If I install a new CCID driver (my CCID driver 1.5.2 for example) then the same sample code works on Sonoma and I get the expected results.

SCardListReaders: OK
Using reader: Gemalto USB GemPCPinpad SmartCard Reader
SCardConnect: OK
SCardControl: OK
Received buffer (24 bytes)
06 04 42 33 00 06 07 04 42 33 00 07 0A 04 42 33 00 0A 12 04 42 33 00 12
SCardDisconnect: OK
Program ended with exit code: 0

It looks like the problem is with the CCID driver provided by Apple and not in the macOS PC/SC or resource manager layer.

If you need a customer driver to solve this problem please contact me.

[UPDATE November 2023]

This problem is caused by the Apple CCID driver included in Sonoma. See Apple's own CCID driver in Sonoma.

An easy way to fix the problem is to upgrade to Sonoma 14.1, or to enable my CCID driver (also provided by Apple in Sonoma) by doing:

sudo defaults write /Library/Preferences/com.apple.security.smartcard useIFDCCID -bool yes

[UPDATE February 2024]

Apple has worked on SCardControl() support. The issue FB12779458 is fixed in macOS Sonoma 14.3.

macOS Sonoma and smart cards: known bugs

In Sonoma Apple did a (lot of) rework of the smart card layer. It is not explicit in my previous article macOS Sonoma and smart cards status.

I will try to document what I find in new blog posts.

Sonoma: macOS 14

Ad I did for previous versions of macOS I propose to maintain a list of know issues (bug, regression or missing feature) in PC/SC (WinSCard API) or CryptoTokenKit on macOS Sonoma 14.

Previous lists:

I will only list new bugs in macOS Sonoma. Bugs or missing features that were already present in previous macOS versions will not be listed again here. See my previous "macOS xyz and smart cards: known bugs" blog articles listed above.

Bug list

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

If you have found a bug not listed here then please contact me so I can add it to the list.

  1. macOS Sonoma bug: SCardControl() returns SCARD_E_NOT_TRANSACTED (fixed in Sonoma 14.3)

  2. macOS Sonoma bug: Race condition in SCardGetStatusChange()?

  3. macOS Sonoma bug: The reader name should include the CCID interface name

  4. macOS Sonoma: The reader name should include the USB serial number

  5. macOS Sonoma bug: SCardControl() (part 2)

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 or macOS Ventura but has a strange behaviour when executed on macOS Sonoma.

macOS Sonoma and smart cards status

Sonoma (macOS 14.0) is now available since September 26th, 2023.

I will compare this version to the previous one, Ventura, I presented in macOS Ventura and smart cards status.

/images/2023/09/macOS-Sonoma.jpg

CCID

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

The CCID driver has been updated from 1.5.0 in Ventura to 1.5.1 in Sonoma.

The CCID version 1.5.2 was released in January 2023 but that version has not (yet) been included by Apple in macOS. That is a bit surprising.

Updated CCID driver

If you need a CCID driver more recent than the version 1.5.1 provided by Apple you can contact me.

Apple Open Source

The Open Source components included in macOS are listed at https://opensource.apple.com/releases/

The Open Source components of Sonoma 14.0 are not yet listed. I will publish a new blog article once the Open Source page is updated to include Sonoma. It will be very informative to know what patches Apple applied regarding the bugs introduced in Sonoma.

Crypto Token Kit

My Objective-C sample "PC/SC" sample in Objective-C (synchronous) still builds and works fine.

Reader name dynamically generated

The smart card reader name returned by Crypto Token Kit API or PC/SC API is no more the name contained in the CCID driver configuration file /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist.

For example with my old Gemplus GemPC Key.

  • This device has an USB Product ID of 0x3438

  • The name in the CCID driver Info.plist file is: "Gemalto USB Shell Token V2"

 % grep 0x3438 ccid-1.5.2/readers/supported_readers.txt
 0x08E6:0x3438:Gemalto USB Shell Token V2
 #0x08E6:0x3438:Gemalto USB Shell Token V2 (GemPCKey.txt)
 #0x08E6:0x3438:Gemalto IDBridge K30 (Gemalto_IDBridge_K30.txt)

But the reader name returned by the PC/SC layer is: "Gemplus USB SmartCard Reader" and not the expected "Gemalto USB Shell Token V2".

I searched a bit to understand where this name comes from. And I found. This name comes from the reader itself. The USB specification defines 2 fields iManufacturer and iProduct. This information is visible using the parse tool included in the CCID driver archive.

 % ./ccid-1.5.2/src/parse
 Parsing USB bus/device: 08E6:3438 (bus 0, device 1)
  idVendor:  0x08E6  iManufacturer: Gemplus
  idProduct: 0x3438  iProduct: USB SmartCard Reader
   Found a CCID/ICCD device at interface 0
  idVendor: 0x08E6
   iManufacturer: Gemplus
  idProduct: 0x3438
   iProduct: USB SmartCard Reader
  bcdDevice: 1.00 (firmware release?)
 [...]

I have this behavior only with the CCID driver provided by Apple with macOS Sonoma. I do not get this behavior if I use a custom driver.

The reader name is not generated by the CCID driver, but by the smart card layer above the drivers (it would be pcscd on GNU/Linux).

Know bugs

I found smart card related bugs in Sonoma.

I will open an new blog page to list and track them. The same kind of page I made for macOS High Sierra and smart cards: known bugs in 2018.

[UPDATE Nov 2023] the page listing the bugs I found in Sonoma is now available at macOS Sonoma and smart cards: known bugs.

Conclusion

Apple made changes in the smart card layer in Sonoma, and introduced some bugs.

I hope the bugs will be fixed soon.

Wireshark better at decoding CCID protocol

In 2014 I wrote CCID USB spy using Wireshark to show how to use Wireshark to dissect CCID frames. CCID is the protocol used to communicate to a USB smart card reader.

Some frames were not dissected correctly or not dissected at all so it was not easy to understand what was hapenning. In the present case the CCID frames Set Parameters and the reader answer were not dissected.

I submitted a Wireshark patch to allow the decoding of these CCID frames. My merge request is available at https://gitlab.com/wireshark/wireshark/-/merge_requests/8994 and has been merged upstream.

Before

Using Wireshark 4.0.6 from Debian 12 bookworm (Debian stable when I write this) I have:

  • for the command PC_to_RDR_SetParameters sent to the reader:

/images/2023/08/wireshark_before1.png

The data in abProtocolDataStructure (5 bytes in this case) are displayed as an hex dump (Data: 1100000a00). But you do not get more information.

  • for the answer RDR_to_PC_Parameters from the reader:

/images/2023/08/wireshark_before2.png

Here the data in abProtocolDataStructure are not even displayed in hex.

After

You need to use the development release 4.1.0 of Wireshark to have my patch included. I will use the macOS version of Wireshark just because I can. You then have (for the same USB traffic dump):

  • for the command PC_to_RDR_SetParameters sent to the reader:

/images/2023/08/wireshark_after1.png

The 5 bytes of abProtocolDataStructure are dissected.

Protocol Data Structure for Protocol T=0
    Fi/Di selecting clock rate: 0x11
    Convention used: 0x00
    Extra Guardtime between two characters: 0x00
    WI for T= 0 used to define WWT: 0x0a
    ICC Clock Stop Support: 0x00
  • for the answer RDR_to_PC_Parameters from the reader:

/images/2023/08/wireshark_after2.png

Again the 5 bytes of abProtocolDataStructure are also dissected.

In this case the 5 bytes are identical in the command and the answer since the reader replies with what is acceptable for it.

Conclusion

I used Wireshark to study the USB CCID communication on Windows. I needed to have the PC_to_RDR_SetParameters dissected to know what the Windows driver was sending as configuration.

It was my first Wireshark patch and merge request. The code was easier to modify than I planned. Great Free Software programs are easy to modify and that is a real pleasure to work with such Free Software projects. I could not have done that with a proprietary software.

New version of pcsc-lite: 2.0.0

I just released a new version of pcsc-lite 2.0.0.

pcsc-lite is a Free Software implementation of the PC/SC (or WinSCard) API for Unix systems.

The version changed from 1.9.9 to 2.0.0 but this is a minor version change.

Changes:

2.0.0: Ludovic Rousseau

9 June 2023

  • Adjust USB drivers path at run-time via environment variable PCSCLITE_HP_DROPDIR

  • Add --disable-polkit option

  • Reset eventCounter when a reader is removed

  • Add "polkit" in pcscd -v output if enabled

  • Doxygen: document SCARD_E_INVALID_VALUE for some functions

  • use secure_getenv(3) if available

  • Some other minor improvements

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 (owned by Google since 2003) and host the blog myself on a server I control.

Low tech

The blog is now managed by the Nikola Software. I discovered Nikola by reading a Linux Weekly News article Nikola: static-site generation in Python.

Once generated, the HTML pages are static so it is very easy and simple to host them on a web server. No need to have a database (like MySQL) on the server or run a program (like PHP) to generate the content.

Web design

I use the bootstrap4 Nikola theme with some custom changes.

I am not a web page designer. Some colors or styles may look ugly. Please send me CSS change suggestions.

Update your bookmarks

If you have links pointing to the old blog it is very easy to update them to use the new blog.

For example, you have a link to https://ludovicrousseau.blogspot.com/2021/10/what-happened-20-years-ago.html. The same article is now available at https://blog.apdu.fr/posts/2021/10/what-happened-20-years-ago/

It looks magic, but it works because I used the Nikola plugin import_blogger to import all the articles from Blogger. I then made some "manual" corrections.

Update your RSS feed

To automatically receive new articles you can register your news reader to the RSS feed at https://blog.apdu.fr/rss.xml.

Conclusion

I already updated the links I have on my other web pages to point to the new blog.

I do not plan to close the old blog at Blogger because a lot of other pages still point to it. And it is very annoying to get an HTTP 404 error when you are redirected to a web page that does not exist anymore.

gscriptor now also in French and Russian

I modified gscriptor (included in pcsc-tools) to support internationalization (i18n). The next version of gscriptor (no release date planned yet) will be available (at least) in French and in Russian.

gscriptor

gscriptor is a graphical tool to send APDU commands to a smart card.


It is written in Perl and uses the Gtk+ graphical library.

French


Russian


Conclusion

Thanks to Pro-pra for the initial patch and the Russian localization.

If you want to add another language please copy the file pcsc-tools.pot, add your translations and send me the resulting file.

FAQ: pcsc-lite and SCARD_E_SERVICE_STOPPED error

One of the most popular search request that bring people on my blog is about SCARD_E_SERVICE_STOPPED.

The problem

With pcsc-lite the only cause for the error SCARD_E_SERVICE_STOPPED is that the two sides, pcscd and libpcsclite, are using a different version of the communication protocol.

See for example the reported issue "SCardEstablishContext: Service was stopped.".

In the logs you have something like:

$ journalctl --unit=pcscd
[...]
févr. 11 18:55:07 debian pcscd[3715]: 00000006 winscard_svc.c:361:ContextThread() Received command: CMD_VERSION from client 8
févr. 11 18:55:07 debian pcscd[3715]: 00000004 winscard_svc.c:373:ContextThread() Client is protocol version 4:3
févr. 11 18:55:07 debian pcscd[3715]: 00000001 winscard_svc.c:382:ContextThread() Communication protocol mismatch!
févr. 11 18:55:07 debian pcscd[3715]: 00000002 winscard_svc.c:384:ContextThread() Client protocol is 4:3
févr. 11 18:55:07 debian pcscd[3715]: 00000001 winscard_svc.c:386:ContextThread() Server protocol is 4:4
févr. 11 18:55:07 debian pcscd[3715]: 00000002 winscard_svc.c:396:ContextThread() CMD_VERSION rv=0x8010001E for client 8
Here the server is using version 4.4 but the client is using version 4.3.
The error code 0x8010001E is SCARD_E_SERVICE_STOPPED.

The cause

This situation can happen if you reinstalled pcsc-lite yourself but in /usr/local/ instead of /usr/. In that case you have 2 different versions of pcsc-lite installed at the same time on your system.

You may also use an application inside a flatpak container that uses a different version of pcsc-lite. See the limitations listed in "Accessing smart cards from inside a flatpak sandbox".

The solution

Do not mix different versions of pcsc-lite.

Conclusion

This is the second article in the FAQ "section". The first one was "FAQ: wintypes.h or winscard.h not found". I will try to provide other articles about common errors.

Verify with OpenSSL a signature computed by PyKCS11

With PyKCS11 I provide a sample code signature.py to compute a RSA+SHA256 signature. The Python sample also contains the code to check the signature using PyKCS11.

But what if you want to verify the signature using OpenSSL?

Export the public key

PYKCS11LIB environment variable is used to indicate what PKCS#11 library to use. For the tests I use SoftHSM so I set the variable using:
$ export PYKCS11LIB=/usr/local/lib/softhsm/libsofthsm2.so
#!/bin/bash

set -e

# get the 1st key object ID
ID=$(pkcs11-tool --module $PYKCS11LIB --list-objects --type pubkey \
    | grep ID \
    | cut -d: -f 2)
echo "Object id: $ID"

# export the public key
pkcs11-tool --module $PYKCS11LIB --read-object --type pubkey --id $ID -o rsa_pub.key

# convert the public key to PEM
openssl rsa -pubin -inform DER -in rsa_pub.key -outform PEM -out rsa_pub.pem

The RSA key pair has been generated by the generate.py script and is stored in the PKCS#11 token. We need to export it so that OpenSSL can use it to check the signature.

To export the key I use pkcs11-tool from the OpenSC project. We need to know the object ID of the public key. This ID is configured in generate.py script line 22. We dump the public keys and get the object ID.

$ pkcs11-tool --module $PYKCS11LIB --list-objects --type pubkey
Using slot 0 with a present token (0x27ca3aa)
Public Key Object; RSA 1024 bits
  label:      My Public Key
  ID:         22
  Usage:      encrypt, verify, wrap
  Access:     local

The script will work correctly if only one public key is present in the token. I let you handle more complex cases.

output

$ ./export_key.sh 
Using slot 0 with a present token (0x27ca3aa)
Object id:          22
Using slot 0 with a present token (0x27ca3aa)
writing RSA key

Compute signature

I modified the original signature.py script to also save the clear text message in a file cleartext.txt and the signature in a file sig_sha256.bin so these files can be used later by OpenSSL.

#!/usr/bin/env python3

from PyKCS11 import *
import binascii

pkcs11 = PyKCS11Lib()
pkcs11.load()  # define environment variable PYKCS11LIB=YourPKCS11Lib

# get 1st slot
slot = pkcs11.getSlotList(tokenPresent=True)[0]

session = pkcs11.openSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION)
session.login("1234")

# message to sign
toSign = "Hello World!\n"
mechanism = Mechanism(CKM_SHA256_RSA_PKCS, None)

# find first private key and compute signature
privKey = session.findObjects([(CKA_CLASS, CKO_PRIVATE_KEY)])[0]
signature = session.sign(privKey, toSign, mechanism)
print("\nsignature: {}".format(binascii.hexlify(bytearray(signature))))

# save the clear text in a file
with open("cleartext.txt", "w") as f:
    f.write(toSign)

# save to a signature in a file
with open("sig_sha256.bin", "bw") as f:
    f.write(bytearray(signature))

# find first public key and verify signature
pubKey = session.findObjects([(CKA_CLASS, CKO_PUBLIC_KEY)])[0]
result = session.verify(pubKey, toSign, signature, mechanism)
print("\nVerified:", result)

# logout
session.logout()
session.closeSession()

Output

$ ./signature.py 

signature: b'322c1591cb9aba1e361264b02464a2bd9d55693bf772b4253da0862616e611dc139005742c511795c27c8f609e4ddbaafceba1c3b3ce278b8e0af564c84de54a639cff67a9a3f97dcc542cd6f0200954ef7fce4a0f87b61636272e21fc1e3ef9f0b683e360cca4231405dd90ae2c4a3638ca7a85e2b62f6ae30975ff3885ab60'

Verified: True

Verify signature

#!/bin/bash

set -e

# verify signature
openssl dgst -sha256 -verify rsa_pub.pem -signature sig_sha256.bin cleartext.txt

Output

$ ./verify.sh 
Verified OK

Conclusion

Thanks to Leon Rman for the initial code and the idea.

I let you write the code to do the symmetrical operations: sign using OpenSSL and verify using PyKCS11.