Skip to content

Merge branch develop to master (prepare version 1.2.0) #67

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
#include <stdio.h>
#define PYXMLSEC_DEBUG(fmt) fprintf(stderr, "[%s:%d %s] " fmt "\n", __FILE__, __LINE__, __FUNCTION__)
#define PYXMLSEC_DEBUGF(fmt, ...) fprintf(stderr, "[%s:%d %s] " fmt "\n", __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
#define PYXMLSEC_DUMP(method, obj) method(obj, stderr)
#else
#define PYXMLSEC_DEBUG(...)
#define PYXMLSEC_DEBUGF(...)
#define PYXMLSEC_DUMP(method, obj)
#endif // PYXMLSEC_ENABLE_DEBUG

#endif // __PYXMLSEC_DEBUG_H__
11 changes: 7 additions & 4 deletions src/ds.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,11 @@ static PyObject* PyXmlSec_SignatureContextSign(PyObject* self, PyObject* args, P
goto ON_FAIL;
}

xmlSecDSigCtxPtr ctx = ((PyXmlSec_SignatureContext*)self)->handle;
int rv;
Py_BEGIN_ALLOW_THREADS;
rv = xmlSecDSigCtxSign(((PyXmlSec_SignatureContext*)self)->handle, node->_c_node);
rv = xmlSecDSigCtxSign(ctx, node->_c_node);
PYXMLSEC_DUMP(xmlSecDSigCtxDebugDump, ctx);
Py_END_ALLOW_THREADS;
if (rv < 0) {
PyXmlSec_SetLastError("failed to sign");
Expand Down Expand Up @@ -202,17 +204,18 @@ static PyObject* PyXmlSec_SignatureContextVerify(PyObject* self, PyObject* args,
goto ON_FAIL;
}

xmlSecDSigCtxPtr handle = ((PyXmlSec_SignatureContext*)self)->handle;
xmlSecDSigCtxPtr ctx = ((PyXmlSec_SignatureContext*)self)->handle;
int rv;
Py_BEGIN_ALLOW_THREADS;
rv = xmlSecDSigCtxVerify(handle, node->_c_node);
rv = xmlSecDSigCtxVerify(ctx, node->_c_node);
PYXMLSEC_DUMP(xmlSecDSigCtxDebugDump, ctx);
Py_END_ALLOW_THREADS;

if (rv < 0) {
PyXmlSec_SetLastError("failed to verify");
goto ON_FAIL;
}
if (handle->status != xmlSecDSigStatusSucceeded) {
if (ctx->status != xmlSecDSigStatusSucceeded) {
PyErr_SetString(PyXmlSec_VerificationError, "Signature is invalid.");
goto ON_FAIL;
}
Expand Down
47 changes: 34 additions & 13 deletions src/enc.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "lxml.h"

#include <xmlsec/xmlenc.h>
#include <xmlsec/xmltree.h>

typedef struct {
PyObject_HEAD
Expand Down Expand Up @@ -105,6 +106,19 @@ static int PyXmlSec_EncryptionContextKeySet(PyObject* self, PyObject* value, voi
return 0;
}

static const char PyXmlSec_EncryptionContextReset__doc__[] = \
"Resets *context*, user settings are not touched.\n";
static PyObject* PyXmlSec_EncryptionContextReset(PyObject* self, PyObject* args, PyObject* kwargs) {
PYXMLSEC_DEBUGF("%p: reset context - start", self);
xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle;
Py_BEGIN_ALLOW_THREADS;
xmlSecEncCtxReset(ctx);
PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx);
Py_END_ALLOW_THREADS;
PYXMLSEC_DEBUGF("%p: reset context - ok", self);
Py_RETURN_NONE;
}

static const char PyXmlSec_EncryptionContextEncryptBinary__doc__[] = \
"Encrypts binary *data* according to `EncryptedData` template *template*\n"\
"Note: *template* is modified in place.\n\n"
Expand All @@ -128,6 +142,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptBinary(PyObject* self, PyObjec
int rv;
Py_BEGIN_ALLOW_THREADS;
rv = xmlSecEncCtxBinaryEncrypt(ctx, template->_c_node, (const xmlSecByte*)data, (xmlSecSize)data_size);
PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx);
Py_END_ALLOW_THREADS;

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

PyXmlSec_ClearReplacedNodes(ctx, node->_doc);
Expand Down Expand Up @@ -258,6 +271,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptUri(PyObject* self, PyObject*
int rv;
Py_BEGIN_ALLOW_THREADS;
rv = xmlSecEncCtxUriEncrypt(ctx, template->_c_node, (const xmlSecByte*)uri);
PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx);
Py_END_ALLOW_THREADS;

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

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

static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* args, PyObject* kwargs) {
Expand Down Expand Up @@ -310,15 +322,18 @@ static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* arg
}
// get index of node
node_num = PyObject_CallMethod(parent, "index", "O", node);
PYXMLSEC_DEBUGF("%p, %p", parent, node_num);
PYXMLSEC_DEBUGF("parent: %p, %p", parent, node_num);
}

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

Py_BEGIN_ALLOW_THREADS;
ctx->flags = XMLSEC_ENC_RETURN_REPLACED_NODE;
ctx->mode = xmlSecCheckNodeName(node->_c_node, xmlSecNodeEncryptedKey, xmlSecEncNs) ? xmlEncCtxModeEncryptedKey : xmlEncCtxModeEncryptedData;
PYXMLSEC_DEBUGF("mode: %d", ctx->mode);
rv = xmlSecEncCtxDecrypt(ctx, node->_c_node);
PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx);
Py_END_ALLOW_THREADS;

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

static PyMethodDef PyXmlSec_EncryptionContextMethods[] = {
{
"reset",
(PyCFunction)PyXmlSec_EncryptionContextReset,
METH_NOARGS,
PyXmlSec_EncryptionContextReset__doc__,
},
{
"encrypt_binary",
(PyCFunction)PyXmlSec_EncryptionContextEncryptBinary,
Expand Down
31 changes: 29 additions & 2 deletions src/exception.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@

#include <pythread.h>

#include <stdio.h>

// default error class
PyObject* PyXmlSec_Error;
PyObject* PyXmlSec_InternalError;
PyObject* PyXmlSec_VerificationError;

static int PyXmlSec_LastErrorKey = 0;

static int PyXmlSec_PrintErrorMessage = 0;

typedef struct {
const xmlChar* file;
const xmlChar* func;
Expand Down Expand Up @@ -83,8 +87,27 @@ static void PyXmlSec_ErrorCallback(const char* file, int line, const char* func,
// TODO do not allocate error object each time.
PyXmlSec_ErrorHolderFree(PyXmlSec_ExchangeLastError(PyXmlSec_ErrorHolderCreate(file, line, func, object, subject, reason, msg)));

// also call default callback
xmlSecErrorsDefaultCallback(file, line, func, object, subject, reason, msg);
if (PyXmlSec_PrintErrorMessage) {
const char* error_msg = NULL;
xmlSecSize i;
for (i = 0; (i < XMLSEC_ERRORS_MAX_NUMBER) && (xmlSecErrorsGetMsg(i) != NULL); ++i) {
if(xmlSecErrorsGetCode(i) == reason) {
error_msg = xmlSecErrorsGetMsg(i);
break;
}
}

fprintf(stderr,
"func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s:%s\n",
(func != NULL) ? func : "unknown",
(file != NULL) ? file : "unknown",
line,
(object != NULL) ? object : "unknown",
(subject != NULL) ? subject : "unknown",
reason,
(error_msg != NULL) ? error_msg : "",
(msg != NULL) ? msg : "");
}
}

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

void PyXmlSecEnableDebugTrace(int v) {
PyXmlSec_PrintErrorMessage = v;
}

// initializes errors module
int PyXmlSec_ExceptionsModule_Init(PyObject* package) {
PyXmlSec_Error = NULL;
Expand Down
2 changes: 2 additions & 0 deletions src/exception.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ void PyXmlSec_SetLastError2(PyObject* type, const char* msg);

void PyXmlSec_ClearError(void);

void PyXmlSecEnableDebugTrace(int);

#endif //__PYXMLSEC_EXCEPTIONS_H__
51 changes: 50 additions & 1 deletion src/keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,50 @@ static PyObject* PyXmlSec_KeyFromBinaryFile(PyObject* self, PyObject* args, PyOb
ON_FAIL:
PYXMLSEC_DEBUG("load symmetric key - fail");
Py_XDECREF(key);
Py_DECREF(filepath);
Py_XDECREF(filepath);
return NULL;
}

static const char PyXmlSec_KeyFromBinaryData__doc__[] = \
"Loads (symmetric) key of kind *klass* from *data*.\n\n"
":param klass: the key value data klass\n"
":param data: the key binary data\n"
":return: pointer to newly created key\n";
static PyObject* PyXmlSec_KeyFromBinaryData(PyObject* self, PyObject* args, PyObject* kwargs) {
static char *kwlist[] = { "klass", "data", NULL};

PyXmlSec_KeyData* keydata = NULL;
const char* data = NULL;
Py_ssize_t data_size = 0;

PyXmlSec_Key* key = NULL;

PYXMLSEC_DEBUG("load symmetric key from memory - start");
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!s#:from_binary_data", kwlist,
PyXmlSec_KeyDataType, &keydata, &data, &data_size))
{
goto ON_FAIL;
}

if ((key = PyXmlSec_NewKey1((PyTypeObject*)self)) == NULL) goto ON_FAIL;

Py_BEGIN_ALLOW_THREADS;
key->handle = xmlSecKeyReadMemory(keydata->id, (const xmlSecByte*)data, (xmlSecSize)data_size);
Py_END_ALLOW_THREADS;

if (key->handle == NULL) {
PyXmlSec_SetLastError("cannot read key");
goto ON_FAIL;
}

key->is_own = 1;

PYXMLSEC_DEBUG("load symmetric key from memory - ok");
return (PyObject*)key;

ON_FAIL:
PYXMLSEC_DEBUG("load symmetric key from memory - fail");
Py_XDECREF(key);
return NULL;
}

Expand Down Expand Up @@ -413,6 +456,12 @@ static PyMethodDef PyXmlSec_KeyMethods[] = {
METH_CLASS|METH_VARARGS|METH_KEYWORDS,
PyXmlSec_KeyFromBinaryFile__doc__
},
{
"from_binary_data",
(PyCFunction)PyXmlSec_KeyFromBinaryData,
METH_CLASS|METH_VARARGS|METH_KEYWORDS,
PyXmlSec_KeyFromBinaryData__doc__
},
{
"load_cert_from_memory",
(PyCFunction)PyXmlSec_KeyCertFromMemory,
Expand Down
2 changes: 1 addition & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ static PyObject* PyXmlSec_PyEnableDebugOutput(PyObject *self, PyObject* args, Py
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:enable_debug_trace", kwlist, &enabled)) {
return NULL;
}
xmlSecErrorsDefaultCallbackEnableOutput(PyObject_IsTrue(enabled));
PyXmlSecEnableDebugTrace(PyObject_IsTrue(enabled));
Py_RETURN_NONE;
}

Expand Down
4 changes: 4 additions & 0 deletions tests/data/enc3-in.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
test
</Envelope>
20 changes: 20 additions & 0 deletions tests/data/enc3-out.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
<xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
<xenc:CipherData>
<xenc:CipherValue>HJwrfL7kOIB0QaldMJdza1HitpLCjw+eoult1C6yExDXJ09zKaSQER+pUL9Vt5fm
d4Oitsf0CUNkjG1xWJdFsftqUIuvYGnkUNhT0vtqoYbdhJkCcB9cCwvTrww2+VTF
NIasTdechlSD1qQOR8uf6+S94Ae4PVSfWU+5YLTJFpMjR+OT7f6BSbYNv1By6Cko
G39WTSKTRcVDzcMxRepAGb59r508yKIJhwabCf3Opu+Ams7ia7BH4oa4ro9YSWwm
hAJ0CN4a6b5odcRbNvuHcwWSxpoysWKbOROQ0H4xC4nGZeL/AXlpSc8eNuNG+g6D
CTBwsOXCAEJYXPkTrnB3qQ==</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedKey>
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Content" MimeType="binary/octet-stream">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
<xenc:CipherData>
<xenc:CipherValue>4m5BRKEswOe8JISY7NrPGLBYv7Ay5pBV+nG6it51gz0=</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</Envelope>
20 changes: 19 additions & 1 deletion tests/test_enc.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,25 @@ def test_decrypt1(self):
def test_decrypt2(self):
self.check_decrypt(2)

def check_decrypt(self, i, ):
def test_decrypt_key(self):
root = self.load_xml('enc3-out.xml')
enc_key = xmlsec.tree.find_child(root, consts.NodeEncryptedKey, consts.EncNs)
self.assertIsNotNone(enc_key)

manager = xmlsec.KeysManager()
manager.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem))
ctx = xmlsec.EncryptionContext(manager)
keydata = ctx.decrypt(enc_key)
ctx.reset()
root.remove(enc_key)
ctx.key = xmlsec.Key.from_binary_data(consts.KeyDataAes, keydata)
enc_data = xmlsec.tree.find_child(root, consts.NodeEncryptedData, consts.EncNs)
self.assertIsNotNone(enc_data)
decrypted = ctx.decrypt(enc_data)
self.assertIsNotNone(decrypted)
self.assertEqual(self.load_xml("enc3-in.xml"), decrypted)

def check_decrypt(self, i):
root = self.load_xml('enc%d-out.xml' % i)
enc_data = xmlsec.tree.find_child(root, consts.NodeEncryptedData, consts.EncNs)
self.assertIsNotNone(enc_data)
Expand Down
Loading