[Cryptech-Commits] [sw/pkcs11] 02/02: MUTEX callbacks via ctypes. Beware of Garbage Collector.

git at cryptech.is git at cryptech.is
Fri Sep 18 05:43:46 UTC 2015


This is an automated email from the git hooks/post-receive script.

sra at hactrn.net pushed a commit to branch ecdsa
in repository sw/pkcs11.

commit ec3be7d441b7bc1888186c05db6e6b46abe63879
Author: Rob Austein <sra at hactrn.net>
Date:   Fri Sep 18 01:38:53 2015 -0400

    MUTEX callbacks via ctypes.  Beware of Garbage Collector.
---
 py11/__init__.py     | 33 ++++++++++++++----------
 scripts/py11-test.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 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()
 



More information about the Commits mailing list