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

LudovicRousseau / PyKCS11 / 12855273166

19 Jan 2025 04:26PM UTC coverage: 86.678% (-0.008%) from 86.686%
12855273166

push

github

LudovicRousseau
test_derive: document test_deriveKey_CKM_EXTRACT_KEY_FROM_KEY

2993 of 3453 relevant lines covered (86.68%)

0.87 hits per line

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

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

18

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.src = 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._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
946
        self._mech.mechanism = CKM_CONCATENATE_BASE_AND_KEY
×
947
        self._mech.pParameter = encKey
×
948
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_OBJECT_HANDLE_LENGTH
×
949

950
    def to_native(self):
1✔
951
        return self._mech
×
952

953

954
class KEY_DERIVATION_STRING_DATA_MechanismBase:
1✔
955
    """Base class for mechanisms using derivation string data"""
956

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

964
        self._data = ckbytelist(data)
×
965
        self._param.pData = self._data
×
966
        self._param.ulLen = len(self._data)
×
967

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

975
    def to_native(self):
1✔
976
        return self._mech
×
977

978

979
class CONCATENATE_BASE_AND_DATA_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
980
    """CKM_CONCATENATE_BASE_AND_DATA key derivation mechanism"""
981

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

988

989
class CONCATENATE_DATA_AND_BASE_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
990
    """CKM_CONCATENATE_DATA_AND_BASE key derivation mechanism"""
991

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

998

999
class XOR_BASE_AND_DATA_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
1000
    """CKM_XOR_BASE_AND_DATA key derivation mechanism"""
1001

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

1008

1009
class EXTRACT_KEY_FROM_KEY_Mechanism:
1✔
1010
    """CKM_EXTRACT_KEY_FROM_KEY key derivation mechanism"""
1011

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

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

1025
    def to_native(self):
1✔
1026
        return self._mech
×
1027

1028

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

1038
    def update(self, data):
1✔
1039
        """
1040
        C_DigestUpdate
1041

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

1051
    def digestKey(self, handle):
1✔
1052
        """
1053
        C_DigestKey
1054

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

1063
    def final(self):
1✔
1064
        """
1065
        C_DigestFinal
1066

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

1081

1082
class Session:
1✔
1083
    """Manage :func:`PyKCS11Lib.openSession` objects"""
1084

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

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

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

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

1116
    def getSessionInfo(self):
1✔
1117
        """
1118
        C_GetSessionInfo
1119

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

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

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

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

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

1157
        del self
1✔
1158

1159
    def initPin(self, pin):
1✔
1160
        """
1161
        C_InitPIN
1162

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

1170
    def setPin(self, old_pin, new_pin):
1✔
1171
        """
1172
        C_SetPIN
1173

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

1183
    def createObject(self, template):
1✔
1184
        """
1185
        C_CreateObject
1186

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

1196
    def destroyObject(self, obj):
1✔
1197
        """
1198
        C_DestroyObject
1199

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1357
    def decrypt(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1358
        """
1359
        C_DecryptInit/C_Decrypt
1360

1361
        :param key: a key handle, obtained calling :func:`findObjects`.
1362
        :type key: integer
1363
        :param data: the data to be decrypted
1364
        :type data:  (binary) string or list/tuple of bytes
1365
        :param mecha: the decrypt mechanism to be used
1366
        :type mecha: :class:`Mechanism` instance or :class:`MechanismRSAPKCS1`
1367
          for CKM_RSA_PKCS
1368
        :return: the decrypted data
1369
        :rtype: list of bytes
1370

1371
        :note: the returned value is an instance of :class:`ckbytelist`.
1372
          You can easly convert it to a binary string with:
1373
          ``bytes(ckbytelistData)``
1374
          or, for Python 2:
1375
          ``''.join(chr(i) for i in ckbytelistData)``
1376

1377
        """
1378
        m = mecha.to_native()
1✔
1379
        decrypted = ckbytelist()
1✔
1380
        data1 = ckbytelist(data)
1✔
1381
        rv = self.lib.C_DecryptInit(self.session, m, key)
1✔
1382
        if rv != CKR_OK:
1✔
1383
            raise PyKCS11Error(rv)
×
1384
        # first call get decrypted size
1385
        rv = self.lib.C_Decrypt(self.session, data1, decrypted)
1✔
1386
        if rv != CKR_OK:
1✔
1387
            raise PyKCS11Error(rv)
×
1388
        # second call get actual decrypted data
1389
        rv = self.lib.C_Decrypt(self.session, data1, decrypted)
1✔
1390
        if rv != CKR_OK:
1✔
1391
            raise PyKCS11Error(rv)
×
1392
        return decrypted
1✔
1393

1394
    def wrapKey(self, wrappingKey, key, mecha=MechanismRSAPKCS1):
1✔
1395
        """
1396
        C_WrapKey
1397

1398
        :param wrappingKey: a wrapping key handle
1399
        :type wrappingKey: integer
1400
        :param key: a handle of the key to be wrapped
1401
        :type key: integer
1402
        :param mecha: the encrypt mechanism to be used
1403
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1404
        :type mecha: :class:`Mechanism`
1405
        :return: the wrapped key bytes
1406
        :rtype: list of bytes
1407

1408
        :note: the returned value is an instance of :class:`ckbytelist`.
1409
          You can easily convert it to a binary string with:
1410
          ``bytes(ckbytelistData)``
1411
          or, for Python 2:
1412
          ``''.join(chr(i) for i in ckbytelistData)``
1413

1414
        """
1415
        wrapped = ckbytelist()
1✔
1416
        native = mecha.to_native()
1✔
1417
        # first call get wrapped size
1418
        rv = self.lib.C_WrapKey(self.session, native, wrappingKey, key, wrapped)
1✔
1419
        if rv != CKR_OK:
1✔
1420
            raise PyKCS11Error(rv)
×
1421
        # second call get actual wrapped key data
1422
        rv = self.lib.C_WrapKey(self.session, native, wrappingKey, key, wrapped)
1✔
1423
        if rv != CKR_OK:
1✔
1424
            raise PyKCS11Error(rv)
×
1425
        return wrapped
1✔
1426

1427
    def unwrapKey(self, unwrappingKey, wrappedKey, template, mecha=MechanismRSAPKCS1):
1✔
1428
        """
1429
        C_UnwrapKey
1430

1431
        :param unwrappingKey: the unwrapping key handle
1432
        :type unwrappingKey: integer
1433
        :param wrappedKey: the bytes of the wrapped key
1434
        :type wrappedKey:  (binary) string or list/tuple of bytes
1435
        :param template: template for the unwrapped key
1436
        :param mecha: the decrypt mechanism to be used (use
1437
          `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1438
        :type mecha: :class:`Mechanism`
1439
        :return: the unwrapped key object
1440
        :rtype: integer
1441

1442
        """
1443
        m = mecha.to_native()
1✔
1444
        data1 = ckbytelist(wrappedKey)
1✔
1445
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1446
        attrs = self._template2ckattrlist(template)
1✔
1447
        rv = self.lib.C_UnwrapKey(self.session, m, unwrappingKey, data1, attrs, handle)
1✔
1448
        if rv != CKR_OK:
1✔
1449
            raise PyKCS11Error(rv)
×
1450
        return handle
1✔
1451

1452
    def deriveKey(self, baseKey, template, mecha):
1✔
1453
        """
1454
        C_DeriveKey
1455

1456
        :param baseKey: the base key handle
1457
        :type baseKey: integer
1458
        :param template: template for the unwrapped key
1459
        :param mecha: the decrypt mechanism to be used (use
1460
          `ECDH1_DERIVE_Mechanism(...)` for `CKM_ECDH1_DERIVE`)
1461
        :type mecha: :class:`Mechanism`
1462
        :return: the unwrapped key object
1463
        :rtype: integer
1464
        """
1465
        m = mecha.to_native()
1✔
1466
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1467
        attrs = self._template2ckattrlist(template)
1✔
1468
        rv = self.lib.C_DeriveKey(self.session, m, baseKey, attrs, handle)
1✔
1469
        if rv != CKR_OK:
1✔
1470
            raise PyKCS11Error(rv)
×
1471
        return handle
1✔
1472

1473
    def isNum(self, type):
1✔
1474
        """
1475
        is the type a numerical value?
1476

1477
        :param type: PKCS#11 type like `CKA_CERTIFICATE_TYPE`
1478
        :rtype: bool
1479
        """
1480
        if type in (
1✔
1481
            CKA_CERTIFICATE_TYPE,
1482
            CKA_CLASS,
1483
            CKA_HW_FEATURE_TYPE,
1484
            CKA_KEY_GEN_MECHANISM,
1485
            CKA_KEY_TYPE,
1486
            CKA_MODULUS_BITS,
1487
            CKA_VALUE_BITS,
1488
            CKA_VALUE_LEN,
1489
        ):
1490
            return True
1✔
1491
        return False
1✔
1492

1493
    def isString(self, type):
1✔
1494
        """
1495
        is the type a string value?
1496

1497
        :param type: PKCS#11 type like `CKA_LABEL`
1498
        :rtype: bool
1499
        """
1500
        if type in (CKA_LABEL, CKA_APPLICATION):
1✔
1501
            return True
1✔
1502
        return False
1✔
1503

1504
    def isBool(self, type):
1✔
1505
        """
1506
        is the type a boolean value?
1507

1508
        :param type: PKCS#11 type like `CKA_ALWAYS_SENSITIVE`
1509
        :rtype: bool
1510
        """
1511
        if type in (
1✔
1512
            CKA_ALWAYS_AUTHENTICATE,
1513
            CKA_ALWAYS_SENSITIVE,
1514
            CKA_DECRYPT,
1515
            CKA_DERIVE,
1516
            CKA_ENCRYPT,
1517
            CKA_EXTRACTABLE,
1518
            CKA_HAS_RESET,
1519
            CKA_LOCAL,
1520
            CKA_MODIFIABLE,
1521
            CKA_COPYABLE,
1522
            CKA_DESTROYABLE,
1523
            CKA_NEVER_EXTRACTABLE,
1524
            CKA_PRIVATE,
1525
            CKA_RESET_ON_INIT,
1526
            CKA_SECONDARY_AUTH,
1527
            CKA_SENSITIVE,
1528
            CKA_SIGN,
1529
            CKA_SIGN_RECOVER,
1530
            CKA_TOKEN,
1531
            CKA_TRUSTED,
1532
            CKA_UNWRAP,
1533
            CKA_VERIFY,
1534
            CKA_VERIFY_RECOVER,
1535
            CKA_WRAP,
1536
            CKA_WRAP_WITH_TRUSTED,
1537
        ):
1538
            return True
1✔
1539
        return False
1✔
1540

1541
    def isBin(self, type):
1✔
1542
        """
1543
        is the type a byte array value?
1544

1545
        :param type: PKCS#11 type like `CKA_MODULUS`
1546
        :rtype: bool
1547
        """
1548
        return (
1✔
1549
            (not self.isBool(type))
1550
            and (not self.isString(type))
1551
            and (not self.isNum(type))
1552
        )
1553

1554
    def isAttributeList(self, type):
1✔
1555
        """
1556
        is the type a attribute list value?
1557

1558
        :param type: PKCS#11 type like `CKA_WRAP_TEMPLATE`
1559
        :rtype: bool
1560
        """
1561
        if type in (CKA_WRAP_TEMPLATE, CKA_UNWRAP_TEMPLATE):
1✔
1562
            return True
1✔
1563
        return False
1✔
1564

1565
    def _template2ckattrlist(self, template):
1✔
1566
        t = PyKCS11.LowLevel.ckattrlist(len(template))
1✔
1567
        for x in range(len(template)):
1✔
1568
            attr = template[x]
1✔
1569
            if self.isNum(attr[0]):
1✔
1570
                t[x].SetNum(attr[0], int(attr[1]))
1✔
1571
            elif self.isString(attr[0]):
1✔
1572
                t[x].SetString(attr[0], str(attr[1]))
1✔
1573
            elif self.isBool(attr[0]):
1✔
1574
                t[x].SetBool(attr[0], attr[1] == CK_TRUE)
1✔
1575
            elif self.isAttributeList(attr[0]):
1✔
1576
                t[x].SetList(attr[0], self._template2ckattrlist(attr[1]))
1✔
1577
            elif self.isBin(attr[0]):
1✔
1578
                attrBin = attr[1]
1✔
1579
                attrStr = attr[1]
1✔
1580
                if isinstance(attr[1], int):
1✔
1581
                    attrStr = str(attr[1])
×
1582
                if isinstance(attr[1], bytes):
1✔
1583
                    attrBin = ckbytelist(attrStr)
1✔
1584
                t[x].SetBin(attr[0], attrBin)
1✔
1585
            else:
1586
                raise PyKCS11Error(-2)
×
1587
        return t
1✔
1588

1589
    def generateKey(self, template, mecha=MechanismAESGENERATEKEY):
1✔
1590
        """
1591
        generate a secret key
1592

1593
        :param template: template for the secret key
1594
        :param mecha: mechanism to use
1595
        :return: handle of the generated key
1596
        :rtype: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1597
        """
1598
        t = self._template2ckattrlist(template)
1✔
1599
        ck_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1600
        m = mecha.to_native()
1✔
1601
        rv = self.lib.C_GenerateKey(self.session, m, t, ck_handle)
1✔
1602
        if rv != CKR_OK:
1✔
1603
            raise PyKCS11Error(rv)
×
1604
        return ck_handle
1✔
1605

1606
    def generateKeyPair(
1✔
1607
        self, templatePub, templatePriv, mecha=MechanismRSAGENERATEKEYPAIR
1608
    ):
1609
        """
1610
        generate a key pair
1611

1612
        :param templatePub: template for the public key
1613
        :param templatePriv:  template for the private key
1614
        :param mecha: mechanism to use
1615
        :return: a tuple of handles (pub, priv)
1616
        :rtype: tuple
1617
        """
1618
        tPub = self._template2ckattrlist(templatePub)
1✔
1619
        tPriv = self._template2ckattrlist(templatePriv)
1✔
1620
        ck_pub_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1621
        ck_prv_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1622
        m = mecha.to_native()
1✔
1623
        rv = self.lib.C_GenerateKeyPair(
1✔
1624
            self.session, m, tPub, tPriv, ck_pub_handle, ck_prv_handle
1625
        )
1626

1627
        if rv != CKR_OK:
1✔
1628
            raise PyKCS11Error(rv)
1✔
1629
        return ck_pub_handle, ck_prv_handle
1✔
1630

1631
    def findObjects(self, template=()):
1✔
1632
        """
1633
        find the objects matching the template pattern
1634

1635
        :param template: list of attributes tuples (attribute,value).
1636
          The default value is () and all the objects are returned
1637
        :type template: list
1638
        :return: a list of object ids
1639
        :rtype: list
1640
        """
1641
        t = self._template2ckattrlist(template)
1✔
1642

1643
        # we search for 10 objects by default. speed/memory tradeoff
1644
        result = PyKCS11.LowLevel.ckobjlist(10)
1✔
1645

1646
        rv = self.lib.C_FindObjectsInit(self.session, t)
1✔
1647
        if rv != CKR_OK:
1✔
1648
            raise PyKCS11Error(rv)
×
1649

1650
        res = []
1✔
1651
        while True:
1✔
1652
            rv = self.lib.C_FindObjects(self.session, result)
1✔
1653
            if rv != CKR_OK:
1✔
1654
                raise PyKCS11Error(rv)
×
1655
            for x in result:
1✔
1656
                # make a copy of the handle: the original value get
1657
                # corrupted (!!)
1658
                a = CK_OBJECT_HANDLE(self)
1✔
1659
                a.assign(x.value())
1✔
1660
                res.append(a)
1✔
1661
            if len(result) == 0:
1✔
1662
                break
1✔
1663

1664
        rv = self.lib.C_FindObjectsFinal(self.session)
1✔
1665
        if rv != CKR_OK:
1✔
1666
            raise PyKCS11Error(rv)
×
1667
        return res
1✔
1668

1669
    def getAttributeValue(self, obj_id, attr, allAsBinary=False):
1✔
1670
        """
1671
        C_GetAttributeValue
1672

1673
        :param obj_id: object ID returned by :func:`findObjects`
1674
        :type obj_id: integer
1675
        :param attr: list of attributes
1676
        :type attr: list
1677
        :param allAsBinary: return all values as binary data; default is False.
1678
        :type allAsBinary: Boolean
1679
        :return: a list of values corresponding to the list of attributes
1680
        :rtype: list
1681

1682
        :see: :func:`getAttributeValue_fragmented`
1683

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

1687
          Binary data is returned as :class:`ckbytelist` type, usable
1688
          as a list containing only bytes.
1689
          You can easly convert it to a binary string with:
1690
          ``bytes(ckbytelistVariable)``
1691
          or, for Python 2:
1692
          ``''.join(chr(i) for i in ckbytelistVariable)``
1693

1694
        """
1695
        valTemplate = PyKCS11.LowLevel.ckattrlist(len(attr))
1✔
1696
        for x in range(len(attr)):
1✔
1697
            valTemplate[x].SetType(attr[x])
1✔
1698
        # first call to get the attribute size and reserve the memory
1699
        rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1700
        if rv in (
1✔
1701
            CKR_ATTRIBUTE_TYPE_INVALID,
1702
            CKR_ATTRIBUTE_SENSITIVE,
1703
            CKR_ARGUMENTS_BAD,
1704
        ):
1705
            return self.getAttributeValue_fragmented(obj_id, attr, allAsBinary)
1✔
1706

1707
        if rv != CKR_OK:
1✔
1708
            raise PyKCS11Error(rv)
×
1709
        # second call to get the attribute value
1710
        rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1711
        if rv != CKR_OK:
1✔
1712
            raise PyKCS11Error(rv)
×
1713

1714
        res = []
1✔
1715
        for x in range(len(attr)):
1✔
1716
            if allAsBinary:
1✔
1717
                res.append(valTemplate[x].GetBin())
1✔
1718
            elif valTemplate[x].IsNum():
1✔
1719
                res.append(valTemplate[x].GetNum())
1✔
1720
            elif valTemplate[x].IsBool():
1✔
1721
                res.append(valTemplate[x].GetBool())
1✔
1722
            elif valTemplate[x].IsString():
1✔
1723
                res.append(valTemplate[x].GetString())
1✔
1724
            elif valTemplate[x].IsBin():
1✔
1725
                res.append(valTemplate[x].GetBin())
1✔
1726
            else:
1727
                raise PyKCS11Error(-2)
×
1728

1729
        return res
1✔
1730

1731
    def getAttributeValue_fragmented(self, obj_id, attr, allAsBinary=False):
1✔
1732
        """
1733
        Same as :func:`getAttributeValue` except that when some attribute
1734
        is sensitive or unknown an empty value (None) is returned.
1735

1736
        Note: this is achived by getting attributes one by one.
1737

1738
        :see: :func:`getAttributeValue`
1739
        """
1740
        # some attributes does not exists or is sensitive
1741
        # but we don't know which ones. So try one by one
1742
        valTemplate = PyKCS11.LowLevel.ckattrlist(1)
1✔
1743
        res = []
1✔
1744
        for x in range(len(attr)):
1✔
1745
            valTemplate[0].Reset()
1✔
1746
            valTemplate[0].SetType(attr[x])
1✔
1747
            # first call to get the attribute size and reserve the memory
1748
            rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1749
            if rv in (
1✔
1750
                CKR_ATTRIBUTE_TYPE_INVALID,
1751
                CKR_ATTRIBUTE_SENSITIVE,
1752
                CKR_ARGUMENTS_BAD,
1753
            ):
1754
                # append an empty value
1755
                res.append(None)
1✔
1756
                continue
1✔
1757

1758
            if rv != CKR_OK:
1✔
1759
                raise PyKCS11Error(rv)
×
1760
            # second call to get the attribute value
1761
            rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1762
            if rv != CKR_OK:
1✔
1763
                raise PyKCS11Error(rv)
×
1764

1765
            if allAsBinary:
1✔
1766
                res.append(valTemplate[0].GetBin())
×
1767
            elif valTemplate[0].IsNum():
1✔
1768
                res.append(valTemplate[0].GetNum())
1✔
1769
            elif valTemplate[0].IsBool():
1✔
1770
                res.append(valTemplate[0].GetBool())
1✔
1771
            elif valTemplate[0].IsString():
1✔
1772
                res.append(valTemplate[0].GetString())
1✔
1773
            elif valTemplate[0].IsBin():
1✔
1774
                res.append(valTemplate[0].GetBin())
1✔
1775
            elif valTemplate[0].IsAttributeList():
1✔
1776
                res.append(valTemplate[0].GetBin())
1✔
1777
            else:
1778
                raise PyKCS11Error(-2)
×
1779

1780
        return res
1✔
1781

1782
    def setAttributeValue(self, obj_id, template):
1✔
1783
        """
1784
        C_SetAttributeValue
1785

1786
        :param obj_id: object ID returned by :func:`findObjects`
1787
        :type obj_id: integer
1788
        :param template: list of (attribute, value) pairs
1789
        :type template: list
1790
        :return: Nothing
1791
        :rtype: None
1792
        """
1793

1794
        templ = self._template2ckattrlist(template)
1✔
1795
        rv = self.lib.C_SetAttributeValue(self.session, obj_id, templ)
1✔
1796

1797
        if rv != CKR_OK:
1✔
1798
            raise PyKCS11Error(rv)
×
1799

1800
        return None
1✔
1801

1802
    def seedRandom(self, seed):
1✔
1803
        """
1804
        C_SeedRandom
1805

1806
        :param seed: seed material
1807
        :type seed: iterable
1808
        """
1809
        low_seed = ckbytelist(seed)
1✔
1810
        rv = self.lib.C_SeedRandom(self.session, low_seed)
1✔
1811
        if rv != CKR_OK:
1✔
1812
            raise PyKCS11Error(rv)
×
1813

1814
    def generateRandom(self, size=16):
1✔
1815
        """
1816
        C_GenerateRandom
1817

1818
        :param size: number of random bytes to get
1819
        :type size: integer
1820

1821
        :note: the returned value is an instance of :class:`ckbytelist`.
1822
          You can easly convert it to a binary string with:
1823
          ``bytes(random)``
1824
          or, for Python 2:
1825
          ``''.join(chr(i) for i in random)``
1826
        """
1827
        low_rand = ckbytelist([0] * size)
1✔
1828
        rv = self.lib.C_GenerateRandom(self.session, low_rand)
1✔
1829
        if rv != CKR_OK:
1✔
1830
            raise PyKCS11Error(rv)
×
1831
        return low_rand
1✔
1832

1833

1834
if __name__ == "__main__":
1✔
1835
    # sample test/debug code
1836
    p = PyKCS11Lib()
×
1837
    p.load()
×
1838

1839
    print("getInfo")
×
1840
    print(p.getInfo())
×
1841

1842
    print()
×
1843
    print("getSlotList")
×
1844
    s = p.getSlotList()
×
1845
    print("slots:", s)
×
1846
    slot = s[0]
×
1847
    print("using slot:", slot)
×
1848

1849
    print()
×
1850
    print("getSlotInfo")
×
1851
    print(p.getSlotInfo(slot))
×
1852

1853
    print()
×
1854
    print("getTokenInfo")
×
1855
    print(p.getTokenInfo(slot))
×
1856

1857
    print()
×
1858
    print("openSession")
×
1859
    se = p.openSession(slot)
×
1860

1861
    print()
×
1862
    print("sessionInfo")
×
1863
    print(se.getSessionInfo())
×
1864

1865
    print()
×
1866
    print("seedRandom")
×
1867
    try:
×
1868
        se.seedRandom([1, 2, 3, 4])
×
1869
    except PyKCS11Error as e:
×
1870
        print(e)
×
1871
    print("generateRandom")
×
1872
    print(se.generateRandom())
×
1873

1874
    print()
×
1875
    print("login")
×
1876
    se.login(pin="0000")
×
1877

1878
    print()
×
1879
    print("sessionInfo")
×
1880
    print(se.getSessionInfo())
×
1881

1882
    print()
×
1883
    print("findObjects")
×
1884
    objs = se.findObjects([(CKA_CLASS, CKO_CERTIFICATE)])
×
1885
    print("Nb objetcs:", len(objs))
×
1886
    print(objs)
×
1887

1888
    print()
×
1889
    print("getAttributeValue")
×
1890
    for o in objs:
×
1891
        attr = se.getAttributeValue(o, [CKA_LABEL, CKA_CLASS])
×
1892
        print(attr)
×
1893

1894
    print()
×
1895
    print("logout")
×
1896
    se.logout()
×
1897

1898
    print()
×
1899
    print("closeSession")
×
1900
    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