1 // Copyright (c) 2017 Ryan Leckey
2 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 // SOFTWARE.
9 
10 #include "common.h"
11 #include "platform.h"
12 #include "exception.h"
13 #include "constants.h"
14 #include "keys.h"
15 #include "lxml.h"
16 
17 #include <xmlsec/xmldsig.h>
18 
19 typedef struct {
20     PyObject_HEAD
21     xmlSecDSigCtxPtr handle;
22     PyXmlSec_KeysManager* manager;
23 } PyXmlSec_SignatureContext;
24 
PyXmlSec_SignatureContext__new__(PyTypeObject * type,PyObject * args,PyObject * kwargs)25 static PyObject* PyXmlSec_SignatureContext__new__(PyTypeObject *type, PyObject *args, PyObject *kwargs) {
26     PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)PyType_GenericNew(type, args, kwargs);
27     PYXMLSEC_DEBUGF("%p: new sign context", ctx);
28     if (ctx != NULL) {
29         ctx->handle = NULL;
30         ctx->manager = NULL;
31     }
32     return (PyObject*)(ctx);
33 }
34 
PyXmlSec_SignatureContext__init__(PyObject * self,PyObject * args,PyObject * kwargs)35 static int PyXmlSec_SignatureContext__init__(PyObject* self, PyObject* args, PyObject* kwargs) {
36     static char *kwlist[] = { "manager", NULL};
37     PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self;
38     PyXmlSec_KeysManager* manager = NULL;
39 
40     PYXMLSEC_DEBUGF("%p: init sign context", self);
41     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&:__init__", kwlist, PyXmlSec_KeysManagerConvert, &manager)) {
42         goto ON_FAIL;
43     }
44     ctx->handle = xmlSecDSigCtxCreate(manager != NULL ? manager->handle : NULL);
45     if (ctx->handle == NULL) {
46         PyXmlSec_SetLastError("failed to create the digital signature context");
47         goto ON_FAIL;
48     }
49     ctx->manager = manager;
50     PYXMLSEC_DEBUGF("%p: signMethod: %p", self, ctx->handle->signMethod);
51     PYXMLSEC_DEBUGF("%p: init sign context - ok, manager - %p", self, manager);
52     return 0;
53 ON_FAIL:
54     PYXMLSEC_DEBUGF("%p: init sign context - failed", self);
55     Py_XDECREF(manager);
56     return -1;
57 }
58 
PyXmlSec_SignatureContext__del__(PyObject * self)59 static void PyXmlSec_SignatureContext__del__(PyObject* self) {
60     PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self;
61     PYXMLSEC_DEBUGF("%p: delete sign context", self);
62     if (ctx->handle != NULL) {
63         xmlSecDSigCtxDestroy(ctx->handle);
64     }
65     // release manager object
66     Py_XDECREF(ctx->manager);
67     Py_TYPE(self)->tp_free(self);
68 }
69 
70 static const char PyXmlSec_SignatureContextKey__doc__[] = "Signature key.\n";
PyXmlSec_SignatureContextKeyGet(PyObject * self,void * closure)71 static PyObject* PyXmlSec_SignatureContextKeyGet(PyObject* self, void* closure) {
72     PyXmlSec_SignatureContext* ctx = ((PyXmlSec_SignatureContext*)self);
73     PyXmlSec_Key* key;
74 
75     if (ctx->handle->signKey == NULL) {
76         Py_RETURN_NONE;
77     }
78 
79     key = PyXmlSec_NewKey();
80     key->handle = ctx->handle->signKey;
81     key->is_own = 0;
82     return (PyObject*)key;
83 }
84 
PyXmlSec_SignatureContextKeySet(PyObject * self,PyObject * value,void * closure)85 static int PyXmlSec_SignatureContextKeySet(PyObject* self, PyObject* value, void* closure) {
86     PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self;
87     PyXmlSec_Key* key;
88 
89     PYXMLSEC_DEBUGF("%p, %p", self, value);
90 
91     if (value == NULL) {  // key deletion
92         if (ctx->handle->signKey != NULL) {
93             xmlSecKeyDestroy(ctx->handle->signKey);
94             ctx->handle->signKey = NULL;
95         }
96         return 0;
97     }
98 
99     if (!PyObject_IsInstance(value, (PyObject*)PyXmlSec_KeyType)) {
100         PyErr_SetString(PyExc_TypeError, "instance of *xmlsec.Key* expected.");
101         return -1;
102     }
103     key = (PyXmlSec_Key*)value;
104 
105     if (key->handle == NULL) {
106         PyErr_SetString(PyExc_TypeError, "empty key.");
107         return -1;
108     }
109 
110     if (ctx->handle->signKey != NULL) {
111         xmlSecKeyDestroy(ctx->handle->signKey);
112     }
113 
114     ctx->handle->signKey = xmlSecKeyDuplicate(key->handle);
115     if (ctx->handle->signKey == NULL) {
116         PyXmlSec_SetLastError("failed to duplicate key");
117         return -1;
118     }
119     return 0;
120 }
121 
122 static const char PyXmlSec_SignatureContextRegisterId__doc__[] = \
123     "register_id(node, id_attr = 'ID', id_ns = None) -> None\n"
124     "Registers new id.\n\n"
125     ":param node: the pointer to XML node\n"
126     ":type node: :class:`lxml.etree._Element`\n"
127     ":param id_attr: the attribute\n"
128     ":type id_attr: :class:`str`\n"
129     ":param id_ns: the namespace (optional)\n"
130     ":type id_ns: :class:`str` or :data:`None`";
PyXmlSec_SignatureContextRegisterId(PyObject * self,PyObject * args,PyObject * kwargs)131 static PyObject* PyXmlSec_SignatureContextRegisterId(PyObject* self, PyObject* args, PyObject* kwargs) {
132     static char *kwlist[] = { "node", "id_attr", "id_ns", NULL};
133 
134     PyXmlSec_LxmlElementPtr node = NULL;
135     const char* id_attr = "ID";
136     const char* id_ns = NULL;
137 
138     xmlChar* name = NULL;
139     xmlAttrPtr attr;
140     xmlAttrPtr tmpAttr;
141 
142     PYXMLSEC_DEBUGF("%p: register id - start", self);
143     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|sz:register_id", kwlist,
144         PyXmlSec_LxmlElementConverter, &node, &id_attr, &id_ns))
145     {
146         goto ON_FAIL;
147     }
148 
149     if (id_ns != NULL) {
150         attr = xmlHasNsProp(node->_c_node, XSTR(id_attr), XSTR(id_ns));
151     } else {
152         attr = xmlHasProp(node->_c_node, XSTR(id_attr));
153     }
154 
155     if (attr == NULL || attr->children == NULL) {
156         PyErr_SetString(PyXmlSec_Error, "missing attribute.");
157         goto ON_FAIL;
158     }
159 
160     name = xmlNodeListGetString(node->_c_node->doc, attr->children, 1);
161     tmpAttr = xmlGetID(node->_c_node->doc, name);
162     if (tmpAttr != attr) {
163         if (tmpAttr != NULL) {
164             PyErr_SetString(PyXmlSec_Error, "duplicated id.");
165             goto ON_FAIL;
166         }
167 
168         Py_BEGIN_ALLOW_THREADS;
169         xmlAddID(NULL, node->_c_node->doc, name, attr);
170         Py_END_ALLOW_THREADS;
171     }
172 
173     xmlFree(name);
174     PYXMLSEC_DEBUGF("%p: register id - ok", self);
175     Py_RETURN_NONE;
176 ON_FAIL:
177     xmlFree(name);
178     PYXMLSEC_DEBUGF("%p: register id - fail", self);
179     return NULL;
180 }
181 
182 static const char PyXmlSec_SignatureContextSign__doc__[] = \
183     "sign(node) -> None\n"
184     "Signs according to the signature template.\n\n"
185     ":param node: the pointer to :xml:`<dsig:Signature/>` node with signature template\n"
186     ":type node: :class:`lxml.etree._Element`";
PyXmlSec_SignatureContextSign(PyObject * self,PyObject * args,PyObject * kwargs)187 static PyObject* PyXmlSec_SignatureContextSign(PyObject* self, PyObject* args, PyObject* kwargs) {
188     static char *kwlist[] = { "node", NULL};
189 
190     PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self;
191     PyXmlSec_LxmlElementPtr node = NULL;
192     int rv;
193 
194     PYXMLSEC_DEBUGF("%p: sign - start", self);
195     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:sign", kwlist, PyXmlSec_LxmlElementConverter, &node)) {
196         goto ON_FAIL;
197     }
198 
199     Py_BEGIN_ALLOW_THREADS;
200     rv = xmlSecDSigCtxSign(ctx->handle, node->_c_node);
201     PYXMLSEC_DUMP(xmlSecDSigCtxDebugDump, ctx->handle);
202     Py_END_ALLOW_THREADS;
203     if (rv < 0) {
204         PyXmlSec_SetLastError("failed to sign");
205         goto ON_FAIL;
206     }
207     PYXMLSEC_DEBUGF("%p: sign - ok", self);
208     Py_RETURN_NONE;
209 
210 ON_FAIL:
211     PYXMLSEC_DEBUGF("%p: sign - fail", self);
212     return NULL;
213 }
214 
215 static const char PyXmlSec_SignatureContextVerify__doc__[] = \
216     "verify(node) -> None\n"
217     "Verifies according to the signature template.\n\n"
218     ":param node: the pointer with :xml:`<dsig:Signature/>` node\n"
219     ":type node: :class:`lxml.etree._Element`\n"
220     ":return: :data:`None` on success\n"
221     ":raise VerificationError: on failure\n";
PyXmlSec_SignatureContextVerify(PyObject * self,PyObject * args,PyObject * kwargs)222 static PyObject* PyXmlSec_SignatureContextVerify(PyObject* self, PyObject* args, PyObject* kwargs) {
223     static char *kwlist[] = { "node", NULL};
224 
225     PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self;
226     PyXmlSec_LxmlElementPtr node = NULL;
227     int rv;
228 
229     PYXMLSEC_DEBUGF("%p: verify - start", self);
230     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:verify", kwlist, PyXmlSec_LxmlElementConverter, &node)) {
231         goto ON_FAIL;
232     }
233 
234     Py_BEGIN_ALLOW_THREADS;
235     rv = xmlSecDSigCtxVerify(ctx->handle, node->_c_node);
236     PYXMLSEC_DUMP(xmlSecDSigCtxDebugDump, ctx->handle);
237     Py_END_ALLOW_THREADS;
238 
239     if (rv < 0) {
240         PyXmlSec_SetLastError("failed to verify");
241         goto ON_FAIL;
242     }
243     if (ctx->handle->status != xmlSecDSigStatusSucceeded) {
244         PyErr_SetString(PyXmlSec_VerificationError, "Signature is invalid.");
245         goto ON_FAIL;
246     }
247     PYXMLSEC_DEBUGF("%p: verify - ok", self);
248     Py_RETURN_NONE;
249 ON_FAIL:
250     PYXMLSEC_DEBUGF("%p: verify - fail", self);
251     return NULL;
252 }
253 
254 // common helper for operations binary_verify and binary_sign
PyXmlSec_ProcessSignBinary(PyXmlSec_SignatureContext * ctx,const xmlSecByte * data,xmlSecSize data_size,xmlSecTransformId method)255 static int PyXmlSec_ProcessSignBinary(PyXmlSec_SignatureContext* ctx, const xmlSecByte* data, xmlSecSize data_size, xmlSecTransformId method) {
256     int rv;
257 
258     if (!(method->usage & xmlSecTransformUsageSignatureMethod)) {
259         PyErr_SetString(PyXmlSec_Error, "incompatible signature method");
260         return -1;
261     }
262 
263     if (ctx->handle->signKey == NULL) {
264         PyErr_SetString(PyXmlSec_Error, "Sign key is not specified.");
265         return -1;
266     }
267 
268     if (ctx->handle->signMethod != NULL) {
269         PYXMLSEC_DEBUGF("%p: signMethod: %p", ctx, ctx->handle->signMethod);
270         PyErr_SetString(PyXmlSec_Error, "Signature context already used; it is designed for one use only.");
271         return -1;
272     }
273 
274     ctx->handle->signMethod = xmlSecTransformCtxCreateAndAppend(&(ctx->handle->transformCtx), method);
275     if (ctx->handle->signMethod == NULL) {
276         PyXmlSec_SetLastError("could not create signature transform.");
277         return -1;
278     }
279 
280     ctx->handle->signMethod->operation = ctx->handle->operation;
281     xmlSecTransformSetKeyReq(ctx->handle->signMethod, &(ctx->handle->keyInfoReadCtx.keyReq));
282     rv = xmlSecKeyMatch(ctx->handle->signKey, NULL, &(ctx->handle->keyInfoReadCtx.keyReq));
283     if (rv != 1) {
284         PyXmlSec_SetLastError("inappropriate key type.");
285         return -1;
286     }
287 
288     rv = xmlSecTransformSetKey(ctx->handle->signMethod, ctx->handle->signKey);
289     if (rv < 0) {
290         PyXmlSec_SetLastError("cannot set key.");
291         return -1;
292     }
293     ctx->handle->transformCtx.result = NULL;
294     ctx->handle->transformCtx.status = xmlSecTransformStatusNone;
295 
296     Py_BEGIN_ALLOW_THREADS;
297     rv = xmlSecTransformCtxBinaryExecute(&(ctx->handle->transformCtx), data, data_size);
298     Py_END_ALLOW_THREADS;
299 
300     if (rv < 0) {
301         PyXmlSec_SetLastError("failed to transform.");
302         return -1;
303     }
304     ctx->handle->result = ctx->handle->transformCtx.result;
305 
306     return 0;
307 }
308 
309 static const char PyXmlSec_SignatureContextSignBinary__doc__[] = \
310     "sign_binary(bytes, transform) -> bytes\n"
311     "Signs binary data ``data`` with algorithm ``transform``.\n\n"
312     ":param bytes: the binary data\n"
313     ":type bytes: :class:`bytes`\n"
314     ":param transform: the signature algorithm\n"
315     ":type transform: :class:`__Transform`\n"
316     ":return: the signature\n"
317     ":rtype: :class:`bytes`";
PyXmlSec_SignatureContextSignBinary(PyObject * self,PyObject * args,PyObject * kwargs)318 static PyObject* PyXmlSec_SignatureContextSignBinary(PyObject* self, PyObject* args, PyObject* kwargs) {
319     static char *kwlist[] = { "bytes", "transform", NULL};
320     PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self;
321     PyXmlSec_Transform* transform = NULL;
322     const char* data = NULL;
323     Py_ssize_t data_size = 0;
324 
325     PYXMLSEC_DEBUGF("%p: sign_binary - start", self);
326     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#O!:sign_binary", kwlist,
327         &data, &data_size, PyXmlSec_TransformType, &transform))
328     {
329         goto ON_FAIL;
330     }
331 
332     ctx->handle->operation = xmlSecTransformOperationSign;
333 
334     if (PyXmlSec_ProcessSignBinary(ctx, (const xmlSecByte*)data, (xmlSecSize)data_size, transform->id) != 0) {
335         goto ON_FAIL;
336     }
337 
338     PYXMLSEC_DEBUGF("%p: sign_binary - ok", self);
339     return PyBytes_FromStringAndSize(
340         (const char*)xmlSecBufferGetData(ctx->handle->result),
341         (Py_ssize_t)xmlSecBufferGetSize(ctx->handle->result)
342     );
343 ON_FAIL:
344     PYXMLSEC_DEBUGF("%p: sign_binary - fail", self);
345     return NULL;
346 }
347 
348 static const char PyXmlSec_SignatureContextVerifyBinary__doc__[] = \
349     "verify_binary(bytes, transform, signature) -> None\n"
350     "Verifies signature for binary data.\n\n"
351     ":param bytes: the binary data\n"
352     ":type bytes: :class:`bytes`\n"
353     ":param transform: the signature algorithm\n"
354     ":type transform: :class:`__Transform`\n"
355     ":param signature: the signature\n"
356     ":type signature: :class:`bytes`\n"
357     ":return: :data:`None` on success\n"
358     ":raise VerificationError: on failure";
PyXmlSec_SignatureContextVerifyBinary(PyObject * self,PyObject * args,PyObject * kwargs)359 static PyObject* PyXmlSec_SignatureContextVerifyBinary(PyObject* self, PyObject* args, PyObject* kwargs) {
360     static char *kwlist[] = { "bytes", "transform", "signature", NULL};
361 
362     PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self;
363     PyXmlSec_Transform* transform = NULL;
364     const char* data = NULL;
365     Py_ssize_t data_size = 0;
366     const char* sign = NULL;
367     Py_ssize_t sign_size = 0;
368     int rv;
369 
370     PYXMLSEC_DEBUGF("%p: verify binary - start", self);
371     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#O!s#:verify_binary", kwlist,
372         &data, &data_size, PyXmlSec_TransformType, &transform, &sign, &sign_size))
373     {
374         goto ON_FAIL;
375     }
376 
377     ctx->handle->operation = xmlSecTransformOperationVerify;
378     if (PyXmlSec_ProcessSignBinary(ctx, (const xmlSecByte*)data, (xmlSecSize)data_size, transform->id) != 0) {
379         goto ON_FAIL;
380     }
381 
382     Py_BEGIN_ALLOW_THREADS;
383     rv = xmlSecTransformVerify(ctx->handle->signMethod, (const xmlSecByte*)sign, (xmlSecSize)sign_size, &(ctx->handle->transformCtx));
384     Py_END_ALLOW_THREADS;
385 
386     if (rv < 0) {
387         PyXmlSec_SetLastError2(PyXmlSec_VerificationError, "Cannot verify signature.");
388         goto ON_FAIL;
389     }
390 
391     if (ctx->handle->signMethod->status != xmlSecTransformStatusOk) {
392         PyXmlSec_SetLastError2(PyXmlSec_VerificationError, "Signature is invalid.");
393         goto ON_FAIL;
394     }
395 
396     PYXMLSEC_DEBUGF("%p: verify binary - ok", self);
397     Py_RETURN_NONE;
398 ON_FAIL:
399     PYXMLSEC_DEBUGF("%p: verify binary - fail", self);
400     return NULL;
401 }
402 
403 static const char PyXmlSec_SignatureContextEnableReferenceTransform__doc__[] = \
404     "enable_reference_transform(transform) -> None\n"
405     "Enables use of ``transform`` as reference transform.\n\n"
406     ".. note:: by default, all transforms are enabled. The first call of "
407     ":meth:`~SignatureContext.enable_reference_transform` will switch to explicitly enabled transforms.\n\n"
408     ":param transform: the transform klass.\n"
409     ":type transform: :class:`__Transform`";
PyXmlSec_SignatureContextEnableReferenceTransform(PyObject * self,PyObject * args,PyObject * kwargs)410 static PyObject* PyXmlSec_SignatureContextEnableReferenceTransform(PyObject* self, PyObject* args, PyObject* kwargs) {
411     static char *kwlist[] = { "transform", NULL};
412 
413     PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self;
414     PyXmlSec_Transform* transform = NULL;
415     int rv;
416 
417     PYXMLSEC_DEBUGF("%p: enable_reference_transform - start", self);
418     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:enable_reference_transform", kwlist, PyXmlSec_TransformType, &transform))
419     {
420         goto ON_FAIL;
421     }
422 
423     Py_BEGIN_ALLOW_THREADS;
424     rv = xmlSecDSigCtxEnableReferenceTransform(ctx->handle, transform->id);
425     Py_END_ALLOW_THREADS;
426 
427     if (rv < 0) {
428         PyXmlSec_SetLastError("cannot enable reference transform.");
429         goto ON_FAIL;
430     }
431 
432     PYXMLSEC_DEBUGF("%p: enable_reference_transform - ok", self);
433     Py_RETURN_NONE;
434 ON_FAIL:
435     PYXMLSEC_DEBUGF("%p: enable_reference_transform - fail", self);
436     return NULL;
437 }
438 
439 static const char PyXmlSec_SignatureContextEnableSignatureTransform__doc__[] = \
440     "enable_signature_transform(transform) -> None\n"
441     "Enables use of ``transform`` as signature transform.\n\n"
442     ".. note:: by default, all transforms are enabled. The first call of "
443     ":meth:`~SignatureContext.enable_signature_transform` will switch to explicitly enabled transforms.\n\n"
444     ":param transform: the transform klass.\n"
445     ":type transform: :class:`__Transform`\n";
PyXmlSec_SignatureContextEnableSignatureTransform(PyObject * self,PyObject * args,PyObject * kwargs)446 static PyObject* PyXmlSec_SignatureContextEnableSignatureTransform(PyObject* self, PyObject* args, PyObject* kwargs) {
447     static char *kwlist[] = { "transform", NULL};
448 
449     PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self;
450     PyXmlSec_Transform* transform = NULL;
451     int rv;
452 
453     PYXMLSEC_DEBUGF("%p: enable_signature_transform - start", self);
454     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:enable_signature_transform", kwlist, PyXmlSec_TransformType, &transform)) {
455         goto ON_FAIL;
456     }
457 
458     Py_BEGIN_ALLOW_THREADS;
459     rv = xmlSecDSigCtxEnableSignatureTransform(ctx->handle, transform->id);
460     Py_END_ALLOW_THREADS;
461 
462     if (rv < 0) {
463         PyXmlSec_SetLastError("cannot enable signature transform.");
464         goto ON_FAIL;
465     }
466 
467     PYXMLSEC_DEBUGF("%p: enable_signature_transform - ok", self);
468     Py_RETURN_NONE;
469 ON_FAIL:
470     PYXMLSEC_DEBUGF("%p: enable_signature_transform - fail", self);
471     return NULL;
472 }
473 
474 static const char PyXmlSec_SignatureContextSetEnabledKeyData__doc__[] = \
475     "set_enabled_key_data(keydata_list) -> None\n"
476     "Adds selected :class:`__KeyData` to the list of enabled key data list.\n\n"
477     ":param keydata_list: the list\n"
478     ":type keydata_list: :class:`list` of :class:`__KeyData`";
PyXmlSec_SignatureContextSetEnabledKeyData(PyObject * self,PyObject * args,PyObject * kwargs)479 static PyObject* PyXmlSec_SignatureContextSetEnabledKeyData(PyObject* self, PyObject* args, PyObject* kwargs) {
480     static char *kwlist[] = { "keydata_list", NULL};
481 
482     PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self;
483     PyObject* keydata_list = NULL;
484     PyObject* iter = NULL;
485     PyObject* item = NULL;
486     xmlSecPtrListPtr enabled_list;
487 
488     PYXMLSEC_DEBUGF("%p: set_enabled_key_data - start", self);
489     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:set_enabled_key_data", kwlist, &keydata_list)) {
490         goto ON_FAIL;
491     }
492     if ((iter = PyObject_GetIter(keydata_list)) == NULL) goto ON_FAIL;
493 
494     enabled_list = &(ctx->handle->keyInfoReadCtx.enabledKeyData);
495     xmlSecPtrListEmpty(enabled_list);
496 
497     while ((item = PyIter_Next(iter)) != NULL) {
498         if (!PyObject_IsInstance(item, (PyObject*)PyXmlSec_KeyDataType)) {
499             PyErr_SetString(PyExc_TypeError, "expected list of KeyData constants.");
500             goto ON_FAIL;
501         }
502         if (xmlSecPtrListAdd(enabled_list, (xmlSecPtr)((PyXmlSec_KeyData*)item)->id) < 0) {
503             PyXmlSec_SetLastError("cannot set enabled key.");
504             goto ON_FAIL;
505         }
506         Py_DECREF(item);
507     }
508     Py_DECREF(iter);
509 
510     PYXMLSEC_DEBUGF("%p: set_enabled_key_data - ok", self);
511 
512     Py_RETURN_NONE;
513 ON_FAIL:
514     PYXMLSEC_DEBUGF("%p: set_enabled_key_data - fail", self);
515     Py_XDECREF(item);
516     Py_XDECREF(iter);
517     return NULL;
518 }
519 
520 static PyGetSetDef PyXmlSec_SignatureContextGetSet[] = {
521     {
522         "key",
523         (getter)PyXmlSec_SignatureContextKeyGet,
524         (setter)PyXmlSec_SignatureContextKeySet,
525         (char*)PyXmlSec_SignatureContextKey__doc__,
526         NULL
527     },
528     {NULL} /* Sentinel */
529 };
530 
531 static PyMethodDef PyXmlSec_SignatureContextMethods[] = {
532     {
533         "register_id",
534         (PyCFunction)PyXmlSec_SignatureContextRegisterId,
535         METH_VARARGS|METH_KEYWORDS,
536         PyXmlSec_SignatureContextRegisterId__doc__,
537     },
538     {
539         "sign",
540         (PyCFunction)PyXmlSec_SignatureContextSign,
541         METH_VARARGS|METH_KEYWORDS,
542         PyXmlSec_SignatureContextSign__doc__
543     },
544     {
545         "verify",
546         (PyCFunction)PyXmlSec_SignatureContextVerify,
547         METH_VARARGS|METH_KEYWORDS,
548         PyXmlSec_SignatureContextVerify__doc__
549     },
550     {
551         "sign_binary",
552         (PyCFunction)PyXmlSec_SignatureContextSignBinary,
553         METH_VARARGS|METH_KEYWORDS,
554         PyXmlSec_SignatureContextSignBinary__doc__
555     },
556     {
557         "verify_binary",
558         (PyCFunction)PyXmlSec_SignatureContextVerifyBinary,
559         METH_VARARGS|METH_KEYWORDS,
560         PyXmlSec_SignatureContextVerifyBinary__doc__
561     },
562     {
563         "enable_reference_transform",
564         (PyCFunction)PyXmlSec_SignatureContextEnableReferenceTransform,
565         METH_VARARGS|METH_KEYWORDS,
566         PyXmlSec_SignatureContextEnableReferenceTransform__doc__
567     },
568     {
569         "enable_signature_transform",
570         (PyCFunction)PyXmlSec_SignatureContextEnableSignatureTransform,
571         METH_VARARGS|METH_KEYWORDS,
572         PyXmlSec_SignatureContextEnableSignatureTransform__doc__,
573     },
574     {
575         "set_enabled_key_data",
576         (PyCFunction)PyXmlSec_SignatureContextSetEnabledKeyData,
577         METH_VARARGS|METH_KEYWORDS,
578         PyXmlSec_SignatureContextSetEnabledKeyData__doc__,
579     },
580     {NULL, NULL} /* sentinel */
581 };
582 
583 static PyTypeObject _PyXmlSec_SignatureContextType = {
584     PyVarObject_HEAD_INIT(NULL, 0)
585     STRINGIFY(MODULE_NAME) ".SignatureContext", /* tp_name */
586     sizeof(PyXmlSec_SignatureContext),          /* tp_basicsize */
587     0,                                          /* tp_itemsize */
588     PyXmlSec_SignatureContext__del__,           /* tp_dealloc */
589     0,                                          /* tp_print */
590     0,                                          /* tp_getattr */
591     0,                                          /* tp_setattr */
592     0,                                          /* tp_reserved */
593     0,                                          /* tp_repr */
594     0,                                          /* tp_as_number */
595     0,                                          /* tp_as_sequence */
596     0,                                          /* tp_as_mapping */
597     0,                                          /* tp_hash  */
598     0,                                          /* tp_call */
599     0,                                          /* tp_str */
600     0,                                          /* tp_getattro */
601     0,                                          /* tp_setattro */
602     0,                                          /* tp_as_buffer */
603     Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,     /* tp_flags */
604     "XML Digital Signature implementation",     /* tp_doc */
605     0,                                          /* tp_traverse */
606     0,                                          /* tp_clear */
607     0,                                          /* tp_richcompare */
608     0,                                          /* tp_weaklistoffset */
609     0,                                          /* tp_iter */
610     0,                                          /* tp_iternext */
611     PyXmlSec_SignatureContextMethods,           /* tp_methods */
612     0,                                          /* tp_members */
613     PyXmlSec_SignatureContextGetSet,            /* tp_getset */
614     0,                                          /* tp_base */
615     0,                                          /* tp_dict */
616     0,                                          /* tp_descr_get */
617     0,                                          /* tp_descr_set */
618     0,                                          /* tp_dictoffset */
619     PyXmlSec_SignatureContext__init__,          /* tp_init */
620     0,                                          /* tp_alloc */
621     PyXmlSec_SignatureContext__new__,           /* tp_new */
622     0,                                          /* tp_free */
623 };
624 
625 PyTypeObject* PyXmlSec_SignatureContextType = &_PyXmlSec_SignatureContextType;
626 
PyXmlSec_DSModule_Init(PyObject * package)627 int PyXmlSec_DSModule_Init(PyObject* package) {
628     if (PyType_Ready(PyXmlSec_SignatureContextType) < 0) goto ON_FAIL;
629 
630     // since objects is created as static objects, need to increase refcount to prevent deallocate
631     Py_INCREF(PyXmlSec_SignatureContextType);
632 
633     if (PyModule_AddObject(package, "SignatureContext", (PyObject*)PyXmlSec_SignatureContextType) < 0) goto ON_FAIL;
634     return 0;
635 ON_FAIL:
636     return -1;
637 }
638