python-pkcs11 0.10.1__cp315-cp315-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pkcs11/__init__.py +50 -0
- pkcs11/_pkcs11.cp315-win_amd64.pyd +0 -0
- pkcs11/_pkcs11.pxd +964 -0
- pkcs11/_pkcs11.pyi +35 -0
- pkcs11/_pkcs11.pyx +2327 -0
- pkcs11/attributes.py +272 -0
- pkcs11/constants.py +559 -0
- pkcs11/defaults.py +121 -0
- pkcs11/exceptions.py +410 -0
- pkcs11/mechanisms.py +862 -0
- pkcs11/py.typed +0 -0
- pkcs11/types.py +1457 -0
- pkcs11/util/__init__.py +17 -0
- pkcs11/util/dh.py +79 -0
- pkcs11/util/dsa.py +108 -0
- pkcs11/util/ec.py +143 -0
- pkcs11/util/rsa.py +95 -0
- pkcs11/util/x509.py +136 -0
- python_pkcs11-0.10.1.dist-info/METADATA +399 -0
- python_pkcs11-0.10.1.dist-info/RECORD +23 -0
- python_pkcs11-0.10.1.dist-info/WHEEL +5 -0
- python_pkcs11-0.10.1.dist-info/licenses/LICENSE +21 -0
- python_pkcs11-0.10.1.dist-info/top_level.txt +1 -0
pkcs11/_pkcs11.pyx
ADDED
|
@@ -0,0 +1,2327 @@
|
|
|
1
|
+
#cython: language_level=3
|
|
2
|
+
#coverage#cython: linetrace=True
|
|
3
|
+
"""
|
|
4
|
+
High-level Python PKCS#11 Wrapper.
|
|
5
|
+
|
|
6
|
+
Most class here inherit from pkcs11.types, which provides easier introspection
|
|
7
|
+
for Sphinx/Jedi/etc, as this module is not importable without having the
|
|
8
|
+
library loaded.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import (absolute_import, unicode_literals,
|
|
12
|
+
print_function, division)
|
|
13
|
+
|
|
14
|
+
from threading import RLock
|
|
15
|
+
|
|
16
|
+
from cpython.mem cimport PyMem_Malloc, PyMem_Free
|
|
17
|
+
from cpython.bytes cimport PyBytes_FromStringAndSize
|
|
18
|
+
from libc.string cimport memcpy
|
|
19
|
+
|
|
20
|
+
from pkcs11 import types
|
|
21
|
+
from pkcs11.attributes import AttributeMapper
|
|
22
|
+
from pkcs11.defaults import *
|
|
23
|
+
from pkcs11.exceptions import *
|
|
24
|
+
from pkcs11.constants import *
|
|
25
|
+
from pkcs11.mechanisms import *
|
|
26
|
+
from pkcs11.types import (
|
|
27
|
+
_CK_UTF8CHAR_to_str,
|
|
28
|
+
_CK_VERSION_to_tuple,
|
|
29
|
+
_CK_MECHANISM_TYPE_to_enum,
|
|
30
|
+
PROTECTED_AUTH,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
cdef class lib(HasFuncList)
|
|
35
|
+
|
|
36
|
+
cdef class HasFuncList:
|
|
37
|
+
cdef CK_FUNCTION_LIST *funclist
|
|
38
|
+
cdef CK_FUNCTION_LIST_3_0 *funclist30
|
|
39
|
+
cdef CK_FUNCTION_LIST_3_2 *funclist32
|
|
40
|
+
|
|
41
|
+
def __cinit__(self, *args, **kwargs):
|
|
42
|
+
self.funclist = NULL
|
|
43
|
+
self.funclist30 = NULL
|
|
44
|
+
self.funclist32 = NULL
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
cdef assertRV(rv) with gil:
|
|
48
|
+
"""Check for an acceptable RV value or thrown an exception."""
|
|
49
|
+
if rv == CKR_OK:
|
|
50
|
+
return
|
|
51
|
+
raise map_rv_to_error(rv)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
cdef class AttributeList:
|
|
55
|
+
"""
|
|
56
|
+
A list of CK_ATTRIBUTE objects.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
cdef CK_ATTRIBUTE *data
|
|
60
|
+
"""CK_ATTRIBUTE * representation of the data."""
|
|
61
|
+
cdef CK_ULONG count
|
|
62
|
+
"""Length of `data`."""
|
|
63
|
+
|
|
64
|
+
def __cinit__(self, attrs):
|
|
65
|
+
self.data = NULL
|
|
66
|
+
self.count = 0
|
|
67
|
+
|
|
68
|
+
@staticmethod
|
|
69
|
+
cdef AttributeList from_owned_pointer(CK_ATTRIBUTE * data, CK_ULONG count):
|
|
70
|
+
cdef AttributeList lst = AttributeList.__new__(AttributeList, ())
|
|
71
|
+
lst.data = data
|
|
72
|
+
lst.count = count
|
|
73
|
+
return lst
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
cdef AttributeList from_template(dict template, object attribute_mapper):
|
|
77
|
+
cdef AttributeList lst = AttributeList.__new__(AttributeList, ())
|
|
78
|
+
|
|
79
|
+
lst.count = count = <CK_ULONG> len(template)
|
|
80
|
+
|
|
81
|
+
lst.data = <CK_ATTRIBUTE *> PyMem_Malloc(count * sizeof(CK_ATTRIBUTE))
|
|
82
|
+
if lst.data is NULL:
|
|
83
|
+
raise MemoryError()
|
|
84
|
+
|
|
85
|
+
cdef bytes value_bytes
|
|
86
|
+
cdef CK_CHAR * value_ptr
|
|
87
|
+
cdef Py_ssize_t value_len
|
|
88
|
+
for index, (key, value) in enumerate(template.items()):
|
|
89
|
+
lst.data[index].type = key
|
|
90
|
+
value_bytes = attribute_mapper.pack_attribute(key, value)
|
|
91
|
+
value_len = len(value_bytes)
|
|
92
|
+
# copy the result into a pointer that we manage, for consistency with the other init method
|
|
93
|
+
value_ptr = <CK_CHAR *> PyMem_Malloc(value_len)
|
|
94
|
+
if value_ptr is NULL:
|
|
95
|
+
raise MemoryError()
|
|
96
|
+
memcpy(value_ptr, <CK_CHAR *> value_bytes, <size_t> value_len)
|
|
97
|
+
lst.data[index].pValue = <CK_CHAR *> value_ptr
|
|
98
|
+
lst.data[index].ulValueLen = <CK_ULONG> value_len
|
|
99
|
+
|
|
100
|
+
return lst
|
|
101
|
+
|
|
102
|
+
def __init__(self, attrs):
|
|
103
|
+
raise TypeError
|
|
104
|
+
|
|
105
|
+
cdef at_index(self, CK_ULONG index, object attribute_mapper):
|
|
106
|
+
cdef CK_ATTRIBUTE * attr
|
|
107
|
+
if index < self.count:
|
|
108
|
+
attr = &self.data[index]
|
|
109
|
+
return attribute_mapper.unpack_attributes(
|
|
110
|
+
attr.type,
|
|
111
|
+
PyBytes_FromStringAndSize(<char *> attr.pValue, <Py_ssize_t> attr.ulValueLen)
|
|
112
|
+
)
|
|
113
|
+
else:
|
|
114
|
+
raise IndexError()
|
|
115
|
+
|
|
116
|
+
def as_dict(self, attribute_mapper):
|
|
117
|
+
cdef CK_ATTRIBUTE * attr
|
|
118
|
+
result = {}
|
|
119
|
+
for index in range(self.count):
|
|
120
|
+
attr = &self.data[index]
|
|
121
|
+
result[attr.type] = self.at_index(index, attribute_mapper)
|
|
122
|
+
return result
|
|
123
|
+
|
|
124
|
+
def get(self, item, attribute_mapper):
|
|
125
|
+
cdef CK_ULONG index = 0
|
|
126
|
+
cdef CK_ATTRIBUTE_TYPE key = item
|
|
127
|
+
for index in range(self.count):
|
|
128
|
+
if self.data[index].type == key:
|
|
129
|
+
return self.at_index(index, attribute_mapper)
|
|
130
|
+
raise KeyError(item)
|
|
131
|
+
|
|
132
|
+
def __dealloc__(self):
|
|
133
|
+
cdef CK_ULONG index = 0
|
|
134
|
+
if self.data is not NULL:
|
|
135
|
+
for index in range(self.count):
|
|
136
|
+
PyMem_Free(self.data[index].pValue)
|
|
137
|
+
PyMem_Free(self.data)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
cdef class MechanismWithParam:
|
|
141
|
+
"""
|
|
142
|
+
Python wrapper for a Mechanism with its parameter
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
cdef CK_MECHANISM *data
|
|
146
|
+
"""The mechanism."""
|
|
147
|
+
cdef void *param
|
|
148
|
+
"""Reference to a pointer we might need to free."""
|
|
149
|
+
cdef object _python_param
|
|
150
|
+
"""
|
|
151
|
+
Hold a reference to the original parameter object so it doesn't get
|
|
152
|
+
GC'd before this one.
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
def __cinit__(self, *args):
|
|
156
|
+
self.data = <CK_MECHANISM *> PyMem_Malloc(sizeof(CK_MECHANISM))
|
|
157
|
+
self.param = NULL
|
|
158
|
+
self._python_param = None
|
|
159
|
+
|
|
160
|
+
def __init__(self, key_type, mapping, mechanism=None, param=None):
|
|
161
|
+
self._python_param = param
|
|
162
|
+
if mechanism is None:
|
|
163
|
+
try:
|
|
164
|
+
mechanism = mapping[key_type]
|
|
165
|
+
except KeyError:
|
|
166
|
+
raise ArgumentsBad("No default mechanism for this key type. "
|
|
167
|
+
"Please specify `mechanism`.")
|
|
168
|
+
|
|
169
|
+
if not isinstance(mechanism, Mechanism):
|
|
170
|
+
raise ArgumentsBad("`mechanism` must be a Mechanism.")
|
|
171
|
+
# Possible types of parameters we might need to allocate
|
|
172
|
+
# These are used to make assigning to the object we malloc() easier
|
|
173
|
+
# FIXME: is there a better way to do this?
|
|
174
|
+
cdef CK_RSA_PKCS_OAEP_PARAMS *oaep_params
|
|
175
|
+
cdef CK_RSA_PKCS_PSS_PARAMS *pss_params
|
|
176
|
+
cdef CK_EDDSA_PARAMS *eddsa_params
|
|
177
|
+
cdef CK_ECDH1_DERIVE_PARAMS *ecdh1_params
|
|
178
|
+
cdef CK_KEY_DERIVATION_STRING_DATA *aes_ecb_params
|
|
179
|
+
cdef CK_AES_CBC_ENCRYPT_DATA_PARAMS *aes_cbc_params
|
|
180
|
+
cdef CK_GCM_PARAMS *gcm_params
|
|
181
|
+
cdef CK_AES_CTR_PARAMS *aes_ctr_params
|
|
182
|
+
|
|
183
|
+
# Unpack mechanism parameters
|
|
184
|
+
|
|
185
|
+
if mechanism == Mechanism.AES_ECB_ENCRYPT_DATA:
|
|
186
|
+
paramlen = sizeof(CK_KEY_DERIVATION_STRING_DATA)
|
|
187
|
+
self.param = aes_ecb_params = \
|
|
188
|
+
<CK_KEY_DERIVATION_STRING_DATA *> PyMem_Malloc(paramlen)
|
|
189
|
+
aes_ecb_params.pData = <CK_BYTE *> param
|
|
190
|
+
aes_ecb_params.ulLen = <CK_ULONG> len(param)
|
|
191
|
+
|
|
192
|
+
elif isinstance(param, bytes):
|
|
193
|
+
# Note: this is an escape hatch of sorts that can be used to provide parameters for
|
|
194
|
+
# unsupported algorithms in raw binary form.
|
|
195
|
+
# We include it at this point in the chain for forwards compatibility reasons:
|
|
196
|
+
# if at a later point, "first class" support for the unsupported mechanism is added
|
|
197
|
+
# to the library, existing code that used this "raw mode" workaround will keep working
|
|
198
|
+
# because this branch takes priority.
|
|
199
|
+
#
|
|
200
|
+
# The parameter convention for AES_ECB_ENCRYPT_DATA predates this ordering decision,
|
|
201
|
+
# so it takes precedence over this branch for backwards compatibility.
|
|
202
|
+
self.data.pParameter = <CK_BYTE *> param
|
|
203
|
+
paramlen = len(param)
|
|
204
|
+
|
|
205
|
+
elif mechanism == Mechanism.RSA_PKCS_OAEP:
|
|
206
|
+
paramlen = sizeof(CK_RSA_PKCS_OAEP_PARAMS)
|
|
207
|
+
self.param = oaep_params = \
|
|
208
|
+
<CK_RSA_PKCS_OAEP_PARAMS *> PyMem_Malloc(paramlen)
|
|
209
|
+
|
|
210
|
+
oaep_params.source = CKZ_DATA_SPECIFIED
|
|
211
|
+
|
|
212
|
+
if param is None:
|
|
213
|
+
param = DEFAULT_MECHANISM_PARAMS[mechanism]
|
|
214
|
+
|
|
215
|
+
(oaep_params.hashAlg, oaep_params.mgf, source_data) = param
|
|
216
|
+
|
|
217
|
+
if source_data is None:
|
|
218
|
+
oaep_params.pSourceData = NULL
|
|
219
|
+
oaep_params.ulSourceDataLen = <CK_ULONG> 0
|
|
220
|
+
else:
|
|
221
|
+
oaep_params.pSourceData = <CK_BYTE *> source_data
|
|
222
|
+
oaep_params.ulSourceDataLen = <CK_ULONG> len(source_data)
|
|
223
|
+
|
|
224
|
+
elif mechanism in (Mechanism.RSA_PKCS_PSS,
|
|
225
|
+
Mechanism.SHA1_RSA_PKCS_PSS,
|
|
226
|
+
Mechanism.SHA224_RSA_PKCS_PSS,
|
|
227
|
+
Mechanism.SHA256_RSA_PKCS_PSS,
|
|
228
|
+
Mechanism.SHA384_RSA_PKCS_PSS,
|
|
229
|
+
Mechanism.SHA512_RSA_PKCS_PSS):
|
|
230
|
+
paramlen = sizeof(CK_RSA_PKCS_PSS_PARAMS)
|
|
231
|
+
self.param = pss_params = \
|
|
232
|
+
<CK_RSA_PKCS_PSS_PARAMS *> PyMem_Malloc(paramlen)
|
|
233
|
+
|
|
234
|
+
if param is None:
|
|
235
|
+
# All PSS mechanisms have the same defaults
|
|
236
|
+
param = DEFAULT_MECHANISM_PARAMS[Mechanism.RSA_PKCS_PSS]
|
|
237
|
+
|
|
238
|
+
(pss_params.hashAlg, pss_params.mgf, pss_params.sLen) = param
|
|
239
|
+
|
|
240
|
+
elif mechanism == Mechanism.EDDSA and param is not None:
|
|
241
|
+
paramlen = sizeof(CK_EDDSA_PARAMS)
|
|
242
|
+
self.param = eddsa_params = \
|
|
243
|
+
<CK_EDDSA_PARAMS *> PyMem_Malloc(paramlen)
|
|
244
|
+
(eddsa_params.phFlag, context_data) = param
|
|
245
|
+
if context_data is None:
|
|
246
|
+
eddsa_params.pContextData = NULL
|
|
247
|
+
eddsa_params.ulContextDataLen = 0
|
|
248
|
+
else:
|
|
249
|
+
eddsa_params.pContextData = context_data
|
|
250
|
+
eddsa_params.ulContextDataLen = <CK_ULONG> len(context_data)
|
|
251
|
+
|
|
252
|
+
elif mechanism in (
|
|
253
|
+
Mechanism.ECDH1_DERIVE,
|
|
254
|
+
Mechanism.ECDH1_COFACTOR_DERIVE):
|
|
255
|
+
paramlen = sizeof(CK_ECDH1_DERIVE_PARAMS)
|
|
256
|
+
self.param = ecdh1_params = \
|
|
257
|
+
<CK_ECDH1_DERIVE_PARAMS *> PyMem_Malloc(paramlen)
|
|
258
|
+
|
|
259
|
+
(ecdh1_params.kdf, shared_data, public_data) = param
|
|
260
|
+
|
|
261
|
+
if shared_data is None:
|
|
262
|
+
ecdh1_params.pSharedData = NULL
|
|
263
|
+
ecdh1_params.ulSharedDataLen = 0
|
|
264
|
+
else:
|
|
265
|
+
ecdh1_params.pSharedData = shared_data
|
|
266
|
+
ecdh1_params.ulSharedDataLen = <CK_ULONG> len(shared_data)
|
|
267
|
+
|
|
268
|
+
ecdh1_params.pPublicData = public_data
|
|
269
|
+
ecdh1_params.ulPublicDataLen = <CK_ULONG> len(public_data)
|
|
270
|
+
|
|
271
|
+
elif mechanism == Mechanism.AES_CBC_ENCRYPT_DATA:
|
|
272
|
+
paramlen = sizeof(CK_AES_CBC_ENCRYPT_DATA_PARAMS)
|
|
273
|
+
self.param = aes_cbc_params = \
|
|
274
|
+
<CK_AES_CBC_ENCRYPT_DATA_PARAMS *> PyMem_Malloc(paramlen)
|
|
275
|
+
(iv, data) = param
|
|
276
|
+
aes_cbc_params.iv = iv[:16]
|
|
277
|
+
aes_cbc_params.pData = <CK_BYTE *> data
|
|
278
|
+
aes_cbc_params.length = <CK_ULONG> len(data)
|
|
279
|
+
|
|
280
|
+
elif mechanism == Mechanism.AES_GCM:
|
|
281
|
+
paramlen = sizeof(CK_GCM_PARAMS)
|
|
282
|
+
if not isinstance(param, GCMParams):
|
|
283
|
+
raise TypeError
|
|
284
|
+
self.param = gcm_params = <CK_GCM_PARAMS *> PyMem_Malloc(paramlen)
|
|
285
|
+
gcm_params.pIv = <CK_BYTE *> param.nonce
|
|
286
|
+
gcm_params.ulIvLen = <CK_ULONG> len(param.nonce)
|
|
287
|
+
gcm_params.ulIvBits = <CK_ULONG> len(param.nonce) * 8
|
|
288
|
+
if param.aad is not None:
|
|
289
|
+
gcm_params.pAAD = <CK_BYTE *> param.aad
|
|
290
|
+
gcm_params.ulAADLen = <CK_ULONG> len(param.aad)
|
|
291
|
+
else:
|
|
292
|
+
gcm_params.pAAD = NULL
|
|
293
|
+
gcm_params.ulAADLen = 0
|
|
294
|
+
gcm_params.ulTagBits = <CK_ULONG> param.tag_bits
|
|
295
|
+
|
|
296
|
+
elif mechanism == Mechanism.AES_CTR:
|
|
297
|
+
paramlen = sizeof(CK_AES_CTR_PARAMS)
|
|
298
|
+
self.param = aes_ctr_params = <CK_AES_CTR_PARAMS *> PyMem_Malloc(paramlen)
|
|
299
|
+
# use a wrapper type to not break the forwards compat rule for params specified as `bytes`
|
|
300
|
+
if not isinstance(param, CTRParams):
|
|
301
|
+
raise TypeError
|
|
302
|
+
aes_ctr_params.ulCounterBits = (16 - len(param.nonce)) * 8
|
|
303
|
+
aes_ctr_params.cb = param.nonce + b"\x00" * (15 - len(param.nonce)) + b"\x01"
|
|
304
|
+
|
|
305
|
+
elif param is None:
|
|
306
|
+
self.data.pParameter = NULL
|
|
307
|
+
paramlen = 0
|
|
308
|
+
|
|
309
|
+
else:
|
|
310
|
+
raise ArgumentsBad("Unexpected argument to mechanism_param")
|
|
311
|
+
|
|
312
|
+
self.data.mechanism = mechanism
|
|
313
|
+
self.data.ulParameterLen = <CK_ULONG> paramlen
|
|
314
|
+
|
|
315
|
+
if self.param != NULL:
|
|
316
|
+
self.data.pParameter = self.param
|
|
317
|
+
|
|
318
|
+
def __dealloc__(self):
|
|
319
|
+
PyMem_Free(self.data)
|
|
320
|
+
PyMem_Free(self.param)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
cdef class Slot(HasFuncList, types.Slot):
|
|
324
|
+
"""Extend Slot with implementation."""
|
|
325
|
+
|
|
326
|
+
cdef readonly CK_SLOT_ID slot_id
|
|
327
|
+
cdef readonly str slot_description
|
|
328
|
+
cdef readonly str manufacturer_id
|
|
329
|
+
cdef CK_FLAGS slot_flags
|
|
330
|
+
cdef CK_VERSION _hw_version
|
|
331
|
+
cdef CK_VERSION _fw_version
|
|
332
|
+
cdef CK_VERSION _cryptoki_version
|
|
333
|
+
|
|
334
|
+
@staticmethod
|
|
335
|
+
cdef Slot make(CK_FUNCTION_LIST *funclist, CK_SLOT_ID slot_id, CK_SLOT_INFO info, CK_VERSION cryptoki_version):
|
|
336
|
+
description = info.slotDescription[:sizeof(info.slotDescription)]
|
|
337
|
+
manufacturer_id = info.manufacturerID[:sizeof(info.manufacturerID)]
|
|
338
|
+
|
|
339
|
+
cdef Slot slot = Slot.__new__(Slot)
|
|
340
|
+
slot.funclist = funclist
|
|
341
|
+
|
|
342
|
+
slot.slot_id = slot_id
|
|
343
|
+
slot.slot_description = _CK_UTF8CHAR_to_str(description)
|
|
344
|
+
slot.manufacturer_id = _CK_UTF8CHAR_to_str(manufacturer_id)
|
|
345
|
+
slot._hw_version = info.hardwareVersion
|
|
346
|
+
slot._fw_version = info.firmwareVersion
|
|
347
|
+
slot._cryptoki_version = cryptoki_version
|
|
348
|
+
slot.slot_flags = info.flags
|
|
349
|
+
return slot
|
|
350
|
+
|
|
351
|
+
def __init__(self):
|
|
352
|
+
raise TypeError
|
|
353
|
+
|
|
354
|
+
@property
|
|
355
|
+
def flags(self):
|
|
356
|
+
"""Capabilities of this slot (:class:`SlotFlag`)."""
|
|
357
|
+
return SlotFlag(self.slot_flags)
|
|
358
|
+
|
|
359
|
+
@property
|
|
360
|
+
def hardware_version(self):
|
|
361
|
+
"""Hardware version (:class:`tuple`)."""
|
|
362
|
+
return _CK_VERSION_to_tuple(self._hw_version)
|
|
363
|
+
|
|
364
|
+
@property
|
|
365
|
+
def firmware_version(self):
|
|
366
|
+
"""Firmware version (:class:`tuple`)."""
|
|
367
|
+
return _CK_VERSION_to_tuple(self._fw_version)
|
|
368
|
+
|
|
369
|
+
@property
|
|
370
|
+
def cryptoki_version(self):
|
|
371
|
+
"""PKCS#11 (cryptoki) API version (:class:`tuple`)."""
|
|
372
|
+
return _CK_VERSION_to_tuple(self._cryptoki_version)
|
|
373
|
+
|
|
374
|
+
def get_token(self):
|
|
375
|
+
cdef CK_SLOT_ID slot_id = self.slot_id
|
|
376
|
+
cdef CK_TOKEN_INFO info
|
|
377
|
+
cdef CK_RV retval
|
|
378
|
+
|
|
379
|
+
with nogil:
|
|
380
|
+
retval = self.funclist.C_GetTokenInfo(slot_id, &info)
|
|
381
|
+
assertRV(retval)
|
|
382
|
+
|
|
383
|
+
return Token.make(self, info)
|
|
384
|
+
|
|
385
|
+
def get_mechanisms(self):
|
|
386
|
+
cdef CK_SLOT_ID slot_id = self.slot_id
|
|
387
|
+
cdef CK_ULONG count
|
|
388
|
+
cdef CK_RV retval
|
|
389
|
+
|
|
390
|
+
with nogil:
|
|
391
|
+
retval = self.funclist.C_GetMechanismList(slot_id, NULL, &count)
|
|
392
|
+
assertRV(retval)
|
|
393
|
+
|
|
394
|
+
if count == 0:
|
|
395
|
+
return set()
|
|
396
|
+
|
|
397
|
+
cdef CK_MECHANISM_TYPE [:] mechanisms = CK_ULONG_buffer(count)
|
|
398
|
+
|
|
399
|
+
with nogil:
|
|
400
|
+
retval = self.funclist.C_GetMechanismList(slot_id, &mechanisms[0], &count)
|
|
401
|
+
assertRV(retval)
|
|
402
|
+
|
|
403
|
+
return set(map(_CK_MECHANISM_TYPE_to_enum, mechanisms))
|
|
404
|
+
|
|
405
|
+
def get_mechanism_info(self, mechanism):
|
|
406
|
+
cdef CK_SLOT_ID slot_id = self.slot_id
|
|
407
|
+
cdef CK_MECHANISM_TYPE mech_type = mechanism
|
|
408
|
+
cdef CK_MECHANISM_INFO info
|
|
409
|
+
cdef CK_RV retval
|
|
410
|
+
|
|
411
|
+
with nogil:
|
|
412
|
+
retval = self.funclist.C_GetMechanismInfo(slot_id, mech_type, &info)
|
|
413
|
+
assertRV(retval)
|
|
414
|
+
|
|
415
|
+
return types.MechanismInfo(self, mechanism, **info)
|
|
416
|
+
|
|
417
|
+
def _identity(self):
|
|
418
|
+
return Slot.__name__, self.slot_id
|
|
419
|
+
|
|
420
|
+
def __str__(self):
|
|
421
|
+
return "\n".join(
|
|
422
|
+
(
|
|
423
|
+
"Slot Description: %s" % self.slot_description,
|
|
424
|
+
"Manufacturer ID: %s" % self.manufacturer_id,
|
|
425
|
+
"Hardware Version: %s.%s" % self.hardware_version,
|
|
426
|
+
"Firmware Version: %s.%s" % self.firmware_version,
|
|
427
|
+
"Flags: %s" % self.flags,
|
|
428
|
+
)
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
def __repr__(self):
|
|
432
|
+
return "<{klass} (slotID={slot_id} flags={flags})>".format(
|
|
433
|
+
klass=type(self).__name__, slot_id=self.slot_id, flags=str(self.flags)
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
cdef class Token(HasFuncList, types.Token):
|
|
438
|
+
"""Extend Token with implementation."""
|
|
439
|
+
|
|
440
|
+
cdef readonly Slot slot
|
|
441
|
+
cdef readonly str label
|
|
442
|
+
cdef readonly bytes serial
|
|
443
|
+
cdef readonly str manufacturer_id
|
|
444
|
+
cdef readonly str model
|
|
445
|
+
cdef CK_FLAGS token_flags
|
|
446
|
+
cdef CK_VERSION _hw_version
|
|
447
|
+
cdef CK_VERSION _fw_version
|
|
448
|
+
|
|
449
|
+
@staticmethod
|
|
450
|
+
cdef Token make(Slot slot, CK_TOKEN_INFO info):
|
|
451
|
+
label = info.label[:sizeof(info.label)]
|
|
452
|
+
serial_number = info.serialNumber[:sizeof(info.serialNumber)]
|
|
453
|
+
model = info.model[:sizeof(info.model)]
|
|
454
|
+
manufacturer_id = info.manufacturerID[:sizeof(info.manufacturerID)]
|
|
455
|
+
|
|
456
|
+
cdef Token token = Token.__new__(Token)
|
|
457
|
+
token.funclist = slot.funclist
|
|
458
|
+
token.funclist30 = slot.funclist30
|
|
459
|
+
token.funclist32 = slot.funclist32
|
|
460
|
+
token.slot = slot
|
|
461
|
+
token.label = _CK_UTF8CHAR_to_str(label)
|
|
462
|
+
token.serial = serial_number.rstrip()
|
|
463
|
+
token.manufacturer_id = _CK_UTF8CHAR_to_str(manufacturer_id)
|
|
464
|
+
token.model = _CK_UTF8CHAR_to_str(model)
|
|
465
|
+
token._hw_version = info.hardwareVersion
|
|
466
|
+
token._fw_version = info.firmwareVersion
|
|
467
|
+
token.token_flags = info.flags
|
|
468
|
+
return token
|
|
469
|
+
|
|
470
|
+
def __init__(self):
|
|
471
|
+
raise TypeError
|
|
472
|
+
|
|
473
|
+
@property
|
|
474
|
+
def flags(self):
|
|
475
|
+
"""Capabilities of this token (:class:`TokenFlag`)."""
|
|
476
|
+
return TokenFlag(self.token_flags)
|
|
477
|
+
|
|
478
|
+
@property
|
|
479
|
+
def hardware_version(self):
|
|
480
|
+
"""Hardware version (:class:`tuple`)."""
|
|
481
|
+
return _CK_VERSION_to_tuple(self._hw_version)
|
|
482
|
+
|
|
483
|
+
@property
|
|
484
|
+
def firmware_version(self):
|
|
485
|
+
"""Firmware version (:class:`tuple`)."""
|
|
486
|
+
return _CK_VERSION_to_tuple(self._fw_version)
|
|
487
|
+
|
|
488
|
+
def open(
|
|
489
|
+
self,
|
|
490
|
+
rw=False,
|
|
491
|
+
user_pin=None,
|
|
492
|
+
so_pin=None,
|
|
493
|
+
user_type=None,
|
|
494
|
+
attribute_mapper=None,
|
|
495
|
+
cancel_strategy=CancelStrategy.DEFAULT
|
|
496
|
+
):
|
|
497
|
+
cdef CK_SLOT_ID slot_id = self.slot.slot_id
|
|
498
|
+
cdef CK_SESSION_HANDLE handle
|
|
499
|
+
cdef CK_FLAGS flags = CKF_SERIAL_SESSION
|
|
500
|
+
cdef CK_USER_TYPE final_user_type
|
|
501
|
+
cdef CK_UTF8CHAR *pin_data
|
|
502
|
+
cdef CK_ULONG pin_length
|
|
503
|
+
cdef CK_RV retval
|
|
504
|
+
cdef CK_USER_TYPE c_user_type
|
|
505
|
+
|
|
506
|
+
if rw:
|
|
507
|
+
flags |= CKF_RW_SESSION
|
|
508
|
+
|
|
509
|
+
if user_pin is not None and so_pin is not None:
|
|
510
|
+
raise ArgumentsBad("Set either `user_pin` or `so_pin`")
|
|
511
|
+
elif user_pin is PROTECTED_AUTH:
|
|
512
|
+
pin = None
|
|
513
|
+
c_user_type = user_type if user_type is not None else CKU_USER
|
|
514
|
+
elif so_pin is PROTECTED_AUTH:
|
|
515
|
+
pin = None
|
|
516
|
+
c_user_type = CKU_SO
|
|
517
|
+
elif user_pin is not None:
|
|
518
|
+
pin = user_pin.encode('utf-8')
|
|
519
|
+
c_user_type = user_type if user_type is not None else CKU_USER
|
|
520
|
+
elif so_pin is not None:
|
|
521
|
+
pin = so_pin.encode('utf-8')
|
|
522
|
+
c_user_type = CKU_SO
|
|
523
|
+
else:
|
|
524
|
+
pin = None
|
|
525
|
+
c_user_type = CKU_USER_NOBODY
|
|
526
|
+
|
|
527
|
+
with nogil:
|
|
528
|
+
retval = self.funclist.C_OpenSession(slot_id, flags, NULL, NULL, &handle)
|
|
529
|
+
assertRV(retval)
|
|
530
|
+
|
|
531
|
+
if so_pin is PROTECTED_AUTH or user_pin is PROTECTED_AUTH:
|
|
532
|
+
if self.flags & TokenFlag.PROTECTED_AUTHENTICATION_PATH:
|
|
533
|
+
with nogil:
|
|
534
|
+
retval = self.funclist.C_Login(handle, c_user_type, NULL, 0)
|
|
535
|
+
assertRV(retval)
|
|
536
|
+
else:
|
|
537
|
+
raise ArgumentsBad("Protected authentication is not supported by loaded module")
|
|
538
|
+
elif pin is not None:
|
|
539
|
+
pin_data = pin
|
|
540
|
+
pin_length = <CK_ULONG> len(pin)
|
|
541
|
+
|
|
542
|
+
with nogil:
|
|
543
|
+
retval = self.funclist.C_Login(handle, c_user_type, pin_data, pin_length)
|
|
544
|
+
assertRV(retval)
|
|
545
|
+
|
|
546
|
+
return Session.make(
|
|
547
|
+
self, handle,
|
|
548
|
+
rw=<bint> rw,
|
|
549
|
+
user_type=c_user_type,
|
|
550
|
+
mapper=attribute_mapper or AttributeMapper(),
|
|
551
|
+
cancel_strategy=<unsigned int> cancel_strategy
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
def __str__(self):
|
|
555
|
+
return self.label
|
|
556
|
+
|
|
557
|
+
def _identity(self):
|
|
558
|
+
return Token.__name__, self.slot
|
|
559
|
+
|
|
560
|
+
def __repr__(self):
|
|
561
|
+
return "<{klass} (label='{label}' serial={serial} flags={flags})>".format(
|
|
562
|
+
klass=type(self).__name__, label=self.label, serial=self.serial, flags=str(self.flags)
|
|
563
|
+
)
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
cdef class OperationContext:
|
|
567
|
+
cdef Session session
|
|
568
|
+
cdef bint active
|
|
569
|
+
|
|
570
|
+
def __cinit__(self, session, *args, **kwargs):
|
|
571
|
+
self.session = session
|
|
572
|
+
self.active = False
|
|
573
|
+
|
|
574
|
+
def __init__(self, session):
|
|
575
|
+
pass
|
|
576
|
+
|
|
577
|
+
def __enter__(self):
|
|
578
|
+
self.session.operation_lock.acquire()
|
|
579
|
+
self.active = True
|
|
580
|
+
self._initiate()
|
|
581
|
+
return self
|
|
582
|
+
|
|
583
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
584
|
+
self._finalize(silent=False)
|
|
585
|
+
|
|
586
|
+
cdef _handle_final_retval(self, CK_RV retval) with gil:
|
|
587
|
+
self.active = False
|
|
588
|
+
self.session.operation_lock.release()
|
|
589
|
+
assertRV(retval)
|
|
590
|
+
|
|
591
|
+
cdef _operation_aware_assert(self, CK_RV retval) with gil:
|
|
592
|
+
if retval != CKR_BUFFER_TOO_SMALL and retval != CKR_OK:
|
|
593
|
+
# This is an error that terminated the operation
|
|
594
|
+
# We flag the operation as completed on our end as well.
|
|
595
|
+
# This is useful to track because there's no way to cleanly cancel
|
|
596
|
+
# cryptographic operations in PCKS#11 2.x.
|
|
597
|
+
self._handle_final_retval(retval)
|
|
598
|
+
|
|
599
|
+
def _initiate(self):
|
|
600
|
+
raise NotImplementedError
|
|
601
|
+
|
|
602
|
+
def _finalize(self, silent=False):
|
|
603
|
+
if self.active:
|
|
604
|
+
self.active = False
|
|
605
|
+
self.session.operation_lock.release()
|
|
606
|
+
|
|
607
|
+
def __del__(self):
|
|
608
|
+
self._finalize()
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
cdef class OperationWithBinaryOutput(OperationContext):
|
|
612
|
+
|
|
613
|
+
cdef MechanismWithParam mech
|
|
614
|
+
|
|
615
|
+
cdef CK_ULONG buffer_size
|
|
616
|
+
cdef CK_ULONG buffer_data_length
|
|
617
|
+
cdef CK_BYTE [:] output_buf
|
|
618
|
+
|
|
619
|
+
@staticmethod
|
|
620
|
+
cdef OperationWithBinaryOutput _setup(
|
|
621
|
+
type cls,
|
|
622
|
+
Session session,
|
|
623
|
+
MechanismWithParam mech,
|
|
624
|
+
CK_ULONG buffer_size
|
|
625
|
+
) with gil:
|
|
626
|
+
cdef OperationWithBinaryOutput op = cls.__new__(cls, session)
|
|
627
|
+
op.mech = mech
|
|
628
|
+
if buffer_size > 0:
|
|
629
|
+
op.output_buf = CK_BYTE_buffer(buffer_size)
|
|
630
|
+
op.buffer_size = buffer_size
|
|
631
|
+
return op
|
|
632
|
+
|
|
633
|
+
cdef resize_buffer(self, CK_ULONG length):
|
|
634
|
+
self.output_buf = CK_BYTE_buffer(length)
|
|
635
|
+
self.buffer_size = length
|
|
636
|
+
|
|
637
|
+
cdef inline bytes current_output(self):
|
|
638
|
+
return bytes(self.output_buf[:self.buffer_data_length])
|
|
639
|
+
|
|
640
|
+
cdef CK_RV update_resizing_output(
|
|
641
|
+
self,
|
|
642
|
+
OperationUpdateWithResult op_update,
|
|
643
|
+
CK_BYTE *data,
|
|
644
|
+
CK_ULONG data_len,
|
|
645
|
+
) with gil:
|
|
646
|
+
|
|
647
|
+
cdef CK_ULONG length = self.buffer_size
|
|
648
|
+
cdef CK_BYTE *output_buf_loc = &self.output_buf[0]
|
|
649
|
+
cdef CK_RV retval
|
|
650
|
+
|
|
651
|
+
with nogil:
|
|
652
|
+
retval = op_update(
|
|
653
|
+
self.session.handle, data, data_len, NULL, &length
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
if retval != CKR_OK:
|
|
657
|
+
return retval
|
|
658
|
+
|
|
659
|
+
if length > self.buffer_size:
|
|
660
|
+
self.resize_buffer(length)
|
|
661
|
+
output_buf_loc = &self.output_buf[0]
|
|
662
|
+
|
|
663
|
+
with nogil:
|
|
664
|
+
retval = op_update(
|
|
665
|
+
self.session.handle, data, data_len, output_buf_loc, &length
|
|
666
|
+
)
|
|
667
|
+
self.buffer_data_length = length
|
|
668
|
+
return retval
|
|
669
|
+
|
|
670
|
+
cdef CK_RV execute_resizing_output(self, OperationWithResult op) with gil:
|
|
671
|
+
|
|
672
|
+
cdef CK_ULONG length = self.buffer_size
|
|
673
|
+
cdef CK_BYTE *output_buf_loc = &self.output_buf[0]
|
|
674
|
+
cdef CK_RV retval
|
|
675
|
+
|
|
676
|
+
with nogil:
|
|
677
|
+
retval = op(self.session.handle, NULL, &length)
|
|
678
|
+
|
|
679
|
+
if retval != CKR_OK:
|
|
680
|
+
return retval
|
|
681
|
+
|
|
682
|
+
if length > self.buffer_size:
|
|
683
|
+
self.resize_buffer(length)
|
|
684
|
+
output_buf_loc = &self.output_buf[0]
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
with nogil:
|
|
688
|
+
retval = op(self.session.handle, output_buf_loc, &length)
|
|
689
|
+
self.buffer_data_length = length
|
|
690
|
+
return retval
|
|
691
|
+
|
|
692
|
+
cdef bytes process_fully(
|
|
693
|
+
self,
|
|
694
|
+
OperationUpdateWithResult op,
|
|
695
|
+
CK_BYTE *data,
|
|
696
|
+
CK_ULONG data_len
|
|
697
|
+
) with gil:
|
|
698
|
+
cdef CK_RV retval = self.update_resizing_output(op, data, data_len)
|
|
699
|
+
self._handle_final_retval(retval)
|
|
700
|
+
return self.current_output()
|
|
701
|
+
|
|
702
|
+
cdef bytes update_with_result(
|
|
703
|
+
self, OperationUpdateWithResult op, CK_BYTE *data, CK_ULONG data_len
|
|
704
|
+
) with gil:
|
|
705
|
+
cdef CK_RV retval = self.update_resizing_output(op, data, data_len)
|
|
706
|
+
self._operation_aware_assert(retval)
|
|
707
|
+
return self.current_output()
|
|
708
|
+
|
|
709
|
+
cdef update_no_output(
|
|
710
|
+
self, OperationUpdate op, CK_BYTE *data, CK_ULONG data_len
|
|
711
|
+
) with gil:
|
|
712
|
+
cdef CK_RV retval
|
|
713
|
+
with nogil:
|
|
714
|
+
retval = op(self.session.handle, data, data_len)
|
|
715
|
+
self._operation_aware_assert(retval)
|
|
716
|
+
|
|
717
|
+
cdef bytes finish_with_output(self, OperationWithResult op_final) with gil:
|
|
718
|
+
cdef CK_RV retval = self.execute_resizing_output(op_final)
|
|
719
|
+
self._handle_final_retval(retval)
|
|
720
|
+
return self.current_output()
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
cdef class SearchIter(OperationContext):
|
|
724
|
+
"""Iterate a search for objects on a session."""
|
|
725
|
+
|
|
726
|
+
cdef AttributeList template
|
|
727
|
+
cdef CK_ULONG batch_size
|
|
728
|
+
|
|
729
|
+
def __init__(self, session, attrs, batch_size):
|
|
730
|
+
cdef Session _session = session
|
|
731
|
+
cdef AttributeList template = _session.make_attribute_list(attrs)
|
|
732
|
+
self.template = template
|
|
733
|
+
self.batch_size = batch_size
|
|
734
|
+
super().__init__(_session)
|
|
735
|
+
|
|
736
|
+
def __iter__(self):
|
|
737
|
+
return self
|
|
738
|
+
|
|
739
|
+
def _batch_iter(self, results, count):
|
|
740
|
+
for ix in range(count):
|
|
741
|
+
yield make_object(self.session, results[ix])
|
|
742
|
+
|
|
743
|
+
def __next__(self):
|
|
744
|
+
"""Get the next batch of objects."""
|
|
745
|
+
cdef CK_SESSION_HANDLE handle = self.session.handle
|
|
746
|
+
cdef CK_OBJECT_HANDLE obj
|
|
747
|
+
cdef CK_ULONG count
|
|
748
|
+
cdef CK_RV retval
|
|
749
|
+
|
|
750
|
+
cdef CK_OBJECT_HANDLE [:] results = CK_ULONG_buffer(self.batch_size)
|
|
751
|
+
|
|
752
|
+
with nogil:
|
|
753
|
+
retval = self.session.funclist.C_FindObjects(handle, &results[0], self.batch_size, &count)
|
|
754
|
+
assertRV(retval)
|
|
755
|
+
|
|
756
|
+
if count == 0:
|
|
757
|
+
self._finalize()
|
|
758
|
+
raise StopIteration()
|
|
759
|
+
else:
|
|
760
|
+
return self._batch_iter(results, count)
|
|
761
|
+
|
|
762
|
+
def _initiate(self):
|
|
763
|
+
cdef CK_SESSION_HANDLE handle = self.session.handle
|
|
764
|
+
cdef CK_ATTRIBUTE *attr_data = self.template.data
|
|
765
|
+
cdef CK_ULONG attr_count = self.template.count
|
|
766
|
+
cdef CK_RV retval
|
|
767
|
+
|
|
768
|
+
with nogil:
|
|
769
|
+
retval = self.session.funclist.C_FindObjectsInit(handle, attr_data, attr_count)
|
|
770
|
+
assertRV(retval)
|
|
771
|
+
|
|
772
|
+
def _finalize(self, silent=False):
|
|
773
|
+
"""Finish the operation."""
|
|
774
|
+
cdef CK_SESSION_HANDLE handle = self.session.handle
|
|
775
|
+
cdef CK_RV retval
|
|
776
|
+
|
|
777
|
+
if self.active:
|
|
778
|
+
with nogil:
|
|
779
|
+
retval = self.session.funclist.C_FindObjectsFinal(handle)
|
|
780
|
+
if not silent:
|
|
781
|
+
self._handle_final_retval(retval)
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
cdef class DigestOperation(OperationWithBinaryOutput):
|
|
785
|
+
|
|
786
|
+
@staticmethod
|
|
787
|
+
cdef DigestOperation setup(
|
|
788
|
+
Session session,
|
|
789
|
+
MechanismWithParam mech,
|
|
790
|
+
CK_ULONG buffer_size
|
|
791
|
+
) with gil:
|
|
792
|
+
cdef DigestOperation op = <DigestOperation> OperationWithBinaryOutput._setup(
|
|
793
|
+
DigestOperation, session, mech, buffer_size
|
|
794
|
+
)
|
|
795
|
+
return op
|
|
796
|
+
|
|
797
|
+
def _initiate(self):
|
|
798
|
+
cdef CK_RV retval
|
|
799
|
+
with nogil:
|
|
800
|
+
retval = self.session.funclist.C_DigestInit(self.session.handle, self.mech.data)
|
|
801
|
+
self._operation_aware_assert(retval)
|
|
802
|
+
|
|
803
|
+
cdef bytes digest_process_fully(self, CK_BYTE *data, CK_ULONG data_len) with gil:
|
|
804
|
+
cdef Session session = self.session
|
|
805
|
+
return self.process_fully(session.funclist.C_Digest, data, data_len)
|
|
806
|
+
|
|
807
|
+
cdef void update_digest(self, CK_BYTE *data, CK_ULONG data_len):
|
|
808
|
+
self.update_no_output(self.session.funclist.C_DigestUpdate, data, data_len)
|
|
809
|
+
|
|
810
|
+
cdef void update_digest_with_key(self, CK_OBJECT_HANDLE key):
|
|
811
|
+
cdef Session session = self.session
|
|
812
|
+
with nogil:
|
|
813
|
+
retval = session.funclist.C_DigestKey(session.handle, key)
|
|
814
|
+
self._operation_aware_assert(retval)
|
|
815
|
+
|
|
816
|
+
def ingest_chunks(self, chunks):
|
|
817
|
+
cdef CK_BYTE *data_ptr
|
|
818
|
+
cdef CK_ULONG data_len
|
|
819
|
+
cdef CK_OBJECT_HANDLE key
|
|
820
|
+
|
|
821
|
+
for chunk in chunks:
|
|
822
|
+
if not chunk:
|
|
823
|
+
continue
|
|
824
|
+
if isinstance(chunk, types.Key):
|
|
825
|
+
key = chunk.handle
|
|
826
|
+
self.update_digest_with_key(key)
|
|
827
|
+
else:
|
|
828
|
+
data_ptr = chunk
|
|
829
|
+
data_len = <CK_ULONG> len(chunk)
|
|
830
|
+
self.update_digest(data_ptr, data_len)
|
|
831
|
+
|
|
832
|
+
cdef bytes finish(self):
|
|
833
|
+
return self.finish_with_output(self.session.funclist.C_DigestFinal)
|
|
834
|
+
|
|
835
|
+
def _finalize(self, silent=False):
|
|
836
|
+
cdef Session session = self.session
|
|
837
|
+
if self.active:
|
|
838
|
+
self.execute_resizing_output(session.funclist.C_DigestFinal)
|
|
839
|
+
super()._finalize(silent=silent)
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
def merge_templates(default_template, *user_templates):
|
|
843
|
+
template = default_template.copy()
|
|
844
|
+
|
|
845
|
+
for user_template in user_templates:
|
|
846
|
+
if user_template is not None:
|
|
847
|
+
template.update(user_template)
|
|
848
|
+
|
|
849
|
+
return {
|
|
850
|
+
key: value
|
|
851
|
+
for key, value in template.items()
|
|
852
|
+
if value is not DEFAULT
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
|
|
856
|
+
cdef _check_key_type(key_type):
|
|
857
|
+
if not isinstance(key_type, KeyType):
|
|
858
|
+
raise ArgumentsBad("`key_type` must be KeyType.")
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
cdef _check_bit_length(value, name, required=False):
|
|
862
|
+
if value is None and not required:
|
|
863
|
+
return
|
|
864
|
+
if not isinstance(value, int):
|
|
865
|
+
raise ArgumentsBad("`%s` is the length in bits." % name)
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
cdef _resolve_capabilities(key_type, capabilities):
|
|
869
|
+
if capabilities is not None:
|
|
870
|
+
return capabilities
|
|
871
|
+
try:
|
|
872
|
+
return DEFAULT_KEY_CAPABILITIES[key_type]
|
|
873
|
+
except KeyError:
|
|
874
|
+
raise ArgumentsBad("No default capabilities for this key "
|
|
875
|
+
"type. Please specify `capabilities`.")
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
cdef class Session(HasFuncList, types.Session):
|
|
879
|
+
"""Extend Session with implementation."""
|
|
880
|
+
|
|
881
|
+
cdef readonly CK_SESSION_HANDLE handle
|
|
882
|
+
cdef readonly Token token
|
|
883
|
+
cdef readonly bint rw
|
|
884
|
+
cdef CK_USER_TYPE _user_type
|
|
885
|
+
cdef object operation_lock
|
|
886
|
+
cdef object attribute_mapper
|
|
887
|
+
cdef unsigned int cancel_strategy
|
|
888
|
+
|
|
889
|
+
@staticmethod
|
|
890
|
+
cdef Session make(
|
|
891
|
+
Token token,
|
|
892
|
+
CK_SESSION_HANDLE handle,
|
|
893
|
+
bint rw,
|
|
894
|
+
CK_USER_TYPE user_type,
|
|
895
|
+
object mapper,
|
|
896
|
+
unsigned int cancel_strategy
|
|
897
|
+
):
|
|
898
|
+
cdef Session session = Session.__new__(Session)
|
|
899
|
+
|
|
900
|
+
session.funclist = token.funclist
|
|
901
|
+
session.funclist30 = token.funclist30
|
|
902
|
+
session.funclist32 = token.funclist32
|
|
903
|
+
session.token = token
|
|
904
|
+
|
|
905
|
+
session.handle = handle
|
|
906
|
+
# Big operation lock prevents other threads from entering/reentering
|
|
907
|
+
# operations. If the same thread enters the lock, they will get a
|
|
908
|
+
# Cryptoki warning
|
|
909
|
+
session.operation_lock = RLock()
|
|
910
|
+
|
|
911
|
+
session.rw = rw
|
|
912
|
+
session._user_type = user_type
|
|
913
|
+
session.attribute_mapper = mapper
|
|
914
|
+
session.cancel_strategy = cancel_strategy
|
|
915
|
+
return session
|
|
916
|
+
|
|
917
|
+
def __init__(self):
|
|
918
|
+
raise TypeError
|
|
919
|
+
|
|
920
|
+
def _identity(self):
|
|
921
|
+
return Session.__name__, self.token, self.handle
|
|
922
|
+
|
|
923
|
+
@property
|
|
924
|
+
def user_type(self):
|
|
925
|
+
"""User type for this session (:class:`pkcs11.constants.UserType` or :class:`int` for vendor-specific values)."""
|
|
926
|
+
try:
|
|
927
|
+
return UserType(self._user_type)
|
|
928
|
+
except ValueError:
|
|
929
|
+
# Return raw value for vendor-specific user types
|
|
930
|
+
return self._user_type
|
|
931
|
+
|
|
932
|
+
def close(self):
|
|
933
|
+
cdef CK_SESSION_HANDLE handle = self.handle
|
|
934
|
+
cdef CK_RV retval
|
|
935
|
+
|
|
936
|
+
if self._user_type != CKU_USER_NOBODY:
|
|
937
|
+
with nogil:
|
|
938
|
+
retval = self.funclist.C_Logout(handle)
|
|
939
|
+
assertRV(retval)
|
|
940
|
+
|
|
941
|
+
with nogil:
|
|
942
|
+
retval = self.funclist.C_CloseSession(handle)
|
|
943
|
+
assertRV(retval)
|
|
944
|
+
|
|
945
|
+
def get_objects(self, attrs=None, batch_size=10):
|
|
946
|
+
with SearchIter(self, attrs or {}, batch_size) as op:
|
|
947
|
+
for batch in op:
|
|
948
|
+
yield from batch
|
|
949
|
+
|
|
950
|
+
def reaffirm_credentials(self, pin):
|
|
951
|
+
cdef CK_UTF8CHAR *pin_data
|
|
952
|
+
cdef CK_ULONG pin_length
|
|
953
|
+
|
|
954
|
+
pin = pin.encode('utf-8')
|
|
955
|
+
pin_data = pin
|
|
956
|
+
pin_length = <CK_ULONG> len(pin)
|
|
957
|
+
user_type = CKU_CONTEXT_SPECIFIC
|
|
958
|
+
|
|
959
|
+
with nogil:
|
|
960
|
+
retval = self.funclist.C_Login(self.handle, user_type, pin_data, pin_length)
|
|
961
|
+
assertRV(retval)
|
|
962
|
+
|
|
963
|
+
def create_object(self, attrs):
|
|
964
|
+
template = self.make_attribute_list(attrs)
|
|
965
|
+
|
|
966
|
+
cdef CK_OBJECT_HANDLE handle = self.handle
|
|
967
|
+
cdef CK_ATTRIBUTE *attr_data = template.data
|
|
968
|
+
cdef CK_ULONG attr_count = template.count
|
|
969
|
+
cdef CK_OBJECT_HANDLE new
|
|
970
|
+
cdef CK_RV retval
|
|
971
|
+
|
|
972
|
+
with nogil:
|
|
973
|
+
retval = self.funclist.C_CreateObject(handle, attr_data, attr_count, &new)
|
|
974
|
+
assertRV(retval)
|
|
975
|
+
|
|
976
|
+
return make_object(self, new)
|
|
977
|
+
|
|
978
|
+
def create_domain_parameters(self, key_type, attrs,
|
|
979
|
+
local=False, store=False):
|
|
980
|
+
if local and store:
|
|
981
|
+
raise ArgumentsBad("Cannot set both `local` and `store`")
|
|
982
|
+
|
|
983
|
+
attrs = dict(attrs)
|
|
984
|
+
attrs[Attribute.CLASS] = ObjectClass.DOMAIN_PARAMETERS
|
|
985
|
+
attrs[Attribute.KEY_TYPE] = key_type
|
|
986
|
+
attrs[Attribute.TOKEN] = store
|
|
987
|
+
|
|
988
|
+
if local:
|
|
989
|
+
return LocalDomainParameters(self, attrs)
|
|
990
|
+
else:
|
|
991
|
+
return self.create_object(attrs)
|
|
992
|
+
|
|
993
|
+
def generate_domain_parameters(self, key_type, param_length, store=False,
|
|
994
|
+
mechanism=None, mechanism_param=None,
|
|
995
|
+
template=None):
|
|
996
|
+
_check_key_type(key_type)
|
|
997
|
+
_check_bit_length(param_length, "param_length", required=True)
|
|
998
|
+
|
|
999
|
+
mech = MechanismWithParam(
|
|
1000
|
+
key_type, DEFAULT_PARAM_GENERATE_MECHANISMS,
|
|
1001
|
+
mechanism, mechanism_param)
|
|
1002
|
+
|
|
1003
|
+
template_ = {
|
|
1004
|
+
Attribute.CLASS: ObjectClass.DOMAIN_PARAMETERS,
|
|
1005
|
+
Attribute.TOKEN: store,
|
|
1006
|
+
Attribute.PRIME_BITS: param_length,
|
|
1007
|
+
}
|
|
1008
|
+
attrs = self.make_attribute_list(merge_templates(template_, template))
|
|
1009
|
+
|
|
1010
|
+
return self.generate_key_from_attrs(attrs, mech)
|
|
1011
|
+
|
|
1012
|
+
cdef AttributeList make_attribute_list(self, template):
|
|
1013
|
+
return AttributeList.from_template(dict(template), self.attribute_mapper)
|
|
1014
|
+
|
|
1015
|
+
def generate_key(self, key_type, key_length=None,
|
|
1016
|
+
id=None, label=None,
|
|
1017
|
+
store=False, capabilities=None,
|
|
1018
|
+
mechanism=None, mechanism_param=None,
|
|
1019
|
+
template=None):
|
|
1020
|
+
|
|
1021
|
+
_check_key_type(key_type)
|
|
1022
|
+
_check_bit_length(key_length, "key_length")
|
|
1023
|
+
capabilities = _resolve_capabilities(key_type, capabilities)
|
|
1024
|
+
|
|
1025
|
+
mech = MechanismWithParam(
|
|
1026
|
+
key_type, DEFAULT_GENERATE_MECHANISMS,
|
|
1027
|
+
mechanism, mechanism_param)
|
|
1028
|
+
|
|
1029
|
+
template_ = self.attribute_mapper.secret_key_template(
|
|
1030
|
+
capabilities=capabilities, id_=id, label=label, store=store,
|
|
1031
|
+
)
|
|
1032
|
+
# Build attributes
|
|
1033
|
+
if key_type not in (KeyType.DES2, KeyType.DES3, KeyType.GOST28147, KeyType.SEED):
|
|
1034
|
+
if key_length is None:
|
|
1035
|
+
raise ArgumentsBad("Must provide `key_length'")
|
|
1036
|
+
|
|
1037
|
+
template_[Attribute.VALUE_LEN] = key_length // 8 # In bytes
|
|
1038
|
+
|
|
1039
|
+
attrs = self.make_attribute_list(merge_templates(template_, template))
|
|
1040
|
+
|
|
1041
|
+
return self.generate_key_from_attrs(attrs, mech)
|
|
1042
|
+
|
|
1043
|
+
cdef object generate_key_from_attrs(
|
|
1044
|
+
self, AttributeList attrs, MechanismWithParam mech
|
|
1045
|
+
):
|
|
1046
|
+
cdef CK_SESSION_HANDLE handle = self.handle
|
|
1047
|
+
cdef CK_MECHANISM *mech_data = mech.data
|
|
1048
|
+
cdef CK_ATTRIBUTE *attr_data = attrs.data
|
|
1049
|
+
cdef CK_ULONG attr_count = attrs.count
|
|
1050
|
+
cdef CK_OBJECT_HANDLE key
|
|
1051
|
+
|
|
1052
|
+
with nogil:
|
|
1053
|
+
retval = self.funclist.C_GenerateKey(handle, mech_data, attr_data, attr_count, &key)
|
|
1054
|
+
assertRV(retval)
|
|
1055
|
+
|
|
1056
|
+
return make_object(self, key)
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
def _generate_keypair(self, key_type, key_length=None,
|
|
1060
|
+
id=None, label=None,
|
|
1061
|
+
store=False, capabilities=None,
|
|
1062
|
+
mechanism=None, mechanism_param=None,
|
|
1063
|
+
public_template=None, private_template=None):
|
|
1064
|
+
|
|
1065
|
+
_check_key_type(key_type)
|
|
1066
|
+
_check_bit_length(key_length, "key_length")
|
|
1067
|
+
capabilities = _resolve_capabilities(key_type, capabilities)
|
|
1068
|
+
|
|
1069
|
+
mech = MechanismWithParam(
|
|
1070
|
+
key_type, DEFAULT_GENERATE_MECHANISMS,
|
|
1071
|
+
mechanism, mechanism_param)
|
|
1072
|
+
|
|
1073
|
+
public_template_ = self.attribute_mapper.public_key_template(
|
|
1074
|
+
id_=id, label=label, store=store, capabilities=capabilities,
|
|
1075
|
+
)
|
|
1076
|
+
private_template_ = self.attribute_mapper.private_key_template(
|
|
1077
|
+
id_=id, label=label, store=store, capabilities=capabilities,
|
|
1078
|
+
)
|
|
1079
|
+
|
|
1080
|
+
if key_type is KeyType.RSA:
|
|
1081
|
+
if key_length is None:
|
|
1082
|
+
raise ArgumentsBad("Must provide `key_length'")
|
|
1083
|
+
|
|
1084
|
+
# Some PKCS#11 implementations don't default this, it makes sense
|
|
1085
|
+
# to do it here
|
|
1086
|
+
public_template_.update({
|
|
1087
|
+
Attribute.PUBLIC_EXPONENT: b'\1\0\1',
|
|
1088
|
+
Attribute.MODULUS_BITS: key_length,
|
|
1089
|
+
})
|
|
1090
|
+
|
|
1091
|
+
elif key_type is KeyType.ML_DSA:
|
|
1092
|
+
if public_template is None or Attribute.PARAMETER_SET not in public_template:
|
|
1093
|
+
raise ArgumentsBad(
|
|
1094
|
+
"ML-DSA key generation requires `Attribute.PARAMETER_SET` "
|
|
1095
|
+
"in `public_template` (e.g. MLDSAParameterSet.ML_DSA_65)."
|
|
1096
|
+
)
|
|
1097
|
+
|
|
1098
|
+
elif key_type is KeyType.ML_KEM:
|
|
1099
|
+
if public_template is None or Attribute.PARAMETER_SET not in public_template:
|
|
1100
|
+
raise ArgumentsBad(
|
|
1101
|
+
"ML-KEM key generation requires `Attribute.PARAMETER_SET` "
|
|
1102
|
+
"in `public_template` (e.g. MLKEMParameterSet.ML_KEM_768)."
|
|
1103
|
+
)
|
|
1104
|
+
public_template_[Attribute.ENCAPSULATE] = True
|
|
1105
|
+
private_template_[Attribute.DECAPSULATE] = True
|
|
1106
|
+
|
|
1107
|
+
public_attrs = self.make_attribute_list(merge_templates(public_template_, public_template))
|
|
1108
|
+
private_attrs = self.make_attribute_list(merge_templates(private_template_, private_template))
|
|
1109
|
+
return self.generate_keypair_from_attrs(public_attrs, private_attrs, mech)
|
|
1110
|
+
|
|
1111
|
+
cdef tuple generate_keypair_from_attrs(
|
|
1112
|
+
self,
|
|
1113
|
+
AttributeList public_attrs,
|
|
1114
|
+
AttributeList private_attrs,
|
|
1115
|
+
MechanismWithParam mech
|
|
1116
|
+
):
|
|
1117
|
+
|
|
1118
|
+
cdef CK_SESSION_HANDLE handle = self.handle
|
|
1119
|
+
cdef CK_MECHANISM *mech_data = mech.data
|
|
1120
|
+
cdef CK_ATTRIBUTE *public_attr_data = public_attrs.data
|
|
1121
|
+
cdef CK_ULONG public_attr_count = public_attrs.count
|
|
1122
|
+
cdef CK_ATTRIBUTE *private_attr_data = private_attrs.data
|
|
1123
|
+
cdef CK_ULONG private_attr_count = private_attrs.count
|
|
1124
|
+
cdef CK_OBJECT_HANDLE public_key
|
|
1125
|
+
cdef CK_OBJECT_HANDLE private_key
|
|
1126
|
+
cdef CK_RV retval
|
|
1127
|
+
|
|
1128
|
+
with nogil:
|
|
1129
|
+
retval = self.funclist.C_GenerateKeyPair(handle, mech_data, public_attr_data, public_attr_count, private_attr_data, private_attr_count, &public_key, &private_key)
|
|
1130
|
+
assertRV(retval)
|
|
1131
|
+
|
|
1132
|
+
return (make_object(self, public_key),
|
|
1133
|
+
make_object(self, private_key))
|
|
1134
|
+
|
|
1135
|
+
def seed_random(self, seed):
|
|
1136
|
+
cdef CK_SESSION_HANDLE handle = self.handle
|
|
1137
|
+
cdef CK_BYTE *seed_data = seed
|
|
1138
|
+
cdef CK_ULONG seed_len = <CK_ULONG> len(seed)
|
|
1139
|
+
cdef CK_RV retval
|
|
1140
|
+
|
|
1141
|
+
with nogil:
|
|
1142
|
+
retval = self.funclist.C_SeedRandom(handle, seed_data, seed_len)
|
|
1143
|
+
assertRV(retval)
|
|
1144
|
+
|
|
1145
|
+
def generate_random(self, nbits):
|
|
1146
|
+
cdef CK_SESSION_HANDLE handle = self.handle
|
|
1147
|
+
cdef CK_ULONG length = nbits // 8
|
|
1148
|
+
cdef CK_CHAR [:] random = CK_BYTE_buffer(length)
|
|
1149
|
+
cdef CK_RV retval
|
|
1150
|
+
|
|
1151
|
+
with nogil:
|
|
1152
|
+
retval = self.funclist.C_GenerateRandom(handle, &random[0], length)
|
|
1153
|
+
assertRV(retval)
|
|
1154
|
+
|
|
1155
|
+
return bytes(random)
|
|
1156
|
+
|
|
1157
|
+
def __digest_operation(self, mechanism, mechanism_param):
|
|
1158
|
+
mech = MechanismWithParam(
|
|
1159
|
+
None, {},
|
|
1160
|
+
mechanism, mechanism_param)
|
|
1161
|
+
return DigestOperation.setup(self, mech, 1024)
|
|
1162
|
+
|
|
1163
|
+
def _digest(self, data, mechanism=None, mechanism_param=None):
|
|
1164
|
+
cdef CK_BYTE *data_ptr = data
|
|
1165
|
+
cdef CK_ULONG data_len = <CK_ULONG> len(data)
|
|
1166
|
+
cdef CK_RV retval
|
|
1167
|
+
|
|
1168
|
+
cdef DigestOperation op = self.__digest_operation(mechanism, mechanism_param)
|
|
1169
|
+
with op:
|
|
1170
|
+
return op.digest_process_fully(data_ptr, data_len)
|
|
1171
|
+
|
|
1172
|
+
def _digest_generator(self, data, mechanism=None, mechanism_param=None):
|
|
1173
|
+
|
|
1174
|
+
cdef DigestOperation op = self.__digest_operation(mechanism, mechanism_param)
|
|
1175
|
+
with op:
|
|
1176
|
+
op.ingest_chunks(data)
|
|
1177
|
+
return op.finish()
|
|
1178
|
+
|
|
1179
|
+
def set_pin(self, old_pin, new_pin):
|
|
1180
|
+
cdef CK_ULONG old_pin_length
|
|
1181
|
+
cdef CK_ULONG new_pin_length
|
|
1182
|
+
cdef CK_OBJECT_HANDLE handle = self.handle
|
|
1183
|
+
cdef CK_UTF8CHAR *old_pin_data
|
|
1184
|
+
cdef CK_UTF8CHAR *new_pin_data
|
|
1185
|
+
cdef CK_RV retval
|
|
1186
|
+
|
|
1187
|
+
pin_old = old_pin.encode('utf-8')
|
|
1188
|
+
pin_new = new_pin.encode('utf-8')
|
|
1189
|
+
|
|
1190
|
+
old_pin_data = pin_old
|
|
1191
|
+
new_pin_data = pin_new
|
|
1192
|
+
old_pin_length = len(pin_old)
|
|
1193
|
+
new_pin_length = len(pin_new)
|
|
1194
|
+
|
|
1195
|
+
with nogil:
|
|
1196
|
+
retval = self.funclist.C_SetPIN(handle, old_pin_data, old_pin_length, new_pin_data, new_pin_length)
|
|
1197
|
+
assertRV(retval)
|
|
1198
|
+
|
|
1199
|
+
def init_pin(self, pin):
|
|
1200
|
+
cdef CK_OBJECT_HANDLE handle = self.handle
|
|
1201
|
+
cdef CK_UTF8CHAR *pin_data
|
|
1202
|
+
cdef CK_ULONG pin_length
|
|
1203
|
+
cdef CK_RV retval
|
|
1204
|
+
|
|
1205
|
+
pin = pin.encode('utf-8')
|
|
1206
|
+
|
|
1207
|
+
pin_data = pin
|
|
1208
|
+
pin_length = len(pin)
|
|
1209
|
+
|
|
1210
|
+
with nogil:
|
|
1211
|
+
retval = self.funclist.C_InitPIN(handle, pin_data, pin_length)
|
|
1212
|
+
assertRV(retval)
|
|
1213
|
+
|
|
1214
|
+
cdef class ObjectHandleWrapper(HasFuncList):
|
|
1215
|
+
"""
|
|
1216
|
+
Class implementing generic operations on PKCS#11 objects.
|
|
1217
|
+
"""
|
|
1218
|
+
|
|
1219
|
+
cdef readonly Session session
|
|
1220
|
+
cdef readonly CK_OBJECT_HANDLE handle
|
|
1221
|
+
|
|
1222
|
+
@staticmethod
|
|
1223
|
+
cdef ObjectHandleWrapper wrap(Session session, CK_OBJECT_HANDLE handle):
|
|
1224
|
+
cdef ObjectHandleWrapper obj = ObjectHandleWrapper.__new__(ObjectHandleWrapper)
|
|
1225
|
+
obj.funclist = session.funclist
|
|
1226
|
+
obj.session = session
|
|
1227
|
+
obj.handle = handle
|
|
1228
|
+
return obj
|
|
1229
|
+
|
|
1230
|
+
def __init__(self):
|
|
1231
|
+
raise TypeError
|
|
1232
|
+
|
|
1233
|
+
cdef AttributeList get_attribute_list(self, CK_ATTRIBUTE_TYPE * keys, CK_ULONG total) with gil:
|
|
1234
|
+
cdef CK_SESSION_HANDLE handle = self.session.handle
|
|
1235
|
+
cdef CK_OBJECT_HANDLE obj = self.handle
|
|
1236
|
+
cdef CK_ULONG ix = 0
|
|
1237
|
+
cdef CK_ULONG retrievable = 0
|
|
1238
|
+
cdef CK_ATTRIBUTE *tpl = <CK_ATTRIBUTE *> PyMem_Malloc(total * sizeof(CK_ATTRIBUTE))
|
|
1239
|
+
cdef CK_RV retval
|
|
1240
|
+
|
|
1241
|
+
for ix in range(total):
|
|
1242
|
+
tpl[ix].type = keys[ix]
|
|
1243
|
+
tpl[ix].pValue = NULL
|
|
1244
|
+
tpl[ix].ulValueLen = <CK_ULONG> 0
|
|
1245
|
+
|
|
1246
|
+
with nogil:
|
|
1247
|
+
retval = self.funclist.C_GetAttributeValue(handle, obj, tpl, total)
|
|
1248
|
+
|
|
1249
|
+
for ix in range(total):
|
|
1250
|
+
if tpl[ix].ulValueLen != CK_UNAVAILABLE_INFORMATION:
|
|
1251
|
+
# overwrite the template at position 'retrievable' in the buffer
|
|
1252
|
+
tpl[retrievable].type = tpl[ix].type
|
|
1253
|
+
tpl[retrievable].pValue = PyMem_Malloc(tpl[ix].ulValueLen)
|
|
1254
|
+
if tpl[retrievable].pValue is NULL:
|
|
1255
|
+
raise MemoryError()
|
|
1256
|
+
tpl[retrievable].ulValueLen = tpl[ix].ulValueLen
|
|
1257
|
+
retrievable += 1
|
|
1258
|
+
# The spec prohibits returning CK_UNAVAILABLE_INFORMATION
|
|
1259
|
+
# together with CKR_OK, but some tokens do that anyway.
|
|
1260
|
+
# Let's be defensive and map that to a proper error,
|
|
1261
|
+
if tpl[ix].ulValueLen == CK_UNAVAILABLE_INFORMATION and retval == CKR_OK:
|
|
1262
|
+
retval = CKR_FUNCTION_FAILED
|
|
1263
|
+
break
|
|
1264
|
+
|
|
1265
|
+
# when this gets GC'd, the __dealloc__ will clean up our buffers
|
|
1266
|
+
result = AttributeList.from_owned_pointer(tpl, retrievable)
|
|
1267
|
+
if retrievable:
|
|
1268
|
+
with nogil:
|
|
1269
|
+
retval = self.funclist.C_GetAttributeValue(handle, obj, tpl, retrievable)
|
|
1270
|
+
for ix in range(retrievable):
|
|
1271
|
+
# Ensure the data returned from the token is sane
|
|
1272
|
+
if tpl[ix].ulValueLen == CK_UNAVAILABLE_INFORMATION or tpl[ix].pValue is NULL:
|
|
1273
|
+
retval = CKR_FUNCTION_FAILED
|
|
1274
|
+
break
|
|
1275
|
+
assertRV(retval)
|
|
1276
|
+
return result
|
|
1277
|
+
|
|
1278
|
+
|
|
1279
|
+
def __getitem__(self, key):
|
|
1280
|
+
cdef CK_ATTRIBUTE_TYPE key_t = key
|
|
1281
|
+
return self.get_attribute_list(&key_t, 1).at_index(0, self.session.attribute_mapper)
|
|
1282
|
+
|
|
1283
|
+
def __setitem__(self, key, value):
|
|
1284
|
+
cdef CK_SESSION_HANDLE handle = self.session.handle
|
|
1285
|
+
cdef CK_OBJECT_HANDLE obj = self.handle
|
|
1286
|
+
cdef CK_ATTRIBUTE template
|
|
1287
|
+
cdef CK_RV retval
|
|
1288
|
+
|
|
1289
|
+
value = self.session.attribute_mapper.pack_attribute(key, value)
|
|
1290
|
+
|
|
1291
|
+
template.type = key
|
|
1292
|
+
template.pValue = <CK_CHAR *> value
|
|
1293
|
+
template.ulValueLen = <CK_ULONG>len(value)
|
|
1294
|
+
|
|
1295
|
+
with nogil:
|
|
1296
|
+
retval = self.funclist.C_SetAttributeValue(handle, obj, &template, 1)
|
|
1297
|
+
assertRV(retval)
|
|
1298
|
+
|
|
1299
|
+
def destroy(self):
|
|
1300
|
+
cdef CK_SESSION_HANDLE handle = self.session.handle
|
|
1301
|
+
cdef CK_OBJECT_HANDLE obj = self.handle
|
|
1302
|
+
cdef CK_RV retval
|
|
1303
|
+
|
|
1304
|
+
with nogil:
|
|
1305
|
+
retval = self.session.funclist.C_DestroyObject(handle, obj)
|
|
1306
|
+
assertRV(retval)
|
|
1307
|
+
|
|
1308
|
+
def copy(self, attrs):
|
|
1309
|
+
template = self.session.make_attribute_list(attrs)
|
|
1310
|
+
|
|
1311
|
+
cdef CK_SESSION_HANDLE handle = self.session.handle
|
|
1312
|
+
cdef CK_OBJECT_HANDLE obj = self.handle
|
|
1313
|
+
cdef CK_ATTRIBUTE *attr_data = template.data
|
|
1314
|
+
cdef CK_ULONG attr_count = template.count
|
|
1315
|
+
cdef CK_OBJECT_HANDLE new_obj
|
|
1316
|
+
cdef CK_RV retval
|
|
1317
|
+
|
|
1318
|
+
with nogil:
|
|
1319
|
+
retval = self.session.funclist.C_CopyObject(handle, obj, attr_data, attr_count, &new_obj)
|
|
1320
|
+
assertRV(retval)
|
|
1321
|
+
return new_obj
|
|
1322
|
+
|
|
1323
|
+
def identity(self):
|
|
1324
|
+
return ObjectHandleWrapper.__name__, self.session, self.handle
|
|
1325
|
+
|
|
1326
|
+
|
|
1327
|
+
class Object(types.Object):
|
|
1328
|
+
"""Expand Object with an implementation."""
|
|
1329
|
+
|
|
1330
|
+
def __init__(self, wrapper: ObjectHandleWrapper):
|
|
1331
|
+
self.wrapper = wrapper
|
|
1332
|
+
|
|
1333
|
+
def __getitem__(self, item):
|
|
1334
|
+
return self.wrapper[item]
|
|
1335
|
+
|
|
1336
|
+
def __setitem__(self, key, value):
|
|
1337
|
+
self.wrapper[key] = value
|
|
1338
|
+
|
|
1339
|
+
def get_attributes(self, keys):
|
|
1340
|
+
cdef ObjectHandleWrapper wrapper = self.wrapper
|
|
1341
|
+
cdef CK_ULONG total = len(keys)
|
|
1342
|
+
|
|
1343
|
+
if not total:
|
|
1344
|
+
return {}
|
|
1345
|
+
|
|
1346
|
+
cdef CK_ATTRIBUTE_TYPE * key_ptr = <CK_ATTRIBUTE_TYPE *> PyMem_Malloc(total * sizeof(CK_ATTRIBUTE_TYPE))
|
|
1347
|
+
cdef CK_ULONG ix = 0
|
|
1348
|
+
for ix, key in enumerate(keys):
|
|
1349
|
+
key_ptr[ix] = <CK_ATTRIBUTE_TYPE> key
|
|
1350
|
+
|
|
1351
|
+
try:
|
|
1352
|
+
result = wrapper.get_attribute_list(key_ptr, total).as_dict(wrapper.session.attribute_mapper)
|
|
1353
|
+
finally:
|
|
1354
|
+
PyMem_Free(key_ptr)
|
|
1355
|
+
return result
|
|
1356
|
+
|
|
1357
|
+
@property
|
|
1358
|
+
def session(self):
|
|
1359
|
+
return self.wrapper.session
|
|
1360
|
+
|
|
1361
|
+
@property
|
|
1362
|
+
def handle(self):
|
|
1363
|
+
return self.wrapper.handle
|
|
1364
|
+
|
|
1365
|
+
def copy(self, attrs):
|
|
1366
|
+
new_obj = self.wrapper.copy(attrs)
|
|
1367
|
+
return make_object(self.wrapper.session, new_obj)
|
|
1368
|
+
|
|
1369
|
+
def destroy(self):
|
|
1370
|
+
self.wrapper.destroy()
|
|
1371
|
+
|
|
1372
|
+
def _identity(self):
|
|
1373
|
+
return Object.__name__, self.wrapper.identity()
|
|
1374
|
+
|
|
1375
|
+
|
|
1376
|
+
cdef object make_object(Session session, CK_OBJECT_HANDLE handle) with gil:
|
|
1377
|
+
"""
|
|
1378
|
+
Make an object with the right bases for its class and capabilities.
|
|
1379
|
+
"""
|
|
1380
|
+
wrapper = ObjectHandleWrapper.wrap(session, handle)
|
|
1381
|
+
|
|
1382
|
+
cdef CK_ATTRIBUTE_TYPE[10] attr_keys = [
|
|
1383
|
+
Attribute.CLASS,
|
|
1384
|
+
Attribute.ENCRYPT,
|
|
1385
|
+
Attribute.DECRYPT,
|
|
1386
|
+
Attribute.SIGN,
|
|
1387
|
+
Attribute.VERIFY,
|
|
1388
|
+
Attribute.WRAP,
|
|
1389
|
+
Attribute.UNWRAP,
|
|
1390
|
+
Attribute.DERIVE,
|
|
1391
|
+
Attribute.ENCAPSULATE,
|
|
1392
|
+
Attribute.DECAPSULATE,
|
|
1393
|
+
]
|
|
1394
|
+
|
|
1395
|
+
try:
|
|
1396
|
+
# Determine a list of base classes to manufacture our class with
|
|
1397
|
+
try:
|
|
1398
|
+
attributes = wrapper.get_attribute_list(&attr_keys[0], 10)
|
|
1399
|
+
except PKCS11Error:
|
|
1400
|
+
# retry fetching the flags one by one, some tokens do not implement error handling
|
|
1401
|
+
# on bulk fetches correctly.
|
|
1402
|
+
attributes = {}
|
|
1403
|
+
for key in attr_keys:
|
|
1404
|
+
try:
|
|
1405
|
+
attributes[key] = wrapper[key]
|
|
1406
|
+
except (AttributeTypeInvalid, AttributeSensitive, FunctionFailed):
|
|
1407
|
+
continue
|
|
1408
|
+
|
|
1409
|
+
object_class = attributes.get(Attribute.CLASS, session.attribute_mapper)
|
|
1410
|
+
bases = (_CLASS_MAP[object_class],)
|
|
1411
|
+
|
|
1412
|
+
# Build a list of mixins for this new class
|
|
1413
|
+
for attribute, mixin in (
|
|
1414
|
+
(Attribute.ENCRYPT, EncryptMixin),
|
|
1415
|
+
(Attribute.DECRYPT, DecryptMixin),
|
|
1416
|
+
(Attribute.SIGN, SignMixin),
|
|
1417
|
+
(Attribute.VERIFY, VerifyMixin),
|
|
1418
|
+
(Attribute.WRAP, WrapMixin),
|
|
1419
|
+
(Attribute.UNWRAP, UnwrapMixin),
|
|
1420
|
+
(Attribute.DERIVE, DeriveMixin),
|
|
1421
|
+
(Attribute.ENCAPSULATE, EncapsulateMixin),
|
|
1422
|
+
(Attribute.DECAPSULATE, DecapsulateMixin),
|
|
1423
|
+
):
|
|
1424
|
+
try:
|
|
1425
|
+
if attributes.get(attribute, session.attribute_mapper):
|
|
1426
|
+
bases += (mixin,)
|
|
1427
|
+
except KeyError:
|
|
1428
|
+
pass
|
|
1429
|
+
|
|
1430
|
+
bases += (Object,)
|
|
1431
|
+
|
|
1432
|
+
# Manufacture a class with the right capabilities.
|
|
1433
|
+
klass = type(bases[0].__name__, bases, {})
|
|
1434
|
+
|
|
1435
|
+
return klass(wrapper)
|
|
1436
|
+
|
|
1437
|
+
except KeyError:
|
|
1438
|
+
return Object(wrapper)
|
|
1439
|
+
|
|
1440
|
+
|
|
1441
|
+
class SecretKey(types.SecretKey):
|
|
1442
|
+
pass
|
|
1443
|
+
|
|
1444
|
+
|
|
1445
|
+
class PublicKey(types.PublicKey):
|
|
1446
|
+
pass
|
|
1447
|
+
|
|
1448
|
+
|
|
1449
|
+
class PrivateKey(types.PrivateKey):
|
|
1450
|
+
pass
|
|
1451
|
+
|
|
1452
|
+
|
|
1453
|
+
class GenerateWithParametersMixin(types.DomainParameters):
|
|
1454
|
+
def generate_keypair(self,
|
|
1455
|
+
id=None, label=None,
|
|
1456
|
+
store=False, capabilities=None,
|
|
1457
|
+
mechanism=None, mechanism_param=None,
|
|
1458
|
+
public_template=None, private_template=None):
|
|
1459
|
+
|
|
1460
|
+
cdef Session session = self.session
|
|
1461
|
+
capabilities = _resolve_capabilities(self.key_type, capabilities)
|
|
1462
|
+
|
|
1463
|
+
mech = MechanismWithParam(self.key_type, DEFAULT_GENERATE_MECHANISMS, mechanism, mechanism_param)
|
|
1464
|
+
|
|
1465
|
+
# Build attributes
|
|
1466
|
+
public_template_ = session.attribute_mapper.public_key_template(
|
|
1467
|
+
id_=id, label=label, store=store, capabilities=capabilities,
|
|
1468
|
+
)
|
|
1469
|
+
|
|
1470
|
+
# Copy in our domain parameters.
|
|
1471
|
+
# Not all parameters are appropriate for all domains.
|
|
1472
|
+
try:
|
|
1473
|
+
public_template_.update(
|
|
1474
|
+
self.get_attributes(
|
|
1475
|
+
(
|
|
1476
|
+
Attribute.BASE,
|
|
1477
|
+
Attribute.PRIME,
|
|
1478
|
+
Attribute.SUBPRIME,
|
|
1479
|
+
Attribute.EC_PARAMS,
|
|
1480
|
+
)
|
|
1481
|
+
)
|
|
1482
|
+
)
|
|
1483
|
+
except (AttributeTypeInvalid, FunctionFailed):
|
|
1484
|
+
pass
|
|
1485
|
+
|
|
1486
|
+
public_attrs = session.make_attribute_list(merge_templates(public_template_, public_template))
|
|
1487
|
+
|
|
1488
|
+
private_template_ = session.attribute_mapper.private_key_template(
|
|
1489
|
+
id_=id, label=label, store=store, capabilities=capabilities,
|
|
1490
|
+
)
|
|
1491
|
+
private_attrs = session.make_attribute_list(merge_templates(private_template_, private_template))
|
|
1492
|
+
|
|
1493
|
+
return session.generate_keypair_from_attrs(public_attrs, private_attrs, mech)
|
|
1494
|
+
|
|
1495
|
+
|
|
1496
|
+
class LocalDomainParameters(GenerateWithParametersMixin, types.LocalDomainParameters):
|
|
1497
|
+
pass
|
|
1498
|
+
|
|
1499
|
+
class StoredDomainParameters(GenerateWithParametersMixin):
|
|
1500
|
+
pass
|
|
1501
|
+
|
|
1502
|
+
class Certificate(types.Certificate):
|
|
1503
|
+
pass
|
|
1504
|
+
|
|
1505
|
+
|
|
1506
|
+
cdef class KeyOperation(OperationWithBinaryOutput):
|
|
1507
|
+
cdef CK_OBJECT_HANDLE key
|
|
1508
|
+
cdef KeyOperationInit op_init
|
|
1509
|
+
|
|
1510
|
+
@staticmethod
|
|
1511
|
+
cdef KeyOperation _common_key_setup(
|
|
1512
|
+
type cls,
|
|
1513
|
+
Session session,
|
|
1514
|
+
MechanismWithParam mech,
|
|
1515
|
+
CK_OBJECT_HANDLE key,
|
|
1516
|
+
CK_ULONG buffer_size
|
|
1517
|
+
) with gil:
|
|
1518
|
+
|
|
1519
|
+
cdef KeyOperation op = <KeyOperation> OperationWithBinaryOutput._setup(
|
|
1520
|
+
cls, session, mech, buffer_size
|
|
1521
|
+
)
|
|
1522
|
+
op.key = key
|
|
1523
|
+
return op
|
|
1524
|
+
|
|
1525
|
+
def unclean_shutdown(self):
|
|
1526
|
+
"""
|
|
1527
|
+
Shutdown implementation for 2.x PKCS#11 modules that don't support shutdown signalling
|
|
1528
|
+
"""
|
|
1529
|
+
raise NotImplementedError
|
|
1530
|
+
|
|
1531
|
+
def _initiate(self):
|
|
1532
|
+
cdef CK_RV retval
|
|
1533
|
+
with nogil:
|
|
1534
|
+
retval = self.op_init(self.session.handle, self.mech.data, self.key)
|
|
1535
|
+
self._operation_aware_assert(retval)
|
|
1536
|
+
|
|
1537
|
+
def _cancel_operation(self, silent):
|
|
1538
|
+
cdef CK_RV retval
|
|
1539
|
+
if self.session.cancel_strategy == CancelStrategy.CANCEL_WITH_INIT:
|
|
1540
|
+
# cancel the operation if still active
|
|
1541
|
+
# This is a PKCS#11 3.x feature
|
|
1542
|
+
with nogil:
|
|
1543
|
+
retval = self.op_init(self.session.handle, NULL, self.key)
|
|
1544
|
+
if retval == CKR_OPERATION_CANCEL_FAILED and not silent:
|
|
1545
|
+
raise PKCS11Error("Failed to cancel operation")
|
|
1546
|
+
else:
|
|
1547
|
+
# No official cancel protocol in v2.x of the standard
|
|
1548
|
+
# Try the poor man's way by making a hail-mary call to C_XYZFinish() and ignoring the response
|
|
1549
|
+
self.unclean_shutdown()
|
|
1550
|
+
|
|
1551
|
+
def _finalize(self, silent=False):
|
|
1552
|
+
if self.active:
|
|
1553
|
+
self._cancel_operation(silent)
|
|
1554
|
+
super()._finalize(silent=silent)
|
|
1555
|
+
|
|
1556
|
+
|
|
1557
|
+
cdef class DataCryptOperation(KeyOperation):
|
|
1558
|
+
|
|
1559
|
+
cdef OperationUpdateWithResult op_update
|
|
1560
|
+
cdef OperationWithResult op_final
|
|
1561
|
+
cdef OperationUpdateWithResult op_full
|
|
1562
|
+
|
|
1563
|
+
@staticmethod
|
|
1564
|
+
cdef DataCryptOperation setup_encrypt(
|
|
1565
|
+
Session session,
|
|
1566
|
+
MechanismWithParam mech,
|
|
1567
|
+
CK_OBJECT_HANDLE key,
|
|
1568
|
+
CK_ULONG buffer_size
|
|
1569
|
+
) with gil:
|
|
1570
|
+
cdef DataCryptOperation op = <DataCryptOperation> KeyOperation._common_key_setup(
|
|
1571
|
+
DataCryptOperation, session, mech, key, buffer_size
|
|
1572
|
+
)
|
|
1573
|
+
op.op_init = session.funclist.C_EncryptInit
|
|
1574
|
+
op.op_update = session.funclist.C_EncryptUpdate
|
|
1575
|
+
op.op_final = session.funclist.C_EncryptFinal
|
|
1576
|
+
op.op_full = session.funclist.C_Encrypt
|
|
1577
|
+
return op
|
|
1578
|
+
|
|
1579
|
+
@staticmethod
|
|
1580
|
+
cdef DataCryptOperation setup_decrypt(
|
|
1581
|
+
Session session,
|
|
1582
|
+
MechanismWithParam mech,
|
|
1583
|
+
CK_OBJECT_HANDLE key,
|
|
1584
|
+
CK_ULONG buffer_size
|
|
1585
|
+
) with gil:
|
|
1586
|
+
cdef DataCryptOperation op = <DataCryptOperation> KeyOperation._common_key_setup(
|
|
1587
|
+
DataCryptOperation, session, mech, key, buffer_size
|
|
1588
|
+
)
|
|
1589
|
+
op.op_init = session.funclist.C_DecryptInit
|
|
1590
|
+
op.op_update = session.funclist.C_DecryptUpdate
|
|
1591
|
+
op.op_final = session.funclist.C_DecryptFinal
|
|
1592
|
+
op.op_full = session.funclist.C_Decrypt
|
|
1593
|
+
return op
|
|
1594
|
+
|
|
1595
|
+
cdef bytes crypt_process_fully(self, CK_BYTE *data, CK_ULONG data_len) with gil:
|
|
1596
|
+
return self.process_fully(self.op_full, data, data_len)
|
|
1597
|
+
|
|
1598
|
+
cdef bytes finish(self) with gil:
|
|
1599
|
+
return self.finish_with_output(self.op_final)
|
|
1600
|
+
|
|
1601
|
+
def unclean_shutdown(self):
|
|
1602
|
+
self.execute_resizing_output(self.op_final)
|
|
1603
|
+
|
|
1604
|
+
def update_chunks(self, chunks):
|
|
1605
|
+
cdef CK_BYTE *data_ptr
|
|
1606
|
+
cdef CK_ULONG data_len
|
|
1607
|
+
|
|
1608
|
+
for chunk in chunks:
|
|
1609
|
+
if not chunk:
|
|
1610
|
+
continue
|
|
1611
|
+
data_ptr = chunk
|
|
1612
|
+
data_len = <CK_ULONG> len(chunk)
|
|
1613
|
+
yield self.update_with_result(self.op_update, data_ptr, data_len)
|
|
1614
|
+
|
|
1615
|
+
|
|
1616
|
+
class EncryptMixin(types.EncryptMixin):
|
|
1617
|
+
"""Expand EncryptMixin with an implementation."""
|
|
1618
|
+
|
|
1619
|
+
def __encrypt_operation(self, mechanism, mechanism_param, buffer_size):
|
|
1620
|
+
|
|
1621
|
+
mech = MechanismWithParam(self.key_type, DEFAULT_ENCRYPT_MECHANISMS, mechanism, mechanism_param)
|
|
1622
|
+
|
|
1623
|
+
return DataCryptOperation.setup_encrypt(self.session, mech, self.handle, buffer_size)
|
|
1624
|
+
|
|
1625
|
+
def _encrypt(self, data, mechanism=None, mechanism_param=None, buffer_size=8192):
|
|
1626
|
+
"""
|
|
1627
|
+
Non chunking encrypt. Needed for some mechanisms.
|
|
1628
|
+
"""
|
|
1629
|
+
cdef CK_BYTE *data_ptr = data
|
|
1630
|
+
cdef CK_ULONG data_len = <CK_ULONG> len(data)
|
|
1631
|
+
|
|
1632
|
+
cdef DataCryptOperation op = self.__encrypt_operation(mechanism, mechanism_param, buffer_size)
|
|
1633
|
+
with op:
|
|
1634
|
+
return op.crypt_process_fully(data, data_len)
|
|
1635
|
+
|
|
1636
|
+
|
|
1637
|
+
def _encrypt_generator(self, data,
|
|
1638
|
+
mechanism=None, mechanism_param=None,
|
|
1639
|
+
buffer_size=8192):
|
|
1640
|
+
"""
|
|
1641
|
+
Do chunked encryption.
|
|
1642
|
+
"""
|
|
1643
|
+
cdef DataCryptOperation op = self.__encrypt_operation(mechanism, mechanism_param, buffer_size)
|
|
1644
|
+
with op:
|
|
1645
|
+
yield from op.update_chunks(data)
|
|
1646
|
+
yield op.finish()
|
|
1647
|
+
|
|
1648
|
+
|
|
1649
|
+
class DecryptMixin(types.DecryptMixin):
|
|
1650
|
+
"""Expand DecryptMixin with an implementation."""
|
|
1651
|
+
|
|
1652
|
+
def __decrypt_operation(self, mechanism, mechanism_param, buffer_size):
|
|
1653
|
+
|
|
1654
|
+
mech = MechanismWithParam(self.key_type, DEFAULT_ENCRYPT_MECHANISMS, mechanism, mechanism_param)
|
|
1655
|
+
|
|
1656
|
+
return DataCryptOperation.setup_decrypt(self.session, mech, self.handle, buffer_size)
|
|
1657
|
+
|
|
1658
|
+
def _decrypt(self, data, mechanism=None, mechanism_param=None, pin=None, buffer_size=8192):
|
|
1659
|
+
"""Non chunking decrypt."""
|
|
1660
|
+
cdef Session session = self.session
|
|
1661
|
+
cdef CK_BYTE *data_ptr = data
|
|
1662
|
+
cdef CK_ULONG data_len = <CK_ULONG> len(data)
|
|
1663
|
+
|
|
1664
|
+
cdef DataCryptOperation op = self.__decrypt_operation(mechanism, mechanism_param, buffer_size)
|
|
1665
|
+
with op:
|
|
1666
|
+
if pin is not None:
|
|
1667
|
+
session.reaffirm_credentials(pin)
|
|
1668
|
+
return op.crypt_process_fully(data, data_len)
|
|
1669
|
+
|
|
1670
|
+
|
|
1671
|
+
def _decrypt_generator(self, data,
|
|
1672
|
+
mechanism=None, mechanism_param=None, pin=None,
|
|
1673
|
+
buffer_size=8192):
|
|
1674
|
+
"""
|
|
1675
|
+
Chunking decrypt.
|
|
1676
|
+
"""
|
|
1677
|
+
cdef Session session = self.session
|
|
1678
|
+
|
|
1679
|
+
cdef DataCryptOperation op = self.__decrypt_operation(mechanism, mechanism_param, buffer_size)
|
|
1680
|
+
with op:
|
|
1681
|
+
if pin is not None:
|
|
1682
|
+
session.reaffirm_credentials(pin)
|
|
1683
|
+
yield from op.update_chunks(data)
|
|
1684
|
+
yield op.finish()
|
|
1685
|
+
|
|
1686
|
+
|
|
1687
|
+
cdef class SignOrVerifyOperation(KeyOperation):
|
|
1688
|
+
cdef OperationUpdate op_update
|
|
1689
|
+
|
|
1690
|
+
def ingest_chunks(self, chunks):
|
|
1691
|
+
cdef Session session = self.session
|
|
1692
|
+
cdef CK_BYTE *data_ptr
|
|
1693
|
+
cdef CK_ULONG data_len
|
|
1694
|
+
|
|
1695
|
+
for chunk in chunks:
|
|
1696
|
+
if not chunk:
|
|
1697
|
+
continue
|
|
1698
|
+
data_ptr = chunk
|
|
1699
|
+
data_len = <CK_ULONG> len(chunk)
|
|
1700
|
+
self.update_no_output(self.op_update, data_ptr, data_len)
|
|
1701
|
+
|
|
1702
|
+
|
|
1703
|
+
cdef class DataSignOperation(SignOrVerifyOperation):
|
|
1704
|
+
|
|
1705
|
+
@staticmethod
|
|
1706
|
+
cdef DataSignOperation setup(
|
|
1707
|
+
Session session,
|
|
1708
|
+
MechanismWithParam mech,
|
|
1709
|
+
CK_OBJECT_HANDLE key,
|
|
1710
|
+
CK_ULONG buffer_size
|
|
1711
|
+
) with gil:
|
|
1712
|
+
cdef DataSignOperation op = <DataSignOperation> KeyOperation._common_key_setup(
|
|
1713
|
+
DataSignOperation, session, mech, key, buffer_size
|
|
1714
|
+
)
|
|
1715
|
+
op.op_init = session.funclist.C_SignInit
|
|
1716
|
+
op.op_update = session.funclist.C_SignUpdate
|
|
1717
|
+
return op
|
|
1718
|
+
|
|
1719
|
+
cdef bytes sign_process_fully(self, CK_BYTE *data, CK_ULONG data_len) with gil:
|
|
1720
|
+
cdef Session session = self.session
|
|
1721
|
+
return self.process_fully(session.funclist.C_Sign, data, data_len)
|
|
1722
|
+
|
|
1723
|
+
cdef bytes finish(self) with gil:
|
|
1724
|
+
cdef Session session = self.session
|
|
1725
|
+
return self.finish_with_output(session.funclist.C_SignFinal)
|
|
1726
|
+
|
|
1727
|
+
def unclean_shutdown(self):
|
|
1728
|
+
cdef Session session = self.session
|
|
1729
|
+
self.execute_resizing_output(session.funclist.C_SignFinal)
|
|
1730
|
+
|
|
1731
|
+
|
|
1732
|
+
class SignMixin(types.SignMixin):
|
|
1733
|
+
"""Expand SignMixin with an implementation."""
|
|
1734
|
+
|
|
1735
|
+
def __sign_operation(self, mechanism, mechanism_param, buffer_size):
|
|
1736
|
+
mech = MechanismWithParam(self.key_type, DEFAULT_SIGN_MECHANISMS, mechanism, mechanism_param)
|
|
1737
|
+
return DataSignOperation.setup(self.session, mech, self.handle, buffer_size)
|
|
1738
|
+
|
|
1739
|
+
def _sign(self, data,
|
|
1740
|
+
mechanism=None, mechanism_param=None, pin=None, buffer_size=8192):
|
|
1741
|
+
cdef Session session = self.session
|
|
1742
|
+
cdef CK_BYTE *data_ptr = data
|
|
1743
|
+
cdef CK_ULONG data_len = <CK_ULONG> len(data)
|
|
1744
|
+
cdef DataSignOperation op = self.__sign_operation(mechanism, mechanism_param, buffer_size)
|
|
1745
|
+
|
|
1746
|
+
with op:
|
|
1747
|
+
if pin is not None:
|
|
1748
|
+
session.reaffirm_credentials(pin)
|
|
1749
|
+
return op.sign_process_fully(data, data_len)
|
|
1750
|
+
|
|
1751
|
+
def _sign_generator(self, data,
|
|
1752
|
+
mechanism=None, mechanism_param=None, pin=None, buffer_size=8192):
|
|
1753
|
+
|
|
1754
|
+
cdef Session session = self.session
|
|
1755
|
+
cdef DataSignOperation op = self.__sign_operation(mechanism, mechanism_param, buffer_size)
|
|
1756
|
+
with op:
|
|
1757
|
+
if pin is not None:
|
|
1758
|
+
session.reaffirm_credentials(pin)
|
|
1759
|
+
op.ingest_chunks(data)
|
|
1760
|
+
return op.finish()
|
|
1761
|
+
|
|
1762
|
+
|
|
1763
|
+
cdef class DataVerifyOperation(SignOrVerifyOperation):
|
|
1764
|
+
|
|
1765
|
+
@staticmethod
|
|
1766
|
+
cdef DataVerifyOperation setup(
|
|
1767
|
+
Session session,
|
|
1768
|
+
MechanismWithParam mech,
|
|
1769
|
+
CK_OBJECT_HANDLE key
|
|
1770
|
+
) with gil:
|
|
1771
|
+
cdef DataVerifyOperation op = <DataVerifyOperation> KeyOperation._common_key_setup(
|
|
1772
|
+
DataVerifyOperation, session, mech, key, 0
|
|
1773
|
+
)
|
|
1774
|
+
op.op_init = session.funclist.C_VerifyInit
|
|
1775
|
+
op.op_update = session.funclist.C_VerifyUpdate
|
|
1776
|
+
return op
|
|
1777
|
+
|
|
1778
|
+
cdef verify_process_fully(
|
|
1779
|
+
self,
|
|
1780
|
+
CK_BYTE *data,
|
|
1781
|
+
CK_ULONG data_len,
|
|
1782
|
+
CK_BYTE *sig,
|
|
1783
|
+
CK_ULONG sig_len,
|
|
1784
|
+
) with gil:
|
|
1785
|
+
cdef Session session = self.session
|
|
1786
|
+
cdef CK_RV retval
|
|
1787
|
+
with nogil:
|
|
1788
|
+
retval = session.funclist.C_Verify(session.handle, data, data_len, sig, sig_len)
|
|
1789
|
+
self._handle_final_retval(retval)
|
|
1790
|
+
|
|
1791
|
+
cdef finish(self, CK_BYTE *sig, CK_ULONG sig_len) with gil:
|
|
1792
|
+
cdef Session session = self.session
|
|
1793
|
+
cdef CK_RV retval
|
|
1794
|
+
with nogil:
|
|
1795
|
+
retval = session.funclist.C_VerifyFinal(session.handle, sig, sig_len)
|
|
1796
|
+
self._handle_final_retval(retval)
|
|
1797
|
+
|
|
1798
|
+
def unclean_shutdown(self):
|
|
1799
|
+
cdef Session session = self.session
|
|
1800
|
+
cdef CK_BYTE dummy = 0
|
|
1801
|
+
with nogil:
|
|
1802
|
+
session.funclist.C_VerifyFinal(session.handle, &dummy, 0)
|
|
1803
|
+
|
|
1804
|
+
|
|
1805
|
+
class VerifyMixin(types.VerifyMixin):
|
|
1806
|
+
"""Expand VerifyMixin with an implementation."""
|
|
1807
|
+
|
|
1808
|
+
def __verify_operation(self, mechanism, mechanism_param):
|
|
1809
|
+
mech = MechanismWithParam(self.key_type, DEFAULT_SIGN_MECHANISMS, mechanism, mechanism_param)
|
|
1810
|
+
return DataVerifyOperation.setup(self.session, mech, self.handle)
|
|
1811
|
+
|
|
1812
|
+
def _verify(self, data, signature,
|
|
1813
|
+
mechanism=None, mechanism_param=None):
|
|
1814
|
+
|
|
1815
|
+
cdef CK_BYTE *data_ptr = data
|
|
1816
|
+
cdef CK_ULONG data_len = <CK_ULONG> len(data)
|
|
1817
|
+
cdef CK_BYTE *sig_ptr = signature
|
|
1818
|
+
cdef CK_ULONG sig_len = <CK_ULONG> len(signature)
|
|
1819
|
+
cdef DataVerifyOperation op = self.__verify_operation(mechanism, mechanism_param)
|
|
1820
|
+
|
|
1821
|
+
with op:
|
|
1822
|
+
op.verify_process_fully(data_ptr, data_len, sig_ptr, sig_len)
|
|
1823
|
+
|
|
1824
|
+
def _verify_generator(self, data, signature,
|
|
1825
|
+
mechanism=None, mechanism_param=None):
|
|
1826
|
+
|
|
1827
|
+
cdef CK_BYTE *sig_ptr = signature
|
|
1828
|
+
cdef CK_ULONG sig_len = <CK_ULONG> len(signature)
|
|
1829
|
+
cdef DataVerifyOperation op = self.__verify_operation(mechanism, mechanism_param)
|
|
1830
|
+
|
|
1831
|
+
with op:
|
|
1832
|
+
op.ingest_chunks(data)
|
|
1833
|
+
return op.finish(sig_ptr, sig_len)
|
|
1834
|
+
|
|
1835
|
+
|
|
1836
|
+
class WrapMixin(types.WrapMixin):
|
|
1837
|
+
"""Expand WrapMixin with an implementation."""
|
|
1838
|
+
|
|
1839
|
+
def wrap_key(self, key,
|
|
1840
|
+
mechanism=None, mechanism_param=None):
|
|
1841
|
+
|
|
1842
|
+
if not isinstance(key, types.Key):
|
|
1843
|
+
raise ArgumentsBad("`key` must be a Key.")
|
|
1844
|
+
|
|
1845
|
+
mech = MechanismWithParam(self.key_type, DEFAULT_WRAP_MECHANISMS, mechanism, mechanism_param)
|
|
1846
|
+
|
|
1847
|
+
cdef Session session = self.session
|
|
1848
|
+
cdef CK_MECHANISM *mech_data = mech.data
|
|
1849
|
+
cdef CK_OBJECT_HANDLE wrapping_key = self.handle
|
|
1850
|
+
cdef CK_OBJECT_HANDLE key_to_wrap = key.handle
|
|
1851
|
+
cdef CK_ULONG length
|
|
1852
|
+
cdef CK_RV retval
|
|
1853
|
+
|
|
1854
|
+
# Find out how many bytes we need to allocate
|
|
1855
|
+
with nogil:
|
|
1856
|
+
retval = session.funclist.C_WrapKey(session.handle, mech_data, wrapping_key, key_to_wrap, NULL, &length)
|
|
1857
|
+
assertRV(retval)
|
|
1858
|
+
|
|
1859
|
+
cdef CK_BYTE [:] data = CK_BYTE_buffer(length)
|
|
1860
|
+
|
|
1861
|
+
with nogil:
|
|
1862
|
+
retval = session.funclist.C_WrapKey(session.handle, mech_data, wrapping_key, key_to_wrap, &data[0], &length)
|
|
1863
|
+
assertRV(retval)
|
|
1864
|
+
|
|
1865
|
+
return bytes(data[:length])
|
|
1866
|
+
|
|
1867
|
+
|
|
1868
|
+
class UnwrapMixin(types.UnwrapMixin):
|
|
1869
|
+
"""Expand UnwrapMixin with an implementation."""
|
|
1870
|
+
|
|
1871
|
+
def unwrap_key(self, object_class, key_type, key_data,
|
|
1872
|
+
id=None, label=None,
|
|
1873
|
+
mechanism=None, mechanism_param=None,
|
|
1874
|
+
store=False, capabilities=None,
|
|
1875
|
+
template=None):
|
|
1876
|
+
|
|
1877
|
+
if not isinstance(object_class, ObjectClass):
|
|
1878
|
+
raise ArgumentsBad("`object_class` must be ObjectClass.")
|
|
1879
|
+
|
|
1880
|
+
_check_key_type(key_type)
|
|
1881
|
+
capabilities = _resolve_capabilities(key_type, capabilities)
|
|
1882
|
+
|
|
1883
|
+
mech = MechanismWithParam(self.key_type, DEFAULT_WRAP_MECHANISMS, mechanism, mechanism_param)
|
|
1884
|
+
|
|
1885
|
+
cdef Session session = self.session
|
|
1886
|
+
|
|
1887
|
+
# Build attributes
|
|
1888
|
+
template_ = session.attribute_mapper.generic_key_template(
|
|
1889
|
+
{
|
|
1890
|
+
Attribute.CLASS: object_class,
|
|
1891
|
+
Attribute.KEY_TYPE: key_type,
|
|
1892
|
+
},
|
|
1893
|
+
id_=id,
|
|
1894
|
+
label=label,
|
|
1895
|
+
store=store,
|
|
1896
|
+
capabilities=capabilities,
|
|
1897
|
+
)
|
|
1898
|
+
cdef AttributeList attrs = session.make_attribute_list(merge_templates(template_, template))
|
|
1899
|
+
cdef CK_MECHANISM *mech_data = mech.data
|
|
1900
|
+
cdef CK_OBJECT_HANDLE unwrapping_key = self.handle
|
|
1901
|
+
cdef CK_BYTE *wrapped_key_ptr = key_data
|
|
1902
|
+
cdef CK_ULONG wrapped_key_len = <CK_ULONG> len(key_data)
|
|
1903
|
+
cdef CK_ATTRIBUTE *attr_data = attrs.data
|
|
1904
|
+
cdef CK_ULONG attr_count = attrs.count
|
|
1905
|
+
cdef CK_OBJECT_HANDLE key
|
|
1906
|
+
cdef CK_RV retval
|
|
1907
|
+
|
|
1908
|
+
with nogil:
|
|
1909
|
+
retval = session.funclist.C_UnwrapKey(session.handle, mech_data, unwrapping_key, wrapped_key_ptr, wrapped_key_len, attr_data, attr_count, &key)
|
|
1910
|
+
assertRV(retval)
|
|
1911
|
+
|
|
1912
|
+
return make_object(session, key)
|
|
1913
|
+
|
|
1914
|
+
|
|
1915
|
+
class DeriveMixin(types.DeriveMixin):
|
|
1916
|
+
"""Expand DeriveMixin with an implementation."""
|
|
1917
|
+
|
|
1918
|
+
def derive_key(self, key_type, key_length,
|
|
1919
|
+
id=None, label=None,
|
|
1920
|
+
store=False, capabilities=None,
|
|
1921
|
+
mechanism=None, mechanism_param=None,
|
|
1922
|
+
template=None):
|
|
1923
|
+
|
|
1924
|
+
_check_key_type(key_type)
|
|
1925
|
+
_check_bit_length(key_length, "key_length", required=True)
|
|
1926
|
+
capabilities = _resolve_capabilities(key_type, capabilities)
|
|
1927
|
+
|
|
1928
|
+
mech = MechanismWithParam(self.key_type, DEFAULT_DERIVE_MECHANISMS, mechanism, mechanism_param)
|
|
1929
|
+
|
|
1930
|
+
cdef Session session = self.session
|
|
1931
|
+
|
|
1932
|
+
template_ = session.attribute_mapper.secret_key_template(
|
|
1933
|
+
capabilities=capabilities, id_=id, label=label, store=store,
|
|
1934
|
+
)
|
|
1935
|
+
template_[Attribute.KEY_TYPE] = key_type
|
|
1936
|
+
template_[Attribute.VALUE_LEN] = key_length // 8 # In bytes
|
|
1937
|
+
cdef AttributeList attrs = session.make_attribute_list(merge_templates(template_, template))
|
|
1938
|
+
cdef CK_MECHANISM *mech_data = mech.data
|
|
1939
|
+
cdef CK_OBJECT_HANDLE src_key = self.handle
|
|
1940
|
+
cdef CK_ATTRIBUTE *attr_data = attrs.data
|
|
1941
|
+
cdef CK_ULONG attr_count = attrs.count
|
|
1942
|
+
cdef CK_OBJECT_HANDLE key
|
|
1943
|
+
cdef CK_RV retval
|
|
1944
|
+
|
|
1945
|
+
with nogil:
|
|
1946
|
+
retval = session.funclist.C_DeriveKey(session.handle, mech_data, src_key, attr_data, attr_count, &key)
|
|
1947
|
+
assertRV(retval)
|
|
1948
|
+
|
|
1949
|
+
return make_object(session, key)
|
|
1950
|
+
|
|
1951
|
+
|
|
1952
|
+
class EncapsulateMixin(types.EncapsulateMixin):
|
|
1953
|
+
"""Expand EncapsulateMixin with an implementation (ML-KEM)."""
|
|
1954
|
+
|
|
1955
|
+
def encapsulate_key(self, key_type,
|
|
1956
|
+
key_length=None,
|
|
1957
|
+
id=None, label=None,
|
|
1958
|
+
store=False, capabilities=None,
|
|
1959
|
+
mechanism=None, mechanism_param=None,
|
|
1960
|
+
template=None):
|
|
1961
|
+
|
|
1962
|
+
_check_key_type(key_type)
|
|
1963
|
+
capabilities = _resolve_capabilities(key_type, capabilities)
|
|
1964
|
+
|
|
1965
|
+
mech = MechanismWithParam(self.key_type, DEFAULT_ENCAPSULATE_MECHANISMS, mechanism, mechanism_param)
|
|
1966
|
+
|
|
1967
|
+
cdef Session session = self.session
|
|
1968
|
+
|
|
1969
|
+
if session.funclist32 == NULL:
|
|
1970
|
+
raise FunctionNotSupported("C_EncapsulateKey requires a PKCS#11 v3.2+ library")
|
|
1971
|
+
|
|
1972
|
+
template_ = session.attribute_mapper.secret_key_template(
|
|
1973
|
+
capabilities=capabilities, id_=id, label=label, store=store,
|
|
1974
|
+
)
|
|
1975
|
+
if key_length is not None:
|
|
1976
|
+
template_[Attribute.VALUE_LEN] = key_length // 8
|
|
1977
|
+
template_[Attribute.KEY_TYPE] = key_type
|
|
1978
|
+
cdef AttributeList attrs = session.make_attribute_list(merge_templates(template_, template))
|
|
1979
|
+
cdef CK_MECHANISM *mech_data = mech.data
|
|
1980
|
+
cdef CK_OBJECT_HANDLE pub_key = self.handle
|
|
1981
|
+
cdef CK_ATTRIBUTE *attr_data = attrs.data
|
|
1982
|
+
cdef CK_ULONG attr_count = attrs.count
|
|
1983
|
+
cdef CK_ULONG ct_len = 0
|
|
1984
|
+
cdef CK_OBJECT_HANDLE ss_handle
|
|
1985
|
+
cdef CK_RV retval
|
|
1986
|
+
|
|
1987
|
+
with nogil:
|
|
1988
|
+
retval = session.funclist32.C_EncapsulateKey(
|
|
1989
|
+
session.handle, mech_data, pub_key,
|
|
1990
|
+
attr_data, attr_count, NULL, &ct_len, &ss_handle)
|
|
1991
|
+
assertRV(retval)
|
|
1992
|
+
|
|
1993
|
+
cdef CK_BYTE [:] ct_buf = CK_BYTE_buffer(ct_len)
|
|
1994
|
+
|
|
1995
|
+
with nogil:
|
|
1996
|
+
retval = session.funclist32.C_EncapsulateKey(
|
|
1997
|
+
session.handle, mech_data, pub_key,
|
|
1998
|
+
attr_data, attr_count, &ct_buf[0], &ct_len, &ss_handle)
|
|
1999
|
+
assertRV(retval)
|
|
2000
|
+
|
|
2001
|
+
return (bytes(ct_buf[:ct_len]), make_object(session, ss_handle))
|
|
2002
|
+
|
|
2003
|
+
|
|
2004
|
+
class DecapsulateMixin(types.DecapsulateMixin):
|
|
2005
|
+
"""Expand DecapsulateMixin with an implementation (ML-KEM)."""
|
|
2006
|
+
|
|
2007
|
+
def decapsulate_key(self, ciphertext, key_type,
|
|
2008
|
+
key_length=None,
|
|
2009
|
+
id=None, label=None,
|
|
2010
|
+
store=False, capabilities=None,
|
|
2011
|
+
mechanism=None, mechanism_param=None,
|
|
2012
|
+
template=None):
|
|
2013
|
+
|
|
2014
|
+
_check_key_type(key_type)
|
|
2015
|
+
capabilities = _resolve_capabilities(key_type, capabilities)
|
|
2016
|
+
|
|
2017
|
+
mech = MechanismWithParam(self.key_type, DEFAULT_ENCAPSULATE_MECHANISMS, mechanism, mechanism_param)
|
|
2018
|
+
|
|
2019
|
+
cdef Session session = self.session
|
|
2020
|
+
|
|
2021
|
+
if session.funclist32 == NULL:
|
|
2022
|
+
raise FunctionNotSupported("C_DecapsulateKey requires a PKCS#11 v3.2+ library")
|
|
2023
|
+
|
|
2024
|
+
template_ = session.attribute_mapper.secret_key_template(
|
|
2025
|
+
capabilities=capabilities, id_=id, label=label, store=store,
|
|
2026
|
+
)
|
|
2027
|
+
if key_length is not None:
|
|
2028
|
+
template_[Attribute.VALUE_LEN] = key_length // 8
|
|
2029
|
+
template_[Attribute.KEY_TYPE] = key_type
|
|
2030
|
+
cdef AttributeList attrs = session.make_attribute_list(merge_templates(template_, template))
|
|
2031
|
+
cdef CK_MECHANISM *mech_data = mech.data
|
|
2032
|
+
cdef CK_OBJECT_HANDLE priv_key = self.handle
|
|
2033
|
+
cdef CK_BYTE *ct_ptr = ciphertext
|
|
2034
|
+
cdef CK_ULONG ct_len = <CK_ULONG> len(ciphertext)
|
|
2035
|
+
cdef CK_ATTRIBUTE *attr_data = attrs.data
|
|
2036
|
+
cdef CK_ULONG attr_count = attrs.count
|
|
2037
|
+
cdef CK_OBJECT_HANDLE key
|
|
2038
|
+
cdef CK_RV retval
|
|
2039
|
+
|
|
2040
|
+
with nogil:
|
|
2041
|
+
retval = session.funclist32.C_DecapsulateKey(
|
|
2042
|
+
session.handle, mech_data, priv_key,
|
|
2043
|
+
attr_data, attr_count, ct_ptr, ct_len, &key)
|
|
2044
|
+
assertRV(retval)
|
|
2045
|
+
|
|
2046
|
+
return make_object(session, key)
|
|
2047
|
+
|
|
2048
|
+
|
|
2049
|
+
_CLASS_MAP = {
|
|
2050
|
+
ObjectClass.SECRET_KEY: SecretKey,
|
|
2051
|
+
ObjectClass.PUBLIC_KEY: PublicKey,
|
|
2052
|
+
ObjectClass.PRIVATE_KEY: PrivateKey,
|
|
2053
|
+
ObjectClass.DOMAIN_PARAMETERS: StoredDomainParameters,
|
|
2054
|
+
ObjectClass.CERTIFICATE: Certificate,
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
cdef extern from "../extern/load_module.c":
|
|
2058
|
+
ctypedef struct P11_HANDLE:
|
|
2059
|
+
void *get_function_list_ptr
|
|
2060
|
+
void *get_interface_ptr
|
|
2061
|
+
|
|
2062
|
+
object p11_error()
|
|
2063
|
+
P11_HANDLE* p11_open(object path_str)
|
|
2064
|
+
int p11_close(P11_HANDLE* handle)
|
|
2065
|
+
|
|
2066
|
+
|
|
2067
|
+
cdef class lib(HasFuncList):
|
|
2068
|
+
"""
|
|
2069
|
+
Main entry point.
|
|
2070
|
+
|
|
2071
|
+
This class needs to be defined cdef, so it can't shadow a class in
|
|
2072
|
+
pkcs11.types.
|
|
2073
|
+
"""
|
|
2074
|
+
|
|
2075
|
+
cdef readonly str so
|
|
2076
|
+
cdef readonly str manufacturer_id
|
|
2077
|
+
cdef readonly str library_description
|
|
2078
|
+
cdef readonly bint initialized
|
|
2079
|
+
cdef CK_VERSION _cryptoki_version
|
|
2080
|
+
cdef CK_VERSION _library_version
|
|
2081
|
+
cdef P11_HANDLE *_p11_handle
|
|
2082
|
+
|
|
2083
|
+
cdef _load_pkcs11_lib(self, so) with gil:
|
|
2084
|
+
"""Load a PKCS#11 library, and extract function calls.
|
|
2085
|
+
|
|
2086
|
+
This method will dynamically load a PKCS11 library, and attempt to
|
|
2087
|
+
resolve the symbol 'C_GetFunctionList()'. Once found, the entry point
|
|
2088
|
+
is called to populate an internal table of function pointers.
|
|
2089
|
+
|
|
2090
|
+
This is a private method, and must never be called directly.
|
|
2091
|
+
Called when a new lib class is instantiated.
|
|
2092
|
+
|
|
2093
|
+
:param so: the path to a valid PKCS#11 library
|
|
2094
|
+
:type so: str
|
|
2095
|
+
:raises: PKCS11Error
|
|
2096
|
+
:rtype: None
|
|
2097
|
+
"""
|
|
2098
|
+
|
|
2099
|
+
# to keep a pointer to the C_GetFunctionList address returned by dlsym()
|
|
2100
|
+
cdef C_GetFunctionList_ptr populate_function_list
|
|
2101
|
+
cdef CK_RV retval
|
|
2102
|
+
|
|
2103
|
+
cdef P11_HANDLE *handle = p11_open(so)
|
|
2104
|
+
if handle == NULL:
|
|
2105
|
+
err = <str> p11_error()
|
|
2106
|
+
if err:
|
|
2107
|
+
raise PKCS11Error(f"OS exception while loading {so}: {err}")
|
|
2108
|
+
else:
|
|
2109
|
+
raise PKCS11Error(f"Unknown exception while loading {so}")
|
|
2110
|
+
populate_function_list = <C_GetFunctionList_ptr> handle.get_function_list_ptr
|
|
2111
|
+
self._p11_handle = handle
|
|
2112
|
+
|
|
2113
|
+
assertRV(populate_function_list(&self.funclist))
|
|
2114
|
+
|
|
2115
|
+
def __cinit__(self, so):
|
|
2116
|
+
cdef CK_RV retval
|
|
2117
|
+
self._p11_handle = NULL
|
|
2118
|
+
self._load_pkcs11_lib(so)
|
|
2119
|
+
self.initialized = False
|
|
2120
|
+
# at this point, _funclist contains all function pointers to the library
|
|
2121
|
+
|
|
2122
|
+
cpdef initialize(self):
|
|
2123
|
+
cdef CK_RV retval
|
|
2124
|
+
if self.funclist != NULL and not self.initialized:
|
|
2125
|
+
with nogil:
|
|
2126
|
+
retval = self.funclist.C_Initialize(NULL)
|
|
2127
|
+
assertRV(retval)
|
|
2128
|
+
self.initialized = True
|
|
2129
|
+
|
|
2130
|
+
cdef CK_RV _finalize(self):
|
|
2131
|
+
cdef CK_RV retval = CKR_OK
|
|
2132
|
+
if self.funclist != NULL and self.initialized:
|
|
2133
|
+
retval = self.funclist.C_Finalize(NULL)
|
|
2134
|
+
self.initialized = False
|
|
2135
|
+
return retval
|
|
2136
|
+
|
|
2137
|
+
def finalize(self):
|
|
2138
|
+
assertRV(self._finalize())
|
|
2139
|
+
|
|
2140
|
+
def reinitialize(self):
|
|
2141
|
+
if self.funclist != NULL:
|
|
2142
|
+
self.finalize()
|
|
2143
|
+
self.initialize()
|
|
2144
|
+
|
|
2145
|
+
def __init__(self, so):
|
|
2146
|
+
self.so = so
|
|
2147
|
+
cdef CK_INFO info
|
|
2148
|
+
cdef CK_RV retval
|
|
2149
|
+
|
|
2150
|
+
self.initialize()
|
|
2151
|
+
|
|
2152
|
+
with nogil:
|
|
2153
|
+
retval = self.funclist.C_GetInfo(&info)
|
|
2154
|
+
assertRV(retval)
|
|
2155
|
+
|
|
2156
|
+
manufacturerID = info.manufacturerID[:sizeof(info.manufacturerID)]
|
|
2157
|
+
libraryDescription = info.libraryDescription[:sizeof(info.libraryDescription)]
|
|
2158
|
+
|
|
2159
|
+
self.manufacturer_id = _CK_UTF8CHAR_to_str(manufacturerID)
|
|
2160
|
+
self.library_description = _CK_UTF8CHAR_to_str(libraryDescription)
|
|
2161
|
+
self._cryptoki_version = info.cryptokiVersion
|
|
2162
|
+
self._library_version = info.libraryVersion
|
|
2163
|
+
|
|
2164
|
+
cdef C_GetInterface_ptr get_interface
|
|
2165
|
+
cdef CK_INTERFACE *iface
|
|
2166
|
+
cdef CK_VERSION ver
|
|
2167
|
+
if self._p11_handle.get_interface_ptr != NULL:
|
|
2168
|
+
get_interface = <C_GetInterface_ptr>self._p11_handle.get_interface_ptr
|
|
2169
|
+
ver.major = 3
|
|
2170
|
+
ver.minor = 0
|
|
2171
|
+
retval = get_interface(<CK_UTF8CHAR*>"PKCS 11", &ver, &iface, 0)
|
|
2172
|
+
if retval == CKR_OK and iface != NULL:
|
|
2173
|
+
self.funclist30 = <CK_FUNCTION_LIST_3_0*>iface.pFunctionList
|
|
2174
|
+
ver.major = 3
|
|
2175
|
+
ver.minor = 2
|
|
2176
|
+
retval = get_interface(<CK_UTF8CHAR*>"PKCS 11", &ver, &iface, 0)
|
|
2177
|
+
if retval == CKR_OK and iface != NULL:
|
|
2178
|
+
self.funclist32 = <CK_FUNCTION_LIST_3_2*>iface.pFunctionList
|
|
2179
|
+
|
|
2180
|
+
@property
|
|
2181
|
+
def library_version(self):
|
|
2182
|
+
"""Hardware version (:class:`tuple`)."""
|
|
2183
|
+
return _CK_VERSION_to_tuple(self._library_version)
|
|
2184
|
+
|
|
2185
|
+
@property
|
|
2186
|
+
def cryptoki_version(self):
|
|
2187
|
+
"""PKCS#11 (cryptoki) API version (:class:`tuple`)."""
|
|
2188
|
+
return _CK_VERSION_to_tuple(self._cryptoki_version)
|
|
2189
|
+
|
|
2190
|
+
def __str__(self):
|
|
2191
|
+
return '\n'.join((
|
|
2192
|
+
"Library: %s" % self.so,
|
|
2193
|
+
"Manufacturer ID: %s" % self.manufacturer_id,
|
|
2194
|
+
"Library Description: %s" % self.library_description,
|
|
2195
|
+
"Cryptoki Version: %s.%s" % self.cryptoki_version,
|
|
2196
|
+
"Library Version: %s.%s" % self.library_version,
|
|
2197
|
+
))
|
|
2198
|
+
|
|
2199
|
+
def __repr__(self):
|
|
2200
|
+
return '<pkcs11.lib ({so})>'.format(
|
|
2201
|
+
so=self.so)
|
|
2202
|
+
|
|
2203
|
+
|
|
2204
|
+
def get_slots(self, token_present=False):
|
|
2205
|
+
"""Get all slots."""
|
|
2206
|
+
|
|
2207
|
+
cdef CK_BBOOL present = token_present
|
|
2208
|
+
cdef CK_ULONG count
|
|
2209
|
+
cdef CK_RV retval
|
|
2210
|
+
|
|
2211
|
+
with nogil:
|
|
2212
|
+
retval = self.funclist.C_GetSlotList(present, NULL, &count)
|
|
2213
|
+
assertRV(retval)
|
|
2214
|
+
|
|
2215
|
+
if count == 0:
|
|
2216
|
+
return []
|
|
2217
|
+
|
|
2218
|
+
cdef CK_SLOT_ID [:] slot_list = CK_ULONG_buffer(count)
|
|
2219
|
+
|
|
2220
|
+
with nogil:
|
|
2221
|
+
retval = self.funclist.C_GetSlotList(present, &slot_list[0], &count)
|
|
2222
|
+
assertRV(retval)
|
|
2223
|
+
|
|
2224
|
+
cdef CK_SLOT_ID slot_id
|
|
2225
|
+
cdef CK_SLOT_INFO info
|
|
2226
|
+
|
|
2227
|
+
slots = []
|
|
2228
|
+
|
|
2229
|
+
for slot_id in slot_list:
|
|
2230
|
+
with nogil:
|
|
2231
|
+
retval = self.funclist.C_GetSlotInfo(slot_id, &info)
|
|
2232
|
+
assertRV(retval)
|
|
2233
|
+
|
|
2234
|
+
slot = Slot.make(self.funclist, slot_id, info, self._cryptoki_version)
|
|
2235
|
+
slot.funclist30 = self.funclist30
|
|
2236
|
+
slot.funclist32 = self.funclist32
|
|
2237
|
+
slots.append(slot)
|
|
2238
|
+
|
|
2239
|
+
return slots
|
|
2240
|
+
|
|
2241
|
+
|
|
2242
|
+
def get_tokens(self,
|
|
2243
|
+
token_label=None,
|
|
2244
|
+
token_serial=None,
|
|
2245
|
+
token_flags=None,
|
|
2246
|
+
slot_flags=None,
|
|
2247
|
+
mechanisms=None):
|
|
2248
|
+
"""Search for a token matching the parameters."""
|
|
2249
|
+
|
|
2250
|
+
for slot in self.get_slots():
|
|
2251
|
+
try:
|
|
2252
|
+
token = slot.get_token()
|
|
2253
|
+
token_mechanisms = slot.get_mechanisms()
|
|
2254
|
+
|
|
2255
|
+
if token_label is not None and \
|
|
2256
|
+
token.label != token_label:
|
|
2257
|
+
continue
|
|
2258
|
+
|
|
2259
|
+
if token_serial is not None and \
|
|
2260
|
+
token.serial != token_serial:
|
|
2261
|
+
continue
|
|
2262
|
+
|
|
2263
|
+
if token_flags is not None and \
|
|
2264
|
+
not token.flags & token_flags:
|
|
2265
|
+
continue
|
|
2266
|
+
|
|
2267
|
+
if slot_flags is not None and \
|
|
2268
|
+
not slot.flags & slot_flags:
|
|
2269
|
+
continue
|
|
2270
|
+
|
|
2271
|
+
if mechanisms is not None and \
|
|
2272
|
+
set(mechanisms) not in token_mechanisms:
|
|
2273
|
+
continue
|
|
2274
|
+
|
|
2275
|
+
yield token
|
|
2276
|
+
except (TokenNotPresent, TokenNotRecognised):
|
|
2277
|
+
continue
|
|
2278
|
+
|
|
2279
|
+
def get_token(self, **kwargs):
|
|
2280
|
+
"""Get a single token."""
|
|
2281
|
+
iterator = self.get_tokens(**kwargs)
|
|
2282
|
+
|
|
2283
|
+
try:
|
|
2284
|
+
token = next(iterator)
|
|
2285
|
+
except StopIteration:
|
|
2286
|
+
raise NoSuchToken("No token matching %s" % kwargs)
|
|
2287
|
+
|
|
2288
|
+
try:
|
|
2289
|
+
next(iterator)
|
|
2290
|
+
raise MultipleTokensReturned(
|
|
2291
|
+
"More than 1 token matches %s" % kwargs)
|
|
2292
|
+
except StopIteration:
|
|
2293
|
+
return token
|
|
2294
|
+
|
|
2295
|
+
def wait_for_slot_event(self, blocking=True):
|
|
2296
|
+
cdef CK_SLOT_ID slot_id
|
|
2297
|
+
cdef CK_FLAGS flag = 0
|
|
2298
|
+
cdef CK_RV retval
|
|
2299
|
+
|
|
2300
|
+
if not blocking:
|
|
2301
|
+
flag |= CKF_DONT_BLOCK
|
|
2302
|
+
|
|
2303
|
+
with nogil:
|
|
2304
|
+
retval = self.funclist.C_WaitForSlotEvent(flag, &slot_id, NULL)
|
|
2305
|
+
assertRV(retval)
|
|
2306
|
+
|
|
2307
|
+
cdef CK_SLOT_INFO info
|
|
2308
|
+
|
|
2309
|
+
with nogil:
|
|
2310
|
+
retval = self.funclist.C_GetSlotInfo(slot_id, &info)
|
|
2311
|
+
assertRV(retval)
|
|
2312
|
+
|
|
2313
|
+
slotDescription = info.slotDescription[:sizeof(info.slotDescription)]
|
|
2314
|
+
manufacturerID = info.manufacturerID[:sizeof(info.manufacturerID)]
|
|
2315
|
+
|
|
2316
|
+
return Slot(self, slot_id, slotDescription, manufacturerID,
|
|
2317
|
+
info.hardwareVersion, info.firmwareVersion, info.flags)
|
|
2318
|
+
|
|
2319
|
+
def unload(self):
|
|
2320
|
+
self._finalize()
|
|
2321
|
+
self.funclist = NULL
|
|
2322
|
+
if self._p11_handle != NULL:
|
|
2323
|
+
p11_close(self._p11_handle)
|
|
2324
|
+
self._p11_handle = NULL
|
|
2325
|
+
|
|
2326
|
+
def __dealloc__(self):
|
|
2327
|
+
self.unload()
|