aboutsummaryrefslogtreecommitdiff
path: root/py11/__init__.py
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2015-09-11 08:57:19 -0400
committerRob Austein <sra@hactrn.net>2015-09-11 08:57:19 -0400
commit6613e3a06ec27bf4bf029b99cfbab1ffa251db15 (patch)
tree0f9b89eb09d76f3c4e7deec6ee6d8569c6a6db51 /py11/__init__.py
parentae7b3e1789a4ff96876ba09b18b5a07777a7d23b (diff)
First cut at Python interface to PKCS #11 using ctypes API.
Diffstat (limited to 'py11/__init__.py')
-rw-r--r--py11/__init__.py197
1 files changed, 197 insertions, 0 deletions
diff --git a/py11/__init__.py b/py11/__init__.py
new file mode 100644
index 0000000..d99c1b0
--- /dev/null
+++ b/py11/__init__.py
@@ -0,0 +1,197 @@
+# An attempt at a Python interface to PKCS 11 using the scary ctypes
+# module from the Python standard library.
+
+from struct import pack, unpack
+from ctypes import *
+from .exceptions import *
+from .types import *
+from .constants import *
+
+# Prototypes for the PKCS #11 public functions.
+#
+# We don't bother implementing C_GetFunctionList(), because it would
+# be extremely tedious and it's not all that useful to us in Python.
+# Instead, we emulate its behavior in the PKCS11 class.
+
+PKCS11_Prototypes = (
+ ("C_Initialize", [CK_VOID_PTR]),
+ ("C_Finalize", [CK_VOID_PTR]),
+ ("C_GetInfo", [CK_INFO_PTR]),
+# ("C_GetFunctionList", [CK_FUNCTION_LIST_PTR_PTR]),
+ ("C_GetSlotList", [CK_BBOOL, CK_SLOT_ID_PTR, CK_ULONG_PTR]),
+ ("C_GetSlotInfo", [CK_SLOT_ID, CK_SLOT_INFO_PTR]),
+ ("C_GetTokenInfo", [CK_SLOT_ID, CK_TOKEN_INFO_PTR]),
+ ("C_GetMechanismList", [CK_SLOT_ID, CK_MECHANISM_TYPE_PTR, CK_ULONG_PTR]),
+ ("C_GetMechanismInfo", [CK_SLOT_ID, CK_MECHANISM_TYPE, CK_MECHANISM_INFO_PTR]),
+ ("C_InitToken", [CK_SLOT_ID, CK_UTF8CHAR_PTR, CK_ULONG, CK_UTF8CHAR_PTR]),
+ ("C_InitPIN", [CK_SESSION_HANDLE, CK_UTF8CHAR_PTR, CK_ULONG]),
+ ("C_SetPIN", [CK_SESSION_HANDLE, CK_UTF8CHAR_PTR, CK_ULONG, CK_UTF8CHAR_PTR, CK_ULONG]),
+ ("C_OpenSession", [CK_SLOT_ID, CK_FLAGS, CK_VOID_PTR, CK_NOTIFY, CK_SESSION_HANDLE_PTR]),
+ ("C_CloseSession", [CK_SESSION_HANDLE]),
+ ("C_CloseAllSessions", [CK_SLOT_ID]),
+ ("C_GetSessionInfo", [CK_SESSION_HANDLE, CK_SESSION_INFO_PTR]),
+ ("C_GetOperationState", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_SetOperationState", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE]),
+ ("C_Login", [CK_SESSION_HANDLE, CK_USER_TYPE, CK_UTF8CHAR_PTR, CK_ULONG]),
+ ("C_Logout", [CK_SESSION_HANDLE]),
+ ("C_CreateObject", [CK_SESSION_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR]),
+ ("C_CopyObject", [CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR]),
+ ("C_DestroyObject", [CK_SESSION_HANDLE, CK_OBJECT_HANDLE]),
+ ("C_GetObjectSize", [CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ULONG_PTR]),
+ ("C_GetAttributeValue", [CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG]),
+ ("C_SetAttributeValue", [CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG]),
+ ("C_FindObjectsInit", [CK_SESSION_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG]),
+ ("C_FindObjects", [CK_SESSION_HANDLE, CK_OBJECT_HANDLE_PTR, CK_ULONG, CK_ULONG_PTR]),
+ ("C_FindObjectsFinal", [CK_SESSION_HANDLE]),
+ ("C_EncryptInit", [CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE]),
+ ("C_Encrypt", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_EncryptUpdate", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_EncryptFinal", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_DecryptInit", [CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE]),
+ ("C_Decrypt", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_DecryptUpdate", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_DecryptFinal", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_DigestInit", [CK_SESSION_HANDLE, CK_MECHANISM_PTR]),
+ ("C_Digest", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_DigestUpdate", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG]),
+ ("C_DigestKey", [CK_SESSION_HANDLE, CK_OBJECT_HANDLE]),
+ ("C_DigestFinal", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_SignInit", [CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE]),
+ ("C_Sign", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_SignUpdate", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG]),
+ ("C_SignFinal", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_SignRecoverInit", [CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE]),
+ ("C_SignRecover", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_VerifyInit", [CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE]),
+ ("C_Verify", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG]),
+ ("C_VerifyUpdate", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG]),
+ ("C_VerifyFinal", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG]),
+ ("C_VerifyRecoverInit", [CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE]),
+ ("C_VerifyRecover", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_DigestEncryptUpdate", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_DecryptDigestUpdate", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_SignEncryptUpdate", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_DecryptVerifyUpdate", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_GenerateKey", [CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR]),
+ ("C_GenerateKeyPair", [CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG,
+ CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR, CK_OBJECT_HANDLE_PTR]),
+ ("C_WrapKey", [CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE,
+ CK_BYTE_PTR, CK_ULONG_PTR]),
+ ("C_UnwrapKey", [CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG,
+ CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR]),
+ ("C_DeriveKey", [CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG,
+ CK_OBJECT_HANDLE_PTR]),
+ ("C_SeedRandom", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG]),
+ ("C_GenerateRandom", [CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG]),
+ ("C_GetFunctionStatus", [CK_SESSION_HANDLE]),
+ ("C_CancelFunction", [CK_SESSION_HANDLE]),
+ ("C_WaitForSlotEvent", [CK_FLAGS, CK_SLOT_ID_PTR, CK_VOID_PTR]))
+
+
+# Need to convert attributes between a sane Pythonic representation
+# and something ctypes can handle. Pythoninc representation would be
+# an iteraable of two element sequences, or perhaps a dict.
+
+def attributes_to_ctypes(dict_or_iterable):
+ if isinstance(dict_or_iterable, dict):
+ dict_or_iterable = dict_or_iterable.iteritems()
+ items = tuple(dict_or_iterable)
+ a = (CK_ATTRIBUTE * len(items))()
+ for i, kv in enumerate(items):
+ k, v = kv
+ if isinstance(v, bool):
+ v = pack("B", int(v))
+ elif isinstance(v, (int, long)):
+ v = pack("L", v)
+ a[i].type = k
+ a[i].pValue = create_string_buffer(v)
+ a[i].ulValueLen = len(v)
+ return a
+
+class PKCS11 (object):
+
+ def __init__(self, so_name = "libpkcs11.so"):
+ self.so_name = so_name
+ self.so = CDLL(so_name)
+ def raise_on_failure(rv):
+ if rv != CKR_OK:
+ raise CKR_Exception.ckr_map[rv]
+ for name, args in PKCS11_Prototypes:
+ func = getattr(self.so, name)
+ func.restype = raise_on_failure
+ func.argtypes = args
+
+ def __getattr__(self, name):
+ return getattr(self.so, name)
+
+ def C_GetFunctionList(self):
+ return self
+
+ @property
+ def version(self):
+ info = CK_INFO()
+ self.so.C_GetInfo(byref(info))
+ return info.cryptokiVersion
+
+ def C_Initialize(self):
+ self.so.C_Initialize(None)
+
+ def C_Finalize(self):
+ self.so.C_Finalize(None)
+
+ def C_GetSlotList(self):
+ slots = (CK_SLOT_ID * 10)()
+ count = CK_ULONG(len(slots))
+ self.so.C_GetSlotList(CK_TRUE, slots, byref(count))
+ return [slots[i] for i in xrange(count.value)]
+
+ def C_GetTokenInfo(self, slot_id):
+ token_info = CK_TOKEN_INFO()
+ self.so.C_GetTokenInfo(slot_id, byref(token_info))
+ return token_info
+
+ def C_OpenSession(self, slot, flags = CKF_SERIAL_SESSION | CKF_RW_SESSION, application = None, notify = CK_NOTIFY()):
+ handle = CK_SESSION_HANDLE()
+ self.so.C_OpenSession(slot, flags, application, notify, byref(handle))
+ return handle.value
+
+ def C_GenerateRandom(self, session, n):
+ buffer = create_string_buffer(n)
+ self.so.C_GenerateRandom(session, buffer, sizeof(buffer))
+ return buffer.raw
+
+ def C_Login(self, session, user, pin):
+ self.so.C_Login(session, user, pin, len(pin))
+
+ def C_GetAttributeValue(self, session_handle, object_handle, attributes):
+ if not isinstance(attributes, (list, tuple)):
+ attributes = tuple(attributes)
+ if not all(isinstance(a, (int, long)) for a in attributes):
+ raise TypeError
+ t = (CK_ATTRIBUTE * len(attributes))()
+ for i in xrange(len(attributes)):
+ t[i].type = attributes[i]
+ t[i].pValue = None
+ t[i].ulValueLen = 0
+ self.so.C_GetAttributeValue(session_handle, object_handle, byref(t), len(t))
+ for a in t:
+ a.pValue = create_string_buffer(a.ulValueLen)
+ self.so.C_GetAttributeValue(session_handle, object_handle, byref(t), len(t))
+ return dict((a.type, a.pValue.raw) for a in t)
+
+ def C_GenerateKeyPair(self, session, mechanism_type, public_template, private_template):
+ mechanism = CK_MECHANISM(mechanism_type, None, 0)
+ public_template = attributes_to_ctypes(public_template)
+ private_template = attributes_to_ctypes(private_template)
+ public_handle = CK_OBJECT_HANDLE()
+ private_handle = CK_OBJECT_HANDLE()
+ self.so.C_GenerateKeyPair(session, byref(mechanism),
+ public_template, len(public_template),
+ private_template, len(private_template),
+ byref(public_handle), byref(private_handle))
+ return public_handle.value, private_handle.value
+
+__all__ = ["PKCS11"]
+__all__.extend(name for name in globals()
+ if name.startswith("CK")
+ or name.startswith("CRYPTOKI_"))