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

LudovicRousseau / PyKCS11 / 15225480482

24 May 2025 08:59AM UTC coverage: 86.864% (+0.3%) from 86.582%
15225480482

Pull #135

github

web-flow
Merge 3ff545560 into 3386f9380
Pull Request #135: improve support for multi-part encryption/decryption

90 of 98 new or added lines in 2 files covered. (91.84%)

3088 of 3555 relevant lines covered (86.86%)

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-2025 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

19
import os
1✔
20
import sys
1✔
21

22
import PyKCS11.LowLevel
1✔
23

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

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

45
# redefine PKCS#11 constants using well known prefixes
46
for x in PyKCS11.LowLevel.__dict__.keys():
1✔
47
    if (
1✔
48
        x[:4] == "CKA_"
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
    ):
62
        a = f"{x}=PyKCS11.LowLevel.{x}"
1✔
63
        exec(a)
1✔
64
        if x[3:] != "_VENDOR_DEFINED":
1✔
65
            eval(x[:3])[eval(x)] = x  # => CKM[CKM_RSA_PKCS] = 'CKM_RSA_PKCS'
1✔
66
            eval(x[:3])[x] = eval(x)  # => CKM['CKM_RSA_PKCS'] = CKM_RSA_PKCS
1✔
67

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

74

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

80
    def __init__(self, data=None):
1✔
81
        if data is None:
1✔
82
            data = 0
1✔
83
        elif isinstance(data, str):
1✔
84
            data = data.encode("utf-8")
1✔
85
        elif isinstance(data, (bytes, list, ckbytelist)):
1✔
86
            data = bytes(data)
1✔
87
        else:
88
            raise PyKCS11.PyKCS11Error(-3, text=str(type(data)))
1✔
89
        super().__init__(data)
1✔
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 isinstance(attr, int)]
1✔
119

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

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

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

147

148
class CkClass:
1✔
149
    """
150
    Base class for CK_* classes
151
    """
152

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

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

160
    flags = 0
1✔
161

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

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

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

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

206

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

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

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

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

237

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

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

254
    fields = {
1✔
255
        "cryptokiVersion": "pair",
256
        "manufacturerID": "text",
257
        "flags": "flags",
258
        "libraryDescription": "text",
259
        "libraryVersion": "pair",
260
    }
261

262

263
class CK_SESSION_INFO(CkClass):
1✔
264
    """
265
    matches the PKCS#11 CK_SESSION_INFO structure
266

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

277
    flags_dict = {
1✔
278
        CKF_RW_SESSION: "CKF_RW_SESSION",
279
        CKF_SERIAL_SESSION: "CKF_SERIAL_SESSION",
280
    }
281

282
    def state2text(self):
1✔
283
        """
284
        parse the `self.state` field and return a `CKS_*` string
285
        corresponding to the state
286

287
        :return: a string
288
        :rtype: string
289
        """
290
        return CKS[self.state]
1✔
291

292
    fields = {
1✔
293
        "slotID": "text",
294
        "state": "text",
295
        "flags": "flags",
296
        "ulDeviceError": "text",
297
    }
298

299

300
class CK_TOKEN_INFO(CkClass):
1✔
301
    """
302
    matches the PKCS#11 CK_TOKEN_INFO structure
303

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

342
    flags_dict = {
1✔
343
        CKF_RNG: "CKF_RNG",
344
        CKF_WRITE_PROTECTED: "CKF_WRITE_PROTECTED",
345
        CKF_LOGIN_REQUIRED: "CKF_LOGIN_REQUIRED",
346
        CKF_USER_PIN_INITIALIZED: "CKF_USER_PIN_INITIALIZED",
347
        CKF_RESTORE_KEY_NOT_NEEDED: "CKF_RESTORE_KEY_NOT_NEEDED",
348
        CKF_CLOCK_ON_TOKEN: "CKF_CLOCK_ON_TOKEN",
349
        CKF_PROTECTED_AUTHENTICATION_PATH: "CKF_PROTECTED_AUTHENTICATION_PATH",
350
        CKF_DUAL_CRYPTO_OPERATIONS: "CKF_DUAL_CRYPTO_OPERATIONS",
351
        CKF_TOKEN_INITIALIZED: "CKF_TOKEN_INITIALIZED",
352
        CKF_SECONDARY_AUTHENTICATION: "CKF_SECONDARY_AUTHENTICATION",
353
        CKF_USER_PIN_COUNT_LOW: "CKF_USER_PIN_COUNT_LOW",
354
        CKF_USER_PIN_FINAL_TRY: "CKF_USER_PIN_FINAL_TRY",
355
        CKF_USER_PIN_LOCKED: "CKF_USER_PIN_LOCKED",
356
        CKF_USER_PIN_TO_BE_CHANGED: "CKF_USER_PIN_TO_BE_CHANGED",
357
        CKF_SO_PIN_COUNT_LOW: "CKF_SO_PIN_COUNT_LOW",
358
        CKF_SO_PIN_FINAL_TRY: "CKF_SO_PIN_FINAL_TRY",
359
        CKF_SO_PIN_LOCKED: "CKF_SO_PIN_LOCKED",
360
        CKF_SO_PIN_TO_BE_CHANGED: "CKF_SO_PIN_TO_BE_CHANGED",
361
    }
362

363
    fields = {
1✔
364
        "label": "text",
365
        "manufacturerID": "text",
366
        "model": "text",
367
        "serialNumber": "text",
368
        "flags": "flags",
369
        "ulMaxSessionCount": "text",
370
        "ulSessionCount": "text",
371
        "ulMaxRwSessionCount": "text",
372
        "ulRwSessionCount": "text",
373
        "ulMaxPinLen": "text",
374
        "ulMinPinLen": "text",
375
        "ulTotalPublicMemory": "text",
376
        "ulFreePublicMemory": "text",
377
        "ulTotalPrivateMemory": "text",
378
        "ulFreePrivateMemory": "text",
379
        "hardwareVersion": "pair",
380
        "firmwareVersion": "pair",
381
        "utcTime": "text",
382
    }
383

384

385
class CK_MECHANISM_INFO(CkClass):
1✔
386
    """
387
    matches the PKCS#11 CK_MECHANISM_INFO structure
388

389
    :ivar ulMinKeySize: minimum size of the key
390
    :type ulMinKeySize: integer
391
    :ivar ulMaxKeySize: maximum size of the key
392
    :type ulMaxKeySize: integer
393
    :ivar flags: bit flags specifying mechanism capabilities
394
    :type flags: integer
395
    """
396

397
    flags_dict = {
1✔
398
        CKF_HW: "CKF_HW",
399
        CKF_ENCRYPT: "CKF_ENCRYPT",
400
        CKF_DECRYPT: "CKF_DECRYPT",
401
        CKF_DIGEST: "CKF_DIGEST",
402
        CKF_SIGN: "CKF_SIGN",
403
        CKF_SIGN_RECOVER: "CKF_SIGN_RECOVER",
404
        CKF_VERIFY: "CKF_VERIFY",
405
        CKF_VERIFY_RECOVER: "CKF_VERIFY_RECOVER",
406
        CKF_GENERATE: "CKF_GENERATE",
407
        CKF_GENERATE_KEY_PAIR: "CKF_GENERATE_KEY_PAIR",
408
        CKF_WRAP: "CKF_WRAP",
409
        CKF_UNWRAP: "CKF_UNWRAP",
410
        CKF_DERIVE: "CKF_DERIVE",
411
        CKF_EXTENSION: "CKF_EXTENSION",
412
    }
413

414
    fields = {"ulMinKeySize": "text", "ulMaxKeySize": "text", "flags": "flags"}
1✔
415

416

417
class PyKCS11Error(Exception):
1✔
418
    """define the possible PyKCS11 exceptions"""
419

420
    def __init__(self, value, text=""):
1✔
421
        self.value = value
1✔
422
        self.text = text
1✔
423

424
    def __str__(self):
1✔
425
        """
426
        The text representation of a PKCS#11 error is something like:
427
        "CKR_DEVICE_ERROR (0x00000030)"
428
        """
429
        if self.value in CKR:
1✔
430
            if self.value < 0:
1✔
431
                return CKR[self.value] + " (%s)" % self.text
1✔
432
            else:
433
                return CKR[self.value] + " (0x%08X)" % self.value
1✔
434
        elif self.value & CKR_VENDOR_DEFINED:
1✔
435
            return "Vendor error (0x%08X)" % (
1✔
436
                self.value & 0xFFFFFFFF & ~CKR_VENDOR_DEFINED
437
            )
438
        else:
439
            return "Unknown error (0x%08X)" % self.value
1✔
440

441

442
class PyKCS11Lib:
1✔
443
    """high level PKCS#11 binding"""
444

445
    # shared by all instances
446
    _loaded_libs = dict()
1✔
447

448
    def __init__(self):
1✔
449
        self.lib = PyKCS11.LowLevel.CPKCS11Lib()
1✔
450

451
    def __del__(self):
1✔
452
        if (
1✔
453
            PyKCS11
454
            and PyKCS11.__name__
455
            and PyKCS11.LowLevel
456
            and PyKCS11.LowLevel.__name__
457
            and PyKCS11.LowLevel._LowLevel
458
            and PyKCS11.LowLevel._LowLevel.__name__
459
        ):
460

461
            # unload the library
462
            self.unload()
1✔
463

464
    def load(self, pkcs11dll_filename=None, *init_string):
1✔
465
        """
466
        load a PKCS#11 library
467

468
        :type pkcs11dll_filename: string
469
        :param pkcs11dll_filename: the library name.
470
          If this parameter is not set then the environment variable
471
          `PYKCS11LIB` is used instead
472
        :returns: a :class:`PyKCS11Lib` object
473
        :raises: :class:`PyKCS11Error` (-1): when the load fails
474
        """
475
        if pkcs11dll_filename is None:
1✔
476
            pkcs11dll_filename = os.getenv("PYKCS11LIB")
1✔
477
            if pkcs11dll_filename is None:
1✔
478
                raise PyKCS11Error(
×
479
                    -1, "No PKCS11 library specified (set PYKCS11LIB env variable)"
480
                )
481

482
        if hasattr(self, "pkcs11dll_filename"):
1✔
483
            self.unload()  # unload the previous library
1✔
484
            # if the instance was previously initialized,
485
            # create a new low level library object for it
486
            self.lib = PyKCS11.LowLevel.CPKCS11Lib()
1✔
487

488
        # if the lib is already in use: reuse it
489
        if pkcs11dll_filename in PyKCS11Lib._loaded_libs:
1✔
490
            self.lib.Duplicate(PyKCS11Lib._loaded_libs[pkcs11dll_filename]["ref"])
1✔
491
        else:
492
            # else load it
493
            rv = self.lib.Load(pkcs11dll_filename)
1✔
494
            if rv != CKR_OK:
1✔
495
                raise PyKCS11Error(rv, pkcs11dll_filename)
1✔
496
            PyKCS11Lib._loaded_libs[pkcs11dll_filename] = {
1✔
497
                "ref": self.lib,
498
                "nb_users": 0,
499
            }
500

501
        # remember the lib file name
502
        self.pkcs11dll_filename = pkcs11dll_filename
1✔
503

504
        # increase user number
505
        PyKCS11Lib._loaded_libs[pkcs11dll_filename]["nb_users"] += 1
1✔
506

507
        return self
1✔
508

509
    def unload(self):
1✔
510
        """
511
        unload the current instance of a PKCS#11 library
512
        """
513

514
        # in case NO library was found and used
515
        if not hasattr(self, "pkcs11dll_filename"):
1✔
516
            return
1✔
517

518
        if self.pkcs11dll_filename not in PyKCS11Lib._loaded_libs:
1✔
519
            raise PyKCS11Error(
×
520
                PyKCS11.LowLevel.CKR_GENERAL_ERROR, "invalid PyKCS11Lib state"
521
            )
522

523
        # decrease user number
524
        PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]["nb_users"] -= 1
1✔
525

526
        if PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]["nb_users"] == 0:
1✔
527
            # unload only if no more used
528
            self.lib.Unload()
1✔
529

530
        # remove unused entry
531
        # the case < 0 happens if lib loading failed
532
        if PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]["nb_users"] <= 0:
1✔
533
            del PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]
1✔
534

535
        delattr(self, "pkcs11dll_filename")
1✔
536

537
    def initToken(self, slot, pin, label):
1✔
538
        """
539
        C_InitToken
540

541
        :param slot: slot number returned by :func:`getSlotList`
542
        :type slot: integer
543
        :param pin: Security Officer's initial PIN
544
        :param label: new label of the token
545
        """
546
        pin1 = ckbytelist(pin)
1✔
547
        rv = self.lib.C_InitToken(slot, pin1, label)
1✔
548
        if rv != CKR_OK:
1✔
549
            raise PyKCS11Error(rv)
×
550

551
    def getInfo(self):
1✔
552
        """
553
        C_GetInfo
554

555
        :return: a :class:`CK_INFO` object
556
        """
557
        info = PyKCS11.LowLevel.CK_INFO()
1✔
558
        rv = self.lib.C_GetInfo(info)
1✔
559
        if rv != CKR_OK:
1✔
560
            raise PyKCS11Error(rv)
×
561

562
        i = CK_INFO()
1✔
563
        i.cryptokiVersion = (info.cryptokiVersion.major, info.cryptokiVersion.minor)
1✔
564
        i.manufacturerID = info.GetManufacturerID()
1✔
565
        i.flags = info.flags
1✔
566
        i.libraryDescription = info.GetLibraryDescription()
1✔
567
        i.libraryVersion = (info.libraryVersion.major, info.libraryVersion.minor)
1✔
568
        return i
1✔
569

570
    def getSlotList(self, tokenPresent=False):
1✔
571
        """
572
        C_GetSlotList
573

574
        :param tokenPresent: `False` (default) to list all slots,
575
          `True` to list only slots with present tokens
576
        :type tokenPresent: bool
577
        :return: a list of available slots
578
        :rtype: list
579
        """
580
        slotList = PyKCS11.LowLevel.ckintlist()
1✔
581
        rv = self.lib.C_GetSlotList(CK_TRUE if tokenPresent else CK_FALSE, slotList)
1✔
582
        if rv != CKR_OK:
1✔
583
            raise PyKCS11Error(rv)
×
584

585
        s = []
1✔
586
        for x in range(len(slotList)):
1✔
587
            s.append(slotList[x])
1✔
588
        return s
1✔
589

590
    def getSlotInfo(self, slot):
1✔
591
        """
592
        C_GetSlotInfo
593

594
        :param slot: slot number returned by :func:`getSlotList`
595
        :type slot: integer
596
        :return: a :class:`CK_SLOT_INFO` object
597
        """
598
        slotInfo = PyKCS11.LowLevel.CK_SLOT_INFO()
1✔
599
        rv = self.lib.C_GetSlotInfo(slot, slotInfo)
1✔
600
        if rv != CKR_OK:
1✔
601
            raise PyKCS11Error(rv)
×
602

603
        s = CK_SLOT_INFO()
1✔
604
        s.slotDescription = slotInfo.GetSlotDescription()
1✔
605
        s.manufacturerID = slotInfo.GetManufacturerID()
1✔
606
        s.flags = slotInfo.flags
1✔
607
        s.hardwareVersion = slotInfo.GetHardwareVersion()
1✔
608
        s.firmwareVersion = slotInfo.GetFirmwareVersion()
1✔
609

610
        return s
1✔
611

612
    def getTokenInfo(self, slot):
1✔
613
        """
614
        C_GetTokenInfo
615

616
        :param slot: slot number returned by :func:`getSlotList`
617
        :type slot: integer
618
        :return: a :class:`CK_TOKEN_INFO` object
619
        """
620
        tokeninfo = PyKCS11.LowLevel.CK_TOKEN_INFO()
1✔
621
        rv = self.lib.C_GetTokenInfo(slot, tokeninfo)
1✔
622
        if rv != CKR_OK:
1✔
623
            raise PyKCS11Error(rv)
×
624

625
        t = CK_TOKEN_INFO()
1✔
626
        t.label = tokeninfo.GetLabel()
1✔
627
        t.manufacturerID = tokeninfo.GetManufacturerID()
1✔
628
        t.model = tokeninfo.GetModel()
1✔
629
        t.serialNumber = tokeninfo.GetSerialNumber()
1✔
630
        t.flags = tokeninfo.flags
1✔
631
        t.ulMaxSessionCount = tokeninfo.ulMaxSessionCount
1✔
632
        if t.ulMaxSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
633
            t.ulMaxSessionCount = -1
×
634
        t.ulSessionCount = tokeninfo.ulSessionCount
1✔
635
        if t.ulSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
636
            t.ulSessionCount = -1
1✔
637
        t.ulMaxRwSessionCount = tokeninfo.ulMaxRwSessionCount
1✔
638
        if t.ulMaxRwSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
639
            t.ulMaxRwSessionCount = -1
×
640
        t.ulRwSessionCount = tokeninfo.ulRwSessionCount
1✔
641
        if t.ulRwSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
642
            t.ulRwSessionCount = -1
1✔
643
        t.ulMaxPinLen = tokeninfo.ulMaxPinLen
1✔
644
        t.ulMinPinLen = tokeninfo.ulMinPinLen
1✔
645
        t.ulTotalPublicMemory = tokeninfo.ulTotalPublicMemory
1✔
646

647
        if t.ulTotalPublicMemory == CK_UNAVAILABLE_INFORMATION:
1✔
648
            t.ulTotalPublicMemory = -1
1✔
649
        t.ulFreePublicMemory = tokeninfo.ulFreePublicMemory
1✔
650
        if t.ulFreePublicMemory == CK_UNAVAILABLE_INFORMATION:
1✔
651
            t.ulFreePublicMemory = -1
1✔
652
        t.ulTotalPrivateMemory = tokeninfo.ulTotalPrivateMemory
1✔
653
        if t.ulTotalPrivateMemory == CK_UNAVAILABLE_INFORMATION:
1✔
654
            t.ulTotalPrivateMemory = -1
1✔
655
        t.ulFreePrivateMemory = tokeninfo.ulFreePrivateMemory
1✔
656
        if t.ulFreePrivateMemory == CK_UNAVAILABLE_INFORMATION:
1✔
657
            t.ulFreePrivateMemory = -1
1✔
658
        t.hardwareVersion = (
1✔
659
            tokeninfo.hardwareVersion.major,
660
            tokeninfo.hardwareVersion.minor,
661
        )
662
        t.firmwareVersion = (
1✔
663
            tokeninfo.firmwareVersion.major,
664
            tokeninfo.firmwareVersion.minor,
665
        )
666
        t.utcTime = tokeninfo.GetUtcTime().replace("\000", " ")
1✔
667

668
        return t
1✔
669

670
    def openSession(self, slot, flags=0):
1✔
671
        """
672
        C_OpenSession
673

674
        :param slot: slot number returned by :func:`getSlotList`
675
        :type slot: integer
676
        :param flags: 0 (default), `CKF_RW_SESSION` for RW session
677
        :type flags: integer
678
        :return: a :class:`Session` object
679
        """
680
        se = PyKCS11.LowLevel.CK_SESSION_HANDLE()
1✔
681
        flags |= CKF_SERIAL_SESSION
1✔
682
        rv = self.lib.C_OpenSession(slot, flags, se)
1✔
683
        if rv != CKR_OK:
1✔
684
            raise PyKCS11Error(rv)
×
685

686
        return Session(self, se)
1✔
687

688
    def closeAllSessions(self, slot):
1✔
689
        """
690
        C_CloseAllSessions
691

692
        :param slot: slot number
693
        :type slot: integer
694
        """
695
        rv = self.lib.C_CloseAllSessions(slot)
1✔
696
        if rv != CKR_OK:
1✔
697
            raise PyKCS11Error(rv)
×
698

699
    def getMechanismList(self, slot):
1✔
700
        """
701
        C_GetMechanismList
702

703
        :param slot: slot number returned by :func:`getSlotList`
704
        :type slot: integer
705
        :return: the list of available mechanisms for a slot
706
        :rtype: list
707
        """
708
        mechanismList = PyKCS11.LowLevel.ckintlist()
1✔
709
        rv = self.lib.C_GetMechanismList(slot, mechanismList)
1✔
710
        if rv != CKR_OK:
1✔
711
            raise PyKCS11Error(rv)
×
712

713
        m = []
1✔
714
        for x in range(len(mechanismList)):
1✔
715
            mechanism = mechanismList[x]
1✔
716
            if mechanism >= CKM_VENDOR_DEFINED:
1✔
717
                k = "CKM_VENDOR_DEFINED_0x%X" % (mechanism - CKM_VENDOR_DEFINED)
×
718
                CKM[k] = mechanism
×
719
                CKM[mechanism] = k
×
720
            m.append(CKM[mechanism])
1✔
721
        return m
1✔
722

723
    def getMechanismInfo(self, slot, type):
1✔
724
        """
725
        C_GetMechanismInfo
726

727
        :param slot: slot number returned by :func:`getSlotList`
728
        :type slot: integer
729
        :param type: a `CKM_*` type
730
        :type type: integer
731
        :return: information about a mechanism
732
        :rtype: a :class:`CK_MECHANISM_INFO` object
733
        """
734
        info = PyKCS11.LowLevel.CK_MECHANISM_INFO()
1✔
735
        rv = self.lib.C_GetMechanismInfo(slot, CKM[type], info)
1✔
736
        if rv != CKR_OK:
1✔
737
            raise PyKCS11Error(rv)
×
738

739
        i = CK_MECHANISM_INFO()
1✔
740
        i.ulMinKeySize = info.ulMinKeySize
1✔
741
        i.ulMaxKeySize = info.ulMaxKeySize
1✔
742
        i.flags = info.flags
1✔
743

744
        return i
1✔
745

746
    def waitForSlotEvent(self, flags=0):
1✔
747
        """
748
        C_WaitForSlotEvent
749

750
        :param flags: 0 (default) or `CKF_DONT_BLOCK`
751
        :type flags: integer
752
        :return: slot
753
        :rtype: integer
754
        """
755
        tmp = 0
×
756
        (rv, slot) = self.lib.C_WaitForSlotEvent(flags, tmp)
×
757
        if rv != CKR_OK:
×
758
            raise PyKCS11Error(rv)
×
759

760
        return slot
×
761

762

763
class Mechanism:
1✔
764
    """Wraps CK_MECHANISM"""
765

766
    def __init__(self, mechanism, param=None):
1✔
767
        """
768
        :param mechanism: the mechanism to be used
769
        :type mechanism: integer, any `CKM_*` value
770
        :param param: data to be used as crypto operation parameter
771
          (i.e. the IV for some algorithms)
772
        :type param: string or list/tuple of bytes
773

774
        :see: :func:`Session.decrypt`, :func:`Session.sign`
775
        """
776
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
777
        self._mech.mechanism = mechanism
1✔
778
        self._param = None
1✔
779
        if param:
1✔
780
            self._param = ckbytelist(param)
1✔
781
            self._mech.pParameter = self._param
1✔
782
            self._mech.ulParameterLen = len(param)
1✔
783

784
    def to_native(self):
1✔
785
        return self._mech
1✔
786

787

788
MechanismSHA1 = Mechanism(CKM_SHA_1, None)
1✔
789
MechanismRSAPKCS1 = Mechanism(CKM_RSA_PKCS, None)
1✔
790
MechanismRSAGENERATEKEYPAIR = Mechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, None)
1✔
791
MechanismECGENERATEKEYPAIR = Mechanism(CKM_EC_KEY_PAIR_GEN, None)
1✔
792
MechanismAESGENERATEKEY = Mechanism(CKM_AES_KEY_GEN, None)
1✔
793

794

795
class AES_GCM_Mechanism:
1✔
796
    """CKM_AES_GCM warpping mechanism"""
797

798
    def __init__(self, iv, aad, tagBits):
1✔
799
        """
800
        :param iv: initialization vector
801
        :param aad: additional authentication data
802
        :param tagBits: length of authentication tag in bits
803
        """
804
        self._param = PyKCS11.LowLevel.CK_GCM_PARAMS()
1✔
805

806
        self._source_iv = ckbytelist(iv)
1✔
807
        self._param.pIv = self._source_iv
1✔
808
        self._param.ulIvLen = len(self._source_iv)
1✔
809

810
        self._source_aad = ckbytelist(aad)
1✔
811
        self._param.pAAD = self._source_aad
1✔
812
        self._param.ulAADLen = len(self._source_aad)
1✔
813

814
        self._param.ulTagBits = tagBits
1✔
815

816
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
817
        self._mech.mechanism = CKM_AES_GCM
1✔
818
        self._mech.pParameter = self._param
1✔
819
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_GCM_PARAMS_LENGTH
1✔
820

821
    def to_native(self):
1✔
822
        return self._mech
1✔
823

824

825
class AES_CTR_Mechanism:
1✔
826
    """CKM_AES_CTR encryption mechanism"""
827

828
    def __init__(self, counterBits, counterBlock):
1✔
829
        """
830
        :param counterBits: the number of incremented bits in the counter block
831
        :param counterBlock: a 16-byte initial value of the counter block
832
        """
833
        self._param = PyKCS11.LowLevel.CK_AES_CTR_PARAMS()
1✔
834

835
        self._source_cb = ckbytelist(counterBlock)
1✔
836
        self._param.ulCounterBits = counterBits
1✔
837
        self._param.cb = self._source_cb
1✔
838

839
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
840
        self._mech.mechanism = CKM_AES_CTR
1✔
841
        self._mech.pParameter = self._param
1✔
842
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_AES_CTR_PARAMS_LENGTH
1✔
843

844
    def to_native(self):
1✔
845
        return self._mech
1✔
846

847

848
class RSAOAEPMechanism:
1✔
849
    """RSA OAEP Wrapping mechanism"""
850

851
    def __init__(self, hashAlg, mgf, label=None):
1✔
852
        """
853
        :param hashAlg: the hash algorithm to use (like `CKM_SHA256`)
854
        :param mgf: the mask generation function to use (like
855
          `CKG_MGF1_SHA256`)
856
        :param label: the (optional) label to use
857
        """
858
        self._param = PyKCS11.LowLevel.CK_RSA_PKCS_OAEP_PARAMS()
1✔
859
        self._param.hashAlg = hashAlg
1✔
860
        self._param.mgf = mgf
1✔
861
        self._source = None
1✔
862
        self._param.source = CKZ_DATA_SPECIFIED
1✔
863
        if label:
1✔
864
            self._source = ckbytelist(label)
×
865
            self._param.ulSourceDataLen = len(self._source)
×
866
        else:
867
            self._param.ulSourceDataLen = 0
1✔
868
        self._param.pSourceData = self._source
1✔
869
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
870
        self._mech.mechanism = CKM_RSA_PKCS_OAEP
1✔
871
        self._mech.pParameter = self._param
1✔
872
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_RSA_PKCS_OAEP_PARAMS_LENGTH
1✔
873

874
    def to_native(self):
1✔
875
        return self._mech
1✔
876

877

878
class RSA_PSS_Mechanism:
1✔
879
    """RSA PSS Wrapping mechanism"""
880

881
    def __init__(self, mecha, hashAlg, mgf, sLen):
1✔
882
        """
883
        :param mecha: the mechanism to use (like
884
          `CKM_SHA384_RSA_PKCS_PSS`)
885
        :param hashAlg: the hash algorithm to use (like `CKM_SHA384`)
886
        :param mgf: the mask generation function to use (like
887
          `CKG_MGF1_SHA384`)
888
        :param sLen: length, in bytes, of the salt value used in the PSS
889
          encoding (like 0 or the message length)
890
        """
891
        self._param = PyKCS11.LowLevel.CK_RSA_PKCS_PSS_PARAMS()
1✔
892
        self._param.hashAlg = hashAlg
1✔
893
        self._param.mgf = mgf
1✔
894
        self._param.sLen = sLen
1✔
895
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
896
        self._mech.mechanism = mecha
1✔
897
        self._mech.pParameter = self._param
1✔
898
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_RSA_PKCS_PSS_PARAMS_LENGTH
1✔
899

900
    def to_native(self):
1✔
901
        return self._mech
1✔
902

903

904
class ECDH1_DERIVE_Mechanism:
1✔
905
    """CKM_ECDH1_DERIVE key derivation mechanism"""
906

907
    def __init__(self, publicData, kdf=CKD_NULL, sharedData=None):
1✔
908
        """
909
        :param publicData: Other party public key which is EC Point [PC || coord-x || coord-y].
910
        :param kdf: Key derivation function. OPTIONAL. Defaults to CKD_NULL
911
        :param sharedData: additional shared data. OPTIONAL
912
        """
913
        self._param = PyKCS11.LowLevel.CK_ECDH1_DERIVE_PARAMS()
1✔
914

915
        self._param.kdf = kdf
1✔
916

917
        if sharedData:
1✔
918
            self._shared_data = ckbytelist(sharedData)
×
919
            self._param.pSharedData = self._shared_data
×
920
            self._param.ulSharedDataLen = len(self._shared_data)
×
921
        else:
922
            self._source_shared_data = None
1✔
923
            self._param.ulSharedDataLen = 0
1✔
924

925
        self._public_data = ckbytelist(publicData)
1✔
926
        self._param.pPublicData = self._public_data
1✔
927
        self._param.ulPublicDataLen = len(self._public_data)
1✔
928

929
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
930
        self._mech.mechanism = CKM_ECDH1_DERIVE
1✔
931
        self._mech.pParameter = self._param
1✔
932
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_ECDH1_DERIVE_PARAMS_LENGTH
1✔
933

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

937

938
class CONCATENATE_BASE_AND_KEY_Mechanism:
1✔
939
    """CKM_CONCATENATE_BASE_AND_KEY key derivation mechanism"""
940

941
    def __init__(self, encKey):
1✔
942
        """
943
        :param encKey: a handle of encryption key
944
        """
945
        self._encKey = encKey
×
946

947
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
948
        self._mech.mechanism = CKM_CONCATENATE_BASE_AND_KEY
×
949
        self._mech.pParameter = self._encKey
×
950
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_OBJECT_HANDLE_LENGTH
×
951

952
    def to_native(self):
1✔
953
        return self._mech
×
954

955

956
class KEY_DERIVATION_STRING_DATA_MechanismBase:
1✔
957
    """Base class for mechanisms using derivation string data"""
958

959
    def __init__(self, data, mechType):
1✔
960
        """
961
        :param data: a byte array to concatenate the key with
962
        :param mechType: mechanism type
963
        """
964
        self._param = PyKCS11.LowLevel.CK_KEY_DERIVATION_STRING_DATA()
×
965

966
        self._data = ckbytelist(data)
×
967
        self._param.pData = self._data
×
968
        self._param.ulLen = len(self._data)
×
969

970
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
971
        self._mech.mechanism = mechType
×
972
        self._mech.pParameter = self._param
×
973
        self._mech.ulParameterLen = (
×
974
            PyKCS11.LowLevel.CK_KEY_DERIVATION_STRING_DATA_LENGTH
975
        )
976

977
    def to_native(self):
1✔
978
        return self._mech
×
979

980

981
class CONCATENATE_BASE_AND_DATA_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
982
    """CKM_CONCATENATE_BASE_AND_DATA key derivation mechanism"""
983

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

990

991
class CONCATENATE_DATA_AND_BASE_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
992
    """CKM_CONCATENATE_DATA_AND_BASE key derivation mechanism"""
993

994
    def __init__(self, data):
1✔
995
        """
996
        :param data: a byte array to concatenate the key with
997
        """
998
        super().__init__(data, CKM_CONCATENATE_DATA_AND_BASE)
×
999

1000

1001
class XOR_BASE_AND_DATA_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
1002
    """CKM_XOR_BASE_AND_DATA key derivation mechanism"""
1003

1004
    def __init__(self, data):
1✔
1005
        """
1006
        :param data: a byte array to xor the key with
1007
        """
1008
        super().__init__(data, CKM_XOR_BASE_AND_DATA)
×
1009

1010

1011
class EXTRACT_KEY_FROM_KEY_Mechanism:
1✔
1012
    """CKM_EXTRACT_KEY_FROM_KEY key derivation mechanism"""
1013

1014
    def __init__(self, extractParams):
1✔
1015
        """
1016
        :param extractParams: the index of the first bit of the original key to be used in the newly-derived key.
1017
                              For example if extractParams=5 then the 5 first bits are skipped and not used.
1018
        """
1019
        self._param = PyKCS11.LowLevel.CK_EXTRACT_PARAMS()
×
1020
        self._param.assign(extractParams)
×
1021

1022
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
1023
        self._mech.mechanism = CKM_EXTRACT_KEY_FROM_KEY
×
1024
        self._mech.pParameter = self._param
×
1025
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_EXTRACT_PARAMS_LENGTH
×
1026

1027
    def to_native(self):
1✔
1028
        return self._mech
×
1029

1030

1031
class DigestSession:
1✔
1032
    def __init__(self, lib, session, mecha):
1✔
1033
        self._lib = lib
1✔
1034
        self._session = session
1✔
1035
        self._mechanism = mecha.to_native()
1✔
1036
        rv = self._lib.C_DigestInit(self._session, self._mechanism)
1✔
1037
        if rv != CKR_OK:
1✔
1038
            raise PyKCS11Error(rv)
×
1039

1040
    def update(self, data):
1✔
1041
        """
1042
        C_DigestUpdate
1043

1044
        :param data: data to add to the digest
1045
        :type data: bytes or string
1046
        """
1047
        data1 = ckbytelist(data)
1✔
1048
        rv = self._lib.C_DigestUpdate(self._session, data1)
1✔
1049
        if rv != CKR_OK:
1✔
1050
            raise PyKCS11Error(rv)
×
1051
        return self
1✔
1052

1053
    def digestKey(self, handle):
1✔
1054
        """
1055
        C_DigestKey
1056

1057
        :param handle: key handle
1058
        :type handle: CK_OBJECT_HANDLE
1059
        """
1060
        rv = self._lib.C_DigestKey(self._session, handle)
×
1061
        if rv != CKR_OK:
×
1062
            raise PyKCS11Error(rv)
×
1063
        return self
×
1064

1065
    def final(self):
1✔
1066
        """
1067
        C_DigestFinal
1068

1069
        :return: the digest
1070
        :rtype: ckbytelist
1071
        """
1072
        digest = ckbytelist()
1✔
1073
        # Get the size of the digest
1074
        rv = self._lib.C_DigestFinal(self._session, digest)
1✔
1075
        if rv != CKR_OK:
1✔
1076
            raise PyKCS11Error(rv)
×
1077
        # Get the actual digest
1078
        rv = self._lib.C_DigestFinal(self._session, digest)
1✔
1079
        if rv != CKR_OK:
1✔
1080
            raise PyKCS11Error(rv)
×
1081
        return digest
1✔
1082

1083

1084
class Session:
1✔
1085
    """Manage :func:`PyKCS11Lib.openSession` objects"""
1086

1087
    def __init__(self, pykcs11, session):
1✔
1088
        """
1089
        :param pykcs11: PyKCS11 library object
1090
        :type pykcs11: PyKCS11Lib
1091
        :param session: session handle
1092
        :type session: instance of :class:`CK_SESSION_HANDLE`
1093
        """
1094
        if not isinstance(pykcs11, PyKCS11Lib):
1✔
1095
            raise TypeError("pykcs11 must be a PyKCS11Lib")
×
1096
        if not isinstance(session, LowLevel.CK_SESSION_HANDLE):
1✔
1097
            raise TypeError("session must be a CK_SESSION_HANDLE")
×
1098

1099
        # hold the PyKCS11Lib reference, so that it's not Garbage Collection'd
1100
        self.pykcs11 = pykcs11
1✔
1101
        self.session = session
1✔
1102

1103
    @property
1✔
1104
    def lib(self):
1✔
1105
        """
1106
        Get the low level lib of the owning PyKCS11Lib
1107
        """
1108
        return self.pykcs11.lib
1✔
1109

1110
    def closeSession(self):
1✔
1111
        """
1112
        C_CloseSession
1113
        """
1114
        rv = self.lib.C_CloseSession(self.session)
1✔
1115
        if rv != CKR_OK:
1✔
1116
            raise PyKCS11Error(rv)
×
1117

1118
    def getSessionInfo(self):
1✔
1119
        """
1120
        C_GetSessionInfo
1121

1122
        :return: a :class:`CK_SESSION_INFO` object
1123
        """
1124
        sessioninfo = PyKCS11.LowLevel.CK_SESSION_INFO()
1✔
1125
        rv = self.lib.C_GetSessionInfo(self.session, sessioninfo)
1✔
1126
        if rv != CKR_OK:
1✔
1127
            raise PyKCS11Error(rv)
×
1128

1129
        s = CK_SESSION_INFO()
1✔
1130
        s.slotID = sessioninfo.slotID
1✔
1131
        s.state = sessioninfo.state
1✔
1132
        s.flags = sessioninfo.flags
1✔
1133
        s.ulDeviceError = sessioninfo.ulDeviceError
1✔
1134
        return s
1✔
1135

1136
    def login(self, pin, user_type=CKU_USER):
1✔
1137
        """
1138
        C_Login
1139

1140
        :param pin: the user's PIN or None for CKF_PROTECTED_AUTHENTICATION_PATH
1141
        :type pin: string
1142
        :param user_type: the user type. The default value is
1143
          CKU_USER. You may also use CKU_SO
1144
        :type user_type: integer
1145
        """
1146
        pin1 = ckbytelist(pin)
1✔
1147
        rv = self.lib.C_Login(self.session, user_type, pin1)
1✔
1148
        if rv != CKR_OK:
1✔
1149
            raise PyKCS11Error(rv)
1✔
1150

1151
    def logout(self):
1✔
1152
        """
1153
        C_Logout
1154
        """
1155
        rv = self.lib.C_Logout(self.session)
1✔
1156
        if rv != CKR_OK:
1✔
1157
            raise PyKCS11Error(rv)
×
1158

1159
        del self
1✔
1160

1161
    def initPin(self, pin):
1✔
1162
        """
1163
        C_InitPIN
1164

1165
        :param pin: new PIN
1166
        """
1167
        new_pin1 = ckbytelist(pin)
1✔
1168
        rv = self.lib.C_InitPIN(self.session, new_pin1)
1✔
1169
        if rv != CKR_OK:
1✔
1170
            raise PyKCS11Error(rv)
×
1171

1172
    def setPin(self, old_pin, new_pin):
1✔
1173
        """
1174
        C_SetPIN
1175

1176
        :param old_pin: old PIN
1177
        :param new_pin: new PIN
1178
        """
1179
        old_pin1 = ckbytelist(old_pin)
1✔
1180
        new_pin1 = ckbytelist(new_pin)
1✔
1181
        rv = self.lib.C_SetPIN(self.session, old_pin1, new_pin1)
1✔
1182
        if rv != CKR_OK:
1✔
1183
            raise PyKCS11Error(rv)
×
1184

1185
    def createObject(self, template):
1✔
1186
        """
1187
        C_CreateObject
1188

1189
        :param template: object template
1190
        """
1191
        attrs = self._template2ckattrlist(template)
1✔
1192
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1193
        rv = self.lib.C_CreateObject(self.session, attrs, handle)
1✔
1194
        if rv != PyKCS11.CKR_OK:
1✔
1195
            raise PyKCS11.PyKCS11Error(rv)
×
1196
        return handle
1✔
1197

1198
    def destroyObject(self, obj):
1✔
1199
        """
1200
        C_DestroyObject
1201

1202
        :param obj: object ID
1203
        """
1204
        rv = self.lib.C_DestroyObject(self.session, obj)
1✔
1205
        if rv != CKR_OK:
1✔
1206
            raise PyKCS11Error(rv)
×
1207

1208
    def digestSession(self, mecha=MechanismSHA1):
1✔
1209
        """
1210
        C_DigestInit/C_DigestUpdate/C_DigestKey/C_DigestFinal
1211

1212
        :param mecha: the digesting mechanism to be used
1213
          (use `MechanismSHA1` for `CKM_SHA_1`)
1214
        :type mecha: :class:`Mechanism`
1215
        :return: A :class:`DigestSession` object
1216
        :rtype: DigestSession
1217
        """
1218
        return DigestSession(self.lib, self.session, mecha)
1✔
1219

1220
    def digest(self, data, mecha=MechanismSHA1):
1✔
1221
        """
1222
        C_DigestInit/C_Digest
1223

1224
        :param data: the data to be digested
1225
        :type data:  (binary) sring or list/tuple of bytes
1226
        :param mecha: the digesting mechanism to be used
1227
          (use `MechanismSHA1` for `CKM_SHA_1`)
1228
        :type mecha: :class:`Mechanism`
1229
        :return: the computed digest
1230
        :rtype: list of bytes
1231

1232
        :note: the returned value is an istance of :class:`ckbytelist`.
1233
          You can easly convert it to a binary string with:
1234
          ``bytes(ckbytelistDigest)``
1235
          or, for Python 2:
1236
          ``''.join(chr(i) for i in ckbytelistDigest)``
1237

1238
        """
1239
        digest = ckbytelist()
1✔
1240
        m = mecha.to_native()
1✔
1241
        data1 = ckbytelist(data)
1✔
1242
        rv = self.lib.C_DigestInit(self.session, m)
1✔
1243
        if rv != CKR_OK:
1✔
1244
            raise PyKCS11Error(rv)
×
1245
        # first call get digest size
1246
        rv = self.lib.C_Digest(self.session, data1, digest)
1✔
1247
        if rv != CKR_OK:
1✔
1248
            raise PyKCS11Error(rv)
×
1249
        # second call get actual digest data
1250
        rv = self.lib.C_Digest(self.session, data1, digest)
1✔
1251
        if rv != CKR_OK:
1✔
1252
            raise PyKCS11Error(rv)
×
1253
        return digest
1✔
1254

1255
    def sign(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1256
        """
1257
        C_SignInit/C_Sign
1258

1259
        :param key: a key handle, obtained calling :func:`findObjects`.
1260
        :type key: integer
1261
        :param data: the data to be signed
1262
        :type data:  (binary) string or list/tuple of bytes
1263
        :param mecha: the signing mechanism to be used
1264
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1265
        :type mecha: :class:`Mechanism`
1266
        :return: the computed signature
1267
        :rtype: list of bytes
1268

1269
        :note: the returned value is an instance of :class:`ckbytelist`.
1270
          You can easly convert it to a binary string with:
1271
          ``bytes(ckbytelistSignature)``
1272
          or, for Python 2:
1273
          ``''.join(chr(i) for i in ckbytelistSignature)``
1274

1275
        """
1276
        m = mecha.to_native()
1✔
1277
        signature = ckbytelist()
1✔
1278
        data1 = ckbytelist(data)
1✔
1279
        rv = self.lib.C_SignInit(self.session, m, key)
1✔
1280
        if rv != CKR_OK:
1✔
1281
            raise PyKCS11Error(rv)
×
1282
        # first call get signature size
1283
        rv = self.lib.C_Sign(self.session, data1, signature)
1✔
1284
        if rv != CKR_OK:
1✔
1285
            raise PyKCS11Error(rv)
×
1286
        # second call get actual signature data
1287
        rv = self.lib.C_Sign(self.session, data1, signature)
1✔
1288
        if rv != CKR_OK:
1✔
1289
            raise PyKCS11Error(rv)
×
1290
        return signature
1✔
1291

1292
    def verify(self, key, data, signature, mecha=MechanismRSAPKCS1):
1✔
1293
        """
1294
        C_VerifyInit/C_Verify
1295

1296
        :param key: a key handle, obtained calling :func:`findObjects`.
1297
        :type key: integer
1298
        :param data: the data that was signed
1299
        :type data:  (binary) string or list/tuple of bytes
1300
        :param signature: the signature to be verified
1301
        :type signature:  (binary) string or list/tuple of bytes
1302
        :param mecha: the signing mechanism to be used
1303
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1304
        :type mecha: :class:`Mechanism`
1305
        :return: True if signature is valid, False otherwise
1306
        :rtype: bool
1307

1308
        """
1309
        m = mecha.to_native()
1✔
1310
        data1 = ckbytelist(data)
1✔
1311
        rv = self.lib.C_VerifyInit(self.session, m, key)
1✔
1312
        if rv != CKR_OK:
1✔
1313
            raise PyKCS11Error(rv)
×
1314
        rv = self.lib.C_Verify(self.session, data1, signature)
1✔
1315
        if rv == CKR_OK:
1✔
1316
            return True
1✔
1317
        elif rv == CKR_SIGNATURE_INVALID:
×
1318
            return False
×
1319
        else:
1320
            raise PyKCS11Error(rv)
×
1321

1322
    def encrypt(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1323
        """
1324
        C_EncryptInit/C_Encrypt
1325

1326
        :param key: a key handle, obtained calling :func:`findObjects`.
1327
        :type key: integer
1328
        :param data: the data to be encrypted
1329
        :type data:  (binary) string or list/tuple of bytes
1330
        :param mecha: the encryption mechanism to be used
1331
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1332
        :type mecha: :class:`Mechanism`
1333
        :return: the encrypted data
1334
        :rtype: list of bytes
1335

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

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

1359
    def encryptInit(self, mech, key):
1✔
1360
        """
1361
        C_EncryptInit
1362

1363
        :param mech: the encryption mechanism to be used
1364
        :type mech: instance of :class:`Mechanism` 
1365
        :param key: a key handle
1366
        :type key: integer
1367
        """
1368
        m = mech.to_native()
1✔
1369
        rv = self.lib.C_EncryptInit(self.session, m, key)
1✔
1370
        if rv != CKR_OK:
1✔
NEW
1371
            raise PyKCS11Error(rv)
×
1372

1373
    def encryptUpdate(self, data):
1✔
1374
        """
1375
        C_EncryptUpdate
1376

1377
        :param data: the data to be encrypted
1378
        :type data: (binary) string or list/tuple of bytes
1379
        """
1380
        encrypted = ckbytelist()
1✔
1381
        data1 = ckbytelist(data)
1✔
1382
        rv = self.lib.C_EncryptUpdate(self.session, data1, encrypted)
1✔
1383
        if rv != CKR_OK:
1✔
NEW
1384
            raise PyKCS11Error(rv)
×
1385
        return encrypted
1✔
1386

1387
    def encryptFinal(self):
1✔
1388
        """
1389
        C_EncryptFinal
1390

1391
        :return: the last part of data to be encrypted
1392
        :rtype: (binary) string or list/tuple of bytes
1393
        """
1394
        encrypted = ckbytelist()
1✔
1395
        rv = self.lib.C_EncryptFinal(self.session, encrypted)
1✔
1396
        if rv != CKR_OK:
1✔
NEW
1397
            raise PyKCS11Error(rv)
×
1398
        return encrypted
1✔
1399

1400
    def decrypt(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1401
        """
1402
        C_DecryptInit/C_Decrypt
1403

1404
        :param key: a key handle, obtained calling :func:`findObjects`.
1405
        :type key: integer
1406
        :param data: the data to be decrypted
1407
        :type data:  (binary) string or list/tuple of bytes
1408
        :param mecha: the decrypt mechanism to be used
1409
        :type mecha: :class:`Mechanism` instance or :class:`MechanismRSAPKCS1`
1410
          for CKM_RSA_PKCS
1411
        :return: the decrypted data
1412
        :rtype: list of bytes
1413

1414
        :note: the returned value is an instance of :class:`ckbytelist`.
1415
          You can easly convert it to a binary string with:
1416
          ``bytes(ckbytelistData)``
1417
          or, for Python 2:
1418
          ``''.join(chr(i) for i in ckbytelistData)``
1419

1420
        """
1421
        m = mecha.to_native()
1✔
1422
        decrypted = ckbytelist()
1✔
1423
        data1 = ckbytelist(data)
1✔
1424
        rv = self.lib.C_DecryptInit(self.session, m, key)
1✔
1425
        if rv != CKR_OK:
1✔
1426
            raise PyKCS11Error(rv)
×
1427
        # first call get decrypted size
1428
        rv = self.lib.C_Decrypt(self.session, data1, decrypted)
1✔
1429
        if rv != CKR_OK:
1✔
1430
            raise PyKCS11Error(rv)
×
1431
        # second call get actual decrypted data
1432
        rv = self.lib.C_Decrypt(self.session, data1, decrypted)
1✔
1433
        if rv != CKR_OK:
1✔
1434
            raise PyKCS11Error(rv)
×
1435
        return decrypted
1✔
1436
    
1437
    def decryptInit(self, mech, key):
1✔
1438
        """
1439
        C_DecryptInit
1440

1441
        :param mech: the decrypt mechanism to be used
1442
        :type mech: instance of :class:`Mechanism` 
1443
        :param key: a key handle
1444
        :type key: integer
1445
        """
1446
        m = mech.to_native()
1✔
1447
        rv = self.lib.C_DecryptInit(self.session, m, key)
1✔
1448
        if rv != CKR_OK:
1✔
NEW
1449
            raise PyKCS11Error(rv)
×
1450

1451
    def decryptUpdate(self, data):
1✔
1452
        """
1453
        C_DecryptUpdate
1454

1455
        :param data: the data to be decrypted
1456
        :type data: (binary) string or list/tuple of bytes
1457
        """
1458
        decrypted = ckbytelist()
1✔
1459
        encrypted = ckbytelist(data)
1✔
1460
        rv = self.lib.C_DecryptUpdate(self.session, encrypted, decrypted)
1✔
1461
        if rv != CKR_OK:
1✔
NEW
1462
            raise PyKCS11Error(rv)
×
1463
        return decrypted
1✔
1464

1465
    def decryptFinal(self):
1✔
1466
        """
1467
        C_DecryptFinal
1468

1469
        :return: the last part of the decrypted data
1470
        :rtype: (binary) string or list/tuple of bytes
1471
        """
1472
        decrypted = ckbytelist()
1✔
1473
        rv = self.lib.C_DecryptFinal(self.session, decrypted)
1✔
1474
        if rv != CKR_OK:
1✔
NEW
1475
            raise PyKCS11Error(rv)
×
1476
        return decrypted
1✔
1477

1478
    def wrapKey(self, wrappingKey, key, mecha=MechanismRSAPKCS1):
1✔
1479
        """
1480
        C_WrapKey
1481

1482
        :param wrappingKey: a wrapping key handle
1483
        :type wrappingKey: integer
1484
        :param key: a handle of the key to be wrapped
1485
        :type key: integer
1486
        :param mecha: the encrypt mechanism to be used
1487
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1488
        :type mecha: :class:`Mechanism`
1489
        :return: the wrapped key bytes
1490
        :rtype: list of bytes
1491

1492
        :note: the returned value is an instance of :class:`ckbytelist`.
1493
          You can easily convert it to a binary string with:
1494
          ``bytes(ckbytelistData)``
1495
          or, for Python 2:
1496
          ``''.join(chr(i) for i in ckbytelistData)``
1497

1498
        """
1499
        wrapped = ckbytelist()
1✔
1500
        native = mecha.to_native()
1✔
1501
        # first call get wrapped size
1502
        rv = self.lib.C_WrapKey(self.session, native, wrappingKey, key, wrapped)
1✔
1503
        if rv != CKR_OK:
1✔
1504
            raise PyKCS11Error(rv)
×
1505
        # second call get actual wrapped key data
1506
        rv = self.lib.C_WrapKey(self.session, native, wrappingKey, key, wrapped)
1✔
1507
        if rv != CKR_OK:
1✔
1508
            raise PyKCS11Error(rv)
×
1509
        return wrapped
1✔
1510

1511
    def unwrapKey(self, unwrappingKey, wrappedKey, template, mecha=MechanismRSAPKCS1):
1✔
1512
        """
1513
        C_UnwrapKey
1514

1515
        :param unwrappingKey: the unwrapping key handle
1516
        :type unwrappingKey: integer
1517
        :param wrappedKey: the bytes of the wrapped key
1518
        :type wrappedKey:  (binary) string or list/tuple of bytes
1519
        :param template: template for the unwrapped key
1520
        :param mecha: the decrypt mechanism to be used (use
1521
          `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1522
        :type mecha: :class:`Mechanism`
1523
        :return: the unwrapped key object
1524
        :rtype: integer
1525

1526
        """
1527
        m = mecha.to_native()
1✔
1528
        data1 = ckbytelist(wrappedKey)
1✔
1529
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1530
        attrs = self._template2ckattrlist(template)
1✔
1531
        rv = self.lib.C_UnwrapKey(self.session, m, unwrappingKey, data1, attrs, handle)
1✔
1532
        if rv != CKR_OK:
1✔
1533
            raise PyKCS11Error(rv)
×
1534
        return handle
1✔
1535

1536
    def deriveKey(self, baseKey, template, mecha):
1✔
1537
        """
1538
        C_DeriveKey
1539

1540
        :param baseKey: the base key handle
1541
        :type baseKey: integer
1542
        :param template: template for the unwrapped key
1543
        :param mecha: the decrypt mechanism to be used (use
1544
          `ECDH1_DERIVE_Mechanism(...)` for `CKM_ECDH1_DERIVE`)
1545
        :type mecha: :class:`Mechanism`
1546
        :return: the unwrapped key object
1547
        :rtype: integer
1548
        """
1549
        m = mecha.to_native()
1✔
1550
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1551
        attrs = self._template2ckattrlist(template)
1✔
1552
        rv = self.lib.C_DeriveKey(self.session, m, baseKey, attrs, handle)
1✔
1553
        if rv != CKR_OK:
1✔
1554
            raise PyKCS11Error(rv)
×
1555
        return handle
1✔
1556

1557
    def isNum(self, type):
1✔
1558
        """
1559
        is the type a numerical value?
1560

1561
        :param type: PKCS#11 type like `CKA_CERTIFICATE_TYPE`
1562
        :rtype: bool
1563
        """
1564
        if type in (
1✔
1565
            CKA_CERTIFICATE_TYPE,
1566
            CKA_CLASS,
1567
            CKA_HW_FEATURE_TYPE,
1568
            CKA_KEY_GEN_MECHANISM,
1569
            CKA_KEY_TYPE,
1570
            CKA_MODULUS_BITS,
1571
            CKA_VALUE_BITS,
1572
            CKA_VALUE_LEN,
1573
        ):
1574
            return True
1✔
1575
        return False
1✔
1576

1577
    def isString(self, type):
1✔
1578
        """
1579
        is the type a string value?
1580

1581
        :param type: PKCS#11 type like `CKA_LABEL`
1582
        :rtype: bool
1583
        """
1584
        if type in (CKA_LABEL, CKA_APPLICATION):
1✔
1585
            return True
1✔
1586
        return False
1✔
1587

1588
    def isBool(self, type):
1✔
1589
        """
1590
        is the type a boolean value?
1591

1592
        :param type: PKCS#11 type like `CKA_ALWAYS_SENSITIVE`
1593
        :rtype: bool
1594
        """
1595
        if type in (
1✔
1596
            CKA_ALWAYS_AUTHENTICATE,
1597
            CKA_ALWAYS_SENSITIVE,
1598
            CKA_DECRYPT,
1599
            CKA_DERIVE,
1600
            CKA_ENCRYPT,
1601
            CKA_EXTRACTABLE,
1602
            CKA_HAS_RESET,
1603
            CKA_LOCAL,
1604
            CKA_MODIFIABLE,
1605
            CKA_COPYABLE,
1606
            CKA_DESTROYABLE,
1607
            CKA_NEVER_EXTRACTABLE,
1608
            CKA_PRIVATE,
1609
            CKA_RESET_ON_INIT,
1610
            CKA_SECONDARY_AUTH,
1611
            CKA_SENSITIVE,
1612
            CKA_SIGN,
1613
            CKA_SIGN_RECOVER,
1614
            CKA_TOKEN,
1615
            CKA_TRUSTED,
1616
            CKA_UNWRAP,
1617
            CKA_VERIFY,
1618
            CKA_VERIFY_RECOVER,
1619
            CKA_WRAP,
1620
            CKA_WRAP_WITH_TRUSTED,
1621
        ):
1622
            return True
1✔
1623
        return False
1✔
1624

1625
    def isBin(self, type):
1✔
1626
        """
1627
        is the type a byte array value?
1628

1629
        :param type: PKCS#11 type like `CKA_MODULUS`
1630
        :rtype: bool
1631
        """
1632
        return (
1✔
1633
            (not self.isBool(type))
1634
            and (not self.isString(type))
1635
            and (not self.isNum(type))
1636
        )
1637

1638
    def isAttributeList(self, type):
1✔
1639
        """
1640
        is the type a attribute list value?
1641

1642
        :param type: PKCS#11 type like `CKA_WRAP_TEMPLATE`
1643
        :rtype: bool
1644
        """
1645
        if type in (CKA_WRAP_TEMPLATE, CKA_UNWRAP_TEMPLATE):
1✔
1646
            return True
1✔
1647
        return False
1✔
1648

1649
    def _template2ckattrlist(self, template):
1✔
1650
        t = PyKCS11.LowLevel.ckattrlist(len(template))
1✔
1651
        for x in range(len(template)):
1✔
1652
            attr = template[x]
1✔
1653
            if self.isNum(attr[0]):
1✔
1654
                t[x].SetNum(attr[0], int(attr[1]))
1✔
1655
            elif self.isString(attr[0]):
1✔
1656
                t[x].SetString(attr[0], str(attr[1]))
1✔
1657
            elif self.isBool(attr[0]):
1✔
1658
                t[x].SetBool(attr[0], attr[1] == CK_TRUE)
1✔
1659
            elif self.isAttributeList(attr[0]):
1✔
1660
                t[x].SetList(attr[0], self._template2ckattrlist(attr[1]))
1✔
1661
            elif self.isBin(attr[0]):
1✔
1662
                attrBin = attr[1]
1✔
1663
                attrStr = attr[1]
1✔
1664
                if isinstance(attr[1], int):
1✔
1665
                    attrStr = str(attr[1])
×
1666
                if isinstance(attr[1], bytes):
1✔
1667
                    attrBin = ckbytelist(attrStr)
1✔
1668
                t[x].SetBin(attr[0], attrBin)
1✔
1669
            else:
1670
                raise PyKCS11Error(-2)
×
1671
        return t
1✔
1672

1673
    def generateKey(self, template, mecha=MechanismAESGENERATEKEY):
1✔
1674
        """
1675
        generate a secret key
1676

1677
        :param template: template for the secret key
1678
        :param mecha: mechanism to use
1679
        :return: handle of the generated key
1680
        :rtype: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1681
        """
1682
        t = self._template2ckattrlist(template)
1✔
1683
        ck_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1684
        m = mecha.to_native()
1✔
1685
        rv = self.lib.C_GenerateKey(self.session, m, t, ck_handle)
1✔
1686
        if rv != CKR_OK:
1✔
1687
            raise PyKCS11Error(rv)
×
1688
        return ck_handle
1✔
1689

1690
    def generateKeyPair(
1✔
1691
        self, templatePub, templatePriv, mecha=MechanismRSAGENERATEKEYPAIR
1692
    ):
1693
        """
1694
        generate a key pair
1695

1696
        :param templatePub: template for the public key
1697
        :param templatePriv:  template for the private key
1698
        :param mecha: mechanism to use
1699
        :return: a tuple of handles (pub, priv)
1700
        :rtype: tuple
1701
        """
1702
        tPub = self._template2ckattrlist(templatePub)
1✔
1703
        tPriv = self._template2ckattrlist(templatePriv)
1✔
1704
        ck_pub_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1705
        ck_prv_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1706
        m = mecha.to_native()
1✔
1707
        rv = self.lib.C_GenerateKeyPair(
1✔
1708
            self.session, m, tPub, tPriv, ck_pub_handle, ck_prv_handle
1709
        )
1710

1711
        if rv != CKR_OK:
1✔
1712
            raise PyKCS11Error(rv)
1✔
1713
        return ck_pub_handle, ck_prv_handle
1✔
1714

1715
    def findObjects(self, template=()):
1✔
1716
        """
1717
        find the objects matching the template pattern
1718

1719
        :param template: list of attributes tuples (attribute,value).
1720
          The default value is () and all the objects are returned
1721
        :type template: list
1722
        :return: a list of object ids
1723
        :rtype: list
1724
        """
1725
        t = self._template2ckattrlist(template)
1✔
1726

1727
        # we search for 10 objects by default. speed/memory tradeoff
1728
        result = PyKCS11.LowLevel.ckobjlist(10)
1✔
1729

1730
        rv = self.lib.C_FindObjectsInit(self.session, t)
1✔
1731
        if rv != CKR_OK:
1✔
1732
            raise PyKCS11Error(rv)
×
1733

1734
        res = []
1✔
1735
        while True:
1✔
1736
            rv = self.lib.C_FindObjects(self.session, result)
1✔
1737
            if rv != CKR_OK:
1✔
1738
                raise PyKCS11Error(rv)
×
1739
            for x in result:
1✔
1740
                # make a copy of the handle: the original value get
1741
                # corrupted (!!)
1742
                a = CK_OBJECT_HANDLE(self)
1✔
1743
                a.assign(x.value())
1✔
1744
                res.append(a)
1✔
1745
            if len(result) == 0:
1✔
1746
                break
1✔
1747

1748
        rv = self.lib.C_FindObjectsFinal(self.session)
1✔
1749
        if rv != CKR_OK:
1✔
1750
            raise PyKCS11Error(rv)
×
1751
        return res
1✔
1752

1753
    def getAttributeValue(self, obj_id, attr, allAsBinary=False):
1✔
1754
        """
1755
        C_GetAttributeValue
1756

1757
        :param obj_id: object ID returned by :func:`findObjects`
1758
        :type obj_id: integer
1759
        :param attr: list of attributes
1760
        :type attr: list
1761
        :param allAsBinary: return all values as binary data; default is False.
1762
        :type allAsBinary: Boolean
1763
        :return: a list of values corresponding to the list of attributes
1764
        :rtype: list
1765

1766
        :see: :func:`getAttributeValue_fragmented`
1767

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

1771
          Binary data is returned as :class:`ckbytelist` type, usable
1772
          as a list containing only bytes.
1773
          You can easly convert it to a binary string with:
1774
          ``bytes(ckbytelistVariable)``
1775
          or, for Python 2:
1776
          ``''.join(chr(i) for i in ckbytelistVariable)``
1777

1778
        """
1779
        valTemplate = PyKCS11.LowLevel.ckattrlist(len(attr))
1✔
1780
        for x in range(len(attr)):
1✔
1781
            valTemplate[x].SetType(attr[x])
1✔
1782
        # first call to get the attribute size and reserve the memory
1783
        rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1784
        if rv in (
1✔
1785
            CKR_ATTRIBUTE_TYPE_INVALID,
1786
            CKR_ATTRIBUTE_SENSITIVE,
1787
            CKR_ARGUMENTS_BAD,
1788
        ):
1789
            return self.getAttributeValue_fragmented(obj_id, attr, allAsBinary)
1✔
1790

1791
        if rv != CKR_OK:
1✔
1792
            raise PyKCS11Error(rv)
×
1793
        # second call to get the attribute value
1794
        rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1795
        if rv != CKR_OK:
1✔
1796
            raise PyKCS11Error(rv)
×
1797

1798
        res = []
1✔
1799
        for x in range(len(attr)):
1✔
1800
            if allAsBinary:
1✔
1801
                res.append(valTemplate[x].GetBin())
1✔
1802
            elif valTemplate[x].IsNum():
1✔
1803
                res.append(valTemplate[x].GetNum())
1✔
1804
            elif valTemplate[x].IsBool():
1✔
1805
                res.append(valTemplate[x].GetBool())
1✔
1806
            elif valTemplate[x].IsString():
1✔
1807
                res.append(valTemplate[x].GetString())
1✔
1808
            elif valTemplate[x].IsBin():
1✔
1809
                res.append(valTemplate[x].GetBin())
1✔
1810
            else:
1811
                raise PyKCS11Error(-2)
×
1812

1813
        return res
1✔
1814

1815
    def getAttributeValue_fragmented(self, obj_id, attr, allAsBinary=False):
1✔
1816
        """
1817
        Same as :func:`getAttributeValue` except that when some attribute
1818
        is sensitive or unknown an empty value (None) is returned.
1819

1820
        Note: this is achived by getting attributes one by one.
1821

1822
        :see: :func:`getAttributeValue`
1823
        """
1824
        # some attributes does not exists or is sensitive
1825
        # but we don't know which ones. So try one by one
1826
        valTemplate = PyKCS11.LowLevel.ckattrlist(1)
1✔
1827
        res = []
1✔
1828
        for x in range(len(attr)):
1✔
1829
            valTemplate[0].Reset()
1✔
1830
            valTemplate[0].SetType(attr[x])
1✔
1831
            # first call to get the attribute size and reserve the memory
1832
            rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1833
            if rv in (
1✔
1834
                CKR_ATTRIBUTE_TYPE_INVALID,
1835
                CKR_ATTRIBUTE_SENSITIVE,
1836
                CKR_ARGUMENTS_BAD,
1837
            ):
1838
                # append an empty value
1839
                res.append(None)
1✔
1840
                continue
1✔
1841

1842
            if rv != CKR_OK:
1✔
1843
                raise PyKCS11Error(rv)
×
1844
            # second call to get the attribute value
1845
            rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1846
            if rv != CKR_OK:
1✔
1847
                raise PyKCS11Error(rv)
×
1848

1849
            if allAsBinary:
1✔
1850
                res.append(valTemplate[0].GetBin())
×
1851
            elif valTemplate[0].IsNum():
1✔
1852
                res.append(valTemplate[0].GetNum())
1✔
1853
            elif valTemplate[0].IsBool():
1✔
1854
                res.append(valTemplate[0].GetBool())
1✔
1855
            elif valTemplate[0].IsString():
1✔
1856
                res.append(valTemplate[0].GetString())
1✔
1857
            elif valTemplate[0].IsBin():
1✔
1858
                res.append(valTemplate[0].GetBin())
1✔
1859
            elif valTemplate[0].IsAttributeList():
1✔
1860
                res.append(valTemplate[0].GetBin())
1✔
1861
            else:
1862
                raise PyKCS11Error(-2)
×
1863

1864
        return res
1✔
1865

1866
    def setAttributeValue(self, obj_id, template):
1✔
1867
        """
1868
        C_SetAttributeValue
1869

1870
        :param obj_id: object ID returned by :func:`findObjects`
1871
        :type obj_id: integer
1872
        :param template: list of (attribute, value) pairs
1873
        :type template: list
1874
        :return: Nothing
1875
        :rtype: None
1876
        """
1877

1878
        templ = self._template2ckattrlist(template)
1✔
1879
        rv = self.lib.C_SetAttributeValue(self.session, obj_id, templ)
1✔
1880

1881
        if rv != CKR_OK:
1✔
1882
            raise PyKCS11Error(rv)
×
1883

1884
        return None
1✔
1885

1886
    def seedRandom(self, seed):
1✔
1887
        """
1888
        C_SeedRandom
1889

1890
        :param seed: seed material
1891
        :type seed: iterable
1892
        """
1893
        low_seed = ckbytelist(seed)
1✔
1894
        rv = self.lib.C_SeedRandom(self.session, low_seed)
1✔
1895
        if rv != CKR_OK:
1✔
1896
            raise PyKCS11Error(rv)
×
1897

1898
    def generateRandom(self, size=16):
1✔
1899
        """
1900
        C_GenerateRandom
1901

1902
        :param size: number of random bytes to get
1903
        :type size: integer
1904

1905
        :note: the returned value is an instance of :class:`ckbytelist`.
1906
          You can easly convert it to a binary string with:
1907
          ``bytes(random)``
1908
          or, for Python 2:
1909
          ``''.join(chr(i) for i in random)``
1910
        """
1911
        low_rand = ckbytelist([0] * size)
1✔
1912
        rv = self.lib.C_GenerateRandom(self.session, low_rand)
1✔
1913
        if rv != CKR_OK:
1✔
1914
            raise PyKCS11Error(rv)
×
1915
        return low_rand
1✔
1916

1917

1918
if __name__ == "__main__":
1✔
1919
    # sample test/debug code
1920
    p = PyKCS11Lib()
×
1921
    p.load()
×
1922

1923
    print("getInfo")
×
1924
    print(p.getInfo())
×
1925

1926
    print()
×
1927
    print("getSlotList")
×
1928
    s = p.getSlotList()
×
1929
    print("slots:", s)
×
1930
    slot = s[0]
×
1931
    print("using slot:", slot)
×
1932

1933
    print()
×
1934
    print("getSlotInfo")
×
1935
    print(p.getSlotInfo(slot))
×
1936

1937
    print()
×
1938
    print("getTokenInfo")
×
1939
    print(p.getTokenInfo(slot))
×
1940

1941
    print()
×
1942
    print("openSession")
×
1943
    se = p.openSession(slot)
×
1944

1945
    print()
×
1946
    print("sessionInfo")
×
1947
    print(se.getSessionInfo())
×
1948

1949
    print()
×
1950
    print("seedRandom")
×
1951
    try:
×
1952
        se.seedRandom([1, 2, 3, 4])
×
1953
    except PyKCS11Error as e:
×
1954
        print(e)
×
1955
    print("generateRandom")
×
1956
    print(se.generateRandom())
×
1957

1958
    print()
×
1959
    print("login")
×
1960
    se.login(pin="0000")
×
1961

1962
    print()
×
1963
    print("sessionInfo")
×
1964
    print(se.getSessionInfo())
×
1965

1966
    print()
×
1967
    print("findObjects")
×
1968
    objs = se.findObjects([(CKA_CLASS, CKO_CERTIFICATE)])
×
1969
    print("Nb objetcs:", len(objs))
×
1970
    print(objs)
×
1971

1972
    print()
×
1973
    print("getAttributeValue")
×
1974
    for o in objs:
×
1975
        attr = se.getAttributeValue(o, [CKA_LABEL, CKA_CLASS])
×
1976
        print(attr)
×
1977

1978
    print()
×
1979
    print("logout")
×
1980
    se.logout()
×
1981

1982
    print()
×
1983
    print("closeSession")
×
1984
    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