# 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 binascii import hexlify, unhexlify
from ctypes import *
from .types import *
from .constants import *
class Attribute(object):
@classmethod
def new(cls, attribute_name, type_name):
from . import constants
from . import types
assert attribute_name.startswith("CKA_")
attribute_number = getattr(constants, attribute_name)
type_class = getattr(types, type_name, bytes)
if type_class is CK_BBOOL:
cls = Attribute_CK_BBOOL
elif type_class is CK_ULONG:
cls = Attribute_CK_ULONG
elif type_name == "biginteger":
cls = Attribute_biginteger
return cls(attribute_name, attribute_number, type_name, type_class)
def __init__(self, attribute_name, attribute_number, type_name, type_class):
assert attribute_name.startswith("CKA_")
self.name = attribute_name
self.code = attribute_number
self.type_name = type_name
self.type_class = type_class
def encode(self, x): return x
def decode(self, x): return x
class Attribute_CK_BBOOL(Attribute):
def encode(self, x): return pack("B", int(x))
def decode(self, x): return bool(unpack("B", x)[0])
class Attribute_CK_ULONG(Attribute):
def encode(self, x): return pack("L", x)
def decode(self, x): return unpack("L", x)[0]
class Attribute_biginteger(Attribute):
def encode(self, x): return "\x00" if x == 0 else unhexlify("{0:0{1}x}".format(x, ((x.bit_length() + 7) // 8) * 2))
def decode(self, x): return int(hexlify(x), 16)
class AttributeDB(object):
def __init__(self):
from .attribute_map import attribute_map
self.db = {}
for attribute_name, type_name in attribute_map.items():
a = Attribute.new(attribute_name, type_name)
self.db[a.name] = a
self.db[a.code] = a
def encode(self, k, v):
return self.db[k].encode(v) if k in self.db else v
def decode(self, k, v):
return self.db[k].decode(v) if k in self.db else v
def getvalue_create_template(self, attributes):
attributes = tuple(self.db[a].code for a in attributes)
template = (CK_ATTRIBUTE * len(attributes))()
for i in range(len(attributes)):
template[i].type = attributes[i]
template[i].pValue = None
template[i].ulValueLen = 0
return template
def getvalue_allocate_template(self, template):
for t in template:
t.pValue = create_string_buffer(t.ulValueLen)
def from_ctypes(self, template):
return dict((t.type, self.decode(t.type, t.pValue[:t.ulValueLen]))
for t in template)
def to_ctypes(self, attributes):
if isinstance(attributes, dict):
attributes = tuple(iter(attributes.items()))
else:
attributes = tuple(attributes)
template = (CK_ATTRIBUTE * len(attributes))()
for i, kv in enumerate(attributes):
k, v = kv
if k in self.db:
a = self.db[k]
k, v = a.code, a.encode(v)
template[i].type = k
template[i].pValue = create_string_buffer(v)
template[i].ulValueLen = len(v)
return template
def attribute_name(self, code):
return self.db[code].name
def attribute_code(self, name):
return self.db[name].code