forked from instructure/nokogiri-xmlsec-instructure
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nokogiri_decrypt_with_key.c
89 lines (75 loc) · 2.58 KB
/
nokogiri_decrypt_with_key.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include "xmlsecrb.h"
#include "util.h"
// technically we should include nokogiri.h, but we don't know
// how to find it. we _know_ this function will exist at runtime
// though, so just declare it here
void noko_xml_document_pin_node(xmlNodePtr);
VALUE decrypt_with_key(VALUE self, VALUE rb_key_name, VALUE rb_key) {
VALUE rb_exception_result = Qnil;
const char* exception_message = NULL;
xmlNodePtr node = NULL;
xmlSecEncCtxPtr encCtx = NULL;
xmlSecKeysMngrPtr keyManager = NULL;
char *key = NULL;
char *keyName = NULL;
unsigned int keyLength = 0;
resetXmlSecError();
Check_Type(rb_key, T_STRING);
Check_Type(rb_key_name, T_STRING);
Noko_Node_Get_Struct(self, xmlNode, node);
key = RSTRING_PTR(rb_key);
keyLength = RSTRING_LEN(rb_key);
keyName = StringValueCStr(rb_key_name);
keyManager = createKeyManagerWithSingleKey(key, keyLength, keyName,
&rb_exception_result,
&exception_message);
if (keyManager == NULL) {
// Propagate the exception.
goto done;
}
// create encryption context
encCtx = xmlSecEncCtxCreate(keyManager);
if(encCtx == NULL) {
rb_exception_result = rb_eDecryptionError;
exception_message = "failed to create encryption context";
goto done;
}
// don't let xmlsec free the node we're looking at out from under us
encCtx->flags |= XMLSEC_ENC_RETURN_REPLACED_NODE;
// decrypt the data
if((xmlSecEncCtxDecrypt(encCtx, node) < 0) || (encCtx->result == NULL)) {
rb_exception_result = rb_eDecryptionError;
exception_message = "decryption failed";
goto done;
}
if(encCtx->resultReplaced == 0) {
rb_exception_result = rb_eDecryptionError;
exception_message = "Not implemented: don't know how to handle decrypted, non-XML data yet";
goto done;
}
done:
// cleanup
if(encCtx != NULL) {
// the replaced node is orphaned, but not freed; let Nokogiri
// own it now
if(encCtx->replacedNodeList != NULL) {
noko_xml_document_pin_node(encCtx->replacedNodeList);
// no really, please don't free it
encCtx->replacedNodeList = NULL;
}
xmlSecEncCtxDestroy(encCtx);
}
if (keyManager != NULL) {
xmlSecKeysMngrDestroy(keyManager);
}
xmlSecErrorsSetCallback(xmlSecErrorsDefaultCallback);
if(rb_exception_result != Qnil) {
if (hasXmlSecLastError()) {
rb_raise(rb_exception_result, "%s, XmlSec error: %s", exception_message,
getXmlSecLastError());
} else {
rb_raise(rb_exception_result, "%s", exception_message);
}
}
return Qnil;
}