• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

LudovicRousseau / PyKCS11 / 12855062003

19 Jan 2025 03:58PM UTC coverage: 86.686% (-0.5%) from 87.2%
12855062003

push

github

web-flow
Merge pull request #128 from fuzzykat/feature/ckm_extract_key_from_key

add CKM_EXTRACT_KEY_FROM_KEY mechanism

6 of 24 new or added lines in 2 files covered. (25.0%)

16 existing lines in 1 file now uncovered.

2995 of 3455 relevant lines covered (86.69%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.62
/PyKCS11/__init__.py
1
#   Copyright (C) 2006-2015 Ludovic Rousseau (ludovic.rousseau@free.fr)
2
#   Copyright (C) 2010 Giuseppe Amato (additions to original interface)
3
#
4
# This file is free software; you can redistribute it and/or modify it
5
# under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful, but
10
# WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
# General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
17

18
from __future__ import print_function
1✔
19

20
import PyKCS11.LowLevel
1✔
21
import os
1✔
22
import sys
1✔
23

24

25
# redefine PKCS#11 constants
26
CK_TRUE = PyKCS11.LowLevel.CK_TRUE
1✔
27
CK_FALSE = PyKCS11.LowLevel.CK_FALSE
1✔
28
CK_UNAVAILABLE_INFORMATION = PyKCS11.LowLevel.CK_UNAVAILABLE_INFORMATION
1✔
29
CK_EFFECTIVELY_INFINITE = PyKCS11.LowLevel.CK_EFFECTIVELY_INFINITE
1✔
30
CK_INVALID_HANDLE = PyKCS11.LowLevel.CK_INVALID_HANDLE
1✔
31

32
CKA = {}
1✔
33
CKC = {}
1✔
34
CKD = {}
1✔
35
CKF = {}
1✔
36
CKG = {}
1✔
37
CKH = {}
1✔
38
CKK = {}
1✔
39
CKM = {}
1✔
40
CKO = {}
1✔
41
CKR = {}
1✔
42
CKS = {}
1✔
43
CKU = {}
1✔
44
CKZ = {}
1✔
45

46
# redefine PKCS#11 constants using well known prefixes
47
for x in PyKCS11.LowLevel.__dict__.keys():
1✔
48
    if x[:4] == 'CKA_' \
1✔
49
      or x[:4] == 'CKC_' \
50
      or x[:4] == 'CKD_' \
51
      or x[:4] == 'CKF_' \
52
      or x[:4] == 'CKG_' \
53
      or x[:4] == 'CKH_' \
54
      or x[:4] == 'CKK_' \
55
      or x[:4] == 'CKM_' \
56
      or x[:4] == 'CKO_' \
57
      or x[:4] == 'CKR_' \
58
      or x[:4] == 'CKS_' \
59
      or x[:4] == 'CKU_' \
60
      or x[:4] == 'CKZ_':
61
        a = "{}=PyKCS11.LowLevel.{}".format(x, x)
1✔
62
        exec(a)
1✔
63
        if x[3:] != "_VENDOR_DEFINED":
1✔
64
            eval(x[:3])[eval(x)] = x  # => CKM[CKM_RSA_PKCS] = 'CKM_RSA_PKCS'
1✔
65
            eval(x[:3])[x] = eval(x)  # => CKM['CKM_RSA_PKCS'] = CKM_RSA_PKCS
1✔
66

67
# special CKR[] values
68
CKR[-4] = "C_GetFunctionList() not found"
1✔
69
CKR[-3] = "Unknown format"
1✔
70
CKR[-2] = "Unkown PKCS#11 type"
1✔
71
CKR[-1] = "Load"
1✔
72

73

74
class ckbytelist(PyKCS11.LowLevel.ckbytelist):
1✔
75
    """
76
    add a __repr__() method to the LowLevel equivalent
77
    """
78

79
    def __init__(self, data=None):
1✔
80
        if data is None:
1✔
81
            data = 0
1✔
82
        elif isinstance(data, str):
1✔
83
            data = data.encode("utf-8")
1✔
84
        elif isinstance(data, (bytes, list, ckbytelist)):
1✔
85
            data = bytes(data)
1✔
86
        else:
87
            raise PyKCS11.PyKCS11Error(-3, text=str(type(data)))
1✔
88
        super(ckbytelist, self).__init__(data)
1✔
89

90

91
    def __repr__(self):
1✔
92
        """
93
        return the representation of a tuple
94
        the __str__ method will use it also
95
        """
96
        rep = [int(elt) for elt in self]
1✔
97
        return repr(rep)
1✔
98

99

100
class CK_OBJECT_HANDLE(PyKCS11.LowLevel.CK_OBJECT_HANDLE):
1✔
101
    """
102
    add a __repr__() method to the LowLevel equivalent
103
    """
104

105
    def __init__(self, session):
1✔
106
        PyKCS11.LowLevel.CK_OBJECT_HANDLE.__init__(self)
1✔
107
        self.session = session
1✔
108
        pass
1✔
109

110
    def to_dict(self):
1✔
111
        """
112
        convert the fields of the object into a dictionnary
113
        """
114
        # all the attibutes defined by PKCS#11
115
        all_attributes = PyKCS11.CKA.keys()
1✔
116

117
        # only use the integer values and not the strings like 'CKM_RSA_PKCS'
118
        all_attributes = [attr for attr in all_attributes if
1✔
119
                          isinstance(attr, int)]
120

121
        # all the attributes of the object
122
        attributes = self.session.getAttributeValue(self, all_attributes)
1✔
123

124
        dico = dict()
1✔
125
        for key, attr in zip(all_attributes, attributes):
1✔
126
            if attr is None:
1✔
127
                continue
1✔
128
            if key == CKA_CLASS:
1✔
129
                dico[PyKCS11.CKA[key]] = PyKCS11.CKO[attr]
1✔
130
            elif key == CKA_CERTIFICATE_TYPE:
1✔
131
                dico[PyKCS11.CKA[key]] = PyKCS11.CKC[attr]
×
132
            elif key == CKA_KEY_TYPE:
1✔
133
                dico[PyKCS11.CKA[key]] = PyKCS11.CKK[attr]
1✔
134
            else:
135
                dico[PyKCS11.CKA[key]] = attr
1✔
136
        return dico
1✔
137

138
    def __repr__(self):
1✔
139
        """
140
        text representation of the object
141
        """
142
        dico = self.to_dict()
1✔
143
        lines = list()
1✔
144
        for key in sorted(dico.keys()):
1✔
145
            lines.append("{}: {}".format(key, dico[key]))
1✔
146
        return "\n".join(lines)
1✔
147

148

149
class CkClass(object):
1✔
150
    """
151
    Base class for CK_* classes
152
    """
153

154
    # dictionnary of integer_value: text_value for the flags bits
155
    flags_dict = dict()
1✔
156

157
    # dictionnary of fields names and types
158
    # type can be "pair", "flags" or "text"
159
    fields = dict()
1✔
160

161
    flags = 0
1✔
162

163
    def flags2text(self):
1✔
164
        """
165
        parse the `self.flags` field and create a list of `CKF_*` strings
166
        corresponding to bits set in flags
167

168
        :return: a list of strings
169
        :rtype: list
170
        """
171
        r = []
1✔
172
        for v in self.flags_dict.keys():
1✔
173
            if self.flags & v:
1✔
174
                r.append(self.flags_dict[v])
1✔
175
        return r
1✔
176

177
    def to_dict(self):
1✔
178
        """
179
        convert the fields of the object into a dictionnary
180
        """
181
        dico = dict()
1✔
182
        for field in self.fields.keys():
1✔
183
            if field == "flags":
1✔
184
                dico[field] = self.flags2text()
1✔
185
            elif field == "state":
1✔
186
                dico[field] = self.state2text()
1✔
187
            else:
188
                dico[field] = eval("self." + field)
1✔
189
        return dico
1✔
190

191
    def __str__(self):
1✔
192
        """
193
        text representation of the object
194
        """
195
        dico = self.to_dict()
1✔
196
        lines = list()
1✔
197
        for key in sorted(dico.keys()):
1✔
198
            type = self.fields[key]
1✔
199
            if type == "flags":
1✔
200
                lines.append("{}: {}".format(key, ", ".join(dico[key])))
1✔
201
            elif type == "pair":
1✔
202
                lines.append("%s: " % key + "%d.%d" % dico[key])
1✔
203
            else:
204
                lines.append("{}: {}".format(key, dico[key]))
1✔
205
        return "\n".join(lines)
1✔
206

207

208
class CK_SLOT_INFO(CkClass):
1✔
209
    """
210
    matches the PKCS#11 CK_SLOT_INFO structure
211

212
    :ivar slotDescription: blank padded
213
    :type slotDescription: string
214
    :ivar manufacturerID: blank padded
215
    :type manufacturerID: string
216
    :ivar flags: See :func:`CkClass.flags2text`
217
    :type flags: integer
218
    :ivar hardwareVersion: 2 elements list
219
    :type hardwareVersion: list
220
    :ivar firmwareVersion: 2 elements list
221
    :type firmwareVersion: list
222
    """
223

224
    flags_dict = {
1✔
225
        CKF_TOKEN_PRESENT: "CKF_TOKEN_PRESENT",
226
        CKF_REMOVABLE_DEVICE: "CKF_REMOVABLE_DEVICE",
227
        CKF_HW_SLOT: "CKF_HW_SLOT"}
228

229
    fields = {"slotDescription": "text",
1✔
230
              "manufacturerID": "text",
231
              "flags": "flags",
232
              "hardwareVersion": "text",
233
              "firmwareVersion": "text"}
234

235

236
class CK_INFO(CkClass):
1✔
237
    """
238
    matches the PKCS#11 CK_INFO structure
239

240
    :ivar cryptokiVersion: Cryptoki interface version
241
    :type cryptokiVersion: integer
242
    :ivar manufacturerID: blank padded
243
    :type manufacturerID: string
244
    :ivar flags: must be zero
245
    :type flags: integer
246
    :ivar libraryDescription: blank padded
247
    :type libraryDescription: string
248
    :var libraryVersion: 2 elements list
249
    :type libraryVersion: list
250
    """
251

252
    fields = {"cryptokiVersion": "pair",
1✔
253
              "manufacturerID": "text",
254
              "flags": "flags",
255
              "libraryDescription": "text",
256
              "libraryVersion": "pair"}
257

258

259
class CK_SESSION_INFO(CkClass):
1✔
260
    """
261
    matches the PKCS#11 CK_SESSION_INFO structure
262

263
    :ivar slotID: ID of the slot that interfaces with the token
264
    :type slotID: integer
265
    :ivar state: state of the session
266
    :type state: integer
267
    :ivar flags: bit flags that define the type of session
268
    :type flags: integer
269
    :ivar ulDeviceError: an error code defined by the cryptographic token
270
    :type ulDeviceError: integer
271
    """
272

273
    flags_dict = {
1✔
274
        CKF_RW_SESSION: "CKF_RW_SESSION",
275
        CKF_SERIAL_SESSION: "CKF_SERIAL_SESSION",
276
    }
277

278
    def state2text(self):
1✔
279
        """
280
        parse the `self.state` field and return a `CKS_*` string
281
        corresponding to the state
282

283
        :return: a string
284
        :rtype: string
285
        """
286
        return CKS[self.state]
1✔
287

288
    fields = {"slotID": "text",
1✔
289
              "state": "text",
290
              "flags": "flags",
291
              "ulDeviceError": "text"}
292

293

294
class CK_TOKEN_INFO(CkClass):
1✔
295
    """
296
    matches the PKCS#11 CK_TOKEN_INFO structure
297

298
    :ivar label: blank padded
299
    :type label: string
300
    :ivar manufacturerID: blank padded
301
    :type manufacturerID: string
302
    :ivar model: string blank padded
303
    :type model: string
304
    :ivar serialNumber: string blank padded
305
    :type serialNumber: string
306
    :ivar flags:
307
    :type flags: integer
308
    :ivar ulMaxSessionCount:
309
    :type ulMaxSessionCount: integer
310
    :ivar ulSessionCount:
311
    :type ulSessionCount: integer
312
    :ivar ulMaxRwSessionCount:
313
    :type ulMaxRwSessionCount: integer
314
    :ivar ulRwSessionCount:
315
    :type ulRwSessionCount: integer
316
    :ivar ulMaxPinLen:
317
    :type ulMaxPinLen: integer
318
    :ivar ulMinPinLen:
319
    :type ulMinPinLen: integer
320
    :ivar ulTotalPublicMemory:
321
    :type ulTotalPublicMemory: integer
322
    :ivar ulFreePublicMemory:
323
    :type ulFreePublicMemory: integer
324
    :ivar ulTotalPrivateMemory:
325
    :type ulTotalPrivateMemory: integer
326
    :ivar ulFreePrivateMemory:
327
    :type ulFreePrivateMemory: integer
328
    :ivar hardwareVersion: 2 elements list
329
    :type hardwareVersion: list
330
    :ivar firmwareVersion: 2 elements list
331
    :type firmwareVersion: list
332
    :ivar utcTime: string
333
    :type utcTime: string
334
    """
335

336
    flags_dict = {
1✔
337
        CKF_RNG: "CKF_RNG",
338
        CKF_WRITE_PROTECTED: "CKF_WRITE_PROTECTED",
339
        CKF_LOGIN_REQUIRED: "CKF_LOGIN_REQUIRED",
340
        CKF_USER_PIN_INITIALIZED: "CKF_USER_PIN_INITIALIZED",
341
        CKF_RESTORE_KEY_NOT_NEEDED: "CKF_RESTORE_KEY_NOT_NEEDED",
342
        CKF_CLOCK_ON_TOKEN: "CKF_CLOCK_ON_TOKEN",
343
        CKF_PROTECTED_AUTHENTICATION_PATH: "CKF_PROTECTED_AUTHENTICATION_PATH",
344
        CKF_DUAL_CRYPTO_OPERATIONS: "CKF_DUAL_CRYPTO_OPERATIONS",
345
        CKF_TOKEN_INITIALIZED: "CKF_TOKEN_INITIALIZED",
346
        CKF_SECONDARY_AUTHENTICATION: "CKF_SECONDARY_AUTHENTICATION",
347
        CKF_USER_PIN_COUNT_LOW: "CKF_USER_PIN_COUNT_LOW",
348
        CKF_USER_PIN_FINAL_TRY: "CKF_USER_PIN_FINAL_TRY",
349
        CKF_USER_PIN_LOCKED: "CKF_USER_PIN_LOCKED",
350
        CKF_USER_PIN_TO_BE_CHANGED: "CKF_USER_PIN_TO_BE_CHANGED",
351
        CKF_SO_PIN_COUNT_LOW: "CKF_SO_PIN_COUNT_LOW",
352
        CKF_SO_PIN_FINAL_TRY: "CKF_SO_PIN_FINAL_TRY",
353
        CKF_SO_PIN_LOCKED: "CKF_SO_PIN_LOCKED",
354
        CKF_SO_PIN_TO_BE_CHANGED: "CKF_SO_PIN_TO_BE_CHANGED",
355
    }
356

357
    fields = {"label": "text",
1✔
358
              "manufacturerID": "text",
359
              "model": "text",
360
              "serialNumber": "text",
361
              "flags": "flags",
362
              "ulMaxSessionCount": "text",
363
              "ulSessionCount": "text",
364
              "ulMaxRwSessionCount": "text",
365
              "ulRwSessionCount": "text",
366
              "ulMaxPinLen": "text",
367
              "ulMinPinLen": "text",
368
              "ulTotalPublicMemory": "text",
369
              "ulFreePublicMemory": "text",
370
              "ulTotalPrivateMemory": "text",
371
              "ulFreePrivateMemory": "text",
372
              "hardwareVersion": "pair",
373
              "firmwareVersion": "pair",
374
              "utcTime": "text"}
375

376

377
class CK_MECHANISM_INFO(CkClass):
1✔
378
    """
379
    matches the PKCS#11 CK_MECHANISM_INFO structure
380

381
    :ivar ulMinKeySize: minimum size of the key
382
    :type ulMinKeySize: integer
383
    :ivar ulMaxKeySize: maximum size of the key
384
    :type ulMaxKeySize: integer
385
    :ivar flags: bit flags specifying mechanism capabilities
386
    :type flags: integer
387
    """
388

389
    flags_dict = {
1✔
390
        CKF_HW: "CKF_HW",
391
        CKF_ENCRYPT: "CKF_ENCRYPT",
392
        CKF_DECRYPT: "CKF_DECRYPT",
393
        CKF_DIGEST: "CKF_DIGEST",
394
        CKF_SIGN: "CKF_SIGN",
395
        CKF_SIGN_RECOVER: "CKF_SIGN_RECOVER",
396
        CKF_VERIFY: "CKF_VERIFY",
397
        CKF_VERIFY_RECOVER: "CKF_VERIFY_RECOVER",
398
        CKF_GENERATE: "CKF_GENERATE",
399
        CKF_GENERATE_KEY_PAIR: "CKF_GENERATE_KEY_PAIR",
400
        CKF_WRAP: "CKF_WRAP",
401
        CKF_UNWRAP: "CKF_UNWRAP",
402
        CKF_DERIVE: "CKF_DERIVE",
403
        CKF_EXTENSION: "CKF_EXTENSION",
404
    }
405

406
    fields = {"ulMinKeySize": "text",
1✔
407
              "ulMaxKeySize": "text",
408
              "flags": "flags"}
409

410

411
class PyKCS11Error(Exception):
1✔
412
    """ define the possible PyKCS11 exceptions """
413

414
    def __init__(self, value, text=""):
1✔
415
        self.value = value
1✔
416
        self.text = text
1✔
417

418
    def __str__(self):
1✔
419
        """
420
        The text representation of a PKCS#11 error is something like:
421
        "CKR_DEVICE_ERROR (0x00000030)"
422
        """
423
        if self.value in CKR:
1✔
424
            if self.value < 0:
1✔
425
                return CKR[self.value] + " (%s)" % self.text
1✔
426
            else:
427
                return CKR[self.value] + " (0x%08X)" % self.value
1✔
428
        elif self.value & CKR_VENDOR_DEFINED:
1✔
429
            return "Vendor error (0x%08X)" % (self.value & 0xffffffff & ~CKR_VENDOR_DEFINED)
1✔
430
        else:
431
            return "Unknown error (0x%08X)" % self.value
1✔
432

433

434
class PyKCS11Lib(object):
1✔
435
    """ high level PKCS#11 binding """
436

437
    # shared by all instances
438
    _loaded_libs = dict()
1✔
439

440
    def __init__(self):
1✔
441
        self.lib = PyKCS11.LowLevel.CPKCS11Lib()
1✔
442

443
    def __del__(self):
1✔
444
        if PyKCS11 and PyKCS11.__name__ and \
1✔
445
                PyKCS11.LowLevel and PyKCS11.LowLevel.__name__ and \
446
                PyKCS11.LowLevel._LowLevel and \
447
                PyKCS11.LowLevel._LowLevel.__name__:
448

449
            # unload the library
450
            self.unload()
1✔
451

452
    def load(self, pkcs11dll_filename=None, *init_string):
1✔
453
        """
454
        load a PKCS#11 library
455

456
        :type pkcs11dll_filename: string
457
        :param pkcs11dll_filename: the library name.
458
          If this parameter is not set then the environment variable
459
          `PYKCS11LIB` is used instead
460
        :returns: a :class:`PyKCS11Lib` object
461
        :raises: :class:`PyKCS11Error` (-1): when the load fails
462
        """
463
        if pkcs11dll_filename is None:
1✔
464
            pkcs11dll_filename = os.getenv("PYKCS11LIB")
1✔
465
            if pkcs11dll_filename is None:
1✔
466
                raise PyKCS11Error(-1, "No PKCS11 library specified (set PYKCS11LIB env variable)")
×
467

468
        if hasattr(self, "pkcs11dll_filename"):
1✔
469
            self.unload() # unload the previous library
1✔
470
            # if the instance was previously initialized,
471
            # create a new low level library object for it
472
            self.lib = PyKCS11.LowLevel.CPKCS11Lib()
1✔
473

474
        # if the lib is already in use: reuse it
475
        if pkcs11dll_filename in PyKCS11Lib._loaded_libs:
1✔
476
            self.lib.Duplicate(PyKCS11Lib._loaded_libs[pkcs11dll_filename]["ref"])
1✔
477
        else:
478
            # else load it
479
            rv = self.lib.Load(pkcs11dll_filename)
1✔
480
            if rv != CKR_OK:
1✔
481
                raise PyKCS11Error(rv, pkcs11dll_filename)
1✔
482
            PyKCS11Lib._loaded_libs[pkcs11dll_filename] = {
1✔
483
                    "ref": self.lib,
484
                    "nb_users": 0
485
                    }
486

487
        # remember the lib file name
488
        self.pkcs11dll_filename = pkcs11dll_filename
1✔
489

490
        # increase user number
491
        PyKCS11Lib._loaded_libs[pkcs11dll_filename]["nb_users"] += 1
1✔
492

493
        return self
1✔
494

495
    def unload(self):
1✔
496
        """
497
        unload the current instance of a PKCS#11 library
498
        """
499

500
        # in case NO library was found and used
501
        if not hasattr(self, "pkcs11dll_filename"):
1✔
502
            return
1✔
503

504
        if self.pkcs11dll_filename not in PyKCS11Lib._loaded_libs:
1✔
505
            raise PyKCS11Error(PyKCS11.LowLevel.CKR_GENERAL_ERROR,
×
506
                               "invalid PyKCS11Lib state")
507

508
        # decrease user number
509
        PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]["nb_users"] -= 1
1✔
510

511
        if PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]["nb_users"] == 0:
1✔
512
            # unload only if no more used
513
            self.lib.Unload()
1✔
514

515
        # remove unused entry
516
        # the case < 0 happens if lib loading failed
517
        if PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]["nb_users"] <= 0:
1✔
518
            del PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]
1✔
519

520
        delattr(self, "pkcs11dll_filename")
1✔
521

522
    def initToken(self, slot, pin, label):
1✔
523
        """
524
        C_InitToken
525

526
        :param slot: slot number returned by :func:`getSlotList`
527
        :type slot: integer
528
        :param pin: Security Officer's initial PIN
529
        :param label: new label of the token
530
        """
531
        pin1 = ckbytelist(pin)
1✔
532
        rv = self.lib.C_InitToken(slot, pin1, label)
1✔
533
        if rv != CKR_OK:
1✔
534
            raise PyKCS11Error(rv)
×
535

536
    def getInfo(self):
1✔
537
        """
538
        C_GetInfo
539

540
        :return: a :class:`CK_INFO` object
541
        """
542
        info = PyKCS11.LowLevel.CK_INFO()
1✔
543
        rv = self.lib.C_GetInfo(info)
1✔
544
        if rv != CKR_OK:
1✔
545
            raise PyKCS11Error(rv)
×
546

547
        i = CK_INFO()
1✔
548
        i.cryptokiVersion = (info.cryptokiVersion.major,
1✔
549
                             info.cryptokiVersion.minor)
550
        i.manufacturerID = info.GetManufacturerID()
1✔
551
        i.flags = info.flags
1✔
552
        i.libraryDescription = info.GetLibraryDescription()
1✔
553
        i.libraryVersion = (info.libraryVersion.major,
1✔
554
                            info.libraryVersion.minor)
555
        return i
1✔
556

557
    def getSlotList(self, tokenPresent=False):
1✔
558
        """
559
        C_GetSlotList
560

561
        :param tokenPresent: `False` (default) to list all slots,
562
          `True` to list only slots with present tokens
563
        :type tokenPresent: bool
564
        :return: a list of available slots
565
        :rtype: list
566
        """
567
        slotList = PyKCS11.LowLevel.ckintlist()
1✔
568
        rv = self.lib.C_GetSlotList(CK_TRUE if tokenPresent else CK_FALSE,
1✔
569
                                    slotList)
570
        if rv != CKR_OK:
1✔
571
            raise PyKCS11Error(rv)
×
572

573
        s = []
1✔
574
        for x in range(len(slotList)):
1✔
575
            s.append(slotList[x])
1✔
576
        return s
1✔
577

578
    def getSlotInfo(self, slot):
1✔
579
        """
580
        C_GetSlotInfo
581

582
        :param slot: slot number returned by :func:`getSlotList`
583
        :type slot: integer
584
        :return: a :class:`CK_SLOT_INFO` object
585
        """
586
        slotInfo = PyKCS11.LowLevel.CK_SLOT_INFO()
1✔
587
        rv = self.lib.C_GetSlotInfo(slot, slotInfo)
1✔
588
        if rv != CKR_OK:
1✔
589
            raise PyKCS11Error(rv)
×
590

591
        s = CK_SLOT_INFO()
1✔
592
        s.slotDescription = slotInfo.GetSlotDescription()
1✔
593
        s.manufacturerID = slotInfo.GetManufacturerID()
1✔
594
        s.flags = slotInfo.flags
1✔
595
        s.hardwareVersion = slotInfo.GetHardwareVersion()
1✔
596
        s.firmwareVersion = slotInfo.GetFirmwareVersion()
1✔
597

598
        return s
1✔
599

600
    def getTokenInfo(self, slot):
1✔
601
        """
602
        C_GetTokenInfo
603

604
        :param slot: slot number returned by :func:`getSlotList`
605
        :type slot: integer
606
        :return: a :class:`CK_TOKEN_INFO` object
607
        """
608
        tokeninfo = PyKCS11.LowLevel.CK_TOKEN_INFO()
1✔
609
        rv = self.lib.C_GetTokenInfo(slot, tokeninfo)
1✔
610
        if rv != CKR_OK:
1✔
611
            raise PyKCS11Error(rv)
×
612

613
        t = CK_TOKEN_INFO()
1✔
614
        t.label = tokeninfo.GetLabel()
1✔
615
        t.manufacturerID = tokeninfo.GetManufacturerID()
1✔
616
        t.model = tokeninfo.GetModel()
1✔
617
        t.serialNumber = tokeninfo.GetSerialNumber()
1✔
618
        t.flags = tokeninfo.flags
1✔
619
        t.ulMaxSessionCount = tokeninfo.ulMaxSessionCount
1✔
620
        if t.ulMaxSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
621
            t.ulMaxSessionCount = -1
×
622
        t.ulSessionCount = tokeninfo.ulSessionCount
1✔
623
        if t.ulSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
624
            t.ulSessionCount = -1
1✔
625
        t.ulMaxRwSessionCount = tokeninfo.ulMaxRwSessionCount
1✔
626
        if t.ulMaxRwSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
627
            t.ulMaxRwSessionCount = -1
×
628
        t.ulRwSessionCount = tokeninfo.ulRwSessionCount
1✔
629
        if t.ulRwSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
630
            t.ulRwSessionCount = -1
1✔
631
        t.ulMaxPinLen = tokeninfo.ulMaxPinLen
1✔
632
        t.ulMinPinLen = tokeninfo.ulMinPinLen
1✔
633
        t.ulTotalPublicMemory = tokeninfo.ulTotalPublicMemory
1✔
634

635
        if t.ulTotalPublicMemory == CK_UNAVAILABLE_INFORMATION:
1✔
636
            t.ulTotalPublicMemory = -1
1✔
637
        t.ulFreePublicMemory = tokeninfo.ulFreePublicMemory
1✔
638
        if t.ulFreePublicMemory == CK_UNAVAILABLE_INFORMATION:
1✔
639
            t.ulFreePublicMemory = -1
1✔
640
        t.ulTotalPrivateMemory = tokeninfo.ulTotalPrivateMemory
1✔
641
        if t.ulTotalPrivateMemory == CK_UNAVAILABLE_INFORMATION:
1✔
642
            t.ulTotalPrivateMemory = -1
1✔
643
        t.ulFreePrivateMemory = tokeninfo.ulFreePrivateMemory
1✔
644
        if t.ulFreePrivateMemory == CK_UNAVAILABLE_INFORMATION:
1✔
645
            t.ulFreePrivateMemory = -1
1✔
646
        t.hardwareVersion = (tokeninfo.hardwareVersion.major,
1✔
647
                             tokeninfo.hardwareVersion.minor)
648
        t.firmwareVersion = (tokeninfo.firmwareVersion.major,
1✔
649
                             tokeninfo.firmwareVersion.minor)
650
        t.utcTime = tokeninfo.GetUtcTime().replace('\000', ' ')
1✔
651

652
        return t
1✔
653

654
    def openSession(self, slot, flags=0):
1✔
655
        """
656
        C_OpenSession
657

658
        :param slot: slot number returned by :func:`getSlotList`
659
        :type slot: integer
660
        :param flags: 0 (default), `CKF_RW_SESSION` for RW session
661
        :type flags: integer
662
        :return: a :class:`Session` object
663
        """
664
        se = PyKCS11.LowLevel.CK_SESSION_HANDLE()
1✔
665
        flags |= CKF_SERIAL_SESSION
1✔
666
        rv = self.lib.C_OpenSession(slot, flags, se)
1✔
667
        if rv != CKR_OK:
1✔
668
            raise PyKCS11Error(rv)
×
669

670
        return Session(self, se)
1✔
671

672
    def closeAllSessions(self, slot):
1✔
673
        """
674
        C_CloseAllSessions
675

676
        :param slot: slot number
677
        :type slot: integer
678
        """
679
        rv = self.lib.C_CloseAllSessions(slot)
1✔
680
        if rv != CKR_OK:
1✔
681
            raise PyKCS11Error(rv)
×
682

683
    def getMechanismList(self, slot):
1✔
684
        """
685
        C_GetMechanismList
686

687
        :param slot: slot number returned by :func:`getSlotList`
688
        :type slot: integer
689
        :return: the list of available mechanisms for a slot
690
        :rtype: list
691
        """
692
        mechanismList = PyKCS11.LowLevel.ckintlist()
1✔
693
        rv = self.lib.C_GetMechanismList(slot, mechanismList)
1✔
694
        if rv != CKR_OK:
1✔
695
            raise PyKCS11Error(rv)
×
696

697
        m = []
1✔
698
        for x in range(len(mechanismList)):
1✔
699
            mechanism = mechanismList[x]
1✔
700
            if mechanism >= CKM_VENDOR_DEFINED:
1✔
701
                k = 'CKM_VENDOR_DEFINED_0x%X' % (mechanism - CKM_VENDOR_DEFINED)
×
702
                CKM[k] = mechanism
×
703
                CKM[mechanism] = k
×
704
            m.append(CKM[mechanism])
1✔
705
        return m
1✔
706

707
    def getMechanismInfo(self, slot, type):
1✔
708
        """
709
        C_GetMechanismInfo
710

711
        :param slot: slot number returned by :func:`getSlotList`
712
        :type slot: integer
713
        :param type: a `CKM_*` type
714
        :type type: integer
715
        :return: information about a mechanism
716
        :rtype: a :class:`CK_MECHANISM_INFO` object
717
        """
718
        info = PyKCS11.LowLevel.CK_MECHANISM_INFO()
1✔
719
        rv = self.lib.C_GetMechanismInfo(slot, CKM[type], info)
1✔
720
        if rv != CKR_OK:
1✔
721
            raise PyKCS11Error(rv)
×
722

723
        i = CK_MECHANISM_INFO()
1✔
724
        i.ulMinKeySize = info.ulMinKeySize
1✔
725
        i.ulMaxKeySize = info.ulMaxKeySize
1✔
726
        i.flags = info.flags
1✔
727

728
        return i
1✔
729

730
    def waitForSlotEvent(self, flags=0):
1✔
731
        """
732
        C_WaitForSlotEvent
733

734
        :param flags: 0 (default) or `CKF_DONT_BLOCK`
735
        :type flags: integer
736
        :return: slot
737
        :rtype: integer
738
        """
739
        tmp = 0
×
740
        (rv, slot) = self.lib.C_WaitForSlotEvent(flags, tmp)
×
741
        if rv != CKR_OK:
×
742
            raise PyKCS11Error(rv)
×
743

744
        return slot
×
745

746

747
class Mechanism(object):
1✔
748
    """Wraps CK_MECHANISM"""
749

750
    def __init__(self, mechanism, param=None):
1✔
751
        """
752
        :param mechanism: the mechanism to be used
753
        :type mechanism: integer, any `CKM_*` value
754
        :param param: data to be used as crypto operation parameter
755
          (i.e. the IV for some algorithms)
756
        :type param: string or list/tuple of bytes
757

758
        :see: :func:`Session.decrypt`, :func:`Session.sign`
759
        """
760
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
761
        self._mech.mechanism = mechanism
1✔
762
        self._param = None
1✔
763
        if param:
1✔
764
            self._param = ckbytelist(param)
1✔
765
            self._mech.pParameter = self._param
1✔
766
            self._mech.ulParameterLen = len(param)
1✔
767

768
    def to_native(self):
1✔
769
        return self._mech
1✔
770

771

772
MechanismSHA1 = Mechanism(CKM_SHA_1, None)
1✔
773
MechanismRSAPKCS1 = Mechanism(CKM_RSA_PKCS, None)
1✔
774
MechanismRSAGENERATEKEYPAIR = Mechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, None)
1✔
775
MechanismECGENERATEKEYPAIR = Mechanism(CKM_EC_KEY_PAIR_GEN, None)
1✔
776
MechanismAESGENERATEKEY = Mechanism(CKM_AES_KEY_GEN, None)
1✔
777

778

779
class AES_GCM_Mechanism(object):
1✔
780
    """CKM_AES_GCM warpping mechanism"""
781

782
    def __init__(self, iv, aad, tagBits):
1✔
783
        """
784
        :param iv: initialization vector
785
        :param aad: additional authentication data
786
        :param tagBits: length of authentication tag in bits
787
        """
788
        self._param = PyKCS11.LowLevel.CK_GCM_PARAMS()
1✔
789

790
        self._source_iv = ckbytelist(iv)
1✔
791
        self._param.pIv = self._source_iv
1✔
792
        self._param.ulIvLen = len(self._source_iv)
1✔
793

794
        self._source_aad = ckbytelist(aad)
1✔
795
        self._param.pAAD = self._source_aad
1✔
796
        self._param.ulAADLen = len(self._source_aad)
1✔
797

798
        self._param.ulTagBits = tagBits
1✔
799

800
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
801
        self._mech.mechanism = CKM_AES_GCM
1✔
802
        self._mech.pParameter = self._param
1✔
803
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_GCM_PARAMS_LENGTH
1✔
804

805
    def to_native(self):
1✔
806
        return self._mech
1✔
807

808

809
class AES_CTR_Mechanism(object):
1✔
810
    """CKM_AES_CTR encryption mechanism"""
811

812
    def __init__(self, counterBits, counterBlock):
1✔
813
        """
814
        :param counterBits: the number of incremented bits in the counter block
815
        :param counterBlock: a 16-byte initial value of the counter block
816
        """
817
        self._param = PyKCS11.LowLevel.CK_AES_CTR_PARAMS()
1✔
818

819
        self._source_cb = ckbytelist(counterBlock)
1✔
820
        self._param.ulCounterBits = counterBits
1✔
821
        self._param.cb = self._source_cb
1✔
822

823
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
824
        self._mech.mechanism = CKM_AES_CTR
1✔
825
        self._mech.pParameter = self._param
1✔
826
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_AES_CTR_PARAMS_LENGTH
1✔
827

828
    def to_native(self):
1✔
829
        return self._mech
1✔
830

831

832
class RSAOAEPMechanism(object):
1✔
833
    """RSA OAEP Wrapping mechanism"""
834

835
    def __init__(self, hashAlg, mgf, label=None):
1✔
836
        """
837
        :param hashAlg: the hash algorithm to use (like `CKM_SHA256`)
838
        :param mgf: the mask generation function to use (like
839
          `CKG_MGF1_SHA256`)
840
        :param label: the (optional) label to use
841
        """
842
        self._param = PyKCS11.LowLevel.CK_RSA_PKCS_OAEP_PARAMS()
1✔
843
        self._param.hashAlg = hashAlg
1✔
844
        self._param.mgf = mgf
1✔
845
        self._source = None
1✔
846
        self._param.src = CKZ_DATA_SPECIFIED
1✔
847
        if label:
1✔
848
            self._source = ckbytelist(label)
×
849
            self._param.ulSourceDataLen = len(self._source)
×
850
        else:
851
            self._param.ulSourceDataLen = 0
1✔
852
        self._param.pSourceData = self._source
1✔
853
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
854
        self._mech.mechanism = CKM_RSA_PKCS_OAEP
1✔
855
        self._mech.pParameter = self._param
1✔
856
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_RSA_PKCS_OAEP_PARAMS_LENGTH
1✔
857

858
    def to_native(self):
1✔
859
        return self._mech
1✔
860

861

862
class RSA_PSS_Mechanism(object):
1✔
863
    """RSA PSS Wrapping mechanism"""
864

865
    def __init__(self, mecha, hashAlg, mgf, sLen):
1✔
866
        """
867
        :param mecha: the mechanism to use (like
868
          `CKM_SHA384_RSA_PKCS_PSS`)
869
        :param hashAlg: the hash algorithm to use (like `CKM_SHA384`)
870
        :param mgf: the mask generation function to use (like
871
          `CKG_MGF1_SHA384`)
872
        :param sLen: length, in bytes, of the salt value used in the PSS
873
          encoding (like 0 or the message length)
874
        """
875
        self._param = PyKCS11.LowLevel.CK_RSA_PKCS_PSS_PARAMS()
1✔
876
        self._param.hashAlg = hashAlg
1✔
877
        self._param.mgf = mgf
1✔
878
        self._param.sLen = sLen
1✔
879
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
880
        self._mech.mechanism = mecha
1✔
881
        self._mech.pParameter = self._param
1✔
882
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_RSA_PKCS_PSS_PARAMS_LENGTH
1✔
883

884
    def to_native(self):
1✔
885
        return self._mech
1✔
886

887
class ECDH1_DERIVE_Mechanism(object):
1✔
888
    """CKM_ECDH1_DERIVE key derivation mechanism"""
889

890
    def __init__(self, publicData, kdf = CKD_NULL, sharedData = None):
1✔
891
        """
892
        :param publicData: Other party public key which is EC Point [PC || coord-x || coord-y].
893
        :param kdf: Key derivation function. OPTIONAL. Defaults to CKD_NULL
894
        :param sharedData: additional shared data. OPTIONAL
895
        """
896
        self._param = PyKCS11.LowLevel.CK_ECDH1_DERIVE_PARAMS()
1✔
897

898
        self._param.kdf = kdf
1✔
899

900
        if sharedData:
1✔
901
            self._shared_data = ckbytelist(sharedData)
×
902
            self._param.pSharedData = self._shared_data
×
903
            self._param.ulSharedDataLen = len(self._shared_data)
×
904
        else:
905
            self._source_shared_data = None
1✔
906
            self._param.ulSharedDataLen = 0
1✔
907

908
        self._public_data = ckbytelist(publicData)
1✔
909
        self._param.pPublicData = self._public_data
1✔
910
        self._param.ulPublicDataLen = len(self._public_data)
1✔
911

912
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
913
        self._mech.mechanism = CKM_ECDH1_DERIVE
1✔
914
        self._mech.pParameter = self._param
1✔
915
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_ECDH1_DERIVE_PARAMS_LENGTH
1✔
916

917
    def to_native(self):
1✔
918
        return self._mech
1✔
919

920

921
class CONCATENATE_BASE_AND_KEY_Mechanism(object):
1✔
922
    """CKM_CONCATENATE_BASE_AND_KEY key derivation mechanism"""
923

924
    def __init__(self, encKey):
1✔
925
        """
926
        :param encKey: a handle of encryption key
927
        """
928
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
929
        self._mech.mechanism = CKM_CONCATENATE_BASE_AND_KEY
×
930
        self._mech.pParameter = encKey
×
931
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_OBJECT_HANDLE_LENGTH
×
932

933
    def to_native(self):
1✔
934
        return self._mech
×
935

936

937
class KEY_DERIVATION_STRING_DATA_MechanismBase(object):
1✔
938
    """Base class for mechanisms using derivation string data"""
939

940
    def __init__(self, data, mechType):
1✔
941
        """
942
        :param data: a byte array to concatenate the key with
943
        :param mechType: mechanism type
944
        """
945
        self._param = PyKCS11.LowLevel.CK_KEY_DERIVATION_STRING_DATA()
×
946

947
        self._data = ckbytelist(data)
×
948
        self._param.pData = self._data
×
949
        self._param.ulLen = len(self._data)
×
950

951
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
952
        self._mech.mechanism = mechType
×
953
        self._mech.pParameter = self._param
×
954
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_KEY_DERIVATION_STRING_DATA_LENGTH
×
955

956
    def to_native(self):
1✔
957
        return self._mech
×
958

959

960
class CONCATENATE_BASE_AND_DATA_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
961
    """CKM_CONCATENATE_BASE_AND_DATA key derivation mechanism"""
962

963
    def __init__(self, data):
1✔
964
        """
965
        :param data: a byte array to concatenate the key with
966
        """
967
        super().__init__(data, CKM_CONCATENATE_BASE_AND_DATA)
×
968

969

970
class CONCATENATE_DATA_AND_BASE_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
971
    """CKM_CONCATENATE_DATA_AND_BASE key derivation mechanism"""
972

973
    def __init__(self, data):
1✔
974
        """
975
        :param data: a byte array to concatenate the key with
976
        """
977
        super().__init__(data, CKM_CONCATENATE_DATA_AND_BASE)
×
978

979

980
class XOR_BASE_AND_DATA_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
981
    """CKM_XOR_BASE_AND_DATA key derivation mechanism"""
982

983
    def __init__(self, data):
1✔
984
        """
985
        :param data: a byte array to xor the key with
986
        """
987
        super().__init__(data, CKM_XOR_BASE_AND_DATA)
×
988

989

990
class EXTRACT_KEY_FROM_KEY_Mechanism():
1✔
991
    """CKM_EXTRACT_KEY_FROM_KEY key derivation mechanism"""
992

993
    def __init__(self, extractParams):
1✔
994
        """
995
        :param extractParams: the index of the first bit of the original key to be used in the newly-derived key. 
996
                              For example if extractParams=5 then the 5 first bits are skipped and not used.
997
        """
NEW
998
        self._param = PyKCS11.LowLevel.CK_EXTRACT_PARAMS()
×
NEW
999
        self._param.assign(extractParams)
×
1000

NEW
1001
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
NEW
1002
        self._mech.mechanism = CKM_EXTRACT_KEY_FROM_KEY
×
NEW
1003
        self._mech.pParameter = self._param
×
NEW
1004
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_EXTRACT_PARAMS_LENGTH
×
1005

1006
    def to_native(self):
1✔
NEW
1007
        return self._mech
×
1008

1009

1010
class DigestSession(object):
1✔
1011
    def __init__(self, lib, session, mecha):
1✔
1012
        self._lib = lib
1✔
1013
        self._session = session
1✔
1014
        self._mechanism = mecha.to_native()
1✔
1015
        rv = self._lib.C_DigestInit(self._session, self._mechanism)
1✔
1016
        if rv != CKR_OK:
1✔
1017
            raise PyKCS11Error(rv)
×
1018

1019
    def update(self, data):
1✔
1020
        """
1021
        C_DigestUpdate
1022

1023
        :param data: data to add to the digest
1024
        :type data: bytes or string
1025
        """
1026
        data1 = ckbytelist(data)
1✔
1027
        rv = self._lib.C_DigestUpdate(self._session, data1)
1✔
1028
        if rv != CKR_OK:
1✔
1029
            raise PyKCS11Error(rv)
×
1030
        return self
1✔
1031

1032
    def digestKey(self, handle):
1✔
1033
        """
1034
        C_DigestKey
1035

1036
        :param handle: key handle
1037
        :type handle: CK_OBJECT_HANDLE
1038
        """
1039
        rv = self._lib.C_DigestKey(self._session, handle)
×
1040
        if rv != CKR_OK:
×
1041
            raise PyKCS11Error(rv)
×
1042
        return self
×
1043

1044
    def final(self):
1✔
1045
        """
1046
        C_DigestFinal
1047

1048
        :return: the digest
1049
        :rtype: ckbytelist
1050
        """
1051
        digest = ckbytelist()
1✔
1052
        # Get the size of the digest
1053
        rv = self._lib.C_DigestFinal(self._session, digest)
1✔
1054
        if rv != CKR_OK:
1✔
1055
            raise PyKCS11Error(rv)
×
1056
        # Get the actual digest
1057
        rv = self._lib.C_DigestFinal(self._session, digest)
1✔
1058
        if rv != CKR_OK:
1✔
1059
            raise PyKCS11Error(rv)
×
1060
        return digest
1✔
1061

1062

1063
class Session(object):
1✔
1064
    """ Manage :func:`PyKCS11Lib.openSession` objects """
1065

1066
    def __init__(self, pykcs11, session):
1✔
1067
        """
1068
        :param pykcs11: PyKCS11 library object
1069
        :type pykcs11: PyKCS11Lib
1070
        :param session: session handle
1071
        :type session: instance of :class:`CK_SESSION_HANDLE`
1072
        """
1073
        if not isinstance(pykcs11, PyKCS11Lib):
1✔
1074
            raise TypeError("pykcs11 must be a PyKCS11Lib")
×
1075
        if not isinstance(session, LowLevel.CK_SESSION_HANDLE):
1✔
1076
            raise TypeError("session must be a CK_SESSION_HANDLE")
×
1077

1078
        # hold the PyKCS11Lib reference, so that it's not Garbage Collection'd
1079
        self.pykcs11 = pykcs11
1✔
1080
        self.session = session
1✔
1081

1082
    @property
1✔
1083
    def lib(self):
1✔
1084
        """
1085
        Get the low level lib of the owning PyKCS11Lib
1086
        """
1087
        return self.pykcs11.lib
1✔
1088

1089
    def closeSession(self):
1✔
1090
        """
1091
        C_CloseSession
1092
        """
1093
        rv = self.lib.C_CloseSession(self.session)
1✔
1094
        if rv != CKR_OK:
1✔
1095
            raise PyKCS11Error(rv)
×
1096

1097
    def getSessionInfo(self):
1✔
1098
        """
1099
        C_GetSessionInfo
1100

1101
        :return: a :class:`CK_SESSION_INFO` object
1102
        """
1103
        sessioninfo = PyKCS11.LowLevel.CK_SESSION_INFO()
1✔
1104
        rv = self.lib.C_GetSessionInfo(self.session, sessioninfo)
1✔
1105
        if rv != CKR_OK:
1✔
1106
            raise PyKCS11Error(rv)
×
1107

1108
        s = CK_SESSION_INFO()
1✔
1109
        s.slotID = sessioninfo.slotID
1✔
1110
        s.state = sessioninfo.state
1✔
1111
        s.flags = sessioninfo.flags
1✔
1112
        s.ulDeviceError = sessioninfo.ulDeviceError
1✔
1113
        return s
1✔
1114

1115
    def login(self, pin, user_type=CKU_USER):
1✔
1116
        """
1117
        C_Login
1118

1119
        :param pin: the user's PIN or None for CKF_PROTECTED_AUTHENTICATION_PATH
1120
        :type pin: string
1121
        :param user_type: the user type. The default value is
1122
          CKU_USER. You may also use CKU_SO
1123
        :type user_type: integer
1124
        """
1125
        pin1 = ckbytelist(pin)
1✔
1126
        rv = self.lib.C_Login(self.session, user_type, pin1)
1✔
1127
        if rv != CKR_OK:
1✔
1128
            raise PyKCS11Error(rv)
1✔
1129

1130
    def logout(self):
1✔
1131
        """
1132
        C_Logout
1133
        """
1134
        rv = self.lib.C_Logout(self.session)
1✔
1135
        if rv != CKR_OK:
1✔
1136
            raise PyKCS11Error(rv)
×
1137

1138
        del self
1✔
1139

1140
    def initPin(self, pin):
1✔
1141
        """
1142
        C_InitPIN
1143

1144
        :param pin: new PIN
1145
        """
1146
        new_pin1 = ckbytelist(pin)
1✔
1147
        rv = self.lib.C_InitPIN(self.session, new_pin1)
1✔
1148
        if rv != CKR_OK:
1✔
1149
            raise PyKCS11Error(rv)
×
1150

1151
    def setPin(self, old_pin, new_pin):
1✔
1152
        """
1153
        C_SetPIN
1154

1155
        :param old_pin: old PIN
1156
        :param new_pin: new PIN
1157
        """
1158
        old_pin1 = ckbytelist(old_pin)
1✔
1159
        new_pin1 = ckbytelist(new_pin)
1✔
1160
        rv = self.lib.C_SetPIN(self.session, old_pin1, new_pin1)
1✔
1161
        if rv != CKR_OK:
1✔
1162
            raise PyKCS11Error(rv)
×
1163

1164
    def createObject(self, template):
1✔
1165
        """
1166
        C_CreateObject
1167

1168
        :param template: object template
1169
        """
1170
        attrs = self._template2ckattrlist(template)
1✔
1171
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1172
        rv = self.lib.C_CreateObject(self.session, attrs, handle)
1✔
1173
        if rv != PyKCS11.CKR_OK:
1✔
1174
            raise PyKCS11.PyKCS11Error(rv)
×
1175
        return handle
1✔
1176

1177
    def destroyObject(self, obj):
1✔
1178
        """
1179
        C_DestroyObject
1180

1181
        :param obj: object ID
1182
        """
1183
        rv = self.lib.C_DestroyObject(self.session, obj)
1✔
1184
        if rv != CKR_OK:
1✔
1185
            raise PyKCS11Error(rv)
×
1186

1187
    def digestSession(self, mecha=MechanismSHA1):
1✔
1188
        """
1189
        C_DigestInit/C_DigestUpdate/C_DigestKey/C_DigestFinal
1190

1191
        :param mecha: the digesting mechanism to be used
1192
          (use `MechanismSHA1` for `CKM_SHA_1`)
1193
        :type mecha: :class:`Mechanism`
1194
        :return: A :class:`DigestSession` object
1195
        :rtype: DigestSession
1196
        """
1197
        return DigestSession(self.lib, self.session, mecha)
1✔
1198

1199
    def digest(self, data, mecha=MechanismSHA1):
1✔
1200
        """
1201
        C_DigestInit/C_Digest
1202

1203
        :param data: the data to be digested
1204
        :type data:  (binary) sring or list/tuple of bytes
1205
        :param mecha: the digesting mechanism to be used
1206
          (use `MechanismSHA1` for `CKM_SHA_1`)
1207
        :type mecha: :class:`Mechanism`
1208
        :return: the computed digest
1209
        :rtype: list of bytes
1210

1211
        :note: the returned value is an istance of :class:`ckbytelist`.
1212
          You can easly convert it to a binary string with:
1213
          ``bytes(ckbytelistDigest)``
1214
          or, for Python 2:
1215
          ``''.join(chr(i) for i in ckbytelistDigest)``
1216

1217
        """
1218
        digest = ckbytelist()
1✔
1219
        m = mecha.to_native()
1✔
1220
        data1 = ckbytelist(data)
1✔
1221
        rv = self.lib.C_DigestInit(self.session, m)
1✔
1222
        if rv != CKR_OK:
1✔
1223
            raise PyKCS11Error(rv)
×
1224
        # first call get digest size
1225
        rv = self.lib.C_Digest(self.session, data1, digest)
1✔
1226
        if rv != CKR_OK:
1✔
1227
            raise PyKCS11Error(rv)
×
1228
        # second call get actual digest data
1229
        rv = self.lib.C_Digest(self.session, data1, digest)
1✔
1230
        if rv != CKR_OK:
1✔
1231
            raise PyKCS11Error(rv)
×
1232
        return digest
1✔
1233

1234
    def sign(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1235
        """
1236
        C_SignInit/C_Sign
1237

1238
        :param key: a key handle, obtained calling :func:`findObjects`.
1239
        :type key: integer
1240
        :param data: the data to be signed
1241
        :type data:  (binary) string or list/tuple of bytes
1242
        :param mecha: the signing mechanism to be used
1243
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1244
        :type mecha: :class:`Mechanism`
1245
        :return: the computed signature
1246
        :rtype: list of bytes
1247

1248
        :note: the returned value is an instance of :class:`ckbytelist`.
1249
          You can easly convert it to a binary string with:
1250
          ``bytes(ckbytelistSignature)``
1251
          or, for Python 2:
1252
          ``''.join(chr(i) for i in ckbytelistSignature)``
1253

1254
        """
1255
        m = mecha.to_native()
1✔
1256
        signature = ckbytelist()
1✔
1257
        data1 = ckbytelist(data)
1✔
1258
        rv = self.lib.C_SignInit(self.session, m, key)
1✔
1259
        if rv != CKR_OK:
1✔
1260
            raise PyKCS11Error(rv)
×
1261
        # first call get signature size
1262
        rv = self.lib.C_Sign(self.session, data1, signature)
1✔
1263
        if rv != CKR_OK:
1✔
1264
            raise PyKCS11Error(rv)
×
1265
        # second call get actual signature data
1266
        rv = self.lib.C_Sign(self.session, data1, signature)
1✔
1267
        if rv != CKR_OK:
1✔
1268
            raise PyKCS11Error(rv)
×
1269
        return signature
1✔
1270

1271
    def verify(self, key, data, signature, mecha=MechanismRSAPKCS1):
1✔
1272
        """
1273
        C_VerifyInit/C_Verify
1274

1275
        :param key: a key handle, obtained calling :func:`findObjects`.
1276
        :type key: integer
1277
        :param data: the data that was signed
1278
        :type data:  (binary) string or list/tuple of bytes
1279
        :param signature: the signature to be verified
1280
        :type signature:  (binary) string or list/tuple of bytes
1281
        :param mecha: the signing mechanism to be used
1282
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1283
        :type mecha: :class:`Mechanism`
1284
        :return: True if signature is valid, False otherwise
1285
        :rtype: bool
1286

1287
        """
1288
        m = mecha.to_native()
1✔
1289
        data1 = ckbytelist(data)
1✔
1290
        rv = self.lib.C_VerifyInit(self.session, m, key)
1✔
1291
        if rv != CKR_OK:
1✔
1292
            raise PyKCS11Error(rv)
×
1293
        rv = self.lib.C_Verify(self.session, data1, signature)
1✔
1294
        if rv == CKR_OK:
1✔
1295
            return True
1✔
1296
        elif rv == CKR_SIGNATURE_INVALID:
×
1297
            return False
×
1298
        else:
1299
            raise PyKCS11Error(rv)
×
1300

1301
    def encrypt(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1302
        """
1303
        C_EncryptInit/C_Encrypt
1304

1305
        :param key: a key handle, obtained calling :func:`findObjects`.
1306
        :type key: integer
1307
        :param data: the data to be encrypted
1308
        :type data:  (binary) string or list/tuple of bytes
1309
        :param mecha: the encryption mechanism to be used
1310
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1311
        :type mecha: :class:`Mechanism`
1312
        :return: the encrypted data
1313
        :rtype: list of bytes
1314

1315
        :note: the returned value is an instance of :class:`ckbytelist`.
1316
          You can easly convert it to a binary string with:
1317
          ``bytes(ckbytelistEncrypted)``
1318
          or, for Python 2:
1319
          ``''.join(chr(i) for i in ckbytelistEncrypted)``
1320

1321
        """
1322
        encrypted = ckbytelist()
1✔
1323
        m = mecha.to_native()
1✔
1324
        data1 = ckbytelist(data)
1✔
1325
        rv = self.lib.C_EncryptInit(self.session, m, key)
1✔
1326
        if rv != CKR_OK:
1✔
1327
            raise PyKCS11Error(rv)
×
1328
        # first call get encrypted size
1329
        rv = self.lib.C_Encrypt(self.session, data1, encrypted)
1✔
1330
        if rv != CKR_OK:
1✔
1331
            raise PyKCS11Error(rv)
×
1332
        # second call get actual encrypted data
1333
        rv = self.lib.C_Encrypt(self.session, data1, encrypted)
1✔
1334
        if rv != CKR_OK:
1✔
1335
            raise PyKCS11Error(rv)
×
1336
        return encrypted
1✔
1337

1338
    def decrypt(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1339
        """
1340
        C_DecryptInit/C_Decrypt
1341

1342
        :param key: a key handle, obtained calling :func:`findObjects`.
1343
        :type key: integer
1344
        :param data: the data to be decrypted
1345
        :type data:  (binary) string or list/tuple of bytes
1346
        :param mecha: the decrypt mechanism to be used
1347
        :type mecha: :class:`Mechanism` instance or :class:`MechanismRSAPKCS1`
1348
          for CKM_RSA_PKCS
1349
        :return: the decrypted data
1350
        :rtype: list of bytes
1351

1352
        :note: the returned value is an instance of :class:`ckbytelist`.
1353
          You can easly convert it to a binary string with:
1354
          ``bytes(ckbytelistData)``
1355
          or, for Python 2:
1356
          ``''.join(chr(i) for i in ckbytelistData)``
1357

1358
        """
1359
        m = mecha.to_native()
1✔
1360
        decrypted = ckbytelist()
1✔
1361
        data1 = ckbytelist(data)
1✔
1362
        rv = self.lib.C_DecryptInit(self.session, m, key)
1✔
1363
        if rv != CKR_OK:
1✔
1364
            raise PyKCS11Error(rv)
×
1365
        # first call get decrypted size
1366
        rv = self.lib.C_Decrypt(self.session, data1, decrypted)
1✔
1367
        if rv != CKR_OK:
1✔
1368
            raise PyKCS11Error(rv)
×
1369
        # second call get actual decrypted data
1370
        rv = self.lib.C_Decrypt(self.session, data1, decrypted)
1✔
1371
        if rv != CKR_OK:
1✔
1372
            raise PyKCS11Error(rv)
×
1373
        return decrypted
1✔
1374

1375
    def wrapKey(self, wrappingKey, key, mecha=MechanismRSAPKCS1):
1✔
1376
        """
1377
        C_WrapKey
1378

1379
        :param wrappingKey: a wrapping key handle
1380
        :type wrappingKey: integer
1381
        :param key: a handle of the key to be wrapped
1382
        :type key: integer
1383
        :param mecha: the encrypt mechanism to be used
1384
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1385
        :type mecha: :class:`Mechanism`
1386
        :return: the wrapped key bytes
1387
        :rtype: list of bytes
1388

1389
        :note: the returned value is an instance of :class:`ckbytelist`.
1390
          You can easily convert it to a binary string with:
1391
          ``bytes(ckbytelistData)``
1392
          or, for Python 2:
1393
          ``''.join(chr(i) for i in ckbytelistData)``
1394

1395
        """
1396
        wrapped = ckbytelist()
1✔
1397
        native = mecha.to_native()
1✔
1398
        # first call get wrapped size
1399
        rv = self.lib.C_WrapKey(self.session, native, wrappingKey, key,
1✔
1400
                                wrapped)
1401
        if rv != CKR_OK:
1✔
1402
            raise PyKCS11Error(rv)
×
1403
        # second call get actual wrapped key data
1404
        rv = self.lib.C_WrapKey(self.session, native, wrappingKey, key,
1✔
1405
                                wrapped)
1406
        if rv != CKR_OK:
1✔
1407
            raise PyKCS11Error(rv)
×
1408
        return wrapped
1✔
1409

1410
    def unwrapKey(self, unwrappingKey, wrappedKey, template,
1✔
1411
                  mecha=MechanismRSAPKCS1):
1412
        """
1413
        C_UnwrapKey
1414

1415
        :param unwrappingKey: the unwrapping key handle
1416
        :type unwrappingKey: integer
1417
        :param wrappedKey: the bytes of the wrapped key
1418
        :type wrappedKey:  (binary) string or list/tuple of bytes
1419
        :param template: template for the unwrapped key
1420
        :param mecha: the decrypt mechanism to be used (use
1421
          `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1422
        :type mecha: :class:`Mechanism`
1423
        :return: the unwrapped key object
1424
        :rtype: integer
1425

1426
        """
1427
        m = mecha.to_native()
1✔
1428
        data1 = ckbytelist(wrappedKey)
1✔
1429
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1430
        attrs = self._template2ckattrlist(template)
1✔
1431
        rv = self.lib.C_UnwrapKey(self.session, m, unwrappingKey,
1✔
1432
                                  data1, attrs, handle)
1433
        if rv != CKR_OK:
1✔
1434
            raise PyKCS11Error(rv)
×
1435
        return handle
1✔
1436

1437
    def deriveKey(self, baseKey, template, mecha):
1✔
1438
        """
1439
        C_DeriveKey
1440

1441
        :param baseKey: the base key handle
1442
        :type baseKey: integer
1443
        :param template: template for the unwrapped key
1444
        :param mecha: the decrypt mechanism to be used (use
1445
          `ECDH1_DERIVE_Mechanism(...)` for `CKM_ECDH1_DERIVE`)
1446
        :type mecha: :class:`Mechanism`
1447
        :return: the unwrapped key object
1448
        :rtype: integer
1449
        """
1450
        m = mecha.to_native()
1✔
1451
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1452
        attrs = self._template2ckattrlist(template)
1✔
1453
        rv = self.lib.C_DeriveKey(self.session, m, baseKey, attrs, handle)
1✔
1454
        if rv != CKR_OK:
1✔
1455
            raise PyKCS11Error(rv)
×
1456
        return handle
1✔
1457

1458
    def isNum(self, type):
1✔
1459
        """
1460
        is the type a numerical value?
1461

1462
        :param type: PKCS#11 type like `CKA_CERTIFICATE_TYPE`
1463
        :rtype: bool
1464
        """
1465
        if type in (CKA_CERTIFICATE_TYPE,
1✔
1466
                    CKA_CLASS,
1467
                    CKA_HW_FEATURE_TYPE,
1468
                    CKA_KEY_GEN_MECHANISM,
1469
                    CKA_KEY_TYPE,
1470
                    CKA_MODULUS_BITS,
1471
                    CKA_VALUE_BITS,
1472
                    CKA_VALUE_LEN):
1473
            return True
1✔
1474
        return False
1✔
1475

1476
    def isString(self, type):
1✔
1477
        """
1478
        is the type a string value?
1479

1480
        :param type: PKCS#11 type like `CKA_LABEL`
1481
        :rtype: bool
1482
        """
1483
        if type in (CKA_LABEL,
1✔
1484
                    CKA_APPLICATION):
1485
            return True
1✔
1486
        return False
1✔
1487

1488
    def isBool(self, type):
1✔
1489
        """
1490
        is the type a boolean value?
1491

1492
        :param type: PKCS#11 type like `CKA_ALWAYS_SENSITIVE`
1493
        :rtype: bool
1494
        """
1495
        if type in (CKA_ALWAYS_AUTHENTICATE,
1✔
1496
                    CKA_ALWAYS_SENSITIVE,
1497
                    CKA_DECRYPT,
1498
                    CKA_DERIVE,
1499
                    CKA_ENCRYPT,
1500
                    CKA_EXTRACTABLE,
1501
                    CKA_HAS_RESET,
1502
                    CKA_LOCAL,
1503
                    CKA_MODIFIABLE,
1504
                    CKA_COPYABLE,
1505
                    CKA_DESTROYABLE,
1506
                    CKA_NEVER_EXTRACTABLE,
1507
                    CKA_PRIVATE,
1508
                    CKA_RESET_ON_INIT,
1509
                    CKA_SECONDARY_AUTH,
1510
                    CKA_SENSITIVE,
1511
                    CKA_SIGN,
1512
                    CKA_SIGN_RECOVER,
1513
                    CKA_TOKEN,
1514
                    CKA_TRUSTED,
1515
                    CKA_UNWRAP,
1516
                    CKA_VERIFY,
1517
                    CKA_VERIFY_RECOVER,
1518
                    CKA_WRAP,
1519
                    CKA_WRAP_WITH_TRUSTED):
1520
            return True
1✔
1521
        return False
1✔
1522

1523
    def isBin(self, type):
1✔
1524
        """
1525
        is the type a byte array value?
1526

1527
        :param type: PKCS#11 type like `CKA_MODULUS`
1528
        :rtype: bool
1529
        """
1530
        return (not self.isBool(type)) \
1✔
1531
            and (not self.isString(type)) \
1532
            and (not self.isNum(type))
1533

1534
    def isAttributeList(self, type):
1✔
1535
        """
1536
        is the type a attribute list value?
1537

1538
        :param type: PKCS#11 type like `CKA_WRAP_TEMPLATE`
1539
        :rtype: bool
1540
        """
1541
        if type in (CKA_WRAP_TEMPLATE,
1✔
1542
                    CKA_UNWRAP_TEMPLATE):
1543
            return True
1✔
1544
        return False
1✔
1545

1546
    def _template2ckattrlist(self, template):
1✔
1547
        t = PyKCS11.LowLevel.ckattrlist(len(template))
1✔
1548
        for x in range(len(template)):
1✔
1549
            attr = template[x]
1✔
1550
            if self.isNum(attr[0]):
1✔
1551
                t[x].SetNum(attr[0], int(attr[1]))
1✔
1552
            elif self.isString(attr[0]):
1✔
1553
                t[x].SetString(attr[0], str(attr[1]))
1✔
1554
            elif self.isBool(attr[0]):
1✔
1555
                t[x].SetBool(attr[0], attr[1] == CK_TRUE)
1✔
1556
            elif self.isAttributeList(attr[0]):
1✔
1557
                t[x].SetList(attr[0],
1✔
1558
                        self._template2ckattrlist(attr[1]))
1559
            elif self.isBin(attr[0]):
1✔
1560
                attrBin = attr[1]
1✔
1561
                attrStr = attr[1]
1✔
1562
                if isinstance(attr[1], int):
1✔
1563
                    attrStr = str(attr[1])
×
1564
                if isinstance(attr[1], bytes):
1✔
1565
                    attrBin = ckbytelist(attrStr)
1✔
1566
                t[x].SetBin(attr[0], attrBin)
1✔
1567
            else:
1568
                raise PyKCS11Error(-2)
×
1569
        return t
1✔
1570

1571
    def generateKey(self, template, mecha=MechanismAESGENERATEKEY):
1✔
1572
        """
1573
        generate a secret key
1574

1575
        :param template: template for the secret key
1576
        :param mecha: mechanism to use
1577
        :return: handle of the generated key
1578
        :rtype: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1579
        """
1580
        t = self._template2ckattrlist(template)
1✔
1581
        ck_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1582
        m = mecha.to_native()
1✔
1583
        rv = self.lib.C_GenerateKey(self.session, m, t, ck_handle)
1✔
1584
        if rv != CKR_OK:
1✔
1585
            raise PyKCS11Error(rv)
×
1586
        return ck_handle
1✔
1587

1588
    def generateKeyPair(self, templatePub, templatePriv,
1✔
1589
                        mecha=MechanismRSAGENERATEKEYPAIR):
1590
        """
1591
        generate a key pair
1592

1593
        :param templatePub: template for the public key
1594
        :param templatePriv:  template for the private key
1595
        :param mecha: mechanism to use
1596
        :return: a tuple of handles (pub, priv)
1597
        :rtype: tuple
1598
        """
1599
        tPub = self._template2ckattrlist(templatePub)
1✔
1600
        tPriv = self._template2ckattrlist(templatePriv)
1✔
1601
        ck_pub_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1602
        ck_prv_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1603
        m = mecha.to_native()
1✔
1604
        rv = self.lib.C_GenerateKeyPair(self.session, m, tPub, tPriv,
1✔
1605
                                        ck_pub_handle, ck_prv_handle)
1606

1607
        if rv != CKR_OK:
1✔
1608
            raise PyKCS11Error(rv)
1✔
1609
        return ck_pub_handle, ck_prv_handle
1✔
1610

1611
    def findObjects(self, template=()):
1✔
1612
        """
1613
        find the objects matching the template pattern
1614

1615
        :param template: list of attributes tuples (attribute,value).
1616
          The default value is () and all the objects are returned
1617
        :type template: list
1618
        :return: a list of object ids
1619
        :rtype: list
1620
        """
1621
        t = self._template2ckattrlist(template)
1✔
1622

1623
        # we search for 10 objects by default. speed/memory tradeoff
1624
        result = PyKCS11.LowLevel.ckobjlist(10)
1✔
1625

1626
        rv = self.lib.C_FindObjectsInit(self.session, t)
1✔
1627
        if rv != CKR_OK:
1✔
1628
            raise PyKCS11Error(rv)
×
1629

1630
        res = []
1✔
1631
        while True:
1✔
1632
            rv = self.lib.C_FindObjects(self.session, result)
1✔
1633
            if rv != CKR_OK:
1✔
1634
                raise PyKCS11Error(rv)
×
1635
            for x in result:
1✔
1636
                # make a copy of the handle: the original value get
1637
                # corrupted (!!)
1638
                a = CK_OBJECT_HANDLE(self)
1✔
1639
                a.assign(x.value())
1✔
1640
                res.append(a)
1✔
1641
            if len(result) == 0:
1✔
1642
                break
1✔
1643

1644
        rv = self.lib.C_FindObjectsFinal(self.session)
1✔
1645
        if rv != CKR_OK:
1✔
1646
            raise PyKCS11Error(rv)
×
1647
        return res
1✔
1648

1649
    def getAttributeValue(self, obj_id, attr, allAsBinary=False):
1✔
1650
        """
1651
        C_GetAttributeValue
1652

1653
        :param obj_id: object ID returned by :func:`findObjects`
1654
        :type obj_id: integer
1655
        :param attr: list of attributes
1656
        :type attr: list
1657
        :param allAsBinary: return all values as binary data; default is False.
1658
        :type allAsBinary: Boolean
1659
        :return: a list of values corresponding to the list of attributes
1660
        :rtype: list
1661

1662
        :see: :func:`getAttributeValue_fragmented`
1663

1664
        :note: if allAsBinary is True the function do not convert results to
1665
          Python types (i.e.: CKA_TOKEN to Bool, CKA_CLASS to int, ...).
1666

1667
          Binary data is returned as :class:`ckbytelist` type, usable
1668
          as a list containing only bytes.
1669
          You can easly convert it to a binary string with:
1670
          ``bytes(ckbytelistVariable)``
1671
          or, for Python 2:
1672
          ``''.join(chr(i) for i in ckbytelistVariable)``
1673

1674
        """
1675
        valTemplate = PyKCS11.LowLevel.ckattrlist(len(attr))
1✔
1676
        for x in range(len(attr)):
1✔
1677
            valTemplate[x].SetType(attr[x])
1✔
1678
        # first call to get the attribute size and reserve the memory
1679
        rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1680
        if rv in (CKR_ATTRIBUTE_TYPE_INVALID, CKR_ATTRIBUTE_SENSITIVE,
1✔
1681
                  CKR_ARGUMENTS_BAD):
1682
            return self.getAttributeValue_fragmented(obj_id, attr, allAsBinary)
1✔
1683

1684
        if rv != CKR_OK:
1✔
1685
            raise PyKCS11Error(rv)
×
1686
        # second call to get the attribute value
1687
        rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1688
        if rv != CKR_OK:
1✔
1689
            raise PyKCS11Error(rv)
×
1690

1691
        res = []
1✔
1692
        for x in range(len(attr)):
1✔
1693
            if allAsBinary:
1✔
1694
                res.append(valTemplate[x].GetBin())
1✔
1695
            elif valTemplate[x].IsNum():
1✔
1696
                res.append(valTemplate[x].GetNum())
1✔
1697
            elif valTemplate[x].IsBool():
1✔
1698
                res.append(valTemplate[x].GetBool())
1✔
1699
            elif valTemplate[x].IsString():
1✔
1700
                res.append(valTemplate[x].GetString())
1✔
1701
            elif valTemplate[x].IsBin():
1✔
1702
                res.append(valTemplate[x].GetBin())
1✔
1703
            else:
1704
                raise PyKCS11Error(-2)
×
1705

1706
        return res
1✔
1707

1708
    def getAttributeValue_fragmented(self, obj_id, attr, allAsBinary=False):
1✔
1709
        """
1710
        Same as :func:`getAttributeValue` except that when some attribute
1711
        is sensitive or unknown an empty value (None) is returned.
1712

1713
        Note: this is achived by getting attributes one by one.
1714

1715
        :see: :func:`getAttributeValue`
1716
        """
1717
        # some attributes does not exists or is sensitive
1718
        # but we don't know which ones. So try one by one
1719
        valTemplate = PyKCS11.LowLevel.ckattrlist(1)
1✔
1720
        res = []
1✔
1721
        for x in range(len(attr)):
1✔
1722
            valTemplate[0].Reset()
1✔
1723
            valTemplate[0].SetType(attr[x])
1✔
1724
            # first call to get the attribute size and reserve the memory
1725
            rv = self.lib.C_GetAttributeValue(self.session, obj_id,
1✔
1726
                                              valTemplate)
1727
            if rv in (CKR_ATTRIBUTE_TYPE_INVALID,
1✔
1728
                      CKR_ATTRIBUTE_SENSITIVE, CKR_ARGUMENTS_BAD):
1729
                # append an empty value
1730
                res.append(None)
1✔
1731
                continue
1✔
1732

1733
            if rv != CKR_OK:
1✔
1734
                raise PyKCS11Error(rv)
×
1735
            # second call to get the attribute value
1736
            rv = self.lib.C_GetAttributeValue(self.session, obj_id,
1✔
1737
                                              valTemplate)
1738
            if rv != CKR_OK:
1✔
1739
                raise PyKCS11Error(rv)
×
1740

1741
            if allAsBinary:
1✔
1742
                res.append(valTemplate[0].GetBin())
×
1743
            elif valTemplate[0].IsNum():
1✔
1744
                res.append(valTemplate[0].GetNum())
1✔
1745
            elif valTemplate[0].IsBool():
1✔
1746
                res.append(valTemplate[0].GetBool())
1✔
1747
            elif valTemplate[0].IsString():
1✔
1748
                res.append(valTemplate[0].GetString())
1✔
1749
            elif valTemplate[0].IsBin():
1✔
1750
                res.append(valTemplate[0].GetBin())
1✔
1751
            elif valTemplate[0].IsAttributeList():
1✔
1752
                res.append(valTemplate[0].GetBin())
1✔
1753
            else:
1754
                raise PyKCS11Error(-2)
×
1755

1756
        return res
1✔
1757

1758
    def setAttributeValue(self, obj_id, template):
1✔
1759
        """
1760
        C_SetAttributeValue
1761

1762
        :param obj_id: object ID returned by :func:`findObjects`
1763
        :type obj_id: integer
1764
        :param template: list of (attribute, value) pairs
1765
        :type template: list
1766
        :return: Nothing
1767
        :rtype: None
1768
        """
1769

1770
        templ = self._template2ckattrlist(template)
1✔
1771
        rv = self.lib.C_SetAttributeValue(self.session, obj_id, templ)
1✔
1772

1773
        if rv != CKR_OK:
1✔
1774
            raise PyKCS11Error(rv)
×
1775

1776
        return None
1✔
1777

1778
    def seedRandom(self, seed):
1✔
1779
        """
1780
        C_SeedRandom
1781

1782
        :param seed: seed material
1783
        :type seed: iterable
1784
        """
1785
        low_seed = ckbytelist(seed)
1✔
1786
        rv = self.lib.C_SeedRandom(self.session, low_seed)
1✔
1787
        if rv != CKR_OK:
1✔
1788
            raise PyKCS11Error(rv)
×
1789

1790
    def generateRandom(self, size=16):
1✔
1791
        """
1792
        C_GenerateRandom
1793

1794
        :param size: number of random bytes to get
1795
        :type size: integer
1796

1797
        :note: the returned value is an instance of :class:`ckbytelist`.
1798
          You can easly convert it to a binary string with:
1799
          ``bytes(random)``
1800
          or, for Python 2:
1801
          ``''.join(chr(i) for i in random)``
1802
        """
1803
        low_rand = ckbytelist([0] * size)
1✔
1804
        rv = self.lib.C_GenerateRandom(self.session, low_rand)
1✔
1805
        if rv != CKR_OK:
1✔
1806
            raise PyKCS11Error(rv)
×
1807
        return low_rand
1✔
1808

1809

1810
if __name__ == "__main__":
1✔
1811
    # sample test/debug code
1812
    p = PyKCS11Lib()
×
1813
    p.load()
×
1814

1815
    print("getInfo")
×
1816
    print(p.getInfo())
×
1817

1818
    print()
×
1819
    print("getSlotList")
×
1820
    s = p.getSlotList()
×
1821
    print("slots:", s)
×
1822
    slot = s[0]
×
1823
    print("using slot:", slot)
×
1824

1825
    print()
×
1826
    print("getSlotInfo")
×
1827
    print(p.getSlotInfo(slot))
×
1828

1829
    print()
×
1830
    print("getTokenInfo")
×
1831
    print(p.getTokenInfo(slot))
×
1832

1833
    print()
×
1834
    print("openSession")
×
1835
    se = p.openSession(slot)
×
1836

1837
    print()
×
1838
    print("sessionInfo")
×
1839
    print(se.getSessionInfo())
×
1840

1841
    print()
×
1842
    print("seedRandom")
×
1843
    try:
×
1844
        se.seedRandom([1, 2, 3, 4])
×
1845
    except PyKCS11Error as e:
×
1846
        print(e)
×
1847
    print("generateRandom")
×
1848
    print(se.generateRandom())
×
1849

1850
    print()
×
1851
    print("login")
×
1852
    se.login(pin="0000")
×
1853

1854
    print()
×
1855
    print("sessionInfo")
×
1856
    print(se.getSessionInfo())
×
1857

1858
    print()
×
1859
    print("findObjects")
×
1860
    objs = se.findObjects([(CKA_CLASS, CKO_CERTIFICATE)])
×
1861
    print("Nb objetcs:", len(objs))
×
1862
    print(objs)
×
1863

1864
    print()
×
1865
    print("getAttributeValue")
×
1866
    for o in objs:
×
1867
        attr = se.getAttributeValue(o, [CKA_LABEL, CKA_CLASS])
×
1868
        print(attr)
×
1869

1870
    print()
×
1871
    print("logout")
×
1872
    se.logout()
×
1873

1874
    print()
×
1875
    print("closeSession")
×
1876
    se.closeSession()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc