2

From within a single python thread, as shown below, I get the error "Please insert a token in any slot" and it seems to not see my token. I change the code to not run from inside a multiprocessing Thread and it works. To take the PyKCS11 library out of the equation I also tested by using ctypes and wrapping the standard pkcs11 functions implemented in opensc, I still run into the same issue where it works except when run from a python Thread. What would cause this?

Using pkcs11 from inside a python Thread fails:

from PyKCS11 import LowLevel
import sys
from multiprocessing import Thread


class MyThread(Thread):
    def run(self):
        lib = "/usr/local/lib/opensc-pkcs11.so" # place here your PKCS#11 library
        pin = "12345678" # place here the pin of your token

        a = LowLevel.CPKCS11Lib()
        info = LowLevel.CK_INFO()
        slotList = LowLevel.ckintlist()

        loadRes = a.Load(lib, 1)
        print "Load of library '%s' : %s " % (lib, str(loadRes) )
        if not loadRes: 
            sys.exit(1)
        print "C_GetInfo: rv=" , hex(a.C_GetInfo(info))
        print "Library manufacturerID: ", info.GetManufacturerID()
        # listing only slots with a token inside.
        rv = a.C_GetSlotList(1, slotList)
        if (rv != LowLevel.CKR_OK): 
            sys.exit(1)
        if len(slotList) == 0:
            print "Please insert a token in any slot"
            sys.exit(1)


mythread = MyThread()
mythread.start()
mythread.join()

Using pkcs11 outside of a Thread works:

from PyKCS11 import LowLevel
import sys

def run(self):
        lib = "/usr/local/lib/opensc-pkcs11.so" # place here your PKCS#11 library
        pin = "12345678" # place here the pin of your token

        a = LowLevel.CPKCS11Lib()
        info = LowLevel.CK_INFO()
        slotList = LowLevel.ckintlist()

        loadRes = a.Load(lib, 1)
        print "Load of library '%s' : %s " % (lib, str(loadRes) )
        if not loadRes: 
            sys.exit(1)
        print "C_GetInfo: rv=" , hex(a.C_GetInfo(info))
        print "Library manufacturerID: ", info.GetManufacturerID()
        # listing only slots with a token inside.
        rv = a.C_GetSlotList(1, slotList)
        if (rv != LowLevel.CKR_OK): 
            sys.exit(1)
        if len(slotList) == 0:
            print "Please insert a token in any slot"
            sys.exit(1)

run()

Testing Environment:

OS: OSX Yosemite

pkcs11 middleware: opensc

1 Answers1

0

More info about multi-threading and PKCS#11 libraries can be found in chapter 6.6.2 of PKCS#11 v2.20 specification:

6.6.2 Applications and threads

Some applications will access a Cryptoki library in a multi-threaded fashion. Cryptoki enables applications to provide information to libraries so that they can give appropriate support for multi-threading. In particular, when an application initializes a Cryptoki library with a call to C_Initialize, it can specify one of four possible multi-threading behaviors for the library:

  1. The application can specify that it will not be accessing the library concurrently from multiple threads, and so the library need not worry about performing any type of locking for the sake of thread-safety.
  2. The application can specify that it will be accessing the library concurrently from multiple threads, and the library must be able to use native operation system synchronization primitives to ensure proper thread-safe behavior.
  3. The application can specify that it will be accessing the library concurrently from multiple threads, and the library must use a set of application-supplied synchronization primitives to ensure proper thread-safe behavior.
  4. The application can specify that it will be accessing the library concurrently from multiple threads, and the library must use either the native operation system synchronization primitives or a set of application-supplied synchronization primitives to ensure proper thread-safe behavior.

IMO the most commonly used type in multi-threaded apps is the 2nd type. To activate it you need to pass CKF_OS_LOCKING_OK flag to C_Initialize function. Following code shows how this can be achieved in C# with Pkcs11Interop library:

Pkcs11 pkcs11 = new Pkcs11(libraryPath);

CK_C_INITIALIZE_ARGS initArgs = new CK_C_INITIALIZE_ARGS();
initArgs.Flags = CKF.CKF_OS_LOCKING_OK;

CKR rv = pkcs11.C_Initialize(initArgs);
if ((rv != CKR.CKR_OK) && (rv != CKR.CKR_CRYPTOKI_ALREADY_INITIALIZED))
    throw new Pkcs11Exception("C_Initialize", rv);

I believe you need to use similar code in Python. Just guessing here but maybe you need to pass some parameter to LowLevel.CPKCS11Lib() ?

jariq
  • 11,681
  • 3
  • 33
  • 52