Skip to content

Commit 2276d51

Browse files
committed
Add support to decrypt separated EncryptedKey
1 parent ace3571 commit 2276d51

File tree

4 files changed

+72
-14
lines changed

4 files changed

+72
-14
lines changed

src/enc.c

Lines changed: 29 additions & 13 deletions
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,18 @@ 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+
Py_END_ALLOW_THREADS;
117+
PYXMLSEC_DEBUGF("%p: reset context - ok", self);
118+
Py_RETURN_NONE;
119+
}
120+
108121
static const char PyXmlSec_EncryptionContextEncryptBinary__doc__[] = \
109122
"Encrypts binary *data* according to `EncryptedData` template *template*\n"\
110123
"Note: *template* is modified in place.\n\n"
@@ -163,12 +176,9 @@ static const char PyXmlSec_EncryptionContextEncryptXml__doc__[] = \
163176
"Note: The `Type` attribute of *template* decides whether *node* itself is encrypted\n"\
164177
"(`http://www.w3.org/2001/04/xmlenc#Element`) or its content (`http://www.w3.org/2001/04/xmlenc#Content`).\n"\
165178
"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"
179+
"The operation modifies the tree and removes replaced nodes.\n"\
180+
":param template: the pointer to <enc:EncryptedData/> template node\n"\
181+
":param node: the pointer to node for encryption\n"\
172182
":return: the pointer to newly created <enc:EncryptedData/> node\n";
173183
static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* args, PyObject* kwargs) {
174184
static char *kwlist[] = { "template", "node", NULL};
@@ -273,14 +283,12 @@ static PyObject* PyXmlSec_EncryptionContextEncryptUri(PyObject* self, PyObject*
273283
}
274284

275285
static const char PyXmlSec_EncryptionContextDecrypt__doc__[] = \
276-
"Decrypts *node* (an `EncryptedData` element) and return the result.\n"\
286+
"Decrypts *node* (an `EncryptedData` or `EncryptedKey` element) and return the result.\n"\
277287
"The decryption may result in binary data or an XML subtree.\n"\
278288
"In the former case, the binary data is returned. In the latter case,\n"\
279289
"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"
290+
"If the operation modifies the tree, it removes replaced nodes.\n"\
291+
":param node: the pointer to <enc:EncryptedData/> or <enc:EncryptedKey/> node\n"
284292
":return: depends on input parameters\n";
285293

286294
static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* args, PyObject* kwargs) {
@@ -310,14 +318,16 @@ static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* arg
310318
}
311319
// get index of node
312320
node_num = PyObject_CallMethod(parent, "index", "O", node);
313-
PYXMLSEC_DEBUGF("%p, %p", parent, node_num);
321+
PYXMLSEC_DEBUGF("parent: %p, %p", parent, node_num);
314322
}
315323

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

320327
Py_BEGIN_ALLOW_THREADS;
328+
ctx->flags = XMLSEC_ENC_RETURN_REPLACED_NODE;
329+
ctx->mode = xmlSecCheckNodeName(node->_c_node, xmlSecNodeEncryptedKey, xmlSecEncNs) ? xmlEncCtxModeEncryptedKey : xmlEncCtxModeEncryptedData;
330+
PYXMLSEC_DEBUGF("mode: %d", ctx->mode);
321331
rv = xmlSecEncCtxDecrypt(ctx, node->_c_node);
322332
Py_END_ALLOW_THREADS;
323333

@@ -385,6 +395,12 @@ static PyGetSetDef PyXmlSec_EncryptionContextGetSet[] = {
385395
};
386396

387397
static PyMethodDef PyXmlSec_EncryptionContextMethods[] = {
398+
{
399+
"reset",
400+
(PyCFunction)PyXmlSec_EncryptionContextReset,
401+
METH_NOARGS,
402+
PyXmlSec_EncryptionContextReset__doc__,
403+
},
388404
{
389405
"encrypt_binary",
390406
(PyCFunction)PyXmlSec_EncryptionContextEncryptBinary,

tests/data/enc3-in.xml

Lines changed: 4 additions & 0 deletions
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

Lines changed: 20 additions & 0 deletions
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

Lines changed: 19 additions & 1 deletion
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)