Skip to content

Commit d6fb258

Browse files
authored
Merge pull request #67 from mehcode/develop
Merge branch develop to master (prepare version 1.2.0)
2 parents 3eb882d + 55f670b commit d6fb258

File tree

11 files changed

+222
-22
lines changed

11 files changed

+222
-22
lines changed

src/debug.h

+2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
#include <stdio.h>
1616
#define PYXMLSEC_DEBUG(fmt) fprintf(stderr, "[%s:%d %s] " fmt "\n", __FILE__, __LINE__, __FUNCTION__)
1717
#define PYXMLSEC_DEBUGF(fmt, ...) fprintf(stderr, "[%s:%d %s] " fmt "\n", __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
18+
#define PYXMLSEC_DUMP(method, obj) method(obj, stderr)
1819
#else
1920
#define PYXMLSEC_DEBUG(...)
2021
#define PYXMLSEC_DEBUGF(...)
22+
#define PYXMLSEC_DUMP(method, obj)
2123
#endif // PYXMLSEC_ENABLE_DEBUG
2224

2325
#endif // __PYXMLSEC_DEBUG_H__

src/ds.c

+7-4
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,11 @@ static PyObject* PyXmlSec_SignatureContextSign(PyObject* self, PyObject* args, P
172172
goto ON_FAIL;
173173
}
174174

175+
xmlSecDSigCtxPtr ctx = ((PyXmlSec_SignatureContext*)self)->handle;
175176
int rv;
176177
Py_BEGIN_ALLOW_THREADS;
177-
rv = xmlSecDSigCtxSign(((PyXmlSec_SignatureContext*)self)->handle, node->_c_node);
178+
rv = xmlSecDSigCtxSign(ctx, node->_c_node);
179+
PYXMLSEC_DUMP(xmlSecDSigCtxDebugDump, ctx);
178180
Py_END_ALLOW_THREADS;
179181
if (rv < 0) {
180182
PyXmlSec_SetLastError("failed to sign");
@@ -202,17 +204,18 @@ static PyObject* PyXmlSec_SignatureContextVerify(PyObject* self, PyObject* args,
202204
goto ON_FAIL;
203205
}
204206

205-
xmlSecDSigCtxPtr handle = ((PyXmlSec_SignatureContext*)self)->handle;
207+
xmlSecDSigCtxPtr ctx = ((PyXmlSec_SignatureContext*)self)->handle;
206208
int rv;
207209
Py_BEGIN_ALLOW_THREADS;
208-
rv = xmlSecDSigCtxVerify(handle, node->_c_node);
210+
rv = xmlSecDSigCtxVerify(ctx, node->_c_node);
211+
PYXMLSEC_DUMP(xmlSecDSigCtxDebugDump, ctx);
209212
Py_END_ALLOW_THREADS;
210213

211214
if (rv < 0) {
212215
PyXmlSec_SetLastError("failed to verify");
213216
goto ON_FAIL;
214217
}
215-
if (handle->status != xmlSecDSigStatusSucceeded) {
218+
if (ctx->status != xmlSecDSigStatusSucceeded) {
216219
PyErr_SetString(PyXmlSec_VerificationError, "Signature is invalid.");
217220
goto ON_FAIL;
218221
}

src/enc.c

+34-13
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "lxml.h"
1616

1717
#include <xmlsec/xmlenc.h>
18+
#include <xmlsec/xmltree.h>
1819

1920
typedef struct {
2021
PyObject_HEAD
@@ -105,6 +106,19 @@ static int PyXmlSec_EncryptionContextKeySet(PyObject* self, PyObject* value, voi
105106
return 0;
106107
}
107108

109+
static const char PyXmlSec_EncryptionContextReset__doc__[] = \
110+
"Resets *context*, user settings are not touched.\n";
111+
static PyObject* PyXmlSec_EncryptionContextReset(PyObject* self, PyObject* args, PyObject* kwargs) {
112+
PYXMLSEC_DEBUGF("%p: reset context - start", self);
113+
xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle;
114+
Py_BEGIN_ALLOW_THREADS;
115+
xmlSecEncCtxReset(ctx);
116+
PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx);
117+
Py_END_ALLOW_THREADS;
118+
PYXMLSEC_DEBUGF("%p: reset context - ok", self);
119+
Py_RETURN_NONE;
120+
}
121+
108122
static const char PyXmlSec_EncryptionContextEncryptBinary__doc__[] = \
109123
"Encrypts binary *data* according to `EncryptedData` template *template*\n"\
110124
"Note: *template* is modified in place.\n\n"
@@ -128,6 +142,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptBinary(PyObject* self, PyObjec
128142
int rv;
129143
Py_BEGIN_ALLOW_THREADS;
130144
rv = xmlSecEncCtxBinaryEncrypt(ctx, template->_c_node, (const xmlSecByte*)data, (xmlSecSize)data_size);
145+
PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx);
131146
Py_END_ALLOW_THREADS;
132147

133148
if (rv < 0) {
@@ -163,12 +178,9 @@ static const char PyXmlSec_EncryptionContextEncryptXml__doc__[] = \
163178
"Note: The `Type` attribute of *template* decides whether *node* itself is encrypted\n"\
164179
"(`http://www.w3.org/2001/04/xmlenc#Element`) or its content (`http://www.w3.org/2001/04/xmlenc#Content`).\n"\
165180
"It must have one of these two values (or an exception is raised).\n"\
166-
"The operation modifies the tree containing *node* in a way that\n"\
167-
"`lxml` references to or into this tree may see a surprising state.\n"\
168-
"You should no longer rely on them. Especially, you should use\n"\
169-
"`getroottree()` on the result to obtain the encrypted result tree.\n\n"
170-
":param template: the pointer to <enc:EncryptedData/> template node\n"
171-
":param node: the pointer to node for encryption\n"
181+
"The operation modifies the tree and removes replaced nodes.\n"\
182+
":param template: the pointer to <enc:EncryptedData/> template node\n"\
183+
":param node: the pointer to node for encryption\n"\
172184
":return: the pointer to newly created <enc:EncryptedData/> node\n";
173185
static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* args, PyObject* kwargs) {
174186
static char *kwlist[] = { "template", "node", NULL};
@@ -216,6 +228,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject*
216228
xnew_node = NULL;
217229
}
218230
}
231+
PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx);
219232
Py_END_ALLOW_THREADS;
220233

221234
PyXmlSec_ClearReplacedNodes(ctx, node->_doc);
@@ -258,6 +271,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptUri(PyObject* self, PyObject*
258271
int rv;
259272
Py_BEGIN_ALLOW_THREADS;
260273
rv = xmlSecEncCtxUriEncrypt(ctx, template->_c_node, (const xmlSecByte*)uri);
274+
PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx);
261275
Py_END_ALLOW_THREADS;
262276

263277
if (rv < 0) {
@@ -273,14 +287,12 @@ static PyObject* PyXmlSec_EncryptionContextEncryptUri(PyObject* self, PyObject*
273287
}
274288

275289
static const char PyXmlSec_EncryptionContextDecrypt__doc__[] = \
276-
"Decrypts *node* (an `EncryptedData` element) and return the result.\n"\
290+
"Decrypts *node* (an `EncryptedData` or `EncryptedKey` element) and return the result.\n"\
277291
"The decryption may result in binary data or an XML subtree.\n"\
278292
"In the former case, the binary data is returned. In the latter case,\n"\
279293
"the input tree is modified and a reference to the decrypted XML subtree is returned.\n"\
280-
"If the operation modifies the tree, `lxml` references to or into this tree may see a surprising state.\n"\
281-
"You should no longer rely on them. Especially, you should use `getroottree()` on the result\n"\
282-
"to obtain the decrypted result tree.\n\n"
283-
":param node: the pointer to <enc:EncryptedData/> node\n"
294+
"If the operation modifies the tree, it removes replaced nodes.\n"\
295+
":param node: the pointer to <enc:EncryptedData/> or <enc:EncryptedKey/> node\n"
284296
":return: depends on input parameters\n";
285297

286298
static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* args, PyObject* kwargs) {
@@ -310,15 +322,18 @@ static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* arg
310322
}
311323
// get index of node
312324
node_num = PyObject_CallMethod(parent, "index", "O", node);
313-
PYXMLSEC_DEBUGF("%p, %p", parent, node_num);
325+
PYXMLSEC_DEBUGF("parent: %p, %p", parent, node_num);
314326
}
315327

316328
xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle;
317-
ctx->flags = XMLSEC_ENC_RETURN_REPLACED_NODE;
318329
int rv;
319330

320331
Py_BEGIN_ALLOW_THREADS;
332+
ctx->flags = XMLSEC_ENC_RETURN_REPLACED_NODE;
333+
ctx->mode = xmlSecCheckNodeName(node->_c_node, xmlSecNodeEncryptedKey, xmlSecEncNs) ? xmlEncCtxModeEncryptedKey : xmlEncCtxModeEncryptedData;
334+
PYXMLSEC_DEBUGF("mode: %d", ctx->mode);
321335
rv = xmlSecEncCtxDecrypt(ctx, node->_c_node);
336+
PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx);
322337
Py_END_ALLOW_THREADS;
323338

324339
PyXmlSec_ClearReplacedNodes(ctx, node->_doc);
@@ -385,6 +400,12 @@ static PyGetSetDef PyXmlSec_EncryptionContextGetSet[] = {
385400
};
386401

387402
static PyMethodDef PyXmlSec_EncryptionContextMethods[] = {
403+
{
404+
"reset",
405+
(PyCFunction)PyXmlSec_EncryptionContextReset,
406+
METH_NOARGS,
407+
PyXmlSec_EncryptionContextReset__doc__,
408+
},
388409
{
389410
"encrypt_binary",
390411
(PyCFunction)PyXmlSec_EncryptionContextEncryptBinary,

src/exception.c

+29-2
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@
1616

1717
#include <pythread.h>
1818

19+
#include <stdio.h>
20+
1921
// default error class
2022
PyObject* PyXmlSec_Error;
2123
PyObject* PyXmlSec_InternalError;
2224
PyObject* PyXmlSec_VerificationError;
2325

2426
static int PyXmlSec_LastErrorKey = 0;
2527

28+
static int PyXmlSec_PrintErrorMessage = 0;
29+
2630
typedef struct {
2731
const xmlChar* file;
2832
const xmlChar* func;
@@ -83,8 +87,27 @@ static void PyXmlSec_ErrorCallback(const char* file, int line, const char* func,
8387
// TODO do not allocate error object each time.
8488
PyXmlSec_ErrorHolderFree(PyXmlSec_ExchangeLastError(PyXmlSec_ErrorHolderCreate(file, line, func, object, subject, reason, msg)));
8589

86-
// also call default callback
87-
xmlSecErrorsDefaultCallback(file, line, func, object, subject, reason, msg);
90+
if (PyXmlSec_PrintErrorMessage) {
91+
const char* error_msg = NULL;
92+
xmlSecSize i;
93+
for (i = 0; (i < XMLSEC_ERRORS_MAX_NUMBER) && (xmlSecErrorsGetMsg(i) != NULL); ++i) {
94+
if(xmlSecErrorsGetCode(i) == reason) {
95+
error_msg = xmlSecErrorsGetMsg(i);
96+
break;
97+
}
98+
}
99+
100+
fprintf(stderr,
101+
"func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s:%s\n",
102+
(func != NULL) ? func : "unknown",
103+
(file != NULL) ? file : "unknown",
104+
line,
105+
(object != NULL) ? object : "unknown",
106+
(subject != NULL) ? subject : "unknown",
107+
reason,
108+
(error_msg != NULL) ? error_msg : "",
109+
(msg != NULL) ? msg : "");
110+
}
88111
}
89112

90113
// pops the last error which was occurred in current thread
@@ -133,6 +156,10 @@ void PyXmlSec_ClearError(void) {
133156
PyXmlSec_ErrorHolderFree(PyXmlSec_ExchangeLastError(NULL));
134157
}
135158

159+
void PyXmlSecEnableDebugTrace(int v) {
160+
PyXmlSec_PrintErrorMessage = v;
161+
}
162+
136163
// initializes errors module
137164
int PyXmlSec_ExceptionsModule_Init(PyObject* package) {
138165
PyXmlSec_Error = NULL;

src/exception.h

+2
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,6 @@ void PyXmlSec_SetLastError2(PyObject* type, const char* msg);
2222

2323
void PyXmlSec_ClearError(void);
2424

25+
void PyXmlSecEnableDebugTrace(int);
26+
2527
#endif //__PYXMLSEC_EXCEPTIONS_H__

src/keys.c

+50-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,50 @@ static PyObject* PyXmlSec_KeyFromBinaryFile(PyObject* self, PyObject* args, PyOb
253253
ON_FAIL:
254254
PYXMLSEC_DEBUG("load symmetric key - fail");
255255
Py_XDECREF(key);
256-
Py_DECREF(filepath);
256+
Py_XDECREF(filepath);
257+
return NULL;
258+
}
259+
260+
static const char PyXmlSec_KeyFromBinaryData__doc__[] = \
261+
"Loads (symmetric) key of kind *klass* from *data*.\n\n"
262+
":param klass: the key value data klass\n"
263+
":param data: the key binary data\n"
264+
":return: pointer to newly created key\n";
265+
static PyObject* PyXmlSec_KeyFromBinaryData(PyObject* self, PyObject* args, PyObject* kwargs) {
266+
static char *kwlist[] = { "klass", "data", NULL};
267+
268+
PyXmlSec_KeyData* keydata = NULL;
269+
const char* data = NULL;
270+
Py_ssize_t data_size = 0;
271+
272+
PyXmlSec_Key* key = NULL;
273+
274+
PYXMLSEC_DEBUG("load symmetric key from memory - start");
275+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!s#:from_binary_data", kwlist,
276+
PyXmlSec_KeyDataType, &keydata, &data, &data_size))
277+
{
278+
goto ON_FAIL;
279+
}
280+
281+
if ((key = PyXmlSec_NewKey1((PyTypeObject*)self)) == NULL) goto ON_FAIL;
282+
283+
Py_BEGIN_ALLOW_THREADS;
284+
key->handle = xmlSecKeyReadMemory(keydata->id, (const xmlSecByte*)data, (xmlSecSize)data_size);
285+
Py_END_ALLOW_THREADS;
286+
287+
if (key->handle == NULL) {
288+
PyXmlSec_SetLastError("cannot read key");
289+
goto ON_FAIL;
290+
}
291+
292+
key->is_own = 1;
293+
294+
PYXMLSEC_DEBUG("load symmetric key from memory - ok");
295+
return (PyObject*)key;
296+
297+
ON_FAIL:
298+
PYXMLSEC_DEBUG("load symmetric key from memory - fail");
299+
Py_XDECREF(key);
257300
return NULL;
258301
}
259302

@@ -413,6 +456,12 @@ static PyMethodDef PyXmlSec_KeyMethods[] = {
413456
METH_CLASS|METH_VARARGS|METH_KEYWORDS,
414457
PyXmlSec_KeyFromBinaryFile__doc__
415458
},
459+
{
460+
"from_binary_data",
461+
(PyCFunction)PyXmlSec_KeyFromBinaryData,
462+
METH_CLASS|METH_VARARGS|METH_KEYWORDS,
463+
PyXmlSec_KeyFromBinaryData__doc__
464+
},
416465
{
417466
"load_cert_from_memory",
418467
(PyCFunction)PyXmlSec_KeyCertFromMemory,

src/main.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ static PyObject* PyXmlSec_PyEnableDebugOutput(PyObject *self, PyObject* args, Py
106106
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:enable_debug_trace", kwlist, &enabled)) {
107107
return NULL;
108108
}
109-
xmlSecErrorsDefaultCallbackEnableOutput(PyObject_IsTrue(enabled));
109+
PyXmlSecEnableDebugTrace(PyObject_IsTrue(enabled));
110110
Py_RETURN_NONE;
111111
}
112112

tests/data/enc3-in.xml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Envelope>
3+
test
4+
</Envelope>

tests/data/enc3-out.xml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Envelope>
3+
<xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
4+
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
5+
<xenc:CipherData>
6+
<xenc:CipherValue>HJwrfL7kOIB0QaldMJdza1HitpLCjw+eoult1C6yExDXJ09zKaSQER+pUL9Vt5fm
7+
d4Oitsf0CUNkjG1xWJdFsftqUIuvYGnkUNhT0vtqoYbdhJkCcB9cCwvTrww2+VTF
8+
NIasTdechlSD1qQOR8uf6+S94Ae4PVSfWU+5YLTJFpMjR+OT7f6BSbYNv1By6Cko
9+
G39WTSKTRcVDzcMxRepAGb59r508yKIJhwabCf3Opu+Ams7ia7BH4oa4ro9YSWwm
10+
hAJ0CN4a6b5odcRbNvuHcwWSxpoysWKbOROQ0H4xC4nGZeL/AXlpSc8eNuNG+g6D
11+
CTBwsOXCAEJYXPkTrnB3qQ==</xenc:CipherValue>
12+
</xenc:CipherData>
13+
</xenc:EncryptedKey>
14+
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Content" MimeType="binary/octet-stream">
15+
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
16+
<xenc:CipherData>
17+
<xenc:CipherValue>4m5BRKEswOe8JISY7NrPGLBYv7Ay5pBV+nG6it51gz0=</xenc:CipherValue>
18+
</xenc:CipherData>
19+
</xenc:EncryptedData>
20+
</Envelope>

tests/test_enc.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,25 @@ def test_decrypt1(self):
8787
def test_decrypt2(self):
8888
self.check_decrypt(2)
8989

90-
def check_decrypt(self, i, ):
90+
def test_decrypt_key(self):
91+
root = self.load_xml('enc3-out.xml')
92+
enc_key = xmlsec.tree.find_child(root, consts.NodeEncryptedKey, consts.EncNs)
93+
self.assertIsNotNone(enc_key)
94+
95+
manager = xmlsec.KeysManager()
96+
manager.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem))
97+
ctx = xmlsec.EncryptionContext(manager)
98+
keydata = ctx.decrypt(enc_key)
99+
ctx.reset()
100+
root.remove(enc_key)
101+
ctx.key = xmlsec.Key.from_binary_data(consts.KeyDataAes, keydata)
102+
enc_data = xmlsec.tree.find_child(root, consts.NodeEncryptedData, consts.EncNs)
103+
self.assertIsNotNone(enc_data)
104+
decrypted = ctx.decrypt(enc_data)
105+
self.assertIsNotNone(decrypted)
106+
self.assertEqual(self.load_xml("enc3-in.xml"), decrypted)
107+
108+
def check_decrypt(self, i):
91109
root = self.load_xml('enc%d-out.xml' % i)
92110
enc_data = xmlsec.tree.find_child(root, consts.NodeEncryptedData, consts.EncNs)
93111
self.assertIsNotNone(enc_data)

0 commit comments

Comments
 (0)