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

LudovicRousseau / PyKCS11 / 12963539823

25 Jan 2025 08:54AM UTC coverage: 86.578% (-0.1%) from 86.678%
12963539823

Pull #129

github

web-flow
Merge a6288e768 into d2c9b1e63
Pull Request #129: bugfix: store CKM_CONCATENATE_BASE_AND_KEY parameter in the mechanism context

0 of 7 new or added lines in 2 files covered. (0.0%)

27 existing lines in 1 file now uncovered.

2993 of 3457 relevant lines covered (86.58%)

0.87 hits per line

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

80.5
/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
        """
NEW
945
        self._encKey = encKey
×
946

947
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
948
        self._mech.mechanism = CKM_CONCATENATE_BASE_AND_KEY
×
NEW
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 decrypt(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1360
        """
1361
        C_DecryptInit/C_Decrypt
1362

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1684
        :see: :func:`getAttributeValue_fragmented`
1685

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

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

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

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

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

1731
        return res
1✔
1732

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

1738
        Note: this is achived by getting attributes one by one.
1739

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

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

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

1782
        return res
1✔
1783

1784
    def setAttributeValue(self, obj_id, template):
1✔
1785
        """
1786
        C_SetAttributeValue
1787

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

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

1799
        if rv != CKR_OK:
1✔
1800
            raise PyKCS11Error(rv)
×
1801

1802
        return None
1✔
1803

1804
    def seedRandom(self, seed):
1✔
1805
        """
1806
        C_SeedRandom
1807

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

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

1820
        :param size: number of random bytes to get
1821
        :type size: integer
1822

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

1835

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

1841
    print("getInfo")
×
1842
    print(p.getInfo())
×
1843

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

1851
    print()
×
1852
    print("getSlotInfo")
×
1853
    print(p.getSlotInfo(slot))
×
1854

1855
    print()
×
1856
    print("getTokenInfo")
×
1857
    print(p.getTokenInfo(slot))
×
1858

1859
    print()
×
1860
    print("openSession")
×
1861
    se = p.openSession(slot)
×
1862

1863
    print()
×
1864
    print("sessionInfo")
×
1865
    print(se.getSessionInfo())
×
1866

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

1876
    print()
×
1877
    print("login")
×
1878
    se.login(pin="0000")
×
1879

1880
    print()
×
1881
    print("sessionInfo")
×
1882
    print(se.getSessionInfo())
×
1883

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

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

1896
    print()
×
1897
    print("logout")
×
1898
    se.logout()
×
1899

1900
    print()
×
1901
    print("closeSession")
×
1902
    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