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/xmlenc.h>
18 #include <xmlsec/xmltree.h>
19 
20 typedef struct {
21     PyObject_HEAD
22     xmlSecEncCtxPtr handle;
23     PyXmlSec_KeysManager* manager;
24 } PyXmlSec_EncryptionContext;
25 
PyXmlSec_EncryptionContext__new__(PyTypeObject * type,PyObject * args,PyObject * kwargs)26 static PyObject* PyXmlSec_EncryptionContext__new__(PyTypeObject *type, PyObject *args, PyObject *kwargs) {
27     PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)PyType_GenericNew(type, args, kwargs);
28     PYXMLSEC_DEBUGF("%p: new enc context", ctx);
29     if (ctx != NULL) {
30         ctx->handle = NULL;
31         ctx->manager = NULL;
32     }
33     return (PyObject*)(ctx);
34 }
35 
PyXmlSec_EncryptionContext__init__(PyObject * self,PyObject * args,PyObject * kwargs)36 static int PyXmlSec_EncryptionContext__init__(PyObject* self, PyObject* args, PyObject* kwargs) {
37     static char *kwlist[] = { "manager", NULL};
38 
39     PyXmlSec_KeysManager* manager = NULL;
40     PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self;
41 
42     PYXMLSEC_DEBUGF("%p: init enc context", self);
43     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&:__init__", kwlist, PyXmlSec_KeysManagerConvert, &manager)) {
44         goto ON_FAIL;
45     }
46     ctx->handle = xmlSecEncCtxCreate(manager != NULL ? manager->handle : NULL);
47     if (ctx->handle == NULL) {
48         PyXmlSec_SetLastError("failed to create the encryption context");
49         goto ON_FAIL;
50     }
51     ctx->manager = manager;
52     PYXMLSEC_DEBUGF("%p: init enc context - ok, manager - %p", self, manager);
53     return 0;
54 ON_FAIL:
55     PYXMLSEC_DEBUGF("%p: init enc context - failed", self);
56     Py_XDECREF(manager);
57     return -1;
58 }
59 
PyXmlSec_EncryptionContext__del__(PyObject * self)60 static void PyXmlSec_EncryptionContext__del__(PyObject* self) {
61     PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self;
62 
63     PYXMLSEC_DEBUGF("%p: delete enc context", self);
64 
65     if (ctx->handle != NULL) {
66         xmlSecEncCtxDestroy(ctx->handle);
67     }
68     // release manager object
69     Py_XDECREF(ctx->manager);
70     Py_TYPE(self)->tp_free(self);
71 }
72 
73 static const char PyXmlSec_EncryptionContextKey__doc__[] = "Encryption key.\n";
PyXmlSec_EncryptionContextKeyGet(PyObject * self,void * closure)74 static PyObject* PyXmlSec_EncryptionContextKeyGet(PyObject* self, void* closure) {
75     PyXmlSec_EncryptionContext* ctx = ((PyXmlSec_EncryptionContext*)self);
76     PyXmlSec_Key* key;
77 
78     if (ctx->handle->encKey == NULL) {
79         Py_RETURN_NONE;
80     }
81 
82     key = PyXmlSec_NewKey();
83     key->handle = ctx->handle->encKey;
84     key->is_own = 0;
85     return (PyObject*)key;
86 }
87 
PyXmlSec_EncryptionContextKeySet(PyObject * self,PyObject * value,void * closure)88 static int PyXmlSec_EncryptionContextKeySet(PyObject* self, PyObject* value, void* closure) {
89     PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self;
90     PyXmlSec_Key* key;
91 
92     PYXMLSEC_DEBUGF("%p, %p", self, value);
93 
94     if (value == NULL) {  // key deletion
95         if (ctx->handle->encKey != NULL) {
96             xmlSecKeyDestroy(ctx->handle->encKey);
97             ctx->handle->encKey = NULL;
98         }
99         return 0;
100     }
101 
102     if (!PyObject_IsInstance(value, (PyObject*)PyXmlSec_KeyType)) {
103         PyErr_SetString(PyExc_TypeError, "instance of *xmlsec.Key* expected.");
104         return -1;
105     }
106 
107     key = (PyXmlSec_Key*)value;
108     if (key->handle == NULL) {
109         PyErr_SetString(PyExc_TypeError, "empty key.");
110         return -1;
111     }
112 
113     if (ctx->handle->encKey != NULL) {
114         xmlSecKeyDestroy(ctx->handle->encKey);
115     }
116 
117     ctx->handle->encKey = xmlSecKeyDuplicate(key->handle);
118     if (ctx->handle->encKey == NULL) {
119         PyXmlSec_SetLastError("failed to duplicate key");
120         return -1;
121     }
122     return 0;
123 }
124 
125 static const char PyXmlSec_EncryptionContextReset__doc__[] = \
126     "reset() -> None\n"\
127     "Reset this context, user settings are not touched.\n";
PyXmlSec_EncryptionContextReset(PyObject * self,PyObject * args,PyObject * kwargs)128 static PyObject* PyXmlSec_EncryptionContextReset(PyObject* self, PyObject* args, PyObject* kwargs) {
129     PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self;
130 
131     PYXMLSEC_DEBUGF("%p: reset context - start", self);
132     Py_BEGIN_ALLOW_THREADS;
133     xmlSecEncCtxReset(ctx->handle);
134     PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx->handle);
135     Py_END_ALLOW_THREADS;
136     PYXMLSEC_DEBUGF("%p: reset context - ok", self);
137     Py_RETURN_NONE;
138 }
139 
140 static const char PyXmlSec_EncryptionContextEncryptBinary__doc__[] = \
141     "encrypt_binary(template, data) -> lxml.etree._Element\n"
142     "Encrypts binary ``data`` according to ``EncryptedData`` template ``template``.\n\n"
143     ".. note:: ``template`` is modified in place.\n\n"
144     ":param template: the pointer to :xml:`<enc:EncryptedData/>` template node\n"
145     ":type template: :class:`lxml.etree._Element`\n"
146     ":param data: the data\n"
147     ":type data: :class:`bytes`\n"
148     ":return: the resulting :xml:`<enc:EncryptedData/>` subtree\n"
149     ":rtype: :class:`lxml.etree._Element`";
PyXmlSec_EncryptionContextEncryptBinary(PyObject * self,PyObject * args,PyObject * kwargs)150 static PyObject* PyXmlSec_EncryptionContextEncryptBinary(PyObject* self, PyObject* args, PyObject* kwargs) {
151     static char *kwlist[] = { "template", "data", NULL};
152 
153     PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self;
154     PyXmlSec_LxmlElementPtr template = NULL;
155     const char* data = NULL;
156     Py_ssize_t data_size = 0;
157     int rv;
158 
159     PYXMLSEC_DEBUGF("%p: encrypt_binary - start", self);
160     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s#:encrypt_binary", kwlist,
161         PyXmlSec_LxmlElementConverter, &template, &data, &data_size))
162     {
163         goto ON_FAIL;
164     }
165 
166     Py_BEGIN_ALLOW_THREADS;
167     rv = xmlSecEncCtxBinaryEncrypt(ctx->handle, template->_c_node, (const xmlSecByte*)data, (xmlSecSize)data_size);
168     PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx->handle);
169     Py_END_ALLOW_THREADS;
170 
171     if (rv < 0) {
172         PyXmlSec_SetLastError("failed to encrypt binary");
173         goto ON_FAIL;
174     }
175     Py_INCREF(template);
176     PYXMLSEC_DEBUGF("%p: encrypt_binary - ok", self);
177 
178     return (PyObject*)template;
179 ON_FAIL:
180     PYXMLSEC_DEBUGF("%p: encrypt_binary - fail", self);
181     return NULL;
182 }
183 
184 // release the replaced nodes in a way safe for `lxml`
PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx,PyXmlSec_LxmlDocumentPtr doc)185 static void PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx, PyXmlSec_LxmlDocumentPtr doc) {
186     PyXmlSec_LxmlElementPtr* elem;
187     // release the replaced nodes in a way safe for `lxml`
188     xmlNodePtr n = ctx->replacedNodeList;
189     xmlNodePtr nn;
190 
191     while (n != NULL) {
192         PYXMLSEC_DEBUGF("clear replaced node %p", n);
193         nn = n->next;
194         // if n has references, it will not be deleted
195         elem = PyXmlSec_elementFactory(doc, n);
196         if (NULL == elem)
197             xmlFreeNode(n);
198         else
199             Py_DECREF(elem);
200         n = nn;
201     }
202     ctx->replacedNodeList = NULL;
203 }
204 
205 static const char PyXmlSec_EncryptionContextEncryptXml__doc__[] = \
206     "encrypt_xml(template, node) -> lxml.etree._Element\n"
207     "Encrypts ``node`` using ``template``.\n\n"
208     ".. note:: The ``\"Type\"`` attribute of ``template`` decides whether ``node`` itself "
209     "(``http://www.w3.org/2001/04/xmlenc#Element``) or its content (``http://www.w3.org/2001/04/xmlenc#Content``) is encrypted.\n"
210     "   It must have one of these two values (or an exception is raised).\n"
211     "   The operation modifies the tree and removes replaced nodes.\n\n"
212     ":param template: the pointer to :xml:`<enc:EncryptedData/>` template node\n\n"
213     ":type template: :class:`lxml.etree._Element`\n"
214     ":param node: the pointer to node for encryption\n\n"
215     ":type node: :class:`lxml.etree._Element`\n"
216     ":return: the pointer to newly created :xml:`<enc:EncryptedData/>` node\n"
217     ":rtype: :class:`lxml.etree._Element`";
PyXmlSec_EncryptionContextEncryptXml(PyObject * self,PyObject * args,PyObject * kwargs)218 static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* args, PyObject* kwargs) {
219     static char *kwlist[] = { "template", "node", NULL};
220 
221     PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self;
222     PyXmlSec_LxmlElementPtr template = NULL;
223     PyXmlSec_LxmlElementPtr node = NULL;
224     xmlNodePtr xnew_node = NULL;
225     xmlChar* tmpType = NULL;
226     int rv = 0;
227 
228     PYXMLSEC_DEBUGF("%p: encrypt_xml - start", self);
229     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&:encrypt_xml", kwlist,
230         PyXmlSec_LxmlElementConverter, &template, PyXmlSec_LxmlElementConverter, &node))
231     {
232         goto ON_FAIL;
233     }
234     tmpType = xmlGetProp(template->_c_node, XSTR("Type"));
235     if (tmpType == NULL || !(xmlStrEqual(tmpType, xmlSecTypeEncElement) || xmlStrEqual(tmpType, xmlSecTypeEncContent))) {
236         PyErr_SetString(PyXmlSec_Error, "unsupported `Type`, it should be `element` or `content`");
237         goto ON_FAIL;
238     }
239 
240     // `xmlSecEncCtxXmlEncrypt` will replace the subtree rooted
241     //  at `node._c_node` or its children by an extended subtree rooted at "c_node".
242     //  We set `XMLSEC_ENC_RETURN_REPLACED_NODE` to prevent deallocation
243     //  of the replaced node. This is important as `node` is still referencing it
244     ctx->handle->flags = XMLSEC_ENC_RETURN_REPLACED_NODE;
245 
246     // try to do all actions whithin single python-free section
247     // rv has the following codes, 1 - failed to copy node, -1 - op failed, 0 - success
248     Py_BEGIN_ALLOW_THREADS;
249     if (template->_doc->_c_doc != node->_doc->_c_doc) {
250         // `xmlSecEncCtxEncrypt` expects *template* to belong to the document of *node*
251         // if this is not the case, we copy the `libxml2` subtree there.
252         xnew_node = xmlDocCopyNode(template->_c_node, node->_doc->_c_doc, 1); // recursive
253         if (xnew_node == NULL) {
254             rv = 1;
255         }
256     }
257     if (rv == 0 && xmlSecEncCtxXmlEncrypt(ctx->handle, xnew_node != NULL ? xnew_node: template->_c_node, node->_c_node) < 0) {
258         rv = -1;
259         if (xnew_node != NULL) {
260             xmlFreeNode(xnew_node);
261             xnew_node = NULL;
262         }
263     }
264     PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx->handle);
265     Py_END_ALLOW_THREADS;
266 
267     PyXmlSec_ClearReplacedNodes(ctx->handle, node->_doc);
268     if (NULL != PyErr_Occurred()) {
269         goto ON_FAIL;
270     }
271 
272     if (rv != 0) {
273         if (rv > 0) {
274             PyErr_SetString(PyXmlSec_InternalError, "could not copy template tree");
275         } else {
276             PyXmlSec_SetLastError("failed to encrypt xml");
277         }
278         goto ON_FAIL;
279     }
280 
281     xmlFree(tmpType);
282 
283     PYXMLSEC_DEBUGF("%p: encrypt_xml - ok", self);
284     return (PyObject*)PyXmlSec_elementFactory(node->_doc, xnew_node != NULL ? xnew_node : template->_c_node);
285 ON_FAIL:
286     PYXMLSEC_DEBUGF("%p: encrypt_xml - fail", self);
287     xmlFree(tmpType);
288     return NULL;
289 }
290 
291 static const char PyXmlSec_EncryptionContextEncryptUri__doc__[] = \
292     "encrypt_uri(template, uri) -> lxml.etree._Element\n"
293     "Encrypts binary data obtained from ``uri`` according to ``template``.\n\n"
294     ".. note:: ``template`` is modified in place.\n\n"
295     ":param template: the pointer to :xml:`<enc:EncryptedData/>` template node\n"
296     ":type template: :class:`lxml.etree._Element`\n"
297     ":param uri: the URI\n"
298     ":type uri: :class:`str`\n"
299     ":return: the resulting :xml:`<enc:EncryptedData/>` subtree\n"
300     ":rtype: :class:`lxml.etree._Element`";
PyXmlSec_EncryptionContextEncryptUri(PyObject * self,PyObject * args,PyObject * kwargs)301 static PyObject* PyXmlSec_EncryptionContextEncryptUri(PyObject* self, PyObject* args, PyObject* kwargs) {
302     static char *kwlist[] = { "template", "uri", NULL};
303 
304     PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self;
305     PyXmlSec_LxmlElementPtr template = NULL;
306     const char* uri = NULL;
307     int rv;
308 
309     PYXMLSEC_DEBUGF("%p: encrypt_uri - start", self);
310     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s:encrypt_uri", kwlist, PyXmlSec_LxmlElementConverter, &template, &uri)) {
311         goto ON_FAIL;
312     }
313 
314     Py_BEGIN_ALLOW_THREADS;
315     rv = xmlSecEncCtxUriEncrypt(ctx->handle, template->_c_node, (const xmlSecByte*)uri);
316     PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx->handle);
317     Py_END_ALLOW_THREADS;
318 
319     if (rv < 0) {
320         PyXmlSec_SetLastError("failed to encrypt URI");
321         goto ON_FAIL;
322     }
323     PYXMLSEC_DEBUGF("%p: encrypt_uri - ok", self);
324     Py_INCREF(template);
325     return (PyObject*)template;
326 ON_FAIL:
327     PYXMLSEC_DEBUGF("%p: encrypt_uri - fail", self);
328     return NULL;
329 }
330 
331 static const char PyXmlSec_EncryptionContextDecrypt__doc__[] = \
332     "decrypt(node)\n"
333     "Decrypts ``node`` (an ``EncryptedData`` or ``EncryptedKey`` element) and returns the result. "
334     "The decryption may result in binary data or an XML subtree. "
335     "In the former case, the binary data is returned. In the latter case, "
336     "the input tree is modified and a reference to the decrypted XML subtree is returned.\n"
337     "If the operation modifies the tree, it removes replaced nodes.\n\n"
338     ":param node: the pointer to :xml:`<enc:EncryptedData/>` or :xml:`<enc:EncryptedKey/>` node\n"
339     ":type node: :class:`lxml.etree._Element`\n"
340     ":return: depends on input parameters\n"
341     ":rtype: :class:`lxml.etree._Element` or :class:`bytes`";
PyXmlSec_EncryptionContextDecrypt(PyObject * self,PyObject * args,PyObject * kwargs)342 static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* args, PyObject* kwargs) {
343     static char *kwlist[] = { "node", NULL};
344 
345     PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self;
346     PyXmlSec_LxmlElementPtr node = NULL;
347 
348     PyObject* node_num = NULL;
349     PyObject* parent = NULL;
350 
351     PyObject* tmp;
352     xmlNodePtr root;
353     xmlNodePtr xparent;
354     int rv;
355     xmlChar* ttype;
356     int notContent;
357 
358     PYXMLSEC_DEBUGF("%p: decrypt - start", self);
359     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:decrypt", kwlist, PyXmlSec_LxmlElementConverter, &node)) {
360         goto ON_FAIL;
361     }
362 
363     xparent = node->_c_node->parent;
364     if (xparent != NULL && !PyXmlSec_IsElement(xparent)) {
365         xparent = NULL;
366     }
367 
368     if (xparent != NULL) {
369         parent = (PyObject*)PyXmlSec_elementFactory(node->_doc, xparent);
370         if (parent == NULL) {
371             PyErr_SetString(PyXmlSec_InternalError, "failed to construct parent");
372             goto ON_FAIL;
373         }
374         // get index of node
375         node_num = PyObject_CallMethod(parent, "index", "O", node);
376         PYXMLSEC_DEBUGF("parent: %p, %p", parent, node_num);
377     }
378 
379     Py_BEGIN_ALLOW_THREADS;
380     ctx->handle->flags = XMLSEC_ENC_RETURN_REPLACED_NODE;
381     ctx->handle->mode = xmlSecCheckNodeName(node->_c_node, xmlSecNodeEncryptedKey, xmlSecEncNs) ? xmlEncCtxModeEncryptedKey : xmlEncCtxModeEncryptedData;
382     PYXMLSEC_DEBUGF("mode: %d", ctx->handle->mode);
383     rv = xmlSecEncCtxDecrypt(ctx->handle, node->_c_node);
384     PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx->handle);
385     Py_END_ALLOW_THREADS;
386 
387     PyXmlSec_ClearReplacedNodes(ctx->handle, node->_doc);
388 
389     if (rv < 0) {
390         PyXmlSec_SetLastError("failed to decrypt");
391         goto ON_FAIL;
392     }
393 
394     if (!ctx->handle->resultReplaced) {
395         Py_XDECREF(node_num);
396         Py_XDECREF(parent);
397         PYXMLSEC_DEBUGF("%p: binary.decrypt - ok", self);
398         return PyBytes_FromStringAndSize(
399             (const char*)xmlSecBufferGetData(ctx->handle->result),
400             (Py_ssize_t)xmlSecBufferGetSize(ctx->handle->result)
401         );
402     }
403 
404     if (xparent != NULL) {
405         ttype = xmlGetProp(node->_c_node, XSTR("Type"));
406         notContent = (ttype == NULL || !xmlStrEqual(ttype, xmlSecTypeEncContent));
407         xmlFree(ttype);
408 
409         if (notContent) {
410             tmp = PyObject_GetItem(parent, node_num);
411             if (tmp == NULL) goto ON_FAIL;
412             Py_DECREF(parent);
413             parent = tmp;
414         }
415         Py_DECREF(node_num);
416         PYXMLSEC_DEBUGF("%p: parent.decrypt - ok", self);
417         return parent;
418     }
419 
420     // root has been replaced
421     root = xmlDocGetRootElement(node->_doc->_c_doc);
422     if (root == NULL) {
423         PyErr_SetString(PyXmlSec_Error, "decryption resulted in a non well formed document");
424         goto ON_FAIL;
425     }
426 
427     Py_XDECREF(node_num);
428     Py_XDECREF(parent);
429 
430     PYXMLSEC_DEBUGF("%p: decrypt - ok", self);
431     return (PyObject*)PyXmlSec_elementFactory(node->_doc, root);
432 
433 ON_FAIL:
434     PYXMLSEC_DEBUGF("%p: decrypt - fail", self);
435     Py_XDECREF(node_num);
436     Py_XDECREF(parent);
437     return NULL;
438 }
439 
440 static PyGetSetDef PyXmlSec_EncryptionContextGetSet[] = {
441     {
442         "key",
443         (getter)PyXmlSec_EncryptionContextKeyGet,
444         (setter)PyXmlSec_EncryptionContextKeySet,
445         (char*)PyXmlSec_EncryptionContextKey__doc__,
446         NULL
447     },
448     {NULL} /* Sentinel */
449 };
450 
451 static PyMethodDef PyXmlSec_EncryptionContextMethods[] = {
452     {
453         "reset",
454         (PyCFunction)PyXmlSec_EncryptionContextReset,
455         METH_NOARGS,
456         PyXmlSec_EncryptionContextReset__doc__,
457     },
458     {
459         "encrypt_binary",
460         (PyCFunction)PyXmlSec_EncryptionContextEncryptBinary,
461         METH_VARARGS|METH_KEYWORDS,
462         PyXmlSec_EncryptionContextEncryptBinary__doc__,
463     },
464     {
465         "encrypt_xml",
466         (PyCFunction)PyXmlSec_EncryptionContextEncryptXml,
467         METH_VARARGS|METH_KEYWORDS,
468         PyXmlSec_EncryptionContextEncryptXml__doc__
469     },
470     {
471         "encrypt_uri",
472         (PyCFunction)PyXmlSec_EncryptionContextEncryptUri,
473         METH_VARARGS|METH_KEYWORDS,
474         PyXmlSec_EncryptionContextEncryptUri__doc__
475     },
476     {
477         "decrypt",
478         (PyCFunction)PyXmlSec_EncryptionContextDecrypt,
479         METH_VARARGS|METH_KEYWORDS,
480         PyXmlSec_EncryptionContextDecrypt__doc__
481     },
482     {NULL, NULL} /* sentinel */
483 };
484 
485 static PyTypeObject _PyXmlSec_EncryptionContextType = {
486     PyVarObject_HEAD_INIT(NULL, 0)
487     STRINGIFY(MODULE_NAME) ".EncryptionContext", /* tp_name */
488     sizeof(PyXmlSec_EncryptionContext),          /* tp_basicsize */
489     0,                                           /* tp_itemsize */
490     PyXmlSec_EncryptionContext__del__,           /* tp_dealloc */
491     0,                                           /* tp_print */
492     0,                                           /* tp_getattr */
493     0,                                           /* tp_setattr */
494     0,                                           /* tp_reserved */
495     0,                                           /* tp_repr */
496     0,                                           /* tp_as_number */
497     0,                                           /* tp_as_sequence */
498     0,                                           /* tp_as_mapping */
499     0,                                           /* tp_hash  */
500     0,                                           /* tp_call */
501     0,                                           /* tp_str */
502     0,                                           /* tp_getattro */
503     0,                                           /* tp_setattro */
504     0,                                           /* tp_as_buffer */
505     Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,      /* tp_flags */
506     "XML Encryption implementation",             /* tp_doc */
507     0,                                           /* tp_traverse */
508     0,                                           /* tp_clear */
509     0,                                           /* tp_richcompare */
510     0,                                           /* tp_weaklistoffset */
511     0,                                           /* tp_iter */
512     0,                                           /* tp_iternext */
513     PyXmlSec_EncryptionContextMethods,           /* tp_methods */
514     0,                                           /* tp_members */
515     PyXmlSec_EncryptionContextGetSet,            /* tp_getset */
516     0,                                           /* tp_base */
517     0,                                           /* tp_dict */
518     0,                                           /* tp_descr_get */
519     0,                                           /* tp_descr_set */
520     0,                                           /* tp_dictoffset */
521     PyXmlSec_EncryptionContext__init__,          /* tp_init */
522     0,                                           /* tp_alloc */
523     PyXmlSec_EncryptionContext__new__,           /* tp_new */
524     0                                            /* tp_free */
525 };
526 
527 PyTypeObject* PyXmlSec_EncryptionContextType = &_PyXmlSec_EncryptionContextType;
528 
PyXmlSec_EncModule_Init(PyObject * package)529 int PyXmlSec_EncModule_Init(PyObject* package) {
530     if (PyType_Ready(PyXmlSec_EncryptionContextType) < 0) goto ON_FAIL;
531 
532     PYXMLSEC_DEBUGF("%p", PyXmlSec_EncryptionContextType);
533     // since objects is created as static objects, need to increase refcount to prevent deallocate
534     Py_INCREF(PyXmlSec_EncryptionContextType);
535 
536     if (PyModule_AddObject(package, "EncryptionContext", (PyObject*)PyXmlSec_EncryptionContextType) < 0) goto ON_FAIL;
537     return 0;
538 ON_FAIL:
539     return -1;
540 }
541