diff options
author | Rob Austein <sra@hactrn.net> | 2015-09-12 00:40:01 -0400 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2015-09-12 00:40:01 -0400 |
commit | d4dd9a8becf0c8f28479f0e48cc7f6708f786ee4 (patch) | |
tree | fdf0aa499feba5f9ade16392001c092ed350923e /py11/attributes.py | |
parent | 85ae5390f4511f0bfe4b56179d5583a4997d504d (diff) |
Add attribute database based on attributes.yaml.
Simplify prototype definitions and move them to separate module.
Diffstat (limited to 'py11/attributes.py')
-rw-r--r-- | py11/attributes.py | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/py11/attributes.py b/py11/attributes.py new file mode 100644 index 0000000..00af79c --- /dev/null +++ b/py11/attributes.py @@ -0,0 +1,105 @@ +# 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 .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, str) + 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 chr(int(x)) + def decode(self, x): return bool(ord(x)) + +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 ("%*x" % (((x.bit_length() + 7) / 8) * 2, x)).decode("hex") + def decode(self, x): return long(x.encode("hex"), 16) + + +class AttributeDB(object): + + def __init__(self, initializer = None): + self.db = {} + if isinstance(initializer, str): + initializer = self.parse_yaml(initializer) + for attribute_name, type_name in initializer: + a = Attribute.new(attribute_name, type_name) + self.db[a.name] = a + self.db[a.code] = a + + @staticmethod + def parse_yaml(yaml_filename): + from yaml import safe_load + with open(yaml_filename) as f: + for y in safe_load(f): + for k, v in y.iteritems(): + if k.startswith("CKA_") and "type" in v: + yield k, v["type"] + + 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 xrange(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): + attributes = tuple(attributes.iteritems() + if isinstance(attributes, dict) else + 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 |