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

LudovicRousseau / PyKCS11 / 10291537390

07 Aug 2024 08:46PM UTC coverage: 86.942% (-1.6%) from 88.537%
10291537390

push

github

LudovicRousseau
Add simple derivation mechanisms support

Added support of the following key derivation mechanisms (as per section
2.43 of the PKCS#11 3.0 specification):

- CKM_CONCATENATE_BASE_AND_KEY
- CKM_CONCATENATE_BASE_AND_DATA
- CKM_CONCATENATE_DATA_AND_BASE
- CKM_XOR_BASE_AND_DATA

Unfortunately, these mechanisms are currently not supported by SoftHSM
(2.6.1). However CKM_CONCATENATE* mechanisms are available in develop
branch of SoftHSM (tested with a SoftHSM build from the develop branch)

34 of 99 new or added lines in 2 files covered. (34.34%)

18 existing lines in 1 file now uncovered.

2923 of 3362 relevant lines covered (86.94%)

0.87 hits per line

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

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

18
from __future__ import print_function
1✔
19

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

24

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

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

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

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

73

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

79
    def __init__(self, data=[]):
1✔
80
        # default size of the vector
81
        size = 0
1✔
82
        super(ckbytelist, self).__init__(size)
1✔
83

84
        # No value to initialize
85
        if data is None:
1✔
86
            return
1✔
87

88
        # b'abc'
89
        if isinstance(data, bytes):
1✔
90
            self.reserve(len(data))
1✔
91
            for x in data:
1✔
92
                if sys.version_info[0] <= 2:
1✔
93
                    # Python 2
94
                    v = ord(x)
×
95
                else:
96
                    # Python 3 and more
97
                    v = x
1✔
98
                self.append(v)
1✔
99

100
        # "abc"
101
        elif isinstance(data, str):
1✔
102
            tmp = bytes(data, "utf-8")
1✔
103
            self.reserve(len(tmp))
1✔
104
            for x in tmp:
1✔
105
                self.append(x)
1✔
106

107
        # [141, 142, 143]
108
        elif isinstance(data, list) or isinstance(data, ckbytelist):
1✔
109
            self.reserve(len(data))
1✔
110
            for c in range(len(data)):
1✔
111
                self.append(data[c])
1✔
112
        else:
113
            raise PyKCS11.PyKCS11Error(-3, text=str(type(data)))
1✔
114

115
    def __repr__(self):
1✔
116
        """
117
        return the representation of a tuple
118
        the __str__ method will use it also
119
        """
120
        rep = [int(elt) for elt in self]
1✔
121
        return repr(rep)
1✔
122

123

124
class CK_OBJECT_HANDLE(PyKCS11.LowLevel.CK_OBJECT_HANDLE):
1✔
125
    """
126
    add a __repr__() method to the LowLevel equivalent
127
    """
128

129
    def __init__(self, session):
1✔
130
        PyKCS11.LowLevel.CK_OBJECT_HANDLE.__init__(self)
1✔
131
        self.session = session
1✔
132
        pass
1✔
133

134
    def to_dict(self):
1✔
135
        """
136
        convert the fields of the object into a dictionnary
137
        """
138
        # all the attibutes defined by PKCS#11
139
        all_attributes = PyKCS11.CKA.keys()
1✔
140

141
        # only use the integer values and not the strings like 'CKM_RSA_PKCS'
142
        all_attributes = [attr for attr in all_attributes if
1✔
143
                          isinstance(attr, int)]
144

145
        # all the attributes of the object
146
        attributes = self.session.getAttributeValue(self, all_attributes)
1✔
147

148
        dico = dict()
1✔
149
        for key, attr in zip(all_attributes, attributes):
1✔
150
            if attr is None:
1✔
151
                continue
1✔
152
            if key == CKA_CLASS:
1✔
153
                dico[PyKCS11.CKA[key]] = PyKCS11.CKO[attr]
1✔
154
            elif key == CKA_CERTIFICATE_TYPE:
1✔
155
                dico[PyKCS11.CKA[key]] = PyKCS11.CKC[attr]
×
156
            elif key == CKA_KEY_TYPE:
1✔
157
                dico[PyKCS11.CKA[key]] = PyKCS11.CKK[attr]
1✔
158
            else:
159
                dico[PyKCS11.CKA[key]] = attr
1✔
160
        return dico
1✔
161

162
    def __repr__(self):
1✔
163
        """
164
        text representation of the object
165
        """
166
        dico = self.to_dict()
1✔
167
        lines = list()
1✔
168
        for key in sorted(dico.keys()):
1✔
169
            lines.append("{}: {}".format(key, dico[key]))
1✔
170
        return "\n".join(lines)
1✔
171

172

173
class CkClass(object):
1✔
174
    """
175
    Base class for CK_* classes
176
    """
177

178
    # dictionnary of integer_value: text_value for the flags bits
179
    flags_dict = dict()
1✔
180

181
    # dictionnary of fields names and types
182
    # type can be "pair", "flags" or "text"
183
    fields = dict()
1✔
184

185
    flags = 0
1✔
186

187
    def flags2text(self):
1✔
188
        """
189
        parse the `self.flags` field and create a list of `CKF_*` strings
190
        corresponding to bits set in flags
191

192
        :return: a list of strings
193
        :rtype: list
194
        """
195
        r = []
1✔
196
        for v in self.flags_dict.keys():
1✔
197
            if self.flags & v:
1✔
198
                r.append(self.flags_dict[v])
1✔
199
        return r
1✔
200

201
    def to_dict(self):
1✔
202
        """
203
        convert the fields of the object into a dictionnary
204
        """
205
        dico = dict()
1✔
206
        for field in self.fields.keys():
1✔
207
            if field == "flags":
1✔
208
                dico[field] = self.flags2text()
1✔
209
            elif field == "state":
1✔
210
                dico[field] = self.state2text()
1✔
211
            else:
212
                dico[field] = eval("self." + field)
1✔
213
        return dico
1✔
214

215
    def __str__(self):
1✔
216
        """
217
        text representation of the object
218
        """
219
        dico = self.to_dict()
1✔
220
        lines = list()
1✔
221
        for key in sorted(dico.keys()):
1✔
222
            type = self.fields[key]
1✔
223
            if type == "flags":
1✔
224
                lines.append("{}: {}".format(key, ", ".join(dico[key])))
1✔
225
            elif type == "pair":
1✔
226
                lines.append("%s: " % key + "%d.%d" % dico[key])
1✔
227
            else:
228
                lines.append("{}: {}".format(key, dico[key]))
1✔
229
        return "\n".join(lines)
1✔
230

231

232
class CK_SLOT_INFO(CkClass):
1✔
233
    """
234
    matches the PKCS#11 CK_SLOT_INFO structure
235

236
    :ivar slotDescription: blank padded
237
    :type slotDescription: string
238
    :ivar manufacturerID: blank padded
239
    :type manufacturerID: string
240
    :ivar flags: See :func:`CkClass.flags2text`
241
    :type flags: integer
242
    :ivar hardwareVersion: 2 elements list
243
    :type hardwareVersion: list
244
    :ivar firmwareVersion: 2 elements list
245
    :type firmwareVersion: list
246
    """
247

248
    flags_dict = {
1✔
249
        CKF_TOKEN_PRESENT: "CKF_TOKEN_PRESENT",
250
        CKF_REMOVABLE_DEVICE: "CKF_REMOVABLE_DEVICE",
251
        CKF_HW_SLOT: "CKF_HW_SLOT"}
252

253
    fields = {"slotDescription": "text",
1✔
254
              "manufacturerID": "text",
255
              "flags": "flags",
256
              "hardwareVersion": "text",
257
              "firmwareVersion": "text"}
258

259

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

264
    :ivar cryptokiVersion: Cryptoki interface version
265
    :type cryptokiVersion: integer
266
    :ivar manufacturerID: blank padded
267
    :type manufacturerID: string
268
    :ivar flags: must be zero
269
    :type flags: integer
270
    :ivar libraryDescription: blank padded
271
    :type libraryDescription: string
272
    :var libraryVersion: 2 elements list
273
    :type libraryVersion: list
274
    """
275

276
    fields = {"cryptokiVersion": "pair",
1✔
277
              "manufacturerID": "text",
278
              "flags": "flags",
279
              "libraryDescription": "text",
280
              "libraryVersion": "pair"}
281

282

283
class CK_SESSION_INFO(CkClass):
1✔
284
    """
285
    matches the PKCS#11 CK_SESSION_INFO structure
286

287
    :ivar slotID: ID of the slot that interfaces with the token
288
    :type slotID: integer
289
    :ivar state: state of the session
290
    :type state: integer
291
    :ivar flags: bit flags that define the type of session
292
    :type flags: integer
293
    :ivar ulDeviceError: an error code defined by the cryptographic token
294
    :type ulDeviceError: integer
295
    """
296

297
    flags_dict = {
1✔
298
        CKF_RW_SESSION: "CKF_RW_SESSION",
299
        CKF_SERIAL_SESSION: "CKF_SERIAL_SESSION",
300
    }
301

302
    def state2text(self):
1✔
303
        """
304
        parse the `self.state` field and return a `CKS_*` string
305
        corresponding to the state
306

307
        :return: a string
308
        :rtype: string
309
        """
310
        return CKS[self.state]
1✔
311

312
    fields = {"slotID": "text",
1✔
313
              "state": "text",
314
              "flags": "flags",
315
              "ulDeviceError": "text"}
316

317

318
class CK_TOKEN_INFO(CkClass):
1✔
319
    """
320
    matches the PKCS#11 CK_TOKEN_INFO structure
321

322
    :ivar label: blank padded
323
    :type label: string
324
    :ivar manufacturerID: blank padded
325
    :type manufacturerID: string
326
    :ivar model: string blank padded
327
    :type model: string
328
    :ivar serialNumber: string blank padded
329
    :type serialNumber: string
330
    :ivar flags:
331
    :type flags: integer
332
    :ivar ulMaxSessionCount:
333
    :type ulMaxSessionCount: integer
334
    :ivar ulSessionCount:
335
    :type ulSessionCount: integer
336
    :ivar ulMaxRwSessionCount:
337
    :type ulMaxRwSessionCount: integer
338
    :ivar ulRwSessionCount:
339
    :type ulRwSessionCount: integer
340
    :ivar ulMaxPinLen:
341
    :type ulMaxPinLen: integer
342
    :ivar ulMinPinLen:
343
    :type ulMinPinLen: integer
344
    :ivar ulTotalPublicMemory:
345
    :type ulTotalPublicMemory: integer
346
    :ivar ulFreePublicMemory:
347
    :type ulFreePublicMemory: integer
348
    :ivar ulTotalPrivateMemory:
349
    :type ulTotalPrivateMemory: integer
350
    :ivar ulFreePrivateMemory:
351
    :type ulFreePrivateMemory: integer
352
    :ivar hardwareVersion: 2 elements list
353
    :type hardwareVersion: list
354
    :ivar firmwareVersion: 2 elements list
355
    :type firmwareVersion: list
356
    :ivar utcTime: string
357
    :type utcTime: string
358
    """
359

360
    flags_dict = {
1✔
361
        CKF_RNG: "CKF_RNG",
362
        CKF_WRITE_PROTECTED: "CKF_WRITE_PROTECTED",
363
        CKF_LOGIN_REQUIRED: "CKF_LOGIN_REQUIRED",
364
        CKF_USER_PIN_INITIALIZED: "CKF_USER_PIN_INITIALIZED",
365
        CKF_RESTORE_KEY_NOT_NEEDED: "CKF_RESTORE_KEY_NOT_NEEDED",
366
        CKF_CLOCK_ON_TOKEN: "CKF_CLOCK_ON_TOKEN",
367
        CKF_PROTECTED_AUTHENTICATION_PATH: "CKF_PROTECTED_AUTHENTICATION_PATH",
368
        CKF_DUAL_CRYPTO_OPERATIONS: "CKF_DUAL_CRYPTO_OPERATIONS",
369
        CKF_TOKEN_INITIALIZED: "CKF_TOKEN_INITIALIZED",
370
        CKF_SECONDARY_AUTHENTICATION: "CKF_SECONDARY_AUTHENTICATION",
371
        CKF_USER_PIN_COUNT_LOW: "CKF_USER_PIN_COUNT_LOW",
372
        CKF_USER_PIN_FINAL_TRY: "CKF_USER_PIN_FINAL_TRY",
373
        CKF_USER_PIN_LOCKED: "CKF_USER_PIN_LOCKED",
374
        CKF_USER_PIN_TO_BE_CHANGED: "CKF_USER_PIN_TO_BE_CHANGED",
375
        CKF_SO_PIN_COUNT_LOW: "CKF_SO_PIN_COUNT_LOW",
376
        CKF_SO_PIN_FINAL_TRY: "CKF_SO_PIN_FINAL_TRY",
377
        CKF_SO_PIN_LOCKED: "CKF_SO_PIN_LOCKED",
378
        CKF_SO_PIN_TO_BE_CHANGED: "CKF_SO_PIN_TO_BE_CHANGED",
379
    }
380

381
    fields = {"label": "text",
1✔
382
              "manufacturerID": "text",
383
              "model": "text",
384
              "serialNumber": "text",
385
              "flags": "flags",
386
              "ulMaxSessionCount": "text",
387
              "ulSessionCount": "text",
388
              "ulMaxRwSessionCount": "text",
389
              "ulRwSessionCount": "text",
390
              "ulMaxPinLen": "text",
391
              "ulMinPinLen": "text",
392
              "ulTotalPublicMemory": "text",
393
              "ulFreePublicMemory": "text",
394
              "ulTotalPrivateMemory": "text",
395
              "ulFreePrivateMemory": "text",
396
              "hardwareVersion": "pair",
397
              "firmwareVersion": "pair",
398
              "utcTime": "text"}
399

400

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

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

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

430
    fields = {"ulMinKeySize": "text",
1✔
431
              "ulMaxKeySize": "text",
432
              "flags": "flags"}
433

434

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

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

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

457

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

461
    # shared by all instances
462
    _loaded_libs = dict()
1✔
463

464
    def __init__(self):
1✔
465
        self.lib = PyKCS11.LowLevel.CPKCS11Lib()
1✔
466

467
    def __del__(self):
1✔
468
        if PyKCS11 and PyKCS11.__name__ and \
1✔
469
                PyKCS11.LowLevel and PyKCS11.LowLevel.__name__ and \
470
                PyKCS11.LowLevel._LowLevel and \
471
                PyKCS11.LowLevel._LowLevel.__name__:
472

473
            # in case NO library was found and used
474
            if not hasattr(self, "pkcs11dll_filename"):
1✔
475
                return
×
476

477
            # in case the load failed
478
            if self.pkcs11dll_filename not in PyKCS11Lib._loaded_libs:
1✔
479
                return
1✔
480

481
            # decrease user number
482
            PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]["nb_users"] -= 1
1✔
483

484
            if PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]["nb_users"] == 0:
1✔
485
                # unload only if no more used
486
                self.lib.Unload()
1✔
487

488
            # remove unused entry
489
            # the case < 0 happens if lib loading failed
490
            if PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]["nb_users"] <= 0:
1✔
491
                del PyKCS11Lib._loaded_libs[self.pkcs11dll_filename]
1✔
492

493
    def load(self, pkcs11dll_filename=None, *init_string):
1✔
494
        """
495
        load a PKCS#11 library
496

497
        :type pkcs11dll_filename: string
498
        :param pkcs11dll_filename: the library name.
499
          If this parameter is not set then the environment variable
500
          `PYKCS11LIB` is used instead
501
        :returns: a :class:`PyKCS11Lib` object
502
        :raises: :class:`PyKCS11Error` (-1): when the load fails
503
        """
504
        if pkcs11dll_filename is None:
1✔
505
            pkcs11dll_filename = os.getenv("PYKCS11LIB")
1✔
506
            if pkcs11dll_filename is None:
1✔
507
                raise PyKCS11Error(-1, "No PKCS11 library specified (set PYKCS11LIB env variable)")
×
508

509
        # remember the lib file name
510
        self.pkcs11dll_filename = pkcs11dll_filename
1✔
511

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

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

528
    def initToken(self, slot, pin, label):
1✔
529
        """
530
        C_InitToken
531

532
        :param slot: slot number returned by :func:`getSlotList`
533
        :type slot: integer
534
        :param pin: Security Officer's initial PIN
535
        :param label: new label of the token
536
        """
537
        pin1 = ckbytelist(pin)
1✔
538
        rv = self.lib.C_InitToken(slot, pin1, label)
1✔
539
        if rv != CKR_OK:
1✔
540
            raise PyKCS11Error(rv)
×
541

542
    def getInfo(self):
1✔
543
        """
544
        C_GetInfo
545

546
        :return: a :class:`CK_INFO` object
547
        """
548
        info = PyKCS11.LowLevel.CK_INFO()
1✔
549
        rv = self.lib.C_GetInfo(info)
1✔
550
        if rv != CKR_OK:
1✔
551
            raise PyKCS11Error(rv)
×
552

553
        i = CK_INFO()
1✔
554
        i.cryptokiVersion = (info.cryptokiVersion.major,
1✔
555
                             info.cryptokiVersion.minor)
556
        i.manufacturerID = info.GetManufacturerID()
1✔
557
        i.flags = info.flags
1✔
558
        i.libraryDescription = info.GetLibraryDescription()
1✔
559
        i.libraryVersion = (info.libraryVersion.major,
1✔
560
                            info.libraryVersion.minor)
561
        return i
1✔
562

563
    def getSlotList(self, tokenPresent=False):
1✔
564
        """
565
        C_GetSlotList
566

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

579
        s = []
1✔
580
        for x in range(len(slotList)):
1✔
581
            s.append(slotList[x])
1✔
582
        return s
1✔
583

584
    def getSlotInfo(self, slot):
1✔
585
        """
586
        C_GetSlotInfo
587

588
        :param slot: slot number returned by :func:`getSlotList`
589
        :type slot: integer
590
        :return: a :class:`CK_SLOT_INFO` object
591
        """
592
        slotInfo = PyKCS11.LowLevel.CK_SLOT_INFO()
1✔
593
        rv = self.lib.C_GetSlotInfo(slot, slotInfo)
1✔
594
        if rv != CKR_OK:
1✔
595
            raise PyKCS11Error(rv)
×
596

597
        s = CK_SLOT_INFO()
1✔
598
        s.slotDescription = slotInfo.GetSlotDescription()
1✔
599
        s.manufacturerID = slotInfo.GetManufacturerID()
1✔
600
        s.flags = slotInfo.flags
1✔
601
        s.hardwareVersion = slotInfo.GetHardwareVersion()
1✔
602
        s.firmwareVersion = slotInfo.GetFirmwareVersion()
1✔
603

604
        return s
1✔
605

606
    def getTokenInfo(self, slot):
1✔
607
        """
608
        C_GetTokenInfo
609

610
        :param slot: slot number returned by :func:`getSlotList`
611
        :type slot: integer
612
        :return: a :class:`CK_TOKEN_INFO` object
613
        """
614
        tokeninfo = PyKCS11.LowLevel.CK_TOKEN_INFO()
1✔
615
        rv = self.lib.C_GetTokenInfo(slot, tokeninfo)
1✔
616
        if rv != CKR_OK:
1✔
617
            raise PyKCS11Error(rv)
×
618

619
        t = CK_TOKEN_INFO()
1✔
620
        t.label = tokeninfo.GetLabel()
1✔
621
        t.manufacturerID = tokeninfo.GetManufacturerID()
1✔
622
        t.model = tokeninfo.GetModel()
1✔
623
        t.serialNumber = tokeninfo.GetSerialNumber()
1✔
624
        t.flags = tokeninfo.flags
1✔
625
        t.ulMaxSessionCount = tokeninfo.ulMaxSessionCount
1✔
626
        if t.ulMaxSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
627
            t.ulMaxSessionCount = -1
×
628
        t.ulSessionCount = tokeninfo.ulSessionCount
1✔
629
        if t.ulSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
630
            t.ulSessionCount = -1
1✔
631
        t.ulMaxRwSessionCount = tokeninfo.ulMaxRwSessionCount
1✔
632
        if t.ulMaxRwSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
633
            t.ulMaxRwSessionCount = -1
×
634
        t.ulRwSessionCount = tokeninfo.ulRwSessionCount
1✔
635
        if t.ulRwSessionCount == CK_UNAVAILABLE_INFORMATION:
1✔
636
            t.ulRwSessionCount = -1
1✔
637
        t.ulMaxPinLen = tokeninfo.ulMaxPinLen
1✔
638
        t.ulMinPinLen = tokeninfo.ulMinPinLen
1✔
639
        t.ulTotalPublicMemory = tokeninfo.ulTotalPublicMemory
1✔
640

641
        if t.ulTotalPublicMemory == CK_UNAVAILABLE_INFORMATION:
1✔
642
            t.ulTotalPublicMemory = -1
1✔
643
        t.ulFreePublicMemory = tokeninfo.ulFreePublicMemory
1✔
644
        if t.ulFreePublicMemory == CK_UNAVAILABLE_INFORMATION:
1✔
645
            t.ulFreePublicMemory = -1
1✔
646
        t.ulTotalPrivateMemory = tokeninfo.ulTotalPrivateMemory
1✔
647
        if t.ulTotalPrivateMemory == CK_UNAVAILABLE_INFORMATION:
1✔
648
            t.ulTotalPrivateMemory = -1
1✔
649
        t.ulFreePrivateMemory = tokeninfo.ulFreePrivateMemory
1✔
650
        if t.ulFreePrivateMemory == CK_UNAVAILABLE_INFORMATION:
1✔
651
            t.ulFreePrivateMemory = -1
1✔
652
        t.hardwareVersion = (tokeninfo.hardwareVersion.major,
1✔
653
                             tokeninfo.hardwareVersion.minor)
654
        t.firmwareVersion = (tokeninfo.firmwareVersion.major,
1✔
655
                             tokeninfo.firmwareVersion.minor)
656
        t.utcTime = tokeninfo.GetUtcTime().replace('\000', ' ')
1✔
657

658
        return t
1✔
659

660
    def openSession(self, slot, flags=0):
1✔
661
        """
662
        C_OpenSession
663

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

676
        return Session(self, se)
1✔
677

678
    def closeAllSessions(self, slot):
1✔
679
        """
680
        C_CloseAllSessions
681

682
        :param slot: slot number
683
        :type slot: integer
684
        """
685
        rv = self.lib.C_CloseAllSessions(slot)
1✔
686
        if rv != CKR_OK:
1✔
687
            raise PyKCS11Error(rv)
×
688

689
    def getMechanismList(self, slot):
1✔
690
        """
691
        C_GetMechanismList
692

693
        :param slot: slot number returned by :func:`getSlotList`
694
        :type slot: integer
695
        :return: the list of available mechanisms for a slot
696
        :rtype: list
697
        """
698
        mechanismList = PyKCS11.LowLevel.ckintlist()
1✔
699
        rv = self.lib.C_GetMechanismList(slot, mechanismList)
1✔
700
        if rv != CKR_OK:
1✔
701
            raise PyKCS11Error(rv)
×
702

703
        m = []
1✔
704
        for x in range(len(mechanismList)):
1✔
705
            mechanism = mechanismList[x]
1✔
706
            if mechanism >= CKM_VENDOR_DEFINED:
1✔
707
                k = 'CKM_VENDOR_DEFINED_0x%X' % (mechanism - CKM_VENDOR_DEFINED)
×
708
                CKM[k] = mechanism
×
709
                CKM[mechanism] = k
×
710
            m.append(CKM[mechanism])
1✔
711
        return m
1✔
712

713
    def getMechanismInfo(self, slot, type):
1✔
714
        """
715
        C_GetMechanismInfo
716

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

729
        i = CK_MECHANISM_INFO()
1✔
730
        i.ulMinKeySize = info.ulMinKeySize
1✔
731
        i.ulMaxKeySize = info.ulMaxKeySize
1✔
732
        i.flags = info.flags
1✔
733

734
        return i
1✔
735

736
    def waitForSlotEvent(self, flags=0):
1✔
737
        """
738
        C_WaitForSlotEvent
739

740
        :param flags: 0 (default) or `CKF_DONT_BLOCK`
741
        :type flags: integer
742
        :return: slot
743
        :rtype: integer
744
        """
745
        tmp = 0
×
746
        (rv, slot) = self.lib.C_WaitForSlotEvent(flags, tmp)
×
747
        if rv != CKR_OK:
×
748
            raise PyKCS11Error(rv)
×
749

750
        return slot
×
751

752

753
class Mechanism(object):
1✔
754
    """Wraps CK_MECHANISM"""
755

756
    def __init__(self, mechanism, param=None):
1✔
757
        """
758
        :param mechanism: the mechanism to be used
759
        :type mechanism: integer, any `CKM_*` value
760
        :param param: data to be used as crypto operation parameter
761
          (i.e. the IV for some algorithms)
762
        :type param: string or list/tuple of bytes
763

764
        :see: :func:`Session.decrypt`, :func:`Session.sign`
765
        """
766
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
767
        self._mech.mechanism = mechanism
1✔
768
        self._param = None
1✔
769
        if param:
1✔
770
            self._param = ckbytelist(param)
1✔
771
            self._mech.pParameter = self._param
1✔
772
            self._mech.ulParameterLen = len(param)
1✔
773

774
    def to_native(self):
1✔
775
        return self._mech
1✔
776

777

778
MechanismSHA1 = Mechanism(CKM_SHA_1, None)
1✔
779
MechanismRSAPKCS1 = Mechanism(CKM_RSA_PKCS, None)
1✔
780
MechanismRSAGENERATEKEYPAIR = Mechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, None)
1✔
781
MechanismECGENERATEKEYPAIR = Mechanism(CKM_EC_KEY_PAIR_GEN, None)
1✔
782
MechanismAESGENERATEKEY = Mechanism(CKM_AES_KEY_GEN, None)
1✔
783

784

785
class AES_GCM_Mechanism(object):
1✔
786
    """CKM_AES_GCM warpping mechanism"""
787

788
    def __init__(self, iv, aad, tagBits):
1✔
789
        """
790
        :param iv: initialization vector
791
        :param aad: additional authentication data
792
        :param tagBits: length of authentication tag in bits
793
        """
794
        self._param = PyKCS11.LowLevel.CK_GCM_PARAMS()
1✔
795

796
        self._source_iv = ckbytelist(iv)
1✔
797
        self._param.pIv = self._source_iv
1✔
798
        self._param.ulIvLen = len(self._source_iv)
1✔
799

800
        self._source_aad = ckbytelist(aad)
1✔
801
        self._param.pAAD = self._source_aad
1✔
802
        self._param.ulAADLen = len(self._source_aad)
1✔
803

804
        self._param.ulTagBits = tagBits
1✔
805

806
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
807
        self._mech.mechanism = CKM_AES_GCM
1✔
808
        self._mech.pParameter = self._param
1✔
809
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_GCM_PARAMS_LENGTH
1✔
810

811
    def to_native(self):
1✔
812
        return self._mech
1✔
813

814

815
class AES_CTR_Mechanism(object):
1✔
816
    """CKM_AES_CTR encryption mechanism"""
817

818
    def __init__(self, counterBits, counterBlock):
1✔
819
        """
820
        :param counterBits: the number of incremented bits in the counter block
821
        :param counterBlock: a 16-byte initial value of the counter block
822
        """
823
        self._param = PyKCS11.LowLevel.CK_AES_CTR_PARAMS()
1✔
824

825
        self._source_cb = ckbytelist(counterBlock)
1✔
826
        self._param.ulCounterBits = counterBits
1✔
827
        self._param.cb = self._source_cb
1✔
828

829
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
830
        self._mech.mechanism = CKM_AES_CTR
1✔
831
        self._mech.pParameter = self._param
1✔
832
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_AES_CTR_PARAMS_LENGTH
1✔
833

834
    def to_native(self):
1✔
835
        return self._mech
1✔
836

837

838
class RSAOAEPMechanism(object):
1✔
839
    """RSA OAEP Wrapping mechanism"""
840

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

864
    def to_native(self):
1✔
865
        return self._mech
1✔
866

867

868
class RSA_PSS_Mechanism(object):
1✔
869
    """RSA PSS Wrapping mechanism"""
870

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

890
    def to_native(self):
1✔
891
        return self._mech
1✔
892

893
class ECDH1_DERIVE_Mechanism(object):
1✔
894
    """CKM_ECDH1_DERIVE key derivation mechanism"""
895

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

904
        self._param.kdf = kdf
1✔
905

906
        if sharedData:
1✔
907
            self._shared_data = ckbytelist(sharedData)
×
908
            self._param.pSharedData = self._shared_data
×
909
            self._param.ulSharedDataLen = len(self._shared_data)
×
910
        else:
911
            self._source_shared_data = None
1✔
912
            self._param.ulSharedDataLen = 0
1✔
913

914
        self._public_data = ckbytelist(publicData)
1✔
915
        self._param.pPublicData = self._public_data
1✔
916
        self._param.ulPublicDataLen = len(self._public_data)
1✔
917

918
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
1✔
919
        self._mech.mechanism = CKM_ECDH1_DERIVE
1✔
920
        self._mech.pParameter = self._param
1✔
921
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_ECDH1_DERIVE_PARAMS_LENGTH
1✔
922

923
    def to_native(self):
1✔
924
        return self._mech
1✔
925

926

927
class CONCATENATE_BASE_AND_KEY_Mechanism(object):
1✔
928
    """CKM_CONCATENATE_BASE_AND_KEY key derivation mechanism"""
929

930
    def __init__(self, encKey):
1✔
931
        """
932
        :param encKey: a handle of encryption key
933
        """
NEW
934
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
NEW
935
        self._mech.mechanism = CKM_CONCATENATE_BASE_AND_KEY
×
NEW
936
        self._mech.pParameter = encKey
×
NEW
937
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_OBJECT_HANDLE_LENGTH
×
938

939
    def to_native(self):
1✔
NEW
940
        return self._mech
×
941

942

943
class KEY_DERIVATION_STRING_DATA_MechanismBase(object):
1✔
944
    """Base class for mechanisms using derivation string data"""
945

946
    def __init__(self, data, mechType):
1✔
947
        """
948
        :param data: a byte array to concatenate the key with
949
        :param mechType: mechanism type
950
        """
NEW
951
        self._param = PyKCS11.LowLevel.CK_KEY_DERIVATION_STRING_DATA()
×
952

NEW
953
        self._data = ckbytelist(data)
×
NEW
954
        self._param.pData = self._data
×
NEW
955
        self._param.ulLen = len(self._data)
×
956

NEW
957
        self._mech = PyKCS11.LowLevel.CK_MECHANISM()
×
NEW
958
        self._mech.mechanism = mechType
×
NEW
959
        self._mech.pParameter = self._param
×
NEW
960
        self._mech.ulParameterLen = PyKCS11.LowLevel.CK_KEY_DERIVATION_STRING_DATA_LENGTH
×
961

962
    def to_native(self):
1✔
NEW
963
        return self._mech
×
964

965

966
class CONCATENATE_BASE_AND_DATA_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
967
    """CKM_CONCATENATE_BASE_AND_DATA key derivation mechanism"""
968

969
    def __init__(self, data):
1✔
970
        """
971
        :param data: a byte array to concatenate the key with
972
        """
NEW
973
        super().__init__(data, CKM_CONCATENATE_BASE_AND_DATA)
×
974

975

976
class CONCATENATE_DATA_AND_BASE_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
977
    """CKM_CONCATENATE_DATA_AND_BASE key derivation mechanism"""
978

979
    def __init__(self, data):
1✔
980
        """
981
        :param data: a byte array to concatenate the key with
982
        """
NEW
983
        super().__init__(data, CKM_CONCATENATE_DATA_AND_BASE)
×
984

985

986
class XOR_BASE_AND_DATA_Mechanism(KEY_DERIVATION_STRING_DATA_MechanismBase):
1✔
987
    """CKM_XOR_BASE_AND_DATA key derivation mechanism"""
988

989
    def __init__(self, data):
1✔
990
        """
991
        :param data: a byte array to xor the key with
992
        """
NEW
993
        super().__init__(data, CKM_XOR_BASE_AND_DATA)
×
994

995

996
class DigestSession(object):
1✔
997
    def __init__(self, lib, session, mecha):
1✔
998
        self._lib = lib
1✔
999
        self._session = session
1✔
1000
        self._mechanism = mecha.to_native()
1✔
1001
        rv = self._lib.C_DigestInit(self._session, self._mechanism)
1✔
1002
        if rv != CKR_OK:
1✔
1003
            raise PyKCS11Error(rv)
×
1004

1005
    def update(self, data):
1✔
1006
        """
1007
        C_DigestUpdate
1008

1009
        :param data: data to add to the digest
1010
        :type data: bytes or string
1011
        """
1012
        data1 = ckbytelist(data)
1✔
1013
        rv = self._lib.C_DigestUpdate(self._session, data1)
1✔
1014
        if rv != CKR_OK:
1✔
1015
            raise PyKCS11Error(rv)
×
1016
        return self
1✔
1017

1018
    def digestKey(self, handle):
1✔
1019
        """
1020
        C_DigestKey
1021

1022
        :param handle: key handle
1023
        :type handle: CK_OBJECT_HANDLE
1024
        """
1025
        rv = self._lib.C_DigestKey(self._session, handle)
×
1026
        if rv != CKR_OK:
×
1027
            raise PyKCS11Error(rv)
×
1028
        return self
×
1029

1030
    def final(self):
1✔
1031
        """
1032
        C_DigestFinal
1033

1034
        :return: the digest
1035
        :rtype: ckbytelist
1036
        """
1037
        digest = ckbytelist()
1✔
1038
        # Get the size of the digest
1039
        rv = self._lib.C_DigestFinal(self._session, digest)
1✔
1040
        if rv != CKR_OK:
1✔
1041
            raise PyKCS11Error(rv)
×
1042
        # Get the actual digest
1043
        rv = self._lib.C_DigestFinal(self._session, digest)
1✔
1044
        if rv != CKR_OK:
1✔
1045
            raise PyKCS11Error(rv)
×
1046
        return digest
1✔
1047

1048

1049
class Session(object):
1✔
1050
    """ Manage :func:`PyKCS11Lib.openSession` objects """
1051

1052
    def __init__(self, pykcs11, session):
1✔
1053
        """
1054
        :param pykcs11: PyKCS11 library object
1055
        :type pykcs11: PyKCS11Lib
1056
        :param session: session handle
1057
        :type session: instance of :class:`CK_SESSION_HANDLE`
1058
        """
1059
        if not isinstance(pykcs11, PyKCS11Lib):
1✔
1060
            raise TypeError("pykcs11 must be a PyKCS11Lib")
×
1061
        if not isinstance(session, LowLevel.CK_SESSION_HANDLE):
1✔
1062
            raise TypeError("session must be a CK_SESSION_HANDLE")
×
1063

1064
        # hold the PyKCS11Lib reference, so that it's not Garbage Collection'd
1065
        self.pykcs11 = pykcs11
1✔
1066
        self.session = session
1✔
1067

1068
    @property
1✔
1069
    def lib(self):
1✔
1070
        """
1071
        Get the low level lib of the owning PyKCS11Lib
1072
        """
1073
        return self.pykcs11.lib
1✔
1074

1075
    def closeSession(self):
1✔
1076
        """
1077
        C_CloseSession
1078
        """
1079
        rv = self.lib.C_CloseSession(self.session)
1✔
1080
        if rv != CKR_OK:
1✔
1081
            raise PyKCS11Error(rv)
×
1082

1083
    def getSessionInfo(self):
1✔
1084
        """
1085
        C_GetSessionInfo
1086

1087
        :return: a :class:`CK_SESSION_INFO` object
1088
        """
1089
        sessioninfo = PyKCS11.LowLevel.CK_SESSION_INFO()
1✔
1090
        rv = self.lib.C_GetSessionInfo(self.session, sessioninfo)
1✔
1091
        if rv != CKR_OK:
1✔
1092
            raise PyKCS11Error(rv)
×
1093

1094
        s = CK_SESSION_INFO()
1✔
1095
        s.slotID = sessioninfo.slotID
1✔
1096
        s.state = sessioninfo.state
1✔
1097
        s.flags = sessioninfo.flags
1✔
1098
        s.ulDeviceError = sessioninfo.ulDeviceError
1✔
1099
        return s
1✔
1100

1101
    def login(self, pin, user_type=CKU_USER):
1✔
1102
        """
1103
        C_Login
1104

1105
        :param pin: the user's PIN or None for CKF_PROTECTED_AUTHENTICATION_PATH
1106
        :type pin: string
1107
        :param user_type: the user type. The default value is
1108
          CKU_USER. You may also use CKU_SO
1109
        :type user_type: integer
1110
        """
1111
        pin1 = ckbytelist(pin)
1✔
1112
        rv = self.lib.C_Login(self.session, user_type, pin1)
1✔
1113
        if rv != CKR_OK:
1✔
1114
            raise PyKCS11Error(rv)
1✔
1115

1116
    def logout(self):
1✔
1117
        """
1118
        C_Logout
1119
        """
1120
        rv = self.lib.C_Logout(self.session)
1✔
1121
        if rv != CKR_OK:
1✔
1122
            raise PyKCS11Error(rv)
×
1123

1124
        del self
1✔
1125

1126
    def initPin(self, pin):
1✔
1127
        """
1128
        C_InitPIN
1129

1130
        :param pin: new PIN
1131
        """
1132
        new_pin1 = ckbytelist(pin)
1✔
1133
        rv = self.lib.C_InitPIN(self.session, new_pin1)
1✔
1134
        if rv != CKR_OK:
1✔
1135
            raise PyKCS11Error(rv)
×
1136

1137
    def setPin(self, old_pin, new_pin):
1✔
1138
        """
1139
        C_SetPIN
1140

1141
        :param old_pin: old PIN
1142
        :param new_pin: new PIN
1143
        """
1144
        old_pin1 = ckbytelist(old_pin)
1✔
1145
        new_pin1 = ckbytelist(new_pin)
1✔
1146
        rv = self.lib.C_SetPIN(self.session, old_pin1, new_pin1)
1✔
1147
        if rv != CKR_OK:
1✔
1148
            raise PyKCS11Error(rv)
×
1149

1150
    def createObject(self, template):
1✔
1151
        """
1152
        C_CreateObject
1153

1154
        :param template: object template
1155
        """
1156
        attrs = self._template2ckattrlist(template)
1✔
1157
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1158
        rv = self.lib.C_CreateObject(self.session, attrs, handle)
1✔
1159
        if rv != PyKCS11.CKR_OK:
1✔
1160
            raise PyKCS11.PyKCS11Error(rv)
×
1161
        return handle
1✔
1162

1163
    def destroyObject(self, obj):
1✔
1164
        """
1165
        C_DestroyObject
1166

1167
        :param obj: object ID
1168
        """
1169
        rv = self.lib.C_DestroyObject(self.session, obj)
1✔
1170
        if rv != CKR_OK:
1✔
1171
            raise PyKCS11Error(rv)
×
1172

1173
    def digestSession(self, mecha=MechanismSHA1):
1✔
1174
        """
1175
        C_DigestInit/C_DigestUpdate/C_DigestKey/C_DigestFinal
1176

1177
        :param mecha: the digesting mechanism to be used
1178
          (use `MechanismSHA1` for `CKM_SHA_1`)
1179
        :type mecha: :class:`Mechanism`
1180
        :return: A :class:`DigestSession` object
1181
        :rtype: DigestSession
1182
        """
1183
        return DigestSession(self.lib, self.session, mecha)
1✔
1184

1185
    def digest(self, data, mecha=MechanismSHA1):
1✔
1186
        """
1187
        C_DigestInit/C_Digest
1188

1189
        :param data: the data to be digested
1190
        :type data:  (binary) sring or list/tuple of bytes
1191
        :param mecha: the digesting mechanism to be used
1192
          (use `MechanismSHA1` for `CKM_SHA_1`)
1193
        :type mecha: :class:`Mechanism`
1194
        :return: the computed digest
1195
        :rtype: list of bytes
1196

1197
        :note: the returned value is an istance of :class:`ckbytelist`.
1198
          You can easly convert it to a binary string with:
1199
          ``bytes(ckbytelistDigest)``
1200
          or, for Python 2:
1201
          ``''.join(chr(i) for i in ckbytelistDigest)``
1202

1203
        """
1204
        digest = ckbytelist()
1✔
1205
        m = mecha.to_native()
1✔
1206
        data1 = ckbytelist(data)
1✔
1207
        rv = self.lib.C_DigestInit(self.session, m)
1✔
1208
        if rv != CKR_OK:
1✔
1209
            raise PyKCS11Error(rv)
×
1210
        # first call get digest size
1211
        rv = self.lib.C_Digest(self.session, data1, digest)
1✔
1212
        if rv != CKR_OK:
1✔
1213
            raise PyKCS11Error(rv)
×
1214
        # second call get actual digest data
1215
        rv = self.lib.C_Digest(self.session, data1, digest)
1✔
1216
        if rv != CKR_OK:
1✔
1217
            raise PyKCS11Error(rv)
×
1218
        return digest
1✔
1219

1220
    def sign(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1221
        """
1222
        C_SignInit/C_Sign
1223

1224
        :param key: a key handle, obtained calling :func:`findObjects`.
1225
        :type key: integer
1226
        :param data: the data to be signed
1227
        :type data:  (binary) string or list/tuple of bytes
1228
        :param mecha: the signing mechanism to be used
1229
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1230
        :type mecha: :class:`Mechanism`
1231
        :return: the computed signature
1232
        :rtype: list of bytes
1233

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

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

1257
    def verify(self, key, data, signature, mecha=MechanismRSAPKCS1):
1✔
1258
        """
1259
        C_VerifyInit/C_Verify
1260

1261
        :param key: a key handle, obtained calling :func:`findObjects`.
1262
        :type key: integer
1263
        :param data: the data that was signed
1264
        :type data:  (binary) string or list/tuple of bytes
1265
        :param signature: the signature to be verified
1266
        :type signature:  (binary) string or list/tuple of bytes
1267
        :param mecha: the signing mechanism to be used
1268
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1269
        :type mecha: :class:`Mechanism`
1270
        :return: True if signature is valid, False otherwise
1271
        :rtype: bool
1272

1273
        """
1274
        m = mecha.to_native()
1✔
1275
        data1 = ckbytelist(data)
1✔
1276
        rv = self.lib.C_VerifyInit(self.session, m, key)
1✔
1277
        if rv != CKR_OK:
1✔
1278
            raise PyKCS11Error(rv)
×
1279
        rv = self.lib.C_Verify(self.session, data1, signature)
1✔
1280
        if rv == CKR_OK:
1✔
1281
            return True
1✔
1282
        elif rv == CKR_SIGNATURE_INVALID:
×
1283
            return False
×
1284
        else:
1285
            raise PyKCS11Error(rv)
×
1286

1287
    def encrypt(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1288
        """
1289
        C_EncryptInit/C_Encrypt
1290

1291
        :param key: a key handle, obtained calling :func:`findObjects`.
1292
        :type key: integer
1293
        :param data: the data to be encrypted
1294
        :type data:  (binary) string or list/tuple of bytes
1295
        :param mecha: the encryption mechanism to be used
1296
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1297
        :type mecha: :class:`Mechanism`
1298
        :return: the encrypted data
1299
        :rtype: list of bytes
1300

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

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

1324
    def decrypt(self, key, data, mecha=MechanismRSAPKCS1):
1✔
1325
        """
1326
        C_DecryptInit/C_Decrypt
1327

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

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

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

1361
    def wrapKey(self, wrappingKey, key, mecha=MechanismRSAPKCS1):
1✔
1362
        """
1363
        C_WrapKey
1364

1365
        :param wrappingKey: a wrapping key handle
1366
        :type wrappingKey: integer
1367
        :param key: a handle of the key to be wrapped
1368
        :type key: integer
1369
        :param mecha: the encrypt mechanism to be used
1370
          (use `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1371
        :type mecha: :class:`Mechanism`
1372
        :return: the wrapped key bytes
1373
        :rtype: list of bytes
1374

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

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

1396
    def unwrapKey(self, unwrappingKey, wrappedKey, template,
1✔
1397
                  mecha=MechanismRSAPKCS1):
1398
        """
1399
        C_UnwrapKey
1400

1401
        :param unwrappingKey: the unwrapping key handle
1402
        :type unwrappingKey: integer
1403
        :param wrappedKey: the bytes of the wrapped key
1404
        :type wrappedKey:  (binary) string or list/tuple of bytes
1405
        :param template: template for the unwrapped key
1406
        :param mecha: the decrypt mechanism to be used (use
1407
          `MechanismRSAPKCS1` for `CKM_RSA_PKCS`)
1408
        :type mecha: :class:`Mechanism`
1409
        :return: the unwrapped key object
1410
        :rtype: integer
1411

1412
        """
1413
        m = mecha.to_native()
1✔
1414
        data1 = ckbytelist(wrappedKey)
1✔
1415
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1416
        attrs = self._template2ckattrlist(template)
1✔
1417
        rv = self.lib.C_UnwrapKey(self.session, m, unwrappingKey,
1✔
1418
                                  data1, attrs, handle)
1419
        if rv != CKR_OK:
1✔
1420
            raise PyKCS11Error(rv)
×
1421
        return handle
1✔
1422

1423
    def deriveKey(self, baseKey, template, mecha):
1✔
1424
        """
1425
        C_DeriveKey
1426

1427
        :param baseKey: the base key handle
1428
        :type baseKey: integer
1429
        :param template: template for the unwrapped key
1430
        :param mecha: the decrypt mechanism to be used (use
1431
          `ECDH1_DERIVE_Mechanism(...)` for `CKM_ECDH1_DERIVE`)
1432
        :type mecha: :class:`Mechanism`
1433
        :return: the unwrapped key object
1434
        :rtype: integer
1435
        """
1436
        m = mecha.to_native()
1✔
1437
        handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1438
        attrs = self._template2ckattrlist(template)
1✔
1439
        rv = self.lib.C_DeriveKey(self.session, m, baseKey, attrs, handle)
1✔
1440
        if rv != CKR_OK:
1✔
1441
            raise PyKCS11Error(rv)
×
1442
        return handle
1✔
1443

1444
    def isNum(self, type):
1✔
1445
        """
1446
        is the type a numerical value?
1447

1448
        :param type: PKCS#11 type like `CKA_CERTIFICATE_TYPE`
1449
        :rtype: bool
1450
        """
1451
        if type in (CKA_CERTIFICATE_TYPE,
1✔
1452
                    CKA_CLASS,
1453
                    CKA_HW_FEATURE_TYPE,
1454
                    CKA_KEY_GEN_MECHANISM,
1455
                    CKA_KEY_TYPE,
1456
                    CKA_MODULUS_BITS,
1457
                    CKA_VALUE_BITS,
1458
                    CKA_VALUE_LEN):
1459
            return True
1✔
1460
        return False
1✔
1461

1462
    def isString(self, type):
1✔
1463
        """
1464
        is the type a string value?
1465

1466
        :param type: PKCS#11 type like `CKA_LABEL`
1467
        :rtype: bool
1468
        """
1469
        if type in (CKA_LABEL,
1✔
1470
                    CKA_APPLICATION):
1471
            return True
1✔
1472
        return False
1✔
1473

1474
    def isBool(self, type):
1✔
1475
        """
1476
        is the type a boolean value?
1477

1478
        :param type: PKCS#11 type like `CKA_ALWAYS_SENSITIVE`
1479
        :rtype: bool
1480
        """
1481
        if type in (CKA_ALWAYS_AUTHENTICATE,
1✔
1482
                    CKA_ALWAYS_SENSITIVE,
1483
                    CKA_DECRYPT,
1484
                    CKA_DERIVE,
1485
                    CKA_ENCRYPT,
1486
                    CKA_EXTRACTABLE,
1487
                    CKA_HAS_RESET,
1488
                    CKA_LOCAL,
1489
                    CKA_MODIFIABLE,
1490
                    CKA_COPYABLE,
1491
                    CKA_DESTROYABLE,
1492
                    CKA_NEVER_EXTRACTABLE,
1493
                    CKA_PRIVATE,
1494
                    CKA_RESET_ON_INIT,
1495
                    CKA_SECONDARY_AUTH,
1496
                    CKA_SENSITIVE,
1497
                    CKA_SIGN,
1498
                    CKA_SIGN_RECOVER,
1499
                    CKA_TOKEN,
1500
                    CKA_TRUSTED,
1501
                    CKA_UNWRAP,
1502
                    CKA_VERIFY,
1503
                    CKA_VERIFY_RECOVER,
1504
                    CKA_WRAP,
1505
                    CKA_WRAP_WITH_TRUSTED):
1506
            return True
1✔
1507
        return False
1✔
1508

1509
    def isBin(self, type):
1✔
1510
        """
1511
        is the type a byte array value?
1512

1513
        :param type: PKCS#11 type like `CKA_MODULUS`
1514
        :rtype: bool
1515
        """
1516
        return (not self.isBool(type)) \
1✔
1517
            and (not self.isString(type)) \
1518
            and (not self.isNum(type))
1519

1520
    def isAttributeList(self, type):
1✔
1521
        """
1522
        is the type a attribute list value?
1523

1524
        :param type: PKCS#11 type like `CKA_WRAP_TEMPLATE`
1525
        :rtype: bool
1526
        """
1527
        if type in (CKA_WRAP_TEMPLATE,
1✔
1528
                    CKA_UNWRAP_TEMPLATE):
1529
            return True
1✔
1530
        return False
1✔
1531

1532
    def _template2ckattrlist(self, template):
1✔
1533
        t = PyKCS11.LowLevel.ckattrlist(len(template))
1✔
1534
        for x in range(len(template)):
1✔
1535
            attr = template[x]
1✔
1536
            if self.isNum(attr[0]):
1✔
1537
                t[x].SetNum(attr[0], int(attr[1]))
1✔
1538
            elif self.isString(attr[0]):
1✔
1539
                t[x].SetString(attr[0], str(attr[1]))
1✔
1540
            elif self.isBool(attr[0]):
1✔
1541
                t[x].SetBool(attr[0], attr[1] == CK_TRUE)
1✔
1542
            elif self.isAttributeList(attr[0]):
1✔
1543
                t[x].SetList(attr[0],
1✔
1544
                        self._template2ckattrlist(attr[1]))
1545
            elif self.isBin(attr[0]):
1✔
1546
                attrBin = attr[1]
1✔
1547
                attrStr = attr[1]
1✔
1548
                if isinstance(attr[1], int):
1✔
1549
                    attrStr = str(attr[1])
×
1550
                if isinstance(attr[1], bytes):
1✔
1551
                    attrBin = ckbytelist(attrStr)
1✔
1552
                t[x].SetBin(attr[0], attrBin)
1✔
1553
            else:
1554
                raise PyKCS11Error(-2)
×
1555
        return t
1✔
1556

1557
    def generateKey(self, template, mecha=MechanismAESGENERATEKEY):
1✔
1558
        """
1559
        generate a secret key
1560

1561
        :param template: template for the secret key
1562
        :param mecha: mechanism to use
1563
        :return: handle of the generated key
1564
        :rtype: PyKCS11.LowLevel.CK_OBJECT_HANDLE
1565
        """
1566
        t = self._template2ckattrlist(template)
1✔
1567
        ck_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1568
        m = mecha.to_native()
1✔
1569
        rv = self.lib.C_GenerateKey(self.session, m, t, ck_handle)
1✔
1570
        if rv != CKR_OK:
1✔
1571
            raise PyKCS11Error(rv)
×
1572
        return ck_handle
1✔
1573

1574
    def generateKeyPair(self, templatePub, templatePriv,
1✔
1575
                        mecha=MechanismRSAGENERATEKEYPAIR):
1576
        """
1577
        generate a key pair
1578

1579
        :param templatePub: template for the public key
1580
        :param templatePriv:  template for the private key
1581
        :param mecha: mechanism to use
1582
        :return: a tuple of handles (pub, priv)
1583
        :rtype: tuple
1584
        """
1585
        tPub = self._template2ckattrlist(templatePub)
1✔
1586
        tPriv = self._template2ckattrlist(templatePriv)
1✔
1587
        ck_pub_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1588
        ck_prv_handle = PyKCS11.LowLevel.CK_OBJECT_HANDLE()
1✔
1589
        m = mecha.to_native()
1✔
1590
        rv = self.lib.C_GenerateKeyPair(self.session, m, tPub, tPriv,
1✔
1591
                                        ck_pub_handle, ck_prv_handle)
1592

1593
        if rv != CKR_OK:
1✔
1594
            raise PyKCS11Error(rv)
1✔
1595
        return ck_pub_handle, ck_prv_handle
1✔
1596

1597
    def findObjects(self, template=()):
1✔
1598
        """
1599
        find the objects matching the template pattern
1600

1601
        :param template: list of attributes tuples (attribute,value).
1602
          The default value is () and all the objects are returned
1603
        :type template: list
1604
        :return: a list of object ids
1605
        :rtype: list
1606
        """
1607
        t = self._template2ckattrlist(template)
1✔
1608

1609
        # we search for 10 objects by default. speed/memory tradeoff
1610
        result = PyKCS11.LowLevel.ckobjlist(10)
1✔
1611

1612
        rv = self.lib.C_FindObjectsInit(self.session, t)
1✔
1613
        if rv != CKR_OK:
1✔
1614
            raise PyKCS11Error(rv)
×
1615

1616
        res = []
1✔
1617
        while True:
1✔
1618
            rv = self.lib.C_FindObjects(self.session, result)
1✔
1619
            if rv != CKR_OK:
1✔
1620
                raise PyKCS11Error(rv)
×
1621
            for x in result:
1✔
1622
                # make a copy of the handle: the original value get
1623
                # corrupted (!!)
1624
                a = CK_OBJECT_HANDLE(self)
1✔
1625
                a.assign(x.value())
1✔
1626
                res.append(a)
1✔
1627
            if len(result) == 0:
1✔
1628
                break
1✔
1629

1630
        rv = self.lib.C_FindObjectsFinal(self.session)
1✔
1631
        if rv != CKR_OK:
1✔
1632
            raise PyKCS11Error(rv)
×
1633
        return res
1✔
1634

1635
    def getAttributeValue(self, obj_id, attr, allAsBinary=False):
1✔
1636
        """
1637
        C_GetAttributeValue
1638

1639
        :param obj_id: object ID returned by :func:`findObjects`
1640
        :type obj_id: integer
1641
        :param attr: list of attributes
1642
        :type attr: list
1643
        :param allAsBinary: return all values as binary data; default is False.
1644
        :type allAsBinary: Boolean
1645
        :return: a list of values corresponding to the list of attributes
1646
        :rtype: list
1647

1648
        :see: :func:`getAttributeValue_fragmented`
1649

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

1653
          Binary data is returned as :class:`ckbytelist` type, usable
1654
          as a list containing only bytes.
1655
          You can easly convert it to a binary string with:
1656
          ``bytes(ckbytelistVariable)``
1657
          or, for Python 2:
1658
          ``''.join(chr(i) for i in ckbytelistVariable)``
1659

1660
        """
1661
        valTemplate = PyKCS11.LowLevel.ckattrlist(len(attr))
1✔
1662
        for x in range(len(attr)):
1✔
1663
            valTemplate[x].SetType(attr[x])
1✔
1664
        # first call to get the attribute size and reserve the memory
1665
        rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1666
        if rv in (CKR_ATTRIBUTE_TYPE_INVALID, CKR_ATTRIBUTE_SENSITIVE,
1✔
1667
                  CKR_ARGUMENTS_BAD):
1668
            return self.getAttributeValue_fragmented(obj_id, attr, allAsBinary)
1✔
1669

1670
        if rv != CKR_OK:
1✔
1671
            raise PyKCS11Error(rv)
×
1672
        # second call to get the attribute value
1673
        rv = self.lib.C_GetAttributeValue(self.session, obj_id, valTemplate)
1✔
1674
        if rv != CKR_OK:
1✔
1675
            raise PyKCS11Error(rv)
×
1676

1677
        res = []
1✔
1678
        for x in range(len(attr)):
1✔
1679
            if allAsBinary:
1✔
1680
                res.append(valTemplate[x].GetBin())
1✔
1681
            elif valTemplate[x].IsNum():
1✔
1682
                res.append(valTemplate[x].GetNum())
1✔
1683
            elif valTemplate[x].IsBool():
1✔
1684
                res.append(valTemplate[x].GetBool())
1✔
1685
            elif valTemplate[x].IsString():
1✔
1686
                res.append(valTemplate[x].GetString())
1✔
1687
            elif valTemplate[x].IsBin():
1✔
1688
                res.append(valTemplate[x].GetBin())
1✔
1689
            else:
1690
                raise PyKCS11Error(-2)
×
1691

1692
        return res
1✔
1693

1694
    def getAttributeValue_fragmented(self, obj_id, attr, allAsBinary=False):
1✔
1695
        """
1696
        Same as :func:`getAttributeValue` except that when some attribute
1697
        is sensitive or unknown an empty value (None) is returned.
1698

1699
        Note: this is achived by getting attributes one by one.
1700

1701
        :see: :func:`getAttributeValue`
1702
        """
1703
        # some attributes does not exists or is sensitive
1704
        # but we don't know which ones. So try one by one
1705
        valTemplate = PyKCS11.LowLevel.ckattrlist(1)
1✔
1706
        res = []
1✔
1707
        for x in range(len(attr)):
1✔
1708
            valTemplate[0].Reset()
1✔
1709
            valTemplate[0].SetType(attr[x])
1✔
1710
            # first call to get the attribute size and reserve the memory
1711
            rv = self.lib.C_GetAttributeValue(self.session, obj_id,
1✔
1712
                                              valTemplate)
1713
            if rv in (CKR_ATTRIBUTE_TYPE_INVALID,
1✔
1714
                      CKR_ATTRIBUTE_SENSITIVE, CKR_ARGUMENTS_BAD):
1715
                # append an empty value
1716
                res.append(None)
1✔
1717
                continue
1✔
1718

1719
            if rv != CKR_OK:
1✔
1720
                raise PyKCS11Error(rv)
×
1721
            # second call to get the attribute value
1722
            rv = self.lib.C_GetAttributeValue(self.session, obj_id,
1✔
1723
                                              valTemplate)
1724
            if rv != CKR_OK:
1✔
1725
                raise PyKCS11Error(rv)
×
1726

1727
            if allAsBinary:
1✔
1728
                res.append(valTemplate[0].GetBin())
×
1729
            elif valTemplate[0].IsNum():
1✔
1730
                res.append(valTemplate[0].GetNum())
1✔
1731
            elif valTemplate[0].IsBool():
1✔
1732
                res.append(valTemplate[0].GetBool())
1✔
1733
            elif valTemplate[0].IsString():
1✔
1734
                res.append(valTemplate[0].GetString())
1✔
1735
            elif valTemplate[0].IsBin():
1✔
1736
                res.append(valTemplate[0].GetBin())
1✔
1737
            elif valTemplate[0].IsAttributeList():
1✔
1738
                res.append(valTemplate[0].GetBin())
1✔
1739
            else:
1740
                raise PyKCS11Error(-2)
×
1741

1742
        return res
1✔
1743

1744
    def setAttributeValue(self, obj_id, template):
1✔
1745
        """
1746
        C_SetAttributeValue
1747

1748
        :param obj_id: object ID returned by :func:`findObjects`
1749
        :type obj_id: integer
1750
        :param template: list of (attribute, value) pairs
1751
        :type template: list
1752
        :return: Nothing
1753
        :rtype: None
1754
        """
1755

1756
        templ = self._template2ckattrlist(template)
1✔
1757
        rv = self.lib.C_SetAttributeValue(self.session, obj_id, templ)
1✔
1758

1759
        if rv != CKR_OK:
1✔
1760
            raise PyKCS11Error(rv)
×
1761

1762
        return None
1✔
1763

1764
    def seedRandom(self, seed):
1✔
1765
        """
1766
        C_SeedRandom
1767

1768
        :param seed: seed material
1769
        :type seed: iterable
1770
        """
1771
        low_seed = ckbytelist(seed)
1✔
1772
        rv = self.lib.C_SeedRandom(self.session, low_seed)
1✔
1773
        if rv != CKR_OK:
1✔
1774
            raise PyKCS11Error(rv)
×
1775

1776
    def generateRandom(self, size=16):
1✔
1777
        """
1778
        C_GenerateRandom
1779

1780
        :param size: number of random bytes to get
1781
        :type size: integer
1782

1783
        :note: the returned value is an instance of :class:`ckbytelist`.
1784
          You can easly convert it to a binary string with:
1785
          ``bytes(random)``
1786
          or, for Python 2:
1787
          ``''.join(chr(i) for i in random)``
1788
        """
1789
        low_rand = ckbytelist([0] * size)
1✔
1790
        rv = self.lib.C_GenerateRandom(self.session, low_rand)
1✔
1791
        if rv != CKR_OK:
1✔
1792
            raise PyKCS11Error(rv)
×
1793
        return low_rand
1✔
1794

1795

1796
if __name__ == "__main__":
1✔
1797
    # sample test/debug code
1798
    p = PyKCS11Lib()
×
1799
    p.load()
×
1800

1801
    print("getInfo")
×
1802
    print(p.getInfo())
×
1803

1804
    print()
×
1805
    print("getSlotList")
×
1806
    s = p.getSlotList()
×
1807
    print("slots:", s)
×
1808
    slot = s[0]
×
1809
    print("using slot:", slot)
×
1810

1811
    print()
×
1812
    print("getSlotInfo")
×
1813
    print(p.getSlotInfo(slot))
×
1814

1815
    print()
×
1816
    print("getTokenInfo")
×
1817
    print(p.getTokenInfo(slot))
×
1818

1819
    print()
×
1820
    print("openSession")
×
1821
    se = p.openSession(slot)
×
1822

1823
    print()
×
1824
    print("sessionInfo")
×
1825
    print(se.getSessionInfo())
×
1826

1827
    print()
×
1828
    print("seedRandom")
×
1829
    try:
×
1830
        se.seedRandom([1, 2, 3, 4])
×
1831
    except PyKCS11Error as e:
×
1832
        print(e)
×
1833
    print("generateRandom")
×
1834
    print(se.generateRandom())
×
1835

1836
    print()
×
1837
    print("login")
×
1838
    se.login(pin="0000")
×
1839

1840
    print()
×
1841
    print("sessionInfo")
×
1842
    print(se.getSessionInfo())
×
1843

1844
    print()
×
1845
    print("findObjects")
×
1846
    objs = se.findObjects([(CKA_CLASS, CKO_CERTIFICATE)])
×
1847
    print("Nb objetcs:", len(objs))
×
1848
    print(objs)
×
1849

1850
    print()
×
1851
    print("getAttributeValue")
×
1852
    for o in objs:
×
1853
        attr = se.getAttributeValue(o, [CKA_LABEL, CKA_CLASS])
×
1854
        print(attr)
×
1855

1856
    print()
×
1857
    print("logout")
×
1858
    se.logout()
×
1859

1860
    print()
×
1861
    print("closeSession")
×
1862
    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