diff options
Diffstat (limited to 'cryptech/py11/mutex.py')
-rw-r--r-- | cryptech/py11/mutex.py | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/cryptech/py11/mutex.py b/cryptech/py11/mutex.py new file mode 100644 index 0000000..da2123c --- /dev/null +++ b/cryptech/py11/mutex.py @@ -0,0 +1,89 @@ +""" +Optional Python mutex implementation for cryptech.py11 library, +using the threading.Lock primitive to provide the mutex itself. + +Most of the code in this module has to do with mapping between the +Python and PKCS #11 APIs. + +If you just want locking, it's probably simpler to let the C code +handle it, by passing CKF_OS_LOCKING_OK to C_Initialize(). + +The main reason for having a complete implementation in Python is to +test the API. + +Sample usage: + + from cryptech.py11 import * + from cryptech.py11.mutex import MutexDB + + p11 = PKCS11() + mdb = MutexDB() + p11.C_Initialize(0, mdb.create, mdb.destroy, mdb.lock, mdb.unlock) + +""" + +from struct import pack, unpack +from .types import * +from .exceptions import * + +# This controls how big our mutex handles are. +encoded_format = "=L" + +# These are all determined by encoded_format, don't touch. + +encoded_length = len(pack(encoded_format, 0)) +encoded_type = CK_BYTE * encoded_length +handle_max = unpack(encoded_format, chr(0xff) * encoded_length)[0] + +class Mutex(object): + + def __init__(self, handle): + from threading import Lock + self.encoded = encoded_type(*handle) + self.lock = Lock() + +def p11_callback(func): + from threading import ThreadError + def wrapper(self, arg): + try: + func(self, arg) + except ThreadError, e: + print "Failed: %s" % e + return CKR_MUTEX_NOT_LOCKED.ckr_code + except Exception, e: + print "Failed: %s" % e + return CKR_FUNCTION_FAILED.ckr_code + else: + return CKR_OK + return wrapper + +class MutexDB(object): + + def __init__(self): + self.mutexes = {} + self.next_handle = 0 + + def find_free_handle(self): + if len(self.mutexes) > handle_max: + raise RuntimeError + while self.next_handle in self.mutexes: + self.next_handle = (self.next_handle + 1) & handle_max + return pack(encoded_format, self.next_handle) + + @p11_callback + def create(self, handle_ptr): + handle = self.find_free_handle() + self.mutexes[handle] = Mutex(handle) + handle_ptr[0] = self.mutexes[handle].encoded + + @p11_callback + def destroy(self, handle): + del self.mutexes[handle[:encoded_length]] + + @p11_callback + def lock(self, handle): + self.mutexes[handle[:encoded_length]].lock.acquire() + + @p11_callback + def unlock(self, handle): + self.mutexes[handle[:encoded_length]].lock.release() |