aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2015-09-18 01:38:53 -0400
committerRob Austein <sra@hactrn.net>2015-09-18 01:38:53 -0400
commitec3be7d441b7bc1888186c05db6e6b46abe63879 (patch)
treefd696c15a5e0f6c9a6a35289193e44312fcbbd39
parent261e1e35db97e99df38c12f6a48bb28f6b827ac8 (diff)
MUTEX callbacks via ctypes. Beware of Garbage Collector.
-rw-r--r--py11/__init__.py33
-rw-r--r--scripts/py11-test.py72
2 files changed, 91 insertions, 14 deletions
diff --git a/py11/__init__.py b/py11/__init__.py
index bb4813f..86eb346 100644
--- a/py11/__init__.py
+++ b/py11/__init__.py
@@ -35,24 +35,31 @@ class PKCS11 (object):
self.so.C_GetInfo(byref(info))
return info.cryptokiVersion
- # http://stackoverflow.com/questions/15786635/using-ctypes-to-write-callbacks-that-pass-in-pointer-to-pointer-parameters-to-be
- # suggests that it should be straightforward to write callback
- # functions to implement the mutex semantics, and we get the
- # CK_CREATEMUTEX call, but we dump core on the CK_LOCKMUTEX call.
- # Specifying CKF_OS_LOCKING_OK does work, and is sufficient for most
- # purposes, so leaving the callbacks out of the API for now.
-
- def C_Initialize(self, flags = 0):
- if flags == 0:
+ # Be very careful if you try to provide your own locking functions.
+ # For most purposes, if you really just want locking, you're best
+ # off specifying CKF_OS_LOCKING_OK and letting the C code deal with
+ # it. The one case where you might want to provide your own locking
+ # is when writing tests to verify behavior of the locking code.
+ #
+ # We have to stash references to the callback functions passed to
+ # C_Initialize() to avoid dumping core when the garbage collector
+ # deletes the function pointer instances out from under the C code.
+
+ def C_Initialize(self, flags = 0, create_mutex = None, destroy_mutex = None, lock_mutex = None, unlock_mutex = None):
+ if flags == 0 and create_mutex is None and destroy_mutex is None and lock_mutex is None and unlock_mutex is None:
+ self._C_Initialize_args = None
self.so.C_Initialize(None)
else:
- init_arg = CK_C_INITIALIZE_ARGS(cast(None, CK_CREATEMUTEX), cast(None, CK_DESTROYMUTEX),
- cast(None, CK_LOCKMUTEX), cast(None, CK_UNLOCKMUTEX),
- flags, None)
- self.so.C_Initialize(cast(byref(init_arg), CK_VOID_PTR))
+ create_mutex = cast(None, CK_CREATEMUTEX) if create_mutex is None else CK_CREATEMUTEX(create_mutex)
+ destroy_mutex = cast(None, CK_DESTROYMUTEX) if destroy_mutex is None else CK_DESTROYMUTEX(destroy_mutex)
+ lock_mutex = cast(None, CK_LOCKMUTEX) if lock_mutex is None else CK_LOCKMUTEX(lock_mutex)
+ unlock_mutex = cast(None, CK_UNLOCKMUTEX) if unlock_mutex is None else CK_UNLOCKMUTEX(unlock_mutex)
+ self._C_Initialize_args = CK_C_INITIALIZE_ARGS(create_mutex, destroy_mutex, lock_mutex, unlock_mutex, flags, None)
+ self.so.C_Initialize(cast(byref(self._C_Initialize_args), CK_VOID_PTR))
def C_Finalize(self):
self.so.C_Finalize(None)
+ self._C_Initialize_args = None
def C_GetSlotList(self):
slots = (CK_SLOT_ID * 10)()
diff --git a/scripts/py11-test.py b/scripts/py11-test.py
index 8e189e3..a5e9c88 100644
--- a/scripts/py11-test.py
+++ b/scripts/py11-test.py
@@ -2,6 +2,7 @@
# doodles figuring out what else py11 should be automating for us.
from py11 import *
+from struct import pack, unpack
def show_token(i, t, strip = True):
print "Token in slot #%d:" % i
@@ -66,7 +67,76 @@ ec_curve_oid_p521 = "".join(chr(i) for i in (0x06, 0x05, 0x2b, 0x81, 0x04, 0x00,
p11 = PKCS11("./libpkcs11.so")
-p11.C_Initialize(CKF_OS_LOCKING_OK)
+if False:
+ print "Not using MUTEXes at all"
+ p11.C_Initialize()
+
+elif True:
+ print "Using OS MUTEXes"
+ p11.C_Initialize(CKF_OS_LOCKING_OK)
+
+else:
+ print "Using our own pseudo-MUTEXes"
+
+ # This class probably belongs in the library.
+
+ class Mutexes(object):
+
+ format = "=L"
+ length = len(pack(format, 0))
+
+ def __init__(self, verbose = True, flags = 0):
+ self.init_args = (flags, self.create, self.destroy, self.lock, self.unlock)
+ self.next_mutex = 0
+ self.mutexes = {}
+ self.verbose = verbose
+
+ def find(self):
+ if len(self.mutexes) > 0xFFFFFFFF:
+ raise RuntimeError
+ while self.next_mutex in self.mutexes:
+ self.next_mutex = (self.next_mutex + 1) & 0xFFFFFFFF
+
+ def encode(self, n):
+ return (CK_BYTE * self.length)(*pack(self.format, n))
+
+ def decode(self, m):
+ return unpack(self.format, m[:self.length])[0]
+
+ def create(self, mm):
+ self.find()
+ if self.verbose:
+ print "Creating mutex", self.next_mutex
+ m = self.encode(self.next_mutex)
+ self.mutexes[self.next_mutex] = [False, m]
+ mm[0] = m
+ return CKR_OK
+
+ def destroy(self, m):
+ mutex = self.decode(m)
+ if self.verbose:
+ print "Destroying mutex", mutex
+ del self.mutexes[mutex]
+ return CKR_OK
+
+ def lock(self, m):
+ mutex = self.decode(m)
+ if self.verbose:
+ print "Locking mutex", mutex
+ self.mutexes[mutex][0] = True
+ return CKR_OK
+
+ def unlock(self, m):
+ mutex = self.decode(m)
+ if self.verbose:
+ print "Unlocking mutex", mutex
+ self.mutexes[mutex][0] = False
+ return CKR_OK
+
+ mutexes = Mutexes()
+ p11.C_Initialize(*mutexes.init_args)
+
+# Dun with MUTEX insanit and C_Initialize() call
slots = p11.C_GetSlotList()