nokogiri-xmlsec1 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/.travis.yml +11 -0
- data/Gemfile +4 -0
- data/Guardfile +13 -0
- data/LICENSE.txt +22 -0
- data/README.md +133 -0
- data/Rakefile +30 -0
- data/dependencies.yml +3 -0
- data/ext/nokogiri_ext_xmlsec/extconf.rb +489 -0
- data/ext/nokogiri_ext_xmlsec/init.c +46 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_decrypt_with_key.c +124 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_encrypt_with_key.c +182 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_helpers_set_attribute_id.c +43 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_init.c +32 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_sign_certificate.c +104 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_sign_rsa.c +95 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_verify_signature_certificates.c +96 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_verify_signature_named_keys.c +106 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_verify_signature_rsa.c +56 -0
- data/ext/nokogiri_ext_xmlsec/shutdown.c +12 -0
- data/ext/nokogiri_ext_xmlsec/xmlsecrb.h +39 -0
- data/lib/nokogiri-xmlsec.rb +1 -0
- data/lib/xmlsec.rb +110 -0
- data/lib/xmlsec/version.rb +3 -0
- data/nokogiri-xmlsec1.gemspec +46 -0
- data/ports/patches/libxml2/0001-Fix-parser-local-buffers-size-problems.patch +265 -0
- data/ports/patches/libxml2/0002-Fix-entities-local-buffers-size-problems.patch +102 -0
- data/ports/patches/libxml2/0003-Fix-an-error-in-previous-commit.patch +26 -0
- data/ports/patches/libxml2/0004-Fix-potential-out-of-bound-access.patch +26 -0
- data/ports/patches/libxml2/0005-Detect-excessive-entities-expansion-upon-replacement.patch +158 -0
- data/ports/patches/libxml2/0006-Do-not-fetch-external-parsed-entities.patch +78 -0
- data/ports/patches/libxml2/0007-Enforce-XML_PARSER_EOF-state-handling-through-the-pa.patch +480 -0
- data/ports/patches/libxml2/0008-Improve-handling-of-xmlStopParser.patch +315 -0
- data/ports/patches/libxml2/0009-Fix-a-couple-of-return-without-value.patch +37 -0
- data/ports/patches/libxml2/0010-Keep-non-significant-blanks-node-in-HTML-parser.patch +2006 -0
- data/ports/patches/libxml2/0011-Do-not-fetch-external-parameter-entities.patch +39 -0
- data/ports/patches/libxslt/0001-Adding-doc-update-related-to-1.1.28.patch +222 -0
- data/ports/patches/libxslt/0002-Fix-a-couple-of-places-where-f-printf-parameters-wer.patch +53 -0
- data/ports/patches/libxslt/0003-Initialize-pseudo-random-number-generator-with-curre.patch +60 -0
- data/ports/patches/libxslt/0004-EXSLT-function-str-replace-is-broken-as-is.patch +42 -0
- data/ports/patches/libxslt/0006-Fix-str-padding-to-work-with-UTF-8-strings.patch +164 -0
- data/ports/patches/libxslt/0007-Separate-function-for-predicate-matching-in-patterns.patch +587 -0
- data/ports/patches/libxslt/0008-Fix-direct-pattern-matching.patch +80 -0
- data/ports/patches/libxslt/0009-Fix-certain-patterns-with-predicates.patch +185 -0
- data/ports/patches/libxslt/0010-Fix-handling-of-UTF-8-strings-in-EXSLT-crypto-module.patch +126 -0
- data/ports/patches/libxslt/0013-Memory-leak-in-xsltCompileIdKeyPattern-error-path.patch +25 -0
- data/ports/patches/libxslt/0014-Fix-for-bug-436589.patch +43 -0
- data/ports/patches/libxslt/0015-Fix-mkdir-for-mingw.patch +41 -0
- data/ports/patches/xmlsec1/.keep +0 -0
- data/spec/fixtures/cert/server.crt +14 -0
- data/spec/fixtures/cert/server.csr +11 -0
- data/spec/fixtures/cert/server.key.decrypted +15 -0
- data/spec/fixtures/cert/server.key.encrypted +18 -0
- data/spec/fixtures/rsa.pem +15 -0
- data/spec/fixtures/rsa.pub +6 -0
- data/spec/fixtures/sign2-doc.xml +6 -0
- data/spec/fixtures/sign2-result.xml +24 -0
- data/spec/fixtures/sign3-result.xml +37 -0
- data/spec/lib/nokogiri/xml/document/encryption_and_decryption_spec.rb +22 -0
- data/spec/lib/nokogiri/xml/document/signing_and_verifying_spec.rb +77 -0
- data/spec/spec_helper.rb +10 -0
- metadata +251 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
#include "xmlsecrb.h"
|
2
|
+
|
3
|
+
void Init_nokogiri_ext_xmlsec() {
|
4
|
+
/* xmlsec proper */
|
5
|
+
// libxml
|
6
|
+
xmlInitParser();
|
7
|
+
LIBXML_TEST_VERSION
|
8
|
+
xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
|
9
|
+
xmlSubstituteEntitiesDefault(1);
|
10
|
+
// xslt
|
11
|
+
#ifndef XMLSEC_NO_XSLT
|
12
|
+
xmlIndentTreeOutput = 1;
|
13
|
+
#endif /* XMLSEC_NO_XSLT */
|
14
|
+
// xmlsec
|
15
|
+
if (xmlSecInit() < 0) {
|
16
|
+
rb_raise(rb_eRuntimeError, "xmlsec initialization failed");
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
if (xmlSecCheckVersion() != 1) {
|
20
|
+
rb_raise(rb_eRuntimeError, "xmlsec version is not compatible");
|
21
|
+
return;
|
22
|
+
}
|
23
|
+
// load crypto
|
24
|
+
#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
|
25
|
+
if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
|
26
|
+
rb_raise(rb_eRuntimeError,
|
27
|
+
"Error: unable to load default xmlsec-crypto library. Make sure"
|
28
|
+
"that you have it installed and check shared libraries path\n"
|
29
|
+
"(LD_LIBRARY_PATH) envornment variable.\n");
|
30
|
+
return;
|
31
|
+
}
|
32
|
+
#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */
|
33
|
+
// init crypto
|
34
|
+
if (xmlSecCryptoAppInit(NULL) < 0) {
|
35
|
+
rb_raise(rb_eRuntimeError, "unable to initialize crypto engine");
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
// init xmlsec-crypto library
|
39
|
+
if (xmlSecCryptoInit() < 0) {
|
40
|
+
rb_raise(rb_eRuntimeError, "xmlsec-crypto initialization failed");
|
41
|
+
}
|
42
|
+
|
43
|
+
/* ruby classes & objects */
|
44
|
+
Init_Nokogiri_ext();
|
45
|
+
}
|
46
|
+
|
@@ -0,0 +1,124 @@
|
|
1
|
+
#include "xmlsecrb.h"
|
2
|
+
|
3
|
+
static xmlSecKeysMngrPtr getKeyManager(char* keyStr, unsigned int keyLength, char *keyName) {
|
4
|
+
xmlSecKeysMngrPtr mngr;
|
5
|
+
xmlSecKeyPtr key;
|
6
|
+
|
7
|
+
/* create and initialize keys manager, we use a simple list based
|
8
|
+
* keys manager, implement your own xmlSecKeysStore klass if you need
|
9
|
+
* something more sophisticated
|
10
|
+
*/
|
11
|
+
mngr = xmlSecKeysMngrCreate();
|
12
|
+
if(mngr == NULL) {
|
13
|
+
rb_raise(rb_eDecryptionError, "failed to create keys manager.");
|
14
|
+
return(NULL);
|
15
|
+
}
|
16
|
+
if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) {
|
17
|
+
rb_raise(rb_eDecryptionError, "failed to initialize keys manager.");
|
18
|
+
xmlSecKeysMngrDestroy(mngr);
|
19
|
+
return(NULL);
|
20
|
+
}
|
21
|
+
|
22
|
+
/* load private RSA key */
|
23
|
+
// key = xmlSecCryptoAppKeyLoad(key_file, xmlSecKeyDataFormatPem, NULL, NULL, NULL);
|
24
|
+
key = xmlSecCryptoAppKeyLoadMemory((xmlSecByte *)keyStr,
|
25
|
+
keyLength,
|
26
|
+
xmlSecKeyDataFormatPem,
|
27
|
+
NULL, // password
|
28
|
+
NULL, NULL);
|
29
|
+
if(key == NULL) {
|
30
|
+
rb_raise(rb_eDecryptionError, "failed to load rsa key");
|
31
|
+
xmlSecKeysMngrDestroy(mngr);
|
32
|
+
return(NULL);
|
33
|
+
}
|
34
|
+
|
35
|
+
/* set key name to the file name, this is just an example! */
|
36
|
+
if(xmlSecKeySetName(key, BAD_CAST keyName) < 0) {
|
37
|
+
rb_raise(rb_eDecryptionError, "failed to set key name");
|
38
|
+
xmlSecKeyDestroy(key);
|
39
|
+
xmlSecKeysMngrDestroy(mngr);
|
40
|
+
return(NULL);
|
41
|
+
}
|
42
|
+
|
43
|
+
/* add key to keys manager, from now on keys manager is responsible
|
44
|
+
* for destroying key
|
45
|
+
*/
|
46
|
+
if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(mngr, key) < 0) {
|
47
|
+
rb_raise(rb_eDecryptionError, "failed to add key to keys manager");
|
48
|
+
xmlSecKeyDestroy(key);
|
49
|
+
xmlSecKeysMngrDestroy(mngr);
|
50
|
+
return(NULL);
|
51
|
+
}
|
52
|
+
|
53
|
+
return(mngr);
|
54
|
+
}
|
55
|
+
|
56
|
+
VALUE decrypt_with_key(VALUE self, VALUE rb_key_name, VALUE rb_key) {
|
57
|
+
xmlDocPtr doc;
|
58
|
+
xmlNodePtr node = NULL;
|
59
|
+
xmlSecEncCtxPtr encCtx = NULL;
|
60
|
+
xmlSecKeysMngrPtr keyManager = NULL;
|
61
|
+
char *key;
|
62
|
+
char *keyName;
|
63
|
+
unsigned int keyLength;
|
64
|
+
|
65
|
+
Check_Type(rb_key, T_STRING);
|
66
|
+
Check_Type(rb_key_name, T_STRING);
|
67
|
+
Data_Get_Struct(self, xmlDoc, doc);
|
68
|
+
key = RSTRING_PTR(rb_key);
|
69
|
+
keyLength = RSTRING_LEN(rb_key);
|
70
|
+
keyName = RSTRING_PTR(rb_key_name);
|
71
|
+
|
72
|
+
|
73
|
+
// find start node
|
74
|
+
node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeEncryptedData, xmlSecEncNs);
|
75
|
+
if(node == NULL) {
|
76
|
+
rb_raise(rb_eDecryptionError, "start node not found");
|
77
|
+
goto done;
|
78
|
+
}
|
79
|
+
|
80
|
+
keyManager = getKeyManager(key, keyLength, keyName);
|
81
|
+
if (keyManager == NULL) {
|
82
|
+
rb_raise(rb_eEncryptionError, "failed to create key manager");
|
83
|
+
goto done;
|
84
|
+
}
|
85
|
+
|
86
|
+
// create encryption context
|
87
|
+
encCtx = xmlSecEncCtxCreate(keyManager);
|
88
|
+
if(encCtx == NULL) {
|
89
|
+
rb_raise(rb_eDecryptionError, "failed to create encryption context");
|
90
|
+
goto done;
|
91
|
+
}
|
92
|
+
|
93
|
+
// decrypt the data
|
94
|
+
if((xmlSecEncCtxDecrypt(encCtx, node) < 0) || (encCtx->result == NULL)) {
|
95
|
+
rb_raise(rb_eDecryptionError, "decryption failed");
|
96
|
+
goto done;
|
97
|
+
}
|
98
|
+
|
99
|
+
if(encCtx->resultReplaced == 0) {
|
100
|
+
fprintf(stdout, "Decrypted binary data (%d bytes):", xmlSecBufferGetSize(encCtx->result));
|
101
|
+
if(xmlSecBufferGetData(encCtx->result) != NULL) {
|
102
|
+
fwrite(xmlSecBufferGetData(encCtx->result),
|
103
|
+
1,
|
104
|
+
xmlSecBufferGetSize(encCtx->result),
|
105
|
+
stdout);
|
106
|
+
fprintf(stdout, "\n");
|
107
|
+
}
|
108
|
+
|
109
|
+
rb_raise(rb_eDecryptionError, "Not implemented: don't know how to handle decrypted, non-XML data yet");
|
110
|
+
goto done;
|
111
|
+
}
|
112
|
+
|
113
|
+
done:
|
114
|
+
// cleanup
|
115
|
+
if(encCtx != NULL) {
|
116
|
+
xmlSecEncCtxDestroy(encCtx);
|
117
|
+
}
|
118
|
+
|
119
|
+
if (keyManager != NULL) {
|
120
|
+
xmlSecKeysMngrDestroy(keyManager);
|
121
|
+
}
|
122
|
+
|
123
|
+
return T_NIL;
|
124
|
+
}
|
@@ -0,0 +1,182 @@
|
|
1
|
+
#include "xmlsecrb.h"
|
2
|
+
|
3
|
+
static xmlSecKeysMngrPtr getKeyManager(char* keyStr, unsigned int keyLength, char *keyName) {
|
4
|
+
xmlSecKeysMngrPtr mngr;
|
5
|
+
xmlSecKeyPtr key;
|
6
|
+
|
7
|
+
/* create and initialize keys manager, we use a simple list based
|
8
|
+
* keys manager, implement your own xmlSecKeysStore klass if you need
|
9
|
+
* something more sophisticated
|
10
|
+
*/
|
11
|
+
mngr = xmlSecKeysMngrCreate();
|
12
|
+
if(mngr == NULL) {
|
13
|
+
rb_raise(rb_eDecryptionError, "failed to create keys manager.");
|
14
|
+
return(NULL);
|
15
|
+
}
|
16
|
+
if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) {
|
17
|
+
rb_raise(rb_eDecryptionError, "failed to initialize keys manager.");
|
18
|
+
xmlSecKeysMngrDestroy(mngr);
|
19
|
+
return(NULL);
|
20
|
+
}
|
21
|
+
|
22
|
+
/* load private RSA key */
|
23
|
+
// key = xmlSecCryptoAppKeyLoad(key_file, xmlSecKeyDataFormatPem, NULL, NULL, NULL);
|
24
|
+
key = xmlSecCryptoAppKeyLoadMemory((xmlSecByte *)keyStr,
|
25
|
+
keyLength,
|
26
|
+
xmlSecKeyDataFormatPem,
|
27
|
+
NULL, // password
|
28
|
+
NULL, NULL);
|
29
|
+
if(key == NULL) {
|
30
|
+
rb_raise(rb_eDecryptionError, "failed to load rsa key");
|
31
|
+
xmlSecKeysMngrDestroy(mngr);
|
32
|
+
return(NULL);
|
33
|
+
}
|
34
|
+
|
35
|
+
/* set key name to the file name, this is just an example! */
|
36
|
+
if(xmlSecKeySetName(key, BAD_CAST keyName) < 0) {
|
37
|
+
rb_raise(rb_eDecryptionError, "failed to set key name");
|
38
|
+
xmlSecKeyDestroy(key);
|
39
|
+
xmlSecKeysMngrDestroy(mngr);
|
40
|
+
return(NULL);
|
41
|
+
}
|
42
|
+
|
43
|
+
/* add key to keys manager, from now on keys manager is responsible
|
44
|
+
* for destroying key
|
45
|
+
*/
|
46
|
+
if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(mngr, key) < 0) {
|
47
|
+
rb_raise(rb_eDecryptionError, "failed to add key to keys manager");
|
48
|
+
xmlSecKeyDestroy(key);
|
49
|
+
xmlSecKeysMngrDestroy(mngr);
|
50
|
+
return(NULL);
|
51
|
+
}
|
52
|
+
|
53
|
+
return(mngr);
|
54
|
+
}
|
55
|
+
|
56
|
+
VALUE encrypt_with_key(VALUE self, VALUE rb_key_name, VALUE rb_key) {
|
57
|
+
xmlDocPtr doc;
|
58
|
+
xmlNodePtr encDataNode = NULL;
|
59
|
+
xmlNodePtr encKeyNode = NULL;
|
60
|
+
xmlNodePtr keyInfoNode = NULL;
|
61
|
+
xmlSecEncCtxPtr encCtx = NULL;
|
62
|
+
xmlSecKeysMngrPtr keyManager = NULL;
|
63
|
+
char *keyName;
|
64
|
+
char *key;
|
65
|
+
unsigned int keyLength;
|
66
|
+
|
67
|
+
Check_Type(rb_key_name, T_STRING);
|
68
|
+
Check_Type(rb_key, T_STRING);
|
69
|
+
Data_Get_Struct(self, xmlDoc, doc);
|
70
|
+
key = RSTRING_PTR(rb_key);
|
71
|
+
keyLength = RSTRING_LEN(rb_key);
|
72
|
+
keyName = RSTRING_PTR(rb_key_name);
|
73
|
+
|
74
|
+
// create encryption template to encrypt XML file and replace
|
75
|
+
// its content with encryption result
|
76
|
+
encDataNode = xmlSecTmplEncDataCreate(doc, xmlSecTransformDes3CbcId,
|
77
|
+
NULL, xmlSecTypeEncElement, NULL, NULL);
|
78
|
+
if(encDataNode == NULL) {
|
79
|
+
rb_raise(rb_eEncryptionError, "failed to create encryption template");
|
80
|
+
goto done;
|
81
|
+
}
|
82
|
+
|
83
|
+
// we want to put encrypted data in the <enc:CipherValue/> node
|
84
|
+
if(xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL) {
|
85
|
+
rb_raise(rb_eEncryptionError, "failed to add CipherValue node");
|
86
|
+
goto done;
|
87
|
+
}
|
88
|
+
|
89
|
+
// add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to put key name in the
|
90
|
+
// signed document
|
91
|
+
keyInfoNode = xmlSecTmplEncDataEnsureKeyInfo(encDataNode, NULL);
|
92
|
+
if(keyInfoNode == NULL) {
|
93
|
+
rb_raise(rb_eEncryptionError, "failed to add key info");
|
94
|
+
goto done;
|
95
|
+
}
|
96
|
+
|
97
|
+
if(xmlSecTmplKeyInfoAddKeyName(keyInfoNode, NULL) == NULL) {
|
98
|
+
rb_raise(rb_eEncryptionError, "failed to add key name");
|
99
|
+
goto done;
|
100
|
+
}
|
101
|
+
|
102
|
+
keyManager = getKeyManager(key, keyLength, keyName);
|
103
|
+
if (keyManager == NULL) {
|
104
|
+
rb_raise(rb_eEncryptionError, "failed to create key manager");
|
105
|
+
goto done;
|
106
|
+
}
|
107
|
+
|
108
|
+
// create encryption context, we don't need keys manager in this example
|
109
|
+
encCtx = xmlSecEncCtxCreate(keyManager);
|
110
|
+
if(encCtx == NULL) {
|
111
|
+
rb_raise(rb_eEncryptionError, "failed to create encryption context");
|
112
|
+
goto done;
|
113
|
+
}
|
114
|
+
|
115
|
+
// generate a 3DES key
|
116
|
+
// TODO make a note of this one, it lets us pass in key type and bits from ruby
|
117
|
+
encCtx->encKey = xmlSecKeyGenerateByName((xmlChar *)"des", 192,
|
118
|
+
xmlSecKeyDataTypeSession);
|
119
|
+
|
120
|
+
// encCtx->encKey = xmlSecKeyGenerate(xmlSecKeyDataDesId, 192,
|
121
|
+
// xmlSecKeyDataTypeSession);
|
122
|
+
// encCtx->encKey = xmlSecAppCryptoKeyGenerate(xmlSecAppCmdLineParamGetString(&sessionKeyParam),
|
123
|
+
// NULL, xmlSecKeyDataTypeSession);
|
124
|
+
if(encCtx->encKey == NULL) {
|
125
|
+
rb_raise(rb_eDecryptionError, "failed to generate session des key");
|
126
|
+
goto done;
|
127
|
+
}
|
128
|
+
|
129
|
+
// set key name
|
130
|
+
if(xmlSecKeySetName(encCtx->encKey, (xmlSecByte *)keyName) < 0) {
|
131
|
+
rb_raise(rb_eEncryptionError, "failed to set key name to '%s'", keyName);
|
132
|
+
goto done;
|
133
|
+
}
|
134
|
+
|
135
|
+
// add <enc:EncryptedKey/> node to the <dsig:KeyInfo/> tag to include
|
136
|
+
// the session key
|
137
|
+
encKeyNode = xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode,
|
138
|
+
xmlSecTransformRsaPkcs1Id, // encMethodId encryptionMethod
|
139
|
+
NULL, // xmlChar *idAttribute
|
140
|
+
NULL, // xmlChar *typeAttribute
|
141
|
+
NULL // xmlChar *recipient
|
142
|
+
);
|
143
|
+
if (encKeyNode == NULL) {
|
144
|
+
rb_raise(rb_eEncryptionError, "failed to add encrypted key node");
|
145
|
+
goto done;
|
146
|
+
}
|
147
|
+
if (xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == NULL) {
|
148
|
+
rb_raise(rb_eEncryptionError, "failed to add encrypted cipher value");
|
149
|
+
goto done;
|
150
|
+
}
|
151
|
+
|
152
|
+
// encrypt the data
|
153
|
+
if(xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, xmlDocGetRootElement(doc)) < 0) {
|
154
|
+
rb_raise(rb_eEncryptionError, "encryption failed");
|
155
|
+
goto done;
|
156
|
+
}
|
157
|
+
|
158
|
+
// the template is inserted in the doc, so don't free it
|
159
|
+
encDataNode = NULL;
|
160
|
+
encKeyNode = NULL;
|
161
|
+
|
162
|
+
done:
|
163
|
+
|
164
|
+
/* cleanup */
|
165
|
+
if(encCtx != NULL) {
|
166
|
+
xmlSecEncCtxDestroy(encCtx);
|
167
|
+
}
|
168
|
+
|
169
|
+
if (encKeyNode != NULL) {
|
170
|
+
xmlFreeNode(encKeyNode);
|
171
|
+
}
|
172
|
+
|
173
|
+
if(encDataNode != NULL) {
|
174
|
+
xmlFreeNode(encDataNode);
|
175
|
+
}
|
176
|
+
|
177
|
+
if (keyManager != NULL) {
|
178
|
+
xmlSecKeysMngrDestroy(keyManager);
|
179
|
+
}
|
180
|
+
|
181
|
+
return T_NIL;
|
182
|
+
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#include "xmlsecrb.h"
|
2
|
+
|
3
|
+
VALUE set_id_attribute(VALUE self, VALUE rb_attr_name) {
|
4
|
+
xmlNodePtr node;
|
5
|
+
xmlAttrPtr attr;
|
6
|
+
xmlAttrPtr tmp;
|
7
|
+
xmlChar *name;
|
8
|
+
const xmlChar *idName;
|
9
|
+
|
10
|
+
Data_Get_Struct(self, xmlNode, node);
|
11
|
+
Check_Type(rb_attr_name, T_STRING);
|
12
|
+
idName = (const xmlChar *)RSTRING_PTR(rb_attr_name);
|
13
|
+
|
14
|
+
// find pointer to id attribute
|
15
|
+
attr = xmlHasProp(node, idName);
|
16
|
+
if((attr == NULL) || (attr->children == NULL)) {
|
17
|
+
rb_raise(rb_eRuntimeError, "Can't find attribute to add register as id");
|
18
|
+
return Qfalse;
|
19
|
+
}
|
20
|
+
|
21
|
+
// get the attribute (id) value
|
22
|
+
name = xmlNodeListGetString(node->doc, attr->children, 1);
|
23
|
+
if(name == NULL) {
|
24
|
+
rb_raise(rb_eRuntimeError, "Attribute %s has no value", idName);
|
25
|
+
return Qfalse;
|
26
|
+
}
|
27
|
+
|
28
|
+
// check that we don't have that id already registered
|
29
|
+
tmp = xmlGetID(node->doc, name);
|
30
|
+
if(tmp != NULL) {
|
31
|
+
// rb_raise(rb_eRuntimeError, "Attribute %s is already an ID", idName);
|
32
|
+
xmlFree(name);
|
33
|
+
return Qfalse;
|
34
|
+
}
|
35
|
+
|
36
|
+
// finally register id
|
37
|
+
xmlAddID(NULL, node->doc, name, attr);
|
38
|
+
|
39
|
+
// and do not forget to cleanup
|
40
|
+
xmlFree(name);
|
41
|
+
|
42
|
+
return Qtrue;
|
43
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#include "xmlsecrb.h"
|
2
|
+
|
3
|
+
VALUE rb_cNokogiri_XML_Document = T_NIL;
|
4
|
+
VALUE rb_cNokogiri_XML_Node = T_NIL;
|
5
|
+
VALUE rb_eSigningError = T_NIL;
|
6
|
+
VALUE rb_eVerificationError = T_NIL;
|
7
|
+
VALUE rb_eKeystoreError = T_NIL;
|
8
|
+
VALUE rb_eEncryptionError = T_NIL;
|
9
|
+
VALUE rb_eDecryptionError = T_NIL;
|
10
|
+
|
11
|
+
void Init_Nokogiri_ext() {
|
12
|
+
VALUE XMLSec = rb_define_module("XMLSec");
|
13
|
+
VALUE Nokogiri = rb_define_module("Nokogiri");
|
14
|
+
VALUE Nokogiri_XML = rb_define_module_under(Nokogiri, "XML");
|
15
|
+
rb_cNokogiri_XML_Document = rb_const_get(Nokogiri_XML, rb_intern("Document"));
|
16
|
+
rb_cNokogiri_XML_Node = rb_const_get(Nokogiri_XML, rb_intern("Node"));
|
17
|
+
|
18
|
+
rb_define_method(rb_cNokogiri_XML_Document, "sign_with_key", sign_with_key, 2);
|
19
|
+
rb_define_method(rb_cNokogiri_XML_Document, "sign_with_certificate", sign_with_certificate, 3);
|
20
|
+
rb_define_method(rb_cNokogiri_XML_Document, "verify_with_rsa_key", verify_signature_with_rsa_key, 1);
|
21
|
+
rb_define_method(rb_cNokogiri_XML_Document, "verify_with_named_keys", verify_signature_with_named_keys, 1);
|
22
|
+
rb_define_method(rb_cNokogiri_XML_Document, "verify_with_certificates", verify_signature_with_certificates, 1);
|
23
|
+
rb_define_method(rb_cNokogiri_XML_Document, "encrypt_with_key", encrypt_with_key, 2);
|
24
|
+
rb_define_method(rb_cNokogiri_XML_Document, "decrypt_with_key", decrypt_with_key, 2);
|
25
|
+
rb_define_method(rb_cNokogiri_XML_Node, "set_id_attribute", set_id_attribute, 1);
|
26
|
+
|
27
|
+
rb_eSigningError = rb_define_class_under(XMLSec, "SigningError", rb_eRuntimeError);
|
28
|
+
rb_eVerificationError = rb_define_class_under(XMLSec, "VerificationError", rb_eRuntimeError);
|
29
|
+
rb_eKeystoreError = rb_define_class_under(XMLSec, "KeystoreError", rb_eRuntimeError);
|
30
|
+
rb_eEncryptionError = rb_define_class_under(XMLSec, "EncryptionError", rb_eRuntimeError);
|
31
|
+
rb_eDecryptionError = rb_define_class_under(XMLSec, "DecryptionError", rb_eRuntimeError);
|
32
|
+
}
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#include "xmlsecrb.h"
|
2
|
+
|
3
|
+
VALUE sign_with_certificate(VALUE self, VALUE rb_key_name, VALUE rb_rsa_key, VALUE rb_cert) {
|
4
|
+
xmlDocPtr doc;
|
5
|
+
xmlNodePtr signNode = NULL;
|
6
|
+
xmlNodePtr refNode = NULL;
|
7
|
+
xmlNodePtr keyInfoNode = NULL;
|
8
|
+
xmlSecDSigCtxPtr dsigCtx = NULL;
|
9
|
+
char *keyName;
|
10
|
+
char *certificate;
|
11
|
+
char *rsaKey;
|
12
|
+
unsigned int rsaKeyLength, certificateLength;
|
13
|
+
|
14
|
+
Data_Get_Struct(self, xmlDoc, doc);
|
15
|
+
rsaKey = RSTRING_PTR(rb_rsa_key);
|
16
|
+
rsaKeyLength = RSTRING_LEN(rb_rsa_key);
|
17
|
+
keyName = RSTRING_PTR(rb_key_name);
|
18
|
+
certificate = RSTRING_PTR(rb_cert);
|
19
|
+
certificateLength = RSTRING_LEN(rb_cert);
|
20
|
+
|
21
|
+
// create signature template for RSA-SHA1 enveloped signature
|
22
|
+
signNode = xmlSecTmplSignatureCreate(doc, xmlSecTransformExclC14NId,
|
23
|
+
xmlSecTransformRsaSha1Id, NULL);
|
24
|
+
if (signNode == NULL) {
|
25
|
+
rb_raise(rb_eSigningError, "failed to create signature template");
|
26
|
+
goto done;
|
27
|
+
}
|
28
|
+
|
29
|
+
// add <dsig:Signature/> node to the doc
|
30
|
+
xmlAddChild(xmlDocGetRootElement(doc), signNode);
|
31
|
+
|
32
|
+
// add reference
|
33
|
+
refNode = xmlSecTmplSignatureAddReference(signNode, xmlSecTransformSha1Id,
|
34
|
+
NULL, NULL, NULL);
|
35
|
+
if(refNode == NULL) {
|
36
|
+
rb_raise(rb_eSigningError, "failed to add reference to signature template");
|
37
|
+
goto done;
|
38
|
+
}
|
39
|
+
|
40
|
+
// add enveloped transform
|
41
|
+
if(xmlSecTmplReferenceAddTransform(refNode, xmlSecTransformEnvelopedId) == NULL) {
|
42
|
+
rb_raise(rb_eSigningError, "failed to add enveloped transform to reference");
|
43
|
+
goto done;
|
44
|
+
}
|
45
|
+
|
46
|
+
// add <dsig:KeyInfo/> and <dsig:X509Data/>
|
47
|
+
keyInfoNode = xmlSecTmplSignatureEnsureKeyInfo(signNode, NULL);
|
48
|
+
if(keyInfoNode == NULL) {
|
49
|
+
rb_raise(rb_eSigningError, "failed to add key info");
|
50
|
+
goto done;
|
51
|
+
}
|
52
|
+
|
53
|
+
if(xmlSecTmplKeyInfoAddX509Data(keyInfoNode) == NULL) {
|
54
|
+
rb_raise(rb_eSigningError, "failed to add X509Data node");
|
55
|
+
goto done;
|
56
|
+
}
|
57
|
+
|
58
|
+
// create signature context, we don't need keys manager in this example
|
59
|
+
dsigCtx = xmlSecDSigCtxCreate(NULL);
|
60
|
+
if(dsigCtx == NULL) {
|
61
|
+
rb_raise(rb_eSigningError, "failed to create signature context");
|
62
|
+
goto done;
|
63
|
+
}
|
64
|
+
|
65
|
+
// load private key, assuming that there is not password
|
66
|
+
dsigCtx->signKey = xmlSecCryptoAppKeyLoadMemory((xmlSecByte *)rsaKey,
|
67
|
+
rsaKeyLength,
|
68
|
+
xmlSecKeyDataFormatPem,
|
69
|
+
NULL, // password
|
70
|
+
NULL,
|
71
|
+
NULL);
|
72
|
+
if(dsigCtx->signKey == NULL) {
|
73
|
+
rb_raise(rb_eSigningError, "failed to load private key");
|
74
|
+
goto done;
|
75
|
+
}
|
76
|
+
|
77
|
+
// load certificate and add to the key
|
78
|
+
if(xmlSecCryptoAppKeyCertLoadMemory(dsigCtx->signKey,
|
79
|
+
(xmlSecByte *)certificate,
|
80
|
+
certificateLength,
|
81
|
+
xmlSecKeyDataFormatPem) < 0) {
|
82
|
+
rb_raise(rb_eSigningError, "failed to load certificate");
|
83
|
+
goto done;
|
84
|
+
}
|
85
|
+
|
86
|
+
// set key name
|
87
|
+
if(xmlSecKeySetName(dsigCtx->signKey, (xmlSecByte *)keyName) < 0) {
|
88
|
+
rb_raise(rb_eSigningError, "failed to set key name");
|
89
|
+
goto done;
|
90
|
+
}
|
91
|
+
|
92
|
+
// sign the template
|
93
|
+
if(xmlSecDSigCtxSign(dsigCtx, signNode) < 0) {
|
94
|
+
rb_raise(rb_eSigningError, "signature failed");
|
95
|
+
goto done;
|
96
|
+
}
|
97
|
+
|
98
|
+
done:
|
99
|
+
if(dsigCtx != NULL) {
|
100
|
+
xmlSecDSigCtxDestroy(dsigCtx);
|
101
|
+
}
|
102
|
+
|
103
|
+
return T_NIL;
|
104
|
+
}
|