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

LudovicRousseau / PyKCS11 / 16367380199

18 Jul 2025 09:31AM UTC coverage: 93.474% (+5.9%) from 87.592%
16367380199

push

github

LudovicRousseau
IsNum(): CKA_HW_FEATURE_TYPE is also a numeric value

Thanks to Ivan Wallis for the bug report
"Venafi PKCS#11 Library fails with Unkown PKCS#11 type () during findObjects #140"
Closes: https://github.com/LudovicRousseau/PyKCS11/issues/140

5529 of 5915 relevant lines covered (93.47%)

0.93 hits per line

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

86.13
/PyKCS11/__init__.py
1
"""
2
  Copyright (C) 2006-2025 Ludovic Rousseau (ludovic.rousseau@free.fr)
3
  Copyright (C) 2010 Giuseppe Amato (additions to original interface)
4

5
This file is free software; you can redistribute it and/or modify it
6
under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
9

10
This program is distributed in the hope that it will be useful, but
11
WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
General Public License for more details.
14

15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
18
"""
19

20
# pylint: disable=too-many-lines
21

22
import os
1✔
23
import sys
1✔
24
import threading
1✔
25

26
import PyKCS11.LowLevel
1✔
27

28
from .constants import *
1✔
29

30
# special CKR[] values
31
CKR[-4] = "C_GetFunctionList() not found"
1✔
32
CKR[-3] = "Unknown format"
1✔
33
CKR[-2] = "Unkown PKCS#11 type"
1✔
34
CKR[-1] = "Load"
1✔
35

36

37
class ckbytelist(PyKCS11.LowLevel.ckbytelist):
1✔
38
    """
39
    add a __repr__() method to the LowLevel equivalent
40
    """
41

42
    def __init__(self, data=None):
1✔
43
        if data is None:
1✔
44
            data = 0
1✔
45
        elif isinstance(data, str):
1✔
46
            data = data.encode("utf-8")
1✔
47
        elif isinstance(data, (bytes, list, ckbytelist)):
1✔
48
            data = bytes(data)
1✔
49
        else:
50
            raise PyKCS11.PyKCS11Error(-3, text=str(type(data)))
1✔
51
        super().__init__(data)
1✔
52

53
    def __repr__(self):
1✔
54
        """
55
        return the representation of a tuple
56
        the __str__ method will use it also
57
        """
58
        rep = [int(elt) for elt in self]
1✔
59
        return repr(rep)
1✔
60

61
    def __add__(self, b):
1✔
62
        return ckbytelist(bytes(self) + bytes(b))
1✔
63

64

65
class CK_OBJECT_HANDLE(PyKCS11.LowLevel.CK_OBJECT_HANDLE):
1✔
66
    """
67
    add a __repr__() method to the LowLevel equivalent
68
    """
69

70
    def __init__(self, session):
1✔
71
        PyKCS11.LowLevel.CK_OBJECT_HANDLE.__init__(self)
1✔
72
        self.session = session
1✔
73

74
    def to_dict(self):
1✔
75
        """
76
        convert the fields of the object into a dictionnary
77
        """
78
        # all the attibutes defined by PKCS#11
79
        all_attributes = PyKCS11.CKA.keys()
1✔
80

81
        # only use the integer values and not the strings like 'CKM_RSA_PKCS'
82
        all_attributes = [attr for attr in all_attributes if isinstance(attr, int)]
1✔
83

84
        # all the attributes of the object
85
        attributes = self.session.getAttributeValue(self, all_attributes)
1✔
86

87
        dico = {}
1✔
88
        for key, attr in zip(all_attributes, attributes):
1✔
89
            if attr is None:
1✔
90
                continue
1✔
91
            if key == CKA_CLASS:
1✔
92
                dico[PyKCS11.CKA[key]] = PyKCS11.CKO[attr]
1✔
93
            elif key == CKA_CERTIFICATE_TYPE:
1✔
94
                dico[PyKCS11.CKA[key]] = PyKCS11.CKC[attr]
×
95
            elif key == CKA_KEY_TYPE:
1✔
96
                dico[PyKCS11.CKA[key]] = PyKCS11.CKK[attr]
1✔
97
            else:
98
                dico[PyKCS11.CKA[key]] = attr
1✔
99
        return dico
1✔
100

101
    def __repr__(self):
1✔
102
        """
103
        text representation of the object
104
        """
105
        dico = self.to_dict()
1✔
106
        lines = []
1✔
107
        for key in sorted(dico.keys()):
1✔
108
            lines.append(f"{key}: {dico[key]}")
1✔
109
        return "\n".join(lines)
1✔
110

111

112
class CkClass:
1✔
113
    """
114
    Base class for CK_* classes
115
    """
116

117
    # dictionnary of integer_value: text_value for the flags bits
118
    flags_dict = {}
1✔
119

120
    # dictionnary of fields names and types
121
    # type can be "pair", "flags" or "text"
122
    fields = {}
1✔
123

124
    flags = 0
1✔
125

126
    def flags2text(self):
1✔
127
        """
128
        parse the `self.flags` field and create a list of `CKF_*` strings
129
        corresponding to bits set in flags
130

131
        :return: a list of strings
132
        :rtype: list
133
        """
134
        r = []
1✔
135
        for k, v in self.flags_dict.items():
1✔
136
            if self.flags & k:
1✔
137
                r.append(v)
1✔
138
        return r
1✔
139

140
    def state2text(self):
1✔
141
        """
142
        Dummy method. Will be overwriden if necessary
143
        """
144
        return ""
×
145

146
    def to_dict(self):
1✔
147
        """
148
        convert the fields of the object into a dictionnary
149
        """
150
        dico = {}
1✔
151
        for field in self.fields:
1✔
152
            if field == "flags":
1✔
153
                dico[field] = self.flags2text()
1✔
154
            elif field == "state":
1✔
155
                dico[field] = self.state2text()
1✔
156
            else:
157
                dico[field] = self.__dict__[field]
1✔
158
        return dico
1✔
159

160
    def __str__(self):
1✔
161
        """
162
        text representation of the object
163
        """
164
        dico = self.to_dict()
1✔
165
        lines = []
1✔
166
        for key in sorted(dico.keys()):
1✔
167
            ck_type = self.fields[key]
1✔
168
            if ck_type == "flags":
1✔
169
                flags = ", ".join(dico[key])
1✔
170
                lines.append(f"{key}: {flags}")
1✔
171
            elif ck_type == "pair":
1✔
172
                p1, p2 = dico[key]
1✔
173
                lines.append(f"{key}: {p1}.{p2}")
1✔
174
            else:
175
                lines.append(f"{key}: {dico[key]}")
1✔
176
        return "\n".join(lines)
1✔
177

178

179
class CK_SLOT_INFO(CkClass):
1✔
180
    """
181
    matches the PKCS#11 CK_SLOT_INFO structure
182

183
    :ivar slotDescription: blank padded
184
    :type slotDescription: string
185
    :ivar manufacturerID: blank padded
186
    :type manufacturerID: string
187
    :ivar flags: See :func:`CkClass.flags2text`
188
    :type flags: integer
189
    :ivar hardwareVersion: 2 elements list
190
    :type hardwareVersion: list
191
    :ivar firmwareVersion: 2 elements list
192
    :type firmwareVersion: list
193
    """
194

195
    flags_dict = {
1✔
196
        CKF_TOKEN_PRESENT: "CKF_TOKEN_PRESENT",
197
        CKF_REMOVABLE_DEVICE: "CKF_REMOVABLE_DEVICE",
198
        CKF_HW_SLOT: "CKF_HW_SLOT",
199
    }
200

201
    fields = {
1✔
202
        "slotDescription": "text",
203
        "manufacturerID": "text",
204
        "flags": "flags",
205
        "hardwareVersion": "text",
206
        "firmwareVersion": "text",
207
    }
208

209
    def __init__(self):
1✔
210
        self.slotDescription = None
1✔
211
        self.manufacturerID = None
1✔
212
        self.flags = None
1✔
213
        self.hardwareVersion = None
1✔
214
        self.firmwareVersion = None
1✔
215

216

217
class CK_INFO(CkClass):
1✔
218
    """
219
    matches the PKCS#11 CK_INFO structure
220

221
    :ivar cryptokiVersion: Cryptoki interface version
222
    :type cryptokiVersion: integer
223
    :ivar manufacturerID: blank padded
224
    :type manufacturerID: string
225
    :ivar flags: must be zero
226
    :type flags: integer
227
    :ivar libraryDescription: blank padded
228
    :type libraryDescription: string
229
    :var libraryVersion: 2 elements list
230
    :type libraryVersion: list
231
    """
232

233
    fields = {
1✔
234
        "cryptokiVersion": "pair",
235
        "manufacturerID": "text",
236
        "flags": "flags",
237
        "libraryDescription": "text",
238
        "libraryVersion": "pair",
239
    }
240

241
    def __init__(self):
1✔
242
        self.cryptokiVersion = None
1✔
243
        self.manufacturerID = None
1✔
244
        self.flags = None
1✔
245
        self.libraryDescription = None
1✔
246
        self.libraryVersion = None
1✔
247

248

249
class CK_SESSION_INFO(CkClass):
1✔
250
    """
251
    matches the PKCS#11 CK_SESSION_INFO structure
252

253
    :ivar slotID: ID of the slot that interfaces with the token
254
    :type slotID: integer
255
    :ivar state: state of the session
256
    :type state: integer
257
    :ivar flags: bit flags that define the type of session
258
    :type flags: integer
259
    :ivar ulDeviceError: an error code defined by the cryptographic token
260
    :type ulDeviceError: integer
261
    """
262

263
    flags_dict = {
1✔
264
        CKF_RW_SESSION: "CKF_RW_SESSION",
265
        CKF_SERIAL_SESSION: "CKF_SERIAL_SESSION",
266
    }
267

268
    def __init__(self):
1✔
269
        self.slotID = None
1✔
270
        self.state = None
1✔
271
        self.flags = None
1✔
272
        self.ulDeviceError = None
1✔
273

274
    def state2text(self):
1✔
275
        """
276
        parse the `self.state` field and return a `CKS_*` string
277
        corresponding to the state
278

279
        :return: a string
280
        :rtype: string
281
        """
282
        return CKS[self.state]
1✔
283

284
    fields = {
1✔
285
        "slotID": "text",
286
        "state": "text",
287
        "flags": "flags",
288
        "ulDeviceError": "text",
289
    }
290

291

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

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

334
    # pylint: disable=too-many-instance-attributes
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 = {
1✔
358
        "label": "text",
359
        "manufacturerID": "text",
360
        "model": "text",
361
        "serialNumber": "text",
362
        "flags": "flags",
363
        "ulMaxSessionCount": "text",
364
        "ulSessionCount": "text",
365
        "ulMaxRwSessionCount": "text",
366
        "ulRwSessionCount": "text",
367
        "ulMaxPinLen": "text",
368
        "ulMinPinLen": "text",
369
        "ulTotalPublicMemory": "text",
370
        "ulFreePublicMemory": "text",
371
        "ulTotalPrivateMemory": "text",
372
        "ulFreePrivateMemory": "text",
373
        "hardwareVersion": "pair",
374
        "firmwareVersion": "pair",
375
        "utcTime": "text",
376
    }
377

378
    def __init__(self):
1✔
379
        self.label = None
1✔
380
        self.manufacturerID = None
1✔
381
        self.model = None
1✔
382
        self.serialNumber = None
1✔
383
        self.flags = None
1✔
384
        self.ulMaxSessionCount = None
1✔
385
        self.ulSessionCount = None
1✔
386
        self.ulMaxRwSessionCount = None
1✔
387
        self.ulRwSessionCount = None
1✔
388
        self.ulMaxPinLen = None
1✔
389
        self.ulMinPinLen = None
1✔
390
        self.ulTotalPublicMemory = None
1✔
391
        self.ulFreePublicMemory = None
1✔
392
        self.ulTotalPrivateMemory = None
1✔
393
        self.ulFreePrivateMemory = None
1✔
394
        self.hardwareVersion = None
1✔
395
        self.firmwareVersion = None
1✔
396
        self.utcTime = None
1✔
397

398

399
class CK_MECHANISM_INFO(CkClass):
1✔
400
    """
401
    matches the PKCS#11 CK_MECHANISM_INFO structure
402

403
    :ivar ulMinKeySize: minimum size of the key
404
    :type ulMinKeySize: integer
405
    :ivar ulMaxKeySize: maximum size of the key
406
    :type ulMaxKeySize: integer
407
    :ivar flags: bit flags specifying mechanism capabilities
408
    :type flags: integer
409
    """
410

411
    flags_dict = {
1✔
412
        CKF_HW: "CKF_HW",
413
        CKF_ENCRYPT: "CKF_ENCRYPT",
414
        CKF_DECRYPT: "CKF_DECRYPT",
415
        CKF_DIGEST: "CKF_DIGEST",
416
        CKF_SIGN: "CKF_SIGN",
417
        CKF_SIGN_RECOVER: "CKF_SIGN_RECOVER",
418
        CKF_VERIFY: "CKF_VERIFY",
419
        CKF_VERIFY_RECOVER: "CKF_VERIFY_RECOVER",
420
        CKF_GENERATE: "CKF_GENERATE",
421
        CKF_GENERATE_KEY_PAIR: "CKF_GENERATE_KEY_PAIR",
422
        CKF_WRAP: "CKF_WRAP",
423
        CKF_UNWRAP: "CKF_UNWRAP",
424
        CKF_DERIVE: "CKF_DERIVE",
425
        CKF_EXTENSION: "CKF_EXTENSION",
426
    }
427

428
    fields = {"ulMinKeySize": "text", "ulMaxKeySize": "text", "flags": "flags"}
1✔
429

430
    def __init__(self):
1✔
431
        self.ulMinKeySize = None
1✔
432
        self.ulMaxKeySize = None
1✔
433
        self.flags = None
1✔
434

435

436
class PyKCS11Error(Exception):
1✔
437
    """define the possible PyKCS11 exceptions"""
438

439
    def __init__(self, value, text=""):
1✔
440
        self.value = value
1✔
441
        self.text = text
1✔
442

443
    def __str__(self):
1✔
444
        """
445
        The text representation of a PKCS#11 error is something like:
446
        "CKR_DEVICE_ERROR (0x00000030)"
447
        """
448
        if self.value in CKR:
1✔
449
            if self.value < 0:
1✔
450
                return CKR[self.value] + f" ({self.text})"
1✔
451
            return CKR[self.value] + f" (0x{self.value:08X})"
1✔
452
        if self.value & CKR_VENDOR_DEFINED:
1✔
453
            v = self.value & 0xFFFFFFFF & ~CKR_VENDOR_DEFINED
1✔
454
            return f"Vendor error (0x{v:08X})"
1✔
455
        return f"Unknown error (0x{self.value:08X})"
1✔
456

457

458
class PyKCS11Lib:
1✔
459
    """high level PKCS#11 binding"""
460

461
    # shared by all instances
462
    _loaded_libs = {}
1✔
463
    _lock = threading.Lock()
1✔
464

465
    def __init__(self):
1✔
466
        self.lib = PyKCS11.LowLevel.CPKCS11Lib()
1✔
467
        self.pkcs11dll_filename = None
1✔
468

469
    def __del__(self):
1✔
470
        # pylint: disable=too-many-boolean-expressions
471
        if (
1✔
472
            PyKCS11
473
            and PyKCS11.__name__
474
            and PyKCS11.LowLevel
475
            and PyKCS11.LowLevel.__name__
476
            and PyKCS11.LowLevel._LowLevel
477
            and PyKCS11.LowLevel._LowLevel.__name__
478
        ):
479

480
            # unload the library
481
            self.unload()
1✔
482

483
    def load(self, pkcs11dll_filename=None):
1✔
484
        """
485
        load a PKCS#11 library
486

487
        :type pkcs11dll_filename: string
488
        :param pkcs11dll_filename: the library name.
489
          If this parameter is not set then the environment variable
490
          `PYKCS11LIB` is used instead
491
        :returns: a :class:`PyKCS11Lib` object
492
        :raises: :class:`PyKCS11Error` (-1): when the load fails
493
        """
494
        with PyKCS11Lib._lock:
1✔
495
            if pkcs11dll_filename is None:
1✔
496
                pkcs11dll_filename = os.getenv("PYKCS11LIB")
1✔
497
                if pkcs11dll_filename is None:
1✔
498
                    raise PyKCS11Error(
×
499
                        -1, "No PKCS11 library specified (set PYKCS11LIB env variable)"
500
                    )
501

502
            if self.pkcs11dll_filename is not None:
1✔
503
                self._unload_locked()  # unload the previous library
1✔
504
                # if the instance was previously initialized,
505
                # create a new low level library object for it
506
                self.lib = PyKCS11.LowLevel.CPKCS11Lib()
1✔
507

508
            # if the lib is already in use: reuse it
509
            if pkcs11dll_filename in PyKCS11Lib._loaded_libs:
1✔
510
                self.lib.Duplicate(PyKCS11Lib._loaded_libs[pkcs11dll_filename]["ref"])
1✔
511
            else:
512
                # else load it
513
                rv = self.lib.Load(pkcs11dll_filename)
1✔
514
                if rv != CKR_OK:
1✔
515
                    raise PyKCS11Error(rv, pkcs11dll_filename)
1✔
516
                PyKCS11Lib._loaded_libs[pkcs11dll_filename] = {
1✔
517
                    "ref": self.lib,
518
                    "nb_users": 0,
519
                }
520

521
            # remember the lib file name
522
            self.pkcs11dll_filename = pkcs11dll_filename
1✔
523

524
            # increase user number
525
            PyKCS11Lib._loaded_libs[pkcs11dll_filename]["nb_users"] += 1
1✔
526

527
        return self
1✔
528

529
    def unload(self):
1✔
530
        """
531
        unload the current instance of a PKCS#11 library
532
        """
533
        with PyKCS11Lib._lock:
1✔
534
            self._unload_locked()
1✔
535

536
    def _unload_locked(self):
1✔
537
        """
538
        unload the current instance of a PKCS#11 library
539
        The lock is already held
540
        """
541

542
        # in case NO library was found and used
543
        if self.pkcs11dll_filename is None:
1✔
544
            return
1✔
545

546
        if self.pkcs11dll_filename not in PyKCS11Lib._loaded_libs:
1✔
547
            raise PyKCS11Error(
×
548
                -1,
549
                f"invalid PyKCS11Lib state: {self.pkcs11dll_filename} "
550
                + f"not in {PyKCS11Lib._loaded_libs}",
551
            )
552

553
        # decrease user number
554
        PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]["nb_users"] -= 1
1✔
555

556
        if PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]["nb_users"] == 0:
1✔
557
            # unload only if no more used
558
            self.lib.Unload()
1✔
559

560
        # remove unused entry
561
        # the case < 0 happens if lib loading failed
562
        if PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]["nb_users"] <= 0:
1✔
563
            del PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]
1✔
564

565
        self.pkcs11dll_filename = None
1✔
566

567
    def initToken(self, slot, pin, label):
1✔
568
        """
569
        C_InitToken
570

571
        :param slot: slot number returned by :func:`getSlotList`
572
        :type slot: integer
573
        :param pin: Security Officer's initial PIN
574
        :param label: new label of the token
575
        """
576
        pin1 = ckbytelist(pin)
1✔
577
        rv = self.lib.C_InitToken(slot, pin1, label)
1✔
578
        if rv != CKR_OK:
1✔
579
            raise PyKCS11Error(rv)
×
580

581
    def getInfo(self):
1✔
582
        """
583
        C_GetInfo
584

585
        :return: a :class:`CK_INFO` object
586
        """
587
        info = PyKCS11.LowLevel.CK_INFO()
1✔
588
        rv = self.lib.C_GetInfo(info)
1✔
589
        if rv != CKR_OK:
1✔
590
            raise PyKCS11Error(rv)
×
591

592
        i = CK_INFO()
1✔
593
        i.cryptokiVersion = (info.cryptokiVersion.major, info.cryptokiVersion.minor)
1✔
594
        i.manufacturerID = info.GetManufacturerID()
1✔
595
        i.flags = info.flags
1✔
596
        i.libraryDescription = info.GetLibraryDescription()
1✔
597
        i.libraryVersion = (info.libraryVersion.major, info.libraryVersion.minor)
1✔
598
        return i
1✔
599

600
    def getSlotList(self, tokenPresent=False):
1✔
601
        """
602
        C_GetSlotList
603

604
        :param tokenPresent: `False` (default) to list all slots,
605
          `True` to list only slots with present tokens
606
        :type tokenPresent: bool
607
        :return: a list of available slots
608
        :rtype: list
609
        """
610
        slotList = PyKCS11.LowLevel.ckulonglist()
1✔
611
        rv = self.lib.C_GetSlotList(CK_TRUE if tokenPresent else CK_FALSE, slotList)
1✔
612
        if rv != CKR_OK:
1✔
613
            raise PyKCS11Error(rv)
×
614

615
        s = []
1✔
616
        for x in slotList:
1✔
617
            s.append(x)
1✔
618
        return s
1✔
619

620
    def getSlotInfo(self, slot):
1✔
621
        """
622
        C_GetSlotInfo
623

624
        :param slot: slot number returned by :func:`getSlotList`
625
        :type slot: integer
626
        :return: a :class:`CK_SLOT_INFO` object
627
        """
628
        slotInfo = PyKCS11.LowLevel.CK_SLOT_INFO()
1✔
629
        rv = self.lib.C_GetSlotInfo(slot, slotInfo)
1✔
630
        if rv != CKR_OK:
1✔
631
            raise PyKCS11Error(rv)
×
632

633
        s = CK_SLOT_INFO()
1✔
634
        s.slotDescription = slotInfo.GetSlotDescription()
1✔
635
        s.manufacturerID = slotInfo.GetManufacturerID()
1✔
636
        s.flags = slotInfo.flags
1✔
637
        s.hardwareVersion = slotInfo.GetHardwareVersion()
1✔
638
        s.firmwareVersion = slotInfo.GetFirmwareVersion()
1✔
639

640
        return s
1✔
641

642
    def getTokenInfo(self, slot):
1✔
643
        """
644
        C_GetTokenInfo
645

646
        :param slot: slot number returned by :func:`getSlotList`
647
        :type slot: integer
648
        :return: a :class:`CK_TOKEN_INFO` object
649
        """
650
        tokeninfo = PyKCS11.LowLevel.CK_TOKEN_INFO()
1✔
651
        rv = self.lib.C_GetTokenInfo(slot, tokeninfo)
1✔
652
        if rv != CKR_OK:
1✔
653
            raise PyKCS11Error(rv)
×
654

655
        t = CK_TOKEN_INFO()
1✔
656
        t.label = tokeninfo.GetLabel()
1✔
657
        t.manufacturerID = tokeninfo.GetManufacturerID()
1✔
658
        t.model = tokeninfo.GetModel()
1✔
659
        t.serialNumber = tokeninfo.GetSerialNumber()
1✔
660
        t.flags = tokeninfo.flags
1✔
661
        t.ulMaxSessionCount = tokeninfo.ulMaxSessionCount
1✔
662
        if t.ulMaxSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
663
            t.ulMaxSessionCount = -1
×
664
        t.ulSessionCount = tokeninfo.ulSessionCount
1✔
665
        if t.ulSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
666
            t.ulSessionCount = -1
1✔
667
        t.ulMaxRwSessionCount = tokeninfo.ulMaxRwSessionCount
1✔
668
        if t.ulMaxRwSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
669
            t.ulMaxRwSessionCount = -1
×
670
        t.ulRwSessionCount = tokeninfo.ulRwSessionCount
1✔
671
        if t.ulRwSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
672
            t.ulRwSessionCount = -1
1✔
673
        t.ulMaxPinLen = tokeninfo.ulMaxPinLen
1✔
674
        t.ulMinPinLen = tokeninfo.ulMinPinLen
1✔
675
        t.ulTotalPublicMemory = tokeninfo.ulTotalPublicMemory
1✔
676

677
        if t.ulTotalPublicMemory == CK_UNAVAILABLE_INFORMATION:
1✔
678
            t.ulTotalPublicMemory = -1
1✔
679
        t.ulFreePublicMemory = tokeninfo.ulFreePublicMemory
1✔
680
        if t.ulFreePublicMemory == CK_UNAVAILABLE_INFORMATION:
1✔
681
            t.ulFreePublicMemory = -1
1✔
682
        t.ulTotalPrivateMemory = tokeninfo.ulTotalPrivateMemory
1✔
683
        if t.ulTotalPrivateMemory == CK_UNAVAILABLE_INFORMATION:
1✔
684
            t.ulTotalPrivateMemory = -1
1✔
685
        t.ulFreePrivateMemory = tokeninfo.ulFreePrivateMemory
1✔
686
        if t.ulFreePrivateMemory == CK_UNAVAILABLE_INFORMATION:
1✔
687
            t.ulFreePrivateMemory = -1
1✔
688
        t.hardwareVersion = (
1✔
689
            tokeninfo.hardwareVersion.major,
690
            tokeninfo.hardwareVersion.minor,
691
        )
692
        t.firmwareVersion = (
1✔
693
            tokeninfo.firmwareVersion.major,
694
            tokeninfo.firmwareVersion.minor,
695
        )
696
        t.utcTime = tokeninfo.GetUtcTime().replace("\000", " ")
1✔
697

698
        return t
1✔
699

700
    def openSession(self, slot, flags=0):
1✔
701
        """
702
        C_OpenSession
703

704
        :param slot: slot number returned by :func:`getSlotList`
705
        :type slot: integer
706
        :param flags: 0 (default), `CKF_RW_SESSION` for RW session
707
        :type flags: integer
708
        :return: a :class:`Session` object
709
        """
710
        se = PyKCS11.LowLevel.CK_SESSION_HANDLE()
1✔
711
        flags |= CKF_SERIAL_SESSION
1✔
712
        rv = self.lib.C_OpenSession(slot, flags, se)
1✔
713
        if rv != CKR_OK:
1✔
714
            raise PyKCS11Error(rv)
×
715

716
        return Session(self, se)
1✔
717

718
    def closeAllSessions(self, slot):
1✔
719
        """
720
        C_CloseAllSessions
721

722
        :param slot: slot number
723
        :type slot: integer
724
        """
725
        rv = self.lib.C_CloseAllSessions(slot)
1✔
726
        if rv != CKR_OK:
1✔
727
            raise PyKCS11Error(rv)
×
728

729
    def getMechanismList(self, slot):
1✔
730
        """
731
        C_GetMechanismList
732

733
        :param slot: slot number returned by :func:`getSlotList`
734
        :type slot: integer
735
        :return: the list of available mechanisms for a slot
736
        :rtype: list
737
        """
738
        mechanismList = PyKCS11.LowLevel.ckulonglist()
1✔
739
        rv = self.lib.C_GetMechanismList(slot, mechanismList)
1✔
740
        if rv != CKR_OK:
1✔
741
            raise PyKCS11Error(rv)
×
742

743
        m = []
1✔
744
        for mechanism in mechanismList:
1✔
745
            if mechanism >= CKM_VENDOR_DEFINED:
1✔
746
                mecha = mechanism - CKM_VENDOR_DEFINED
×
747
                k = f"CKM_VENDOR_DEFINED_0x{mecha:X}"
×
748
                CKM[k] = mechanism
×
749
                CKM[mechanism] = k
×
750
            m.append(CKM[mechanism])
1✔
751
        return m
1✔
752

753
    def getMechanismInfo(self, slot, ckm_type):
1✔
754
        """
755
        C_GetMechanismInfo
756

757
        :param slot: slot number returned by :func:`getSlotList`
758
        :type slot: integer
759
        :param ckm_type: a `CKM_*` type
760
        :type ckm_type: integer
761
        :return: information about a mechanism
762
        :rtype: a :class:`CK_MECHANISM_INFO` object
763
        """
764
        info = PyKCS11.LowLevel.CK_MECHANISM_INFO()
1✔
765
        rv = self.lib.C_GetMechanismInfo(slot, CKM[ckm_type], info)
1✔
766
        if rv != CKR_OK:
1✔
767
            raise PyKCS11Error(rv)
×
768

769
        i = CK_MECHANISM_INFO()
1✔
770
        i.ulMinKeySize = info.ulMinKeySize
1✔
771
        i.ulMaxKeySize = info.ulMaxKeySize
1✔
772
        i.flags = info.flags
1✔
773

774
        return i
1✔
775

776
    def waitForSlotEvent(self, flags=0):
1✔
777
        """
778
        C_WaitForSlotEvent
779

780
        :param flags: 0 (default) or `CKF_DONT_BLOCK`
781
        :type flags: integer
782
        :return: slot
783
        :rtype: integer
784
        """
785
        tmp = 0
×
786
        (rv, slot) = self.lib.C_WaitForSlotEvent(flags, tmp)
×
787
        if rv != CKR_OK:
×
788
            raise PyKCS11Error(rv)
×
789

790
        return slot
×
791

792

793
class Mechanism:
1✔
794
    """Wraps CK_MECHANISM"""
795

796
    # pylint: disable=too-few-public-methods
797

798
    def __init__(self, mechanism, param=None):
1✔
799
        """
800
        :param mechanism: the mechanism to be used
801
        :type mechanism: integer, any `CKM_*` value
802
        :param param: data to be used as crypto operation parameter
803
          (i.e. the IV for some algorithms)
804
        :type param: string or list/tuple of bytes
805

806
        :see: :func:`Session.decrypt`, :func:`Session.sign`
807
        """
808
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
809
        self._mech.mechanism = mechanism
1✔
810
        self._param = None
1✔
811
        if param:
1✔
812
            self._param = ckbytelist(param)
1✔
813
            self._mech.pParameter = self._param
1✔
814
            self._mech.ulParameterLen = len(param)
1✔
815

816
    def to_native(self):
1✔
817
        """convert mechanism to native format"""
818
        return self._mech
1✔
819

820

821
MechanismSHA1 = Mechanism(CKM_SHA_1, None)
1✔
822
MechanismRSAPKCS1 = Mechanism(CKM_RSA_PKCS, None)
1✔
823
MechanismRSAGENERATEKEYPAIR = Mechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, None)
1✔
824
MechanismECGENERATEKEYPAIR = Mechanism(CKM_EC_KEY_PAIR_GEN, None)
1✔
825
MechanismAESGENERATEKEY = Mechanism(CKM_AES_KEY_GEN, None)
1✔
826

827

828
class AES_GCM_Mechanism:
1✔
829
    """CKM_AES_GCM warpping mechanism"""
830

831
    # pylint: disable=too-few-public-methods
832

833
    def __init__(self, iv, aad, tagBits):
1✔
834
        """
835
        :param iv: initialization vector
836
        :param aad: additional authentication data
837
        :param tagBits: length of authentication tag in bits
838
        """
839
        self._param = PyKCS11.LowLevel.CK_GCM_PARAMS()
1✔
840

841
        self._source_iv = ckbytelist(iv)
1✔
842
        self._param.pIv = self._source_iv
1✔
843
        self._param.ulIvLen = len(self._source_iv)
1✔
844

845
        self._source_aad = ckbytelist(aad)
1✔
846
        self._param.pAAD = self._source_aad
1✔
847
        self._param.ulAADLen = len(self._source_aad)
1✔
848

849
        self._param.ulTagBits = tagBits
1✔
850

851
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
852
        self._mech.mechanism = CKM_AES_GCM
1✔
853
        self._mech.pParameter = self._param
1✔
854
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_GCM_PARAMS_LENGTH
1✔
855

856
    def to_native(self):
1✔
857
        """convert mechanism to native format"""
858
        return self._mech
1✔
859

860

861
class AES_CTR_Mechanism:
1✔
862
    """CKM_AES_CTR encryption mechanism"""
863

864
    # pylint: disable=too-few-public-methods
865

866
    def __init__(self, counterBits, counterBlock):
1✔
867
        """
868
        :param counterBits: the number of incremented bits in the counter block
869
        :param counterBlock: a 16-byte initial value of the counter block
870
        """
871
        self._param = PyKCS11.LowLevel.CK_AES_CTR_PARAMS()
1✔
872

873
        self._source_cb = ckbytelist(counterBlock)
1✔
874
        self._param.ulCounterBits = counterBits
1✔
875
        self._param.cb = self._source_cb
1✔
876

877
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
878
        self._mech.mechanism = CKM_AES_CTR
1✔
879
        self._mech.pParameter = self._param
1✔
880
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_AES_CTR_PARAMS_LENGTH
1✔
881

882
    def to_native(self):
1✔
883
        """convert mechanism to native format"""
884
        return self._mech
1✔
885

886

887
class RSAOAEPMechanism:
1✔
888
    """RSA OAEP Wrapping mechanism"""
889

890
    # pylint: disable=too-few-public-methods
891

892
    def __init__(self, hashAlg, mgf, label=None):
1✔
893
        """
894
        :param hashAlg: the hash algorithm to use (like `CKM_SHA256`)
895
        :param mgf: the mask generation function to use (like
896
          `CKG_MGF1_SHA256`)
897
        :param label: the (optional) label to use
898
        """
899
        self._param = PyKCS11.LowLevel.CK_RSA_PKCS_OAEP_PARAMS()
1✔
900
        self._param.hashAlg = hashAlg
1✔
901
        self._param.mgf = mgf
1✔
902
        self._source = None
1✔
903
        self._param.source = CKZ_DATA_SPECIFIED
1✔
904
        if label:
1✔
905
            self._source = ckbytelist(label)
×
906
            self._param.ulSourceDataLen = len(self._source)
×
907
        else:
908
            self._param.ulSourceDataLen = 0
1✔
909
        self._param.pSourceData = self._source
1✔
910
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
911
        self._mech.mechanism = CKM_RSA_PKCS_OAEP
1✔
912
        self._mech.pParameter = self._param
1✔
913
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_RSA_PKCS_OAEP_PARAMS_LENGTH
1✔
914

915
    def to_native(self):
1✔
916
        """convert mechanism to native format"""
917
        return self._mech
1✔
918

919

920
class RSA_PSS_Mechanism:
1✔
921
    """RSA PSS Wrapping mechanism"""
922

923
    # pylint: disable=too-few-public-methods
924

925
    def __init__(self, mecha, hashAlg, mgf, sLen):
1✔
926
        """
927
        :param mecha: the mechanism to use (like
928
          `CKM_SHA384_RSA_PKCS_PSS`)
929
        :param hashAlg: the hash algorithm to use (like `CKM_SHA384`)
930
        :param mgf: the mask generation function to use (like
931
          `CKG_MGF1_SHA384`)
932
        :param sLen: length, in bytes, of the salt value used in the PSS
933
          encoding (like 0 or the message length)
934
        """
935
        self._param = PyKCS11.LowLevel.CK_RSA_PKCS_PSS_PARAMS()
1✔
936
        self._param.hashAlg = hashAlg
1✔
937
        self._param.mgf = mgf
1✔
938
        self._param.sLen = sLen
1✔
939
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
940
        self._mech.mechanism = mecha
1✔
941
        self._mech.pParameter = self._param
1✔
942
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_RSA_PKCS_PSS_PARAMS_LENGTH
1✔
943

944
    def to_native(self):
1✔
945
        """convert mechanism to native format"""
946
        return self._mech
1✔
947

948

949
class ECDH1_DERIVE_Mechanism:
1✔
950
    """CKM_ECDH1_DERIVE key derivation mechanism"""
951

952
    # pylint: disable=too-few-public-methods
953

954
    def __init__(self, publicData, kdf=CKD_NULL, sharedData=None):
1✔
955
        """
956
        :param publicData: Other party public key which is EC Point [PC || coord-x || coord-y].
957
        :param kdf: Key derivation function. OPTIONAL. Defaults to CKD_NULL
958
        :param sharedData: additional shared data. OPTIONAL
959
        """
960
        self._param = PyKCS11.LowLevel.CK_ECDH1_DERIVE_PARAMS()
1✔
961

962
        self._param.kdf = kdf
1✔
963

964
        if sharedData:
1✔
965
            self._shared_data = ckbytelist(sharedData)
×
966
            self._param.pSharedData = self._shared_data
×
967
            self._param.ulSharedDataLen = len(self._shared_data)
×
968
        else:
969
            self._source_shared_data = None
1✔
970
            self._param.ulSharedDataLen = 0
1✔
971

972
        self._public_data = ckbytelist(publicData)
1✔
973
        self._param.pPublicData = self._public_data
1✔
974
        self._param.ulPublicDataLen = len(self._public_data)
1✔
975

976
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
977
        self._mech.mechanism = CKM_ECDH1_DERIVE
1✔
978
        self._mech.pParameter = self._param
1✔
979
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_ECDH1_DERIVE_PARAMS_LENGTH
1✔
980

981
    def to_native(self):
1✔
982
        """convert mechanism to native format"""
983
        return self._mech
1✔
984

985

986
class CONCATENATE_BASE_AND_KEY_Mechanism:
1✔
987
    """CKM_CONCATENATE_BASE_AND_KEY key derivation mechanism"""
988

989
    # pylint: disable=too-few-public-methods
990

991
    def __init__(self, encKey):
1✔
992
        """
993
        :param encKey: a handle of encryption key
994
        """
995
        self._encKey = encKey
×
996

997
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
998
        self._mech.mechanism = CKM_CONCATENATE_BASE_AND_KEY
×
999
        self._mech.pParameter = self._encKey
×
1000
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_OBJECT_HANDLE_LENGTH
×
1001

1002
    def to_native(self):
1✔
1003
        """convert mechanism to native format"""
1004
        return self._mech
×
1005

1006

1007
class KEY_DERIVATION_STRING_DATA_MechanismBase:
1✔
1008
    """Base class for mechanisms using derivation string data"""
1009

1010
    # pylint: disable=too-few-public-methods
1011

1012
    def __init__(self, data, mechType):
1✔
1013
        """
1014
        :param data: a byte array to concatenate the key with
1015
        :param mechType: mechanism type
1016
        """
1017
        self._param = PyKCS11.LowLevel.CK_KEY_DERIVATION_STRING_DATA()
×
1018

1019
        self._data = ckbytelist(data)
×
1020
        self._param.pData = self._data
×
1021
        self._param.ulLen = len(self._data)
×
1022

1023
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
1024
        self._mech.mechanism = mechType
×
1025
        self._mech.pParameter = self._param
×
1026
        self._mech.ulParameterLen = (
×
1027
            PyKCS11.LowLevel.CK_KEY_DERIVATION_STRING_DATA_LENGTH
1028
        )
1029

1030
    def to_native(self):
1✔
1031
        """convert mechanism to native format"""
1032
        return self._mech
×
1033

1034

1035
class CONCATENATE_BASE_AND_DATA_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
1036
    """CKM_CONCATENATE_BASE_AND_DATA key derivation mechanism"""
1037

1038
    # pylint: disable=too-few-public-methods
1039

1040
    def __init__(self, data):
1✔
1041
        """
1042
        :param data: a byte array to concatenate the key with
1043
        """
1044
        super().__init__(data, CKM_CONCATENATE_BASE_AND_DATA)
×
1045

1046

1047
class CONCATENATE_DATA_AND_BASE_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
1048
    """CKM_CONCATENATE_DATA_AND_BASE key derivation mechanism"""
1049

1050
    # pylint: disable=too-few-public-methods
1051

1052
    def __init__(self, data):
1✔
1053
        """
1054
        :param data: a byte array to concatenate the key with
1055
        """
1056
        super().__init__(data, CKM_CONCATENATE_DATA_AND_BASE)
×
1057

1058

1059
class XOR_BASE_AND_DATA_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
1060
    """CKM_XOR_BASE_AND_DATA key derivation mechanism"""
1061

1062
    # pylint: disable=too-few-public-methods
1063

1064
    def __init__(self, data):
1✔
1065
        """
1066
        :param data: a byte array to xor the key with
1067
        """
1068
        super().__init__(data, CKM_XOR_BASE_AND_DATA)
×
1069

1070

1071
class EXTRACT_KEY_FROM_KEY_Mechanism:
1✔
1072
    """CKM_EXTRACT_KEY_FROM_KEY key derivation mechanism"""
1073

1074
    # pylint: disable=too-few-public-methods
1075

1076
    def __init__(self, extractParams):
1✔
1077
        """
1078
        :param extractParams: the index of the first bit of the original
1079
        key to be used in the newly-derived key.  For example if
1080
        extractParams=5 then the 5 first bits are skipped and not used.
1081
        """
1082
        self._param = PyKCS11.LowLevel.CK_EXTRACT_PARAMS()
×
1083
        self._param.assign(extractParams)
×
1084

1085
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
1086
        self._mech.mechanism = CKM_EXTRACT_KEY_FROM_KEY
×
1087
        self._mech.pParameter = self._param
×
1088
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_EXTRACT_PARAMS_LENGTH
×
1089

1090
    def to_native(self):
1✔
1091
        """convert mechanism to native format"""
1092
        return self._mech
×
1093

1094

1095
class DigestSession:
1✔
1096
    """Digest session"""
1097

1098
    def __init__(self, lib, session, mecha):
1✔
1099
        self._lib = lib
1✔
1100
        self._session = session
1✔
1101
        self._mechanism = mecha.to_native()
1✔
1102
        rv = self._lib.C_DigestInit(self._session, self._mechanism)
1✔
1103
        if rv != CKR_OK:
1✔
1104
            raise PyKCS11Error(rv)
×
1105

1106
    def update(self, data):
1✔
1107
        """
1108
        C_DigestUpdate
1109

1110
        :param data: data to add to the digest
1111
        :type data: bytes or string
1112
        """
1113
        data1 = ckbytelist(data)
1✔
1114
        rv = self._lib.C_DigestUpdate(self._session, data1)
1✔
1115
        if rv != CKR_OK:
1✔
1116
            raise PyKCS11Error(rv)
×
1117
        return self
1✔
1118

1119
    def digestKey(self, handle):
1✔
1120
        """
1121
        C_DigestKey
1122

1123
        :param handle: key handle
1124
        :type handle: CK_OBJECT_HANDLE
1125
        """
1126
        rv = self._lib.C_DigestKey(self._session, handle)
×
1127
        if rv != CKR_OK:
×
1128
            raise PyKCS11Error(rv)
×
1129
        return self
×
1130

1131
    def final(self):
1✔
1132
        """
1133
        C_DigestFinal
1134

1135
        :return: the digest
1136
        :rtype: ckbytelist
1137
        """
1138
        digest = ckbytelist()
1✔
1139
        # Get the size of the digest
1140
        rv = self._lib.C_DigestFinal(self._session, digest)
1✔
1141
        if rv != CKR_OK:
1✔
1142
            raise PyKCS11Error(rv)
×
1143
        # Get the actual digest
1144
        rv = self._lib.C_DigestFinal(self._session, digest)
1✔
1145
        if rv != CKR_OK:
1✔
1146
            raise PyKCS11Error(rv)
×
1147
        return digest
1✔
1148

1149

1150
class Session:
1✔
1151
    """Manage :func:`PyKCS11Lib.openSession` objects"""
1152

1153
    # pylint: disable=too-many-public-methods
1154

1155
    def __init__(self, pykcs11, session):
1✔
1156
        """
1157
        :param pykcs11: PyKCS11 library object
1158
        :type pykcs11: PyKCS11Lib
1159
        :param session: session handle
1160
        :type session: instance of :class:`CK_SESSION_HANDLE`
1161
        """
1162
        if not isinstance(pykcs11, PyKCS11Lib):
1✔
1163
            raise TypeError("pykcs11 must be a PyKCS11Lib")
×
1164
        if not isinstance(session, PyKCS11.LowLevel.CK_SESSION_HANDLE):
1✔
1165
            raise TypeError("session must be a CK_SESSION_HANDLE")
×
1166

1167
        # hold the PyKCS11Lib reference, so that it's not Garbage Collection'd
1168
        self.pykcs11 = pykcs11
1✔
1169
        self.session = session
1✔
1170

1171
    @property
1✔
1172
    def lib(self):
1✔
1173
        """
1174
        Get the low level lib of the owning PyKCS11Lib
1175
        """
1176
        return self.pykcs11.lib
1✔
1177

1178
    def closeSession(self):
1✔
1179
        """
1180
        C_CloseSession
1181
        """
1182
        rv = self.lib.C_CloseSession(self.session)
1✔
1183
        if rv != CKR_OK:
1✔
1184
            raise PyKCS11Error(rv)
×
1185

1186
    def getSessionInfo(self):
1✔
1187
        """
1188
        C_GetSessionInfo
1189

1190
        :return: a :class:`CK_SESSION_INFO` object
1191
        """
1192
        sessioninfo = PyKCS11.LowLevel.CK_SESSION_INFO()
1✔
1193
        rv = self.lib.C_GetSessionInfo(self.session, sessioninfo)
1✔
1194
        if rv != CKR_OK:
1✔
1195
            raise PyKCS11Error(rv)
×
1196

1197
        s = CK_SESSION_INFO()
1✔
1198
        s.slotID = sessioninfo.slotID
1✔
1199
        s.state = sessioninfo.state
1✔
1200
        s.flags = sessioninfo.flags
1✔
1201
        s.ulDeviceError = sessioninfo.ulDeviceError
1✔
1202
        return s
1✔
1203

1204
    def login(self, pin, user_type=CKU_USER):
1✔
1205
        """
1206
        C_Login
1207

1208
        :param pin: the user's PIN or None for CKF_PROTECTED_AUTHENTICATION_PATH
1209
        :type pin: string
1210
        :param user_type: the user type. The default value is
1211
          CKU_USER. You may also use CKU_SO
1212
        :type user_type: integer
1213
        """
1214
        pin1 = ckbytelist(pin)
1✔
1215
        rv = self.lib.C_Login(self.session, user_type, pin1)
1✔
1216
        if rv != CKR_OK:
1✔
1217
            raise PyKCS11Error(rv)
1✔
1218

1219
    def logout(self):
1✔
1220
        """
1221
        C_Logout
1222
        """
1223
        rv = self.lib.C_Logout(self.session)
1✔
1224
        if rv != CKR_OK:
1✔
1225
            raise PyKCS11Error(rv)
×
1226

1227
        del self
1✔
1228

1229
    def initPin(self, pin):
1✔
1230
        """
1231
        C_InitPIN
1232

1233
        :param pin: new PIN
1234
        """
1235
        new_pin1 = ckbytelist(pin)
1✔
1236
        rv = self.lib.C_InitPIN(self.session, new_pin1)
1✔
1237
        if rv != CKR_OK:
1✔
1238
            raise PyKCS11Error(rv)
×
1239

1240
    def setPin(self, old_pin, new_pin):
1✔
1241
        """
1242
        C_SetPIN
1243

1244
        :param old_pin: old PIN
1245
        :param new_pin: new PIN
1246
        """
1247
        old_pin1 = ckbytelist(old_pin)
1✔
1248
        new_pin1 = ckbytelist(new_pin)
1✔
1249
        rv = self.lib.C_SetPIN(self.session, old_pin1, new_pin1)
1✔
1250
        if rv != CKR_OK:
1✔
1251
            raise PyKCS11Error(rv)
×
1252

1253
    def createObject(self, template):
1✔
1254
        """
1255
        C_CreateObject
1256

1257
        :param template: object template
1258
        """
1259
        attrs = self._template2ckattrlist(template)
1✔
1260
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1261
        rv = self.lib.C_CreateObject(self.session, attrs, handle)
1✔
1262
        if rv != PyKCS11.CKR_OK:
1✔
1263
            raise PyKCS11.PyKCS11Error(rv)
×
1264
        return handle
1✔
1265

1266
    def destroyObject(self, obj):
1✔
1267
        """
1268
        C_DestroyObject
1269

1270
        :param obj: object ID
1271
        """
1272
        rv = self.lib.C_DestroyObject(self.session, obj)
1✔
1273
        if rv != CKR_OK:
1✔
1274
            raise PyKCS11Error(rv)
×
1275

1276
    def digestSession(self, mecha=MechanismSHA1):
1✔
1277
        """
1278
        C_DigestInit/C_DigestUpdate/C_DigestKey/C_DigestFinal
1279

1280
        :param mecha: the digesting mechanism to be used
1281
          (use `MechanismSHA1` for `CKM_SHA_1`)
1282
        :type mecha: :class:`Mechanism`
1283
        :return: A :class:`DigestSession` object
1284
        :rtype: DigestSession
1285
        """
1286
        return DigestSession(self.lib, self.session, mecha)
1✔
1287

1288
    def digest(self, data, mecha=MechanismSHA1):
1✔
1289
        """
1290
        C_DigestInit/C_Digest
1291

1292
        :param data: the data to be digested
1293
        :type data:  (binary) sring or list/tuple of bytes
1294
        :param mecha: the digesting mechanism to be used
1295
          (use `MechanismSHA1` for `CKM_SHA_1`)
1296
        :type mecha: :class:`Mechanism`
1297
        :return: the computed digest
1298
        :rtype: ckbytelist
1299

1300
        :note: the returned value is an istance of :class:`ckbytelist`.
1301
          You can easly convert it to a binary string with:
1302
          ``bytes(ckbytelistDigest)``
1303
          or, for Python 2:
1304
          ``''.join(chr(i) for i in ckbytelistDigest)``
1305

1306
        """
1307
        digest = ckbytelist()
1✔
1308
        m = mecha.to_native()
1✔
1309
        data1 = ckbytelist(data)
1✔
1310
        rv = self.lib.C_DigestInit(self.session, m)
1✔
1311
        if rv != CKR_OK:
1✔
1312
            raise PyKCS11Error(rv)
×
1313
        # first call get digest size
1314
        rv = self.lib.C_Digest(self.session, data1, digest)
1✔
1315
        if rv != CKR_OK:
1✔
1316
            raise PyKCS11Error(rv)
×
1317
        # second call get actual digest data
1318
        rv = self.lib.C_Digest(self.session, data1, digest)
1✔
1319
        if rv != CKR_OK:
1✔
1320
            raise PyKCS11Error(rv)
×
1321
        return digest
1✔
1322

1323
    def sign(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1324
        """
1325
        C_SignInit/C_Sign
1326

1327
        :param key: a key handle, obtained calling :func:`findObjects`.
1328
        :type key: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1329
        :param data: the data to be signed
1330
        :type data:  (binary) string or list/tuple of bytes
1331
        :param mecha: the signing mechanism to be used
1332
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1333
        :type mecha: :class:`Mechanism`
1334
        :return: the computed signature
1335
        :rtype: ckbytelist
1336

1337
        :note: the returned value is an instance of :class:`ckbytelist`.
1338
          You can easly convert it to a binary string with:
1339
          ``bytes(ckbytelistSignature)``
1340
          or, for Python 2:
1341
          ``''.join(chr(i) for i in ckbytelistSignature)``
1342

1343
        """
1344
        m = mecha.to_native()
1✔
1345
        signature = ckbytelist()
1✔
1346
        data1 = ckbytelist(data)
1✔
1347
        rv = self.lib.C_SignInit(self.session, m, key)
1✔
1348
        if rv != CKR_OK:
1✔
1349
            raise PyKCS11Error(rv)
×
1350
        # first call get signature size
1351
        rv = self.lib.C_Sign(self.session, data1, signature)
1✔
1352
        if rv != CKR_OK:
1✔
1353
            raise PyKCS11Error(rv)
×
1354
        # second call get actual signature data
1355
        rv = self.lib.C_Sign(self.session, data1, signature)
1✔
1356
        if rv != CKR_OK:
1✔
1357
            raise PyKCS11Error(rv)
×
1358
        return signature
1✔
1359

1360
    def verify(self, key, data, signature, mecha=MechanismRSAPKCS1):
1✔
1361
        """
1362
        C_VerifyInit/C_Verify
1363

1364
        :param key: a key handle, obtained calling :func:`findObjects`.
1365
        :type key: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1366
        :param data: the data that was signed
1367
        :type data:  (binary) string or list/tuple of bytes
1368
        :param signature: the signature to be verified
1369
        :type signature:  (binary) string or list/tuple of bytes
1370
        :param mecha: the signing mechanism to be used
1371
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1372
        :type mecha: :class:`Mechanism`
1373
        :return: True if signature is valid, False otherwise
1374
        :rtype: bool
1375

1376
        """
1377
        m = mecha.to_native()
1✔
1378
        data1 = ckbytelist(data)
1✔
1379
        rv = self.lib.C_VerifyInit(self.session, m, key)
1✔
1380
        if rv != CKR_OK:
1✔
1381
            raise PyKCS11Error(rv)
×
1382
        rv = self.lib.C_Verify(self.session, data1, signature)
1✔
1383
        if rv == CKR_OK:
1✔
1384
            return True
1✔
1385
        if rv == CKR_SIGNATURE_INVALID:
×
1386
            return False
×
1387
        raise PyKCS11Error(rv)
×
1388

1389
    def encrypt(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1390
        """
1391
        C_EncryptInit/C_Encrypt
1392

1393
        :param key: a key handle, obtained calling :func:`findObjects`.
1394
        :type key: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1395
        :param data: the data to be encrypted
1396
        :type data:  (binary) string or list/tuple of bytes
1397
        :param mecha: the encryption mechanism to be used
1398
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1399
        :type mecha: :class:`Mechanism`
1400
        :return: the encrypted data
1401
        :rtype: ckbytelist
1402

1403
        :note: the returned value is an instance of :class:`ckbytelist`.
1404
          You can easly convert it to a binary string with:
1405
          ``bytes(ckbytelistEncrypted)``
1406
          or, for Python 2:
1407
          ``''.join(chr(i) for i in ckbytelistEncrypted)``
1408

1409
        """
1410
        encrypted = ckbytelist()
1✔
1411
        m = mecha.to_native()
1✔
1412
        data1 = ckbytelist(data)
1✔
1413
        rv = self.lib.C_EncryptInit(self.session, m, key)
1✔
1414
        if rv != CKR_OK:
1✔
1415
            raise PyKCS11Error(rv)
×
1416
        # first call get encrypted size
1417
        rv = self.lib.C_Encrypt(self.session, data1, encrypted)
1✔
1418
        if rv != CKR_OK:
1✔
1419
            raise PyKCS11Error(rv)
×
1420
        # second call get actual encrypted data
1421
        rv = self.lib.C_Encrypt(self.session, data1, encrypted)
1✔
1422
        if rv != CKR_OK:
1✔
1423
            raise PyKCS11Error(rv)
×
1424
        return encrypted
1✔
1425

1426
    def encryptInit(self, mech, key):
1✔
1427
        """
1428
        C_EncryptInit
1429

1430
        :param mech: the encryption mechanism to be used
1431
        :type mech: instance of :class:`Mechanism`
1432
        :param key: a key handle
1433
        :type key: integer
1434
        """
1435
        m = mech.to_native()
1✔
1436
        rv = self.lib.C_EncryptInit(self.session, m, key)
1✔
1437
        if rv != CKR_OK:
1✔
1438
            raise PyKCS11Error(rv)
×
1439

1440
    def encryptUpdate(self, data):
1✔
1441
        """
1442
        C_EncryptUpdate
1443

1444
        :param data: the data to be encrypted
1445
        :type data: (binary) string or list/tuple of bytes
1446
        """
1447
        encrypted = ckbytelist()
1✔
1448
        data1 = ckbytelist(data)
1✔
1449
        rv = self.lib.C_EncryptUpdate(self.session, data1, encrypted)
1✔
1450
        if rv != CKR_OK:
1✔
1451
            raise PyKCS11Error(rv)
×
1452
        return encrypted
1✔
1453

1454
    def encryptFinal(self):
1✔
1455
        """
1456
        C_EncryptFinal
1457

1458
        :return: the last part of data to be encrypted
1459
        :rtype: (binary) string or list/tuple of bytes
1460
        """
1461
        encrypted = ckbytelist()
1✔
1462
        rv = self.lib.C_EncryptFinal(self.session, encrypted)
1✔
1463
        if rv != CKR_OK:
1✔
1464
            raise PyKCS11Error(rv)
×
1465
        return encrypted
1✔
1466

1467
    def decrypt(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1468
        """
1469
        C_DecryptInit/C_Decrypt
1470

1471
        :param key: a key handle, obtained calling :func:`findObjects`.
1472
        :type key: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1473
        :param data: the data to be decrypted
1474
        :type data:  (binary) string or list/tuple of bytes
1475
        :param mecha: the decrypt mechanism to be used
1476
        :type mecha: :class:`Mechanism` instance or :class:`MechanismRSAPKCS1`
1477
          for CKM_RSA_PKCS
1478
        :return: the decrypted data
1479
        :rtype: ckbytelist
1480

1481
        :note: the returned value is an instance of :class:`ckbytelist`.
1482
          You can easly convert it to a binary string with:
1483
          ``bytes(ckbytelistData)``
1484
          or, for Python 2:
1485
          ``''.join(chr(i) for i in ckbytelistData)``
1486

1487
        """
1488
        m = mecha.to_native()
1✔
1489
        decrypted = ckbytelist()
1✔
1490
        data1 = ckbytelist(data)
1✔
1491
        rv = self.lib.C_DecryptInit(self.session, m, key)
1✔
1492
        if rv != CKR_OK:
1✔
1493
            raise PyKCS11Error(rv)
×
1494
        # first call get decrypted size
1495
        rv = self.lib.C_Decrypt(self.session, data1, decrypted)
1✔
1496
        if rv != CKR_OK:
1✔
1497
            raise PyKCS11Error(rv)
×
1498
        # second call get actual decrypted data
1499
        rv = self.lib.C_Decrypt(self.session, data1, decrypted)
1✔
1500
        if rv != CKR_OK:
1✔
1501
            raise PyKCS11Error(rv)
×
1502
        return decrypted
1✔
1503

1504
    def decryptInit(self, mech, key):
1✔
1505
        """
1506
        C_DecryptInit
1507

1508
        :param mech: the decrypt mechanism to be used
1509
        :type mech: instance of :class:`Mechanism`
1510
        :param key: a key handle
1511
        :type key: integer
1512
        """
1513
        m = mech.to_native()
1✔
1514
        rv = self.lib.C_DecryptInit(self.session, m, key)
1✔
1515
        if rv != CKR_OK:
1✔
1516
            raise PyKCS11Error(rv)
×
1517

1518
    def decryptUpdate(self, data):
1✔
1519
        """
1520
        C_DecryptUpdate
1521

1522
        :param data: the data to be decrypted
1523
        :type data: (binary) string or list/tuple of bytes
1524
        """
1525
        decrypted = ckbytelist()
1✔
1526
        encrypted = ckbytelist(data)
1✔
1527
        rv = self.lib.C_DecryptUpdate(self.session, encrypted, decrypted)
1✔
1528
        if rv != CKR_OK:
1✔
1529
            raise PyKCS11Error(rv)
×
1530
        return decrypted
1✔
1531

1532
    def decryptFinal(self):
1✔
1533
        """
1534
        C_DecryptFinal
1535

1536
        :return: the last part of the decrypted data
1537
        :rtype: (binary) string or list/tuple of bytes
1538
        """
1539
        decrypted = ckbytelist()
1✔
1540
        rv = self.lib.C_DecryptFinal(self.session, decrypted)
1✔
1541
        if rv != CKR_OK:
1✔
1542
            raise PyKCS11Error(rv)
×
1543
        return decrypted
1✔
1544

1545
    def wrapKey(self, wrappingKey, key, mecha=MechanismRSAPKCS1):
1✔
1546
        """
1547
        C_WrapKey
1548

1549
        :param wrappingKey: a wrapping key handle
1550
        :type wrappingKey: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1551
        :param key: a handle of the key to be wrapped
1552
        :type key: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1553
        :param mecha: the encrypt mechanism to be used
1554
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1555
        :type mecha: :class:`Mechanism`
1556
        :return: the wrapped key bytes
1557
        :rtype: ckbytelist
1558

1559
        :note: the returned value is an instance of :class:`ckbytelist`.
1560
          You can easily convert it to a binary string with:
1561
          ``bytes(ckbytelistData)``
1562
          or, for Python 2:
1563
          ``''.join(chr(i) for i in ckbytelistData)``
1564

1565
        """
1566
        wrapped = ckbytelist()
1✔
1567
        native = mecha.to_native()
1✔
1568
        # first call get wrapped size
1569
        rv = self.lib.C_WrapKey(self.session, native, wrappingKey, key, wrapped)
1✔
1570
        if rv != CKR_OK:
1✔
1571
            raise PyKCS11Error(rv)
×
1572
        # second call get actual wrapped key data
1573
        rv = self.lib.C_WrapKey(self.session, native, wrappingKey, key, wrapped)
1✔
1574
        if rv != CKR_OK:
1✔
1575
            raise PyKCS11Error(rv)
×
1576
        return wrapped
1✔
1577

1578
    def unwrapKey(self, unwrappingKey, wrappedKey, template, mecha=MechanismRSAPKCS1):
1✔
1579
        """
1580
        C_UnwrapKey
1581

1582
        :param unwrappingKey: the unwrapping key handle
1583
        :type unwrappingKey: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1584
        :param wrappedKey: the bytes of the wrapped key
1585
        :type wrappedKey:  (binary) string or list/tuple of bytes
1586
        :param template: template for the unwrapped key
1587
        :param mecha: the decrypt mechanism to be used (use
1588
          `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1589
        :type mecha: :class:`Mechanism`
1590
        :return: the unwrapped key object
1591
        :rtype: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1592

1593
        """
1594
        m = mecha.to_native()
1✔
1595
        data1 = ckbytelist(wrappedKey)
1✔
1596
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1597
        attrs = self._template2ckattrlist(template)
1✔
1598
        rv = self.lib.C_UnwrapKey(self.session, m, unwrappingKey, data1, attrs, handle)
1✔
1599
        if rv != CKR_OK:
1✔
1600
            raise PyKCS11Error(rv)
×
1601
        return handle
1✔
1602

1603
    def deriveKey(self, baseKey, template, mecha):
1✔
1604
        """
1605
        C_DeriveKey
1606

1607
        :param baseKey: the base key handle
1608
        :type baseKey: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1609
        :param template: template for the unwrapped key
1610
        :param mecha: the decrypt mechanism to be used (use
1611
          `ECDH1_DERIVE_Mechanism(...)` for `CKM_ECDH1_DERIVE`)
1612
        :type mecha: :class:`Mechanism`
1613
        :return: the unwrapped key object
1614
        :rtype: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1615
        """
1616
        m = mecha.to_native()
1✔
1617
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1618
        attrs = self._template2ckattrlist(template)
1✔
1619
        rv = self.lib.C_DeriveKey(self.session, m, baseKey, attrs, handle)
1✔
1620
        if rv != CKR_OK:
1✔
1621
            raise PyKCS11Error(rv)
×
1622
        return handle
1✔
1623

1624
    def isNum(self, p11_type):
1✔
1625
        """
1626
        is the type a numerical value?
1627

1628
        :param p11_type: PKCS#11 type like `CKA_CERTIFICATE_TYPE`
1629
        :rtype: bool
1630
        """
1631
        if p11_type in (
1✔
1632
            CKA_CERTIFICATE_TYPE,
1633
            CKA_CLASS,
1634
            CKA_HW_FEATURE_TYPE,
1635
            CKA_KEY_GEN_MECHANISM,
1636
            CKA_KEY_TYPE,
1637
            CKA_MODULUS_BITS,
1638
            CKA_VALUE_BITS,
1639
            CKA_VALUE_LEN,
1640
        ):
1641
            return True
1✔
1642
        return False
1✔
1643

1644
    def isString(self, p11_type):
1✔
1645
        """
1646
        is the type a string value?
1647

1648
        :param p11_type: PKCS#11 type like `CKA_LABEL`
1649
        :rtype: bool
1650
        """
1651
        if p11_type in (CKA_LABEL, CKA_APPLICATION):
1✔
1652
            return True
1✔
1653
        return False
1✔
1654

1655
    def isBool(self, p11_type):
1✔
1656
        """
1657
        is the type a boolean value?
1658

1659
        :param p11_type: PKCS#11 type like `CKA_ALWAYS_SENSITIVE`
1660
        :rtype: bool
1661
        """
1662
        if p11_type in (
1✔
1663
            CKA_ALWAYS_AUTHENTICATE,
1664
            CKA_ALWAYS_SENSITIVE,
1665
            CKA_DECRYPT,
1666
            CKA_DERIVE,
1667
            CKA_ENCRYPT,
1668
            CKA_EXTRACTABLE,
1669
            CKA_HAS_RESET,
1670
            CKA_LOCAL,
1671
            CKA_MODIFIABLE,
1672
            CKA_COPYABLE,
1673
            CKA_DESTROYABLE,
1674
            CKA_NEVER_EXTRACTABLE,
1675
            CKA_PRIVATE,
1676
            CKA_RESET_ON_INIT,
1677
            CKA_SECONDARY_AUTH,
1678
            CKA_SENSITIVE,
1679
            CKA_SIGN,
1680
            CKA_SIGN_RECOVER,
1681
            CKA_TOKEN,
1682
            CKA_TRUSTED,
1683
            CKA_UNWRAP,
1684
            CKA_VERIFY,
1685
            CKA_VERIFY_RECOVER,
1686
            CKA_WRAP,
1687
            CKA_WRAP_WITH_TRUSTED,
1688
        ):
1689
            return True
1✔
1690
        return False
1✔
1691

1692
    def isBin(self, p11_type):
1✔
1693
        """
1694
        is the type a byte array value?
1695

1696
        :param p11_type: PKCS#11 type like `CKA_MODULUS`
1697
        :rtype: bool
1698
        """
1699
        return (
1✔
1700
            (not self.isBool(p11_type))
1701
            and (not self.isString(p11_type))
1702
            and (not self.isNum(p11_type))
1703
        )
1704

1705
    def isAttributeList(self, p11_type):
1✔
1706
        """
1707
        is the type a attribute list value?
1708

1709
        :param p11_type: PKCS#11 type like `CKA_WRAP_TEMPLATE`
1710
        :rtype: bool
1711
        """
1712
        if p11_type in (CKA_WRAP_TEMPLATE, CKA_UNWRAP_TEMPLATE):
1✔
1713
            return True
1✔
1714
        return False
1✔
1715

1716
    def _template2ckattrlist(self, template):
1✔
1717
        t = PyKCS11.LowLevel.ckattrlist(len(template))
1✔
1718
        for x, attr in enumerate(template):
1✔
1719
            if self.isNum(attr[0]):
1✔
1720
                t[x].SetNum(attr[0], int(attr[1]))
1✔
1721
            elif self.isString(attr[0]):
1✔
1722
                t[x].SetString(attr[0], str(attr[1]))
1✔
1723
            elif self.isBool(attr[0]):
1✔
1724
                t[x].SetBool(attr[0], attr[1] == CK_TRUE)
1✔
1725
            elif self.isAttributeList(attr[0]):
1✔
1726
                t[x].SetList(attr[0], self._template2ckattrlist(attr[1]))
1✔
1727
            elif self.isBin(attr[0]):
1✔
1728
                attrBin = attr[1]
1✔
1729
                attrStr = attr[1]
1✔
1730
                if isinstance(attr[1], int):
1✔
1731
                    attrStr = str(attr[1])
×
1732
                if isinstance(attr[1], bytes):
1✔
1733
                    attrBin = ckbytelist(attrStr)
1✔
1734
                t[x].SetBin(attr[0], attrBin)
1✔
1735
            else:
1736
                raise PyKCS11Error(-2, f"attr: {attr[0]:08X}")
×
1737
        return t
1✔
1738

1739
    def generateKey(self, template, mecha=MechanismAESGENERATEKEY):
1✔
1740
        """
1741
        generate a secret key
1742

1743
        :param template: template for the secret key
1744
        :param mecha: mechanism to use
1745
        :return: handle of the generated key
1746
        :rtype: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1747
        """
1748
        t = self._template2ckattrlist(template)
1✔
1749
        ck_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1750
        m = mecha.to_native()
1✔
1751
        rv = self.lib.C_GenerateKey(self.session, m, t, ck_handle)
1✔
1752
        if rv != CKR_OK:
1✔
1753
            raise PyKCS11Error(rv)
×
1754
        return ck_handle
1✔
1755

1756
    def generateKeyPair(
1✔
1757
        self, templatePub, templatePriv, mecha=MechanismRSAGENERATEKEYPAIR
1758
    ):
1759
        """
1760
        generate a key pair
1761

1762
        :param templatePub: template for the public key
1763
        :param templatePriv:  template for the private key
1764
        :param mecha: mechanism to use
1765
        :return: a tuple of handles (pub, priv)
1766
        :rtype: tuple
1767
        """
1768
        tPub = self._template2ckattrlist(templatePub)
1✔
1769
        tPriv = self._template2ckattrlist(templatePriv)
1✔
1770
        ck_pub_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1771
        ck_prv_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1772
        m = mecha.to_native()
1✔
1773
        rv = self.lib.C_GenerateKeyPair(
1✔
1774
            self.session, m, tPub, tPriv, ck_pub_handle, ck_prv_handle
1775
        )
1776

1777
        if rv != CKR_OK:
1✔
1778
            raise PyKCS11Error(rv)
1✔
1779
        return ck_pub_handle, ck_prv_handle
1✔
1780

1781
    def findObjects(self, template=()):
1✔
1782
        """
1783
        find the objects matching the template pattern
1784

1785
        :param template: list of attributes tuples (attribute,value).
1786
          The default value is () and all the objects are returned
1787
        :type template: list
1788
        :return: a list of object ids
1789
        :rtype: list
1790
        """
1791
        t = self._template2ckattrlist(template)
1✔
1792

1793
        # we search for 10 objects by default. speed/memory tradeoff
1794
        result = PyKCS11.LowLevel.ckulonglist(10)
1✔
1795

1796
        rv = self.lib.C_FindObjectsInit(self.session, t)
1✔
1797
        if rv != CKR_OK:
1✔
1798
            raise PyKCS11Error(rv)
×
1799

1800
        res = []
1✔
1801
        while True:
1✔
1802
            rv = self.lib.C_FindObjects(self.session, result)
1✔
1803
            if rv != CKR_OK:
1✔
1804
                raise PyKCS11Error(rv)
×
1805
            for x in result:
1✔
1806
                # make a copy of the handle: the original value get
1807
                # corrupted (!!)
1808
                a = CK_OBJECT_HANDLE(self)
1✔
1809
                a.assign(x)
1✔
1810
                res.append(a)
1✔
1811
            if len(result) == 0:
1✔
1812
                break
1✔
1813

1814
        rv = self.lib.C_FindObjectsFinal(self.session)
1✔
1815
        if rv != CKR_OK:
1✔
1816
            raise PyKCS11Error(rv)
×
1817
        return res
1✔
1818

1819
    def getAttributeValue(self, obj_id, attr, allAsBinary=False):
1✔
1820
        """
1821
        C_GetAttributeValue
1822

1823
        :param obj_id: object ID returned by :func:`findObjects`
1824
        :type obj_id: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1825
        :param attr: list of attributes
1826
        :type attr: list
1827
        :param allAsBinary: return all values as binary data; default is False.
1828
        :type allAsBinary: Boolean
1829
        :return: a list of values corresponding to the list of attributes
1830
        :rtype: list
1831

1832
        :see: :func:`getAttributeValue_fragmented`
1833

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

1837
          Binary data is returned as :class:`ckbytelist` type, usable
1838
          as a list containing only bytes.
1839
          You can easly convert it to a binary string with:
1840
          ``bytes(ckbytelistVariable)``
1841
          or, for Python 2:
1842
          ``''.join(chr(i) for i in ckbytelistVariable)``
1843

1844
        """
1845
        valTemplate = PyKCS11.LowLevel.ckattrlist(len(attr))
1✔
1846
        for index, value in enumerate(attr):
1✔
1847
            valTemplate[index].SetType(value)
1✔
1848
        # first call to get the attribute size and reserve the memory
1849
        rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1850
        if rv in (
1✔
1851
            CKR_ATTRIBUTE_TYPE_INVALID,
1852
            CKR_ATTRIBUTE_SENSITIVE,
1853
            CKR_ARGUMENTS_BAD,
1854
        ):
1855
            return self.getAttributeValue_fragmented(obj_id, attr, allAsBinary)
1✔
1856

1857
        if rv != CKR_OK:
1✔
1858
            raise PyKCS11Error(rv)
×
1859
        # second call to get the attribute value
1860
        rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1861
        if rv != CKR_OK:
1✔
1862
            raise PyKCS11Error(rv)
×
1863

1864
        res = []
1✔
1865
        for x in range(len(attr)):
1✔
1866
            if allAsBinary:
1✔
1867
                res.append(valTemplate[x].GetBin())
1✔
1868
            elif valTemplate[x].IsNum():
1✔
1869
                res.append(valTemplate[x].GetNum())
1✔
1870
            elif valTemplate[x].IsBool():
1✔
1871
                res.append(valTemplate[x].GetBool())
1✔
1872
            elif valTemplate[x].IsString():
1✔
1873
                res.append(valTemplate[x].GetString())
1✔
1874
            elif valTemplate[x].IsBin():
1✔
1875
                res.append(valTemplate[x].GetBin())
1✔
1876
            else:
1877
                raise PyKCS11Error(-2, f"valTemplate: {valTemplate[x]:08X}")
×
1878

1879
        return res
1✔
1880

1881
    def getAttributeValue_fragmented(self, obj_id, attr, allAsBinary=False):
1✔
1882
        """
1883
        Same as :func:`getAttributeValue` except that when some attribute
1884
        is sensitive or unknown an empty value (None) is returned.
1885

1886
        Note: this is achived by getting attributes one by one.
1887

1888
        :see: :func:`getAttributeValue`
1889
        """
1890
        # some attributes does not exists or is sensitive
1891
        # but we don't know which ones. So try one by one
1892
        valTemplate = PyKCS11.LowLevel.ckattrlist(1)
1✔
1893
        res = []
1✔
1894
        for elt in attr:
1✔
1895
            valTemplate[0].Reset()
1✔
1896
            valTemplate[0].SetType(elt)
1✔
1897
            # first call to get the attribute size and reserve the memory
1898
            rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1899
            if rv in (
1✔
1900
                CKR_ATTRIBUTE_TYPE_INVALID,
1901
                CKR_ATTRIBUTE_SENSITIVE,
1902
                CKR_ARGUMENTS_BAD,
1903
            ):
1904
                # append an empty value
1905
                res.append(None)
1✔
1906
                continue
1✔
1907

1908
            if rv != CKR_OK:
1✔
1909
                raise PyKCS11Error(rv)
×
1910
            # second call to get the attribute value
1911
            rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1912
            if rv != CKR_OK:
1✔
1913
                raise PyKCS11Error(rv)
×
1914

1915
            if allAsBinary:
1✔
1916
                res.append(valTemplate[0].GetBin())
×
1917
            elif valTemplate[0].IsNum():
1✔
1918
                res.append(valTemplate[0].GetNum())
1✔
1919
            elif valTemplate[0].IsBool():
1✔
1920
                res.append(valTemplate[0].GetBool())
1✔
1921
            elif valTemplate[0].IsString():
1✔
1922
                res.append(valTemplate[0].GetString())
1✔
1923
            elif valTemplate[0].IsBin():
1✔
1924
                res.append(valTemplate[0].GetBin())
1✔
1925
            elif valTemplate[0].IsAttributeList():
1✔
1926
                res.append(valTemplate[0].GetBin())
1✔
1927
            else:
1928
                raise PyKCS11Error(-2)
×
1929

1930
        return res
1✔
1931

1932
    def setAttributeValue(self, obj_id, template):
1✔
1933
        """
1934
        C_SetAttributeValue
1935

1936
        :param obj_id: object ID returned by :func:`findObjects`
1937
        :type obj_id: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1938
        :param template: list of (attribute, value) pairs
1939
        :type template: list
1940
        :return: Nothing
1941
        :rtype: None
1942
        """
1943

1944
        templ = self._template2ckattrlist(template)
1✔
1945
        rv = self.lib.C_SetAttributeValue(self.session, obj_id, templ)
1✔
1946

1947
        if rv != CKR_OK:
1✔
1948
            raise PyKCS11Error(rv)
×
1949

1950
    def seedRandom(self, seed):
1✔
1951
        """
1952
        C_SeedRandom
1953

1954
        :param seed: seed material
1955
        :type seed: iterable
1956
        """
1957
        low_seed = ckbytelist(seed)
1✔
1958
        rv = self.lib.C_SeedRandom(self.session, low_seed)
1✔
1959
        if rv != CKR_OK:
1✔
1960
            raise PyKCS11Error(rv)
×
1961

1962
    def generateRandom(self, size=16):
1✔
1963
        """
1964
        C_GenerateRandom
1965

1966
        :param size: number of random bytes to get
1967
        :type size: integer
1968

1969
        :note: the returned value is an instance of :class:`ckbytelist`.
1970
          You can easly convert it to a binary string with:
1971
          ``bytes(random)``
1972
          or, for Python 2:
1973
          ``''.join(chr(i) for i in random)``
1974
        """
1975
        low_rand = ckbytelist([0] * size)
1✔
1976
        rv = self.lib.C_GenerateRandom(self.session, low_rand)
1✔
1977
        if rv != CKR_OK:
1✔
1978
            raise PyKCS11Error(rv)
×
1979
        return low_rand
1✔
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