aboutsummaryrefslogblamecommitdiff
path: root/cryptech/py11/attributes.py
blob: 035677c5990b6e7994d65089a118845f7a7fb7ea (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11



                                                                    
                                         





                        





                                                             
                                                     
















                                                                                

                                    

                                                       

                                    

                                                 

                                      
                                                                                                                       
                                                   



                          



















































                                                                          
# 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