nokogiri-xmlsec1 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,95 @@
|
|
1
|
+
#include "xmlsecrb.h"
|
2
|
+
|
3
|
+
// TODO the signature context probably should be a ruby instance variable
|
4
|
+
// and separate object, instead of being allocated/freed in each method.
|
5
|
+
|
6
|
+
VALUE sign_with_key(VALUE self, VALUE rb_key_name, VALUE rb_rsa_key) {
|
7
|
+
xmlDocPtr doc;
|
8
|
+
xmlNodePtr signNode = NULL;
|
9
|
+
xmlNodePtr refNode = NULL;
|
10
|
+
xmlNodePtr keyInfoNode = NULL;
|
11
|
+
xmlSecDSigCtxPtr dsigCtx = NULL;
|
12
|
+
char *keyName;
|
13
|
+
char *rsaKey;
|
14
|
+
unsigned int rsaKeyLength;
|
15
|
+
|
16
|
+
Data_Get_Struct(self, xmlDoc, doc);
|
17
|
+
rsaKey = RSTRING_PTR(rb_rsa_key);
|
18
|
+
rsaKeyLength = RSTRING_LEN(rb_rsa_key);
|
19
|
+
keyName = RSTRING_PTR(rb_key_name);
|
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:KeyName/> nodes to put key name in the signed
|
47
|
+
// document
|
48
|
+
keyInfoNode = xmlSecTmplSignatureEnsureKeyInfo(signNode, NULL);
|
49
|
+
if(keyInfoNode == NULL) {
|
50
|
+
rb_raise(rb_eSigningError, "failed to add key info");
|
51
|
+
goto done;
|
52
|
+
}
|
53
|
+
if(xmlSecTmplKeyInfoAddKeyName(keyInfoNode, NULL) == NULL) {
|
54
|
+
rb_raise(rb_eSigningError, "failed to add key name");
|
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 no 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 pem key");
|
74
|
+
goto done;
|
75
|
+
}
|
76
|
+
|
77
|
+
// set key name
|
78
|
+
if(xmlSecKeySetName(dsigCtx->signKey, (xmlSecByte *)keyName) < 0) {
|
79
|
+
rb_raise(rb_eSigningError, "failed to set key name");
|
80
|
+
goto done;
|
81
|
+
}
|
82
|
+
|
83
|
+
// sign the template
|
84
|
+
if(xmlSecDSigCtxSign(dsigCtx, signNode) < 0) {
|
85
|
+
rb_raise(rb_eSigningError, "signature failed");
|
86
|
+
goto done;
|
87
|
+
}
|
88
|
+
|
89
|
+
done:
|
90
|
+
if(dsigCtx != NULL) {
|
91
|
+
xmlSecDSigCtxDestroy(dsigCtx);
|
92
|
+
}
|
93
|
+
|
94
|
+
return T_NIL;
|
95
|
+
}
|
@@ -0,0 +1,96 @@
|
|
1
|
+
#include "xmlsecrb.h"
|
2
|
+
|
3
|
+
static xmlSecKeysMngrPtr getKeyManager(VALUE rb_certs) {
|
4
|
+
int i, numCerts = RARRAY_LEN(rb_certs);
|
5
|
+
xmlSecKeysMngrPtr keyManager = xmlSecKeysMngrCreate();
|
6
|
+
VALUE rb_cert;
|
7
|
+
char *cert;
|
8
|
+
unsigned int certLength;
|
9
|
+
int numSuccessful = 0;
|
10
|
+
|
11
|
+
if (keyManager == NULL) return NULL;
|
12
|
+
|
13
|
+
if (xmlSecCryptoAppDefaultKeysMngrInit(keyManager) < 0) {
|
14
|
+
rb_raise(rb_eKeystoreError, "could not initialize key manager");
|
15
|
+
xmlSecKeysMngrDestroy(keyManager);
|
16
|
+
return NULL;
|
17
|
+
}
|
18
|
+
|
19
|
+
for (i = 0; i < numCerts; i++) {
|
20
|
+
rb_cert = RARRAY_PTR(rb_certs)[i];
|
21
|
+
Check_Type(rb_cert, T_STRING);
|
22
|
+
cert = RSTRING_PTR(rb_cert);
|
23
|
+
certLength = RSTRING_LEN(rb_cert);
|
24
|
+
|
25
|
+
if(xmlSecCryptoAppKeysMngrCertLoadMemory(keyManager,
|
26
|
+
(xmlSecByte *)cert,
|
27
|
+
certLength,
|
28
|
+
xmlSecKeyDataFormatPem,
|
29
|
+
xmlSecKeyDataTypeTrusted) < 0) {
|
30
|
+
rb_warn("failed to load certificate at index %d", i);
|
31
|
+
} else {
|
32
|
+
numSuccessful++;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
// note, numCerts could be zero, meaning that we should use system SSL certs
|
37
|
+
if (numSuccessful == 0 && numCerts != 0) {
|
38
|
+
rb_raise(rb_eKeystoreError, "Could not load any of the specified certificates for signature verification");
|
39
|
+
xmlSecKeysMngrDestroy(keyManager);
|
40
|
+
return NULL;
|
41
|
+
}
|
42
|
+
|
43
|
+
return keyManager;
|
44
|
+
}
|
45
|
+
|
46
|
+
VALUE verify_signature_with_certificates(VALUE self, VALUE rb_certs) {
|
47
|
+
xmlDocPtr doc;
|
48
|
+
xmlNodePtr node = NULL;
|
49
|
+
xmlSecDSigCtxPtr dsigCtx = NULL;
|
50
|
+
xmlSecKeysMngrPtr keyManager = NULL;
|
51
|
+
VALUE result = Qfalse;
|
52
|
+
|
53
|
+
Check_Type(rb_certs, T_ARRAY);
|
54
|
+
Data_Get_Struct(self, xmlDoc, doc);
|
55
|
+
|
56
|
+
// find start node
|
57
|
+
node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs);
|
58
|
+
if(node == NULL) {
|
59
|
+
rb_raise(rb_eVerificationError, "start node not found");
|
60
|
+
goto done;
|
61
|
+
}
|
62
|
+
|
63
|
+
keyManager = getKeyManager(rb_certs);
|
64
|
+
if (keyManager == NULL) {
|
65
|
+
rb_raise(rb_eKeystoreError, "failed to create key manager");
|
66
|
+
goto done;
|
67
|
+
}
|
68
|
+
|
69
|
+
// create signature context, we don't need keys manager in this example
|
70
|
+
dsigCtx = xmlSecDSigCtxCreate(keyManager);
|
71
|
+
if(dsigCtx == NULL) {
|
72
|
+
rb_raise(rb_eVerificationError, "failed to create signature context");
|
73
|
+
goto done;
|
74
|
+
}
|
75
|
+
|
76
|
+
// verify signature
|
77
|
+
if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) {
|
78
|
+
rb_raise(rb_eVerificationError, "error occurred during signature verification");
|
79
|
+
goto done;
|
80
|
+
}
|
81
|
+
|
82
|
+
if(dsigCtx->status == xmlSecDSigStatusSucceeded) {
|
83
|
+
result = Qtrue;
|
84
|
+
}
|
85
|
+
|
86
|
+
done:
|
87
|
+
if(dsigCtx != NULL) {
|
88
|
+
xmlSecDSigCtxDestroy(dsigCtx);
|
89
|
+
}
|
90
|
+
|
91
|
+
if (keyManager != NULL) {
|
92
|
+
xmlSecKeysMngrDestroy(keyManager);
|
93
|
+
}
|
94
|
+
|
95
|
+
return result;
|
96
|
+
}
|
@@ -0,0 +1,106 @@
|
|
1
|
+
#include "xmlsecrb.h"
|
2
|
+
|
3
|
+
static int addRubyKeyToManager(VALUE rb_key, VALUE rb_value, VALUE rb_manager) {
|
4
|
+
xmlSecKeysMngrPtr keyManager = (xmlSecKeysMngrPtr)rb_manager;
|
5
|
+
char *keyName, *keyData;
|
6
|
+
unsigned int keyDataLength;
|
7
|
+
xmlSecKeyPtr key;
|
8
|
+
|
9
|
+
Check_Type(rb_key, T_STRING);
|
10
|
+
Check_Type(rb_value, T_STRING);
|
11
|
+
keyName = RSTRING_PTR(rb_key);
|
12
|
+
keyData = RSTRING_PTR(rb_value);
|
13
|
+
keyDataLength = RSTRING_LEN(rb_value);
|
14
|
+
|
15
|
+
// load key
|
16
|
+
key = xmlSecCryptoAppKeyLoadMemory((xmlSecByte *)keyData,
|
17
|
+
keyDataLength,
|
18
|
+
xmlSecKeyDataFormatPem,
|
19
|
+
NULL, // password
|
20
|
+
NULL, NULL);
|
21
|
+
if (key == NULL) {
|
22
|
+
rb_warn("failed to load '%s' public or private pem key", keyName);
|
23
|
+
return ST_CONTINUE;
|
24
|
+
}
|
25
|
+
|
26
|
+
// set key name
|
27
|
+
if (xmlSecKeySetName(key, BAD_CAST keyName) < 0) {
|
28
|
+
rb_warn("failed to set key name for key '%s'", keyName);
|
29
|
+
return ST_CONTINUE;
|
30
|
+
}
|
31
|
+
|
32
|
+
// add key to key manager; from now on the manager is responsible for
|
33
|
+
// destroying the key
|
34
|
+
if (xmlSecCryptoAppDefaultKeysMngrAdoptKey(keyManager, key) < 0) {
|
35
|
+
rb_warn("failed to add key '%s' to key manager", keyName);
|
36
|
+
return ST_CONTINUE;
|
37
|
+
}
|
38
|
+
|
39
|
+
return ST_CONTINUE;
|
40
|
+
}
|
41
|
+
|
42
|
+
static xmlSecKeysMngrPtr getKeyManager(VALUE rb_hash) {
|
43
|
+
xmlSecKeysMngrPtr keyManager = xmlSecKeysMngrCreate();
|
44
|
+
if (keyManager == NULL) return NULL;
|
45
|
+
if (xmlSecCryptoAppDefaultKeysMngrInit(keyManager) < 0) {
|
46
|
+
rb_raise(rb_eKeystoreError, "could not initialize key manager");
|
47
|
+
xmlSecKeysMngrDestroy(keyManager);
|
48
|
+
return NULL;
|
49
|
+
}
|
50
|
+
|
51
|
+
rb_hash_foreach(rb_hash, addRubyKeyToManager, (VALUE)keyManager);
|
52
|
+
|
53
|
+
return keyManager;
|
54
|
+
}
|
55
|
+
|
56
|
+
VALUE verify_signature_with_named_keys(VALUE self, VALUE rb_hash) {
|
57
|
+
xmlDocPtr doc;
|
58
|
+
xmlNodePtr node = NULL;
|
59
|
+
xmlSecDSigCtxPtr dsigCtx = NULL;
|
60
|
+
xmlSecKeysMngrPtr keyManager = NULL;
|
61
|
+
VALUE result = Qfalse;
|
62
|
+
|
63
|
+
Check_Type(rb_hash, T_HASH);
|
64
|
+
Data_Get_Struct(self, xmlDoc, doc);
|
65
|
+
|
66
|
+
// find start node
|
67
|
+
node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs);
|
68
|
+
if(node == NULL) {
|
69
|
+
rb_raise(rb_eVerificationError, "start node not found");
|
70
|
+
goto done;
|
71
|
+
}
|
72
|
+
|
73
|
+
keyManager = getKeyManager(rb_hash);
|
74
|
+
if (keyManager == NULL) {
|
75
|
+
rb_raise(rb_eKeystoreError, "failed to create key manager");
|
76
|
+
goto done;
|
77
|
+
}
|
78
|
+
|
79
|
+
// create signature context, we don't need keys manager in this example
|
80
|
+
dsigCtx = xmlSecDSigCtxCreate(keyManager);
|
81
|
+
if(dsigCtx == NULL) {
|
82
|
+
rb_raise(rb_eVerificationError, "failed to create signature context");
|
83
|
+
goto done;
|
84
|
+
}
|
85
|
+
|
86
|
+
// verify signature
|
87
|
+
if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) {
|
88
|
+
rb_raise(rb_eVerificationError, "signature could not be verified");
|
89
|
+
goto done;
|
90
|
+
}
|
91
|
+
|
92
|
+
if(dsigCtx->status == xmlSecDSigStatusSucceeded) {
|
93
|
+
result = Qtrue;
|
94
|
+
}
|
95
|
+
|
96
|
+
done:
|
97
|
+
if(dsigCtx != NULL) {
|
98
|
+
xmlSecDSigCtxDestroy(dsigCtx);
|
99
|
+
}
|
100
|
+
|
101
|
+
if (keyManager != NULL) {
|
102
|
+
xmlSecKeysMngrDestroy(keyManager);
|
103
|
+
}
|
104
|
+
|
105
|
+
return result;
|
106
|
+
}
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#include "xmlsecrb.h"
|
2
|
+
|
3
|
+
VALUE verify_signature_with_rsa_key(VALUE self, VALUE rb_rsa_key) {
|
4
|
+
xmlDocPtr doc;
|
5
|
+
xmlNodePtr node = NULL;
|
6
|
+
xmlSecDSigCtxPtr dsigCtx = NULL;
|
7
|
+
char *rsaKey;
|
8
|
+
unsigned int rsaKeyLength;
|
9
|
+
VALUE result = Qfalse;
|
10
|
+
|
11
|
+
Data_Get_Struct(self, xmlDoc, doc);
|
12
|
+
rsaKey = RSTRING_PTR(rb_rsa_key);
|
13
|
+
rsaKeyLength = RSTRING_LEN(rb_rsa_key);
|
14
|
+
|
15
|
+
// find start node
|
16
|
+
node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs);
|
17
|
+
if(node == NULL) {
|
18
|
+
rb_raise(rb_eVerificationError, "start node not found");
|
19
|
+
goto done;
|
20
|
+
}
|
21
|
+
|
22
|
+
// create signature context, we don't need keys manager in this example
|
23
|
+
dsigCtx = xmlSecDSigCtxCreate(NULL);
|
24
|
+
if(dsigCtx == NULL) {
|
25
|
+
rb_raise(rb_eVerificationError, "failed to create signature context");
|
26
|
+
goto done;
|
27
|
+
}
|
28
|
+
|
29
|
+
// load public key
|
30
|
+
dsigCtx->signKey = xmlSecCryptoAppKeyLoadMemory((xmlSecByte *)rsaKey,
|
31
|
+
rsaKeyLength,
|
32
|
+
xmlSecKeyDataFormatPem,
|
33
|
+
NULL, // password
|
34
|
+
NULL, NULL);
|
35
|
+
if(dsigCtx->signKey == NULL) {
|
36
|
+
rb_raise(rb_eVerificationError, "failed to load public pem key");
|
37
|
+
goto done;
|
38
|
+
}
|
39
|
+
|
40
|
+
// verify signature
|
41
|
+
if(xmlSecDSigCtxVerify(dsigCtx, node) < 0) {
|
42
|
+
rb_raise(rb_eVerificationError, "signature could not be verified");
|
43
|
+
goto done;
|
44
|
+
}
|
45
|
+
|
46
|
+
if(dsigCtx->status == xmlSecDSigStatusSucceeded) {
|
47
|
+
result = Qtrue;
|
48
|
+
}
|
49
|
+
|
50
|
+
done:
|
51
|
+
if(dsigCtx != NULL) {
|
52
|
+
xmlSecDSigCtxDestroy(dsigCtx);
|
53
|
+
}
|
54
|
+
|
55
|
+
return result;
|
56
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#include "xmlsecrb.h"
|
2
|
+
|
3
|
+
/* not actually called anywhere right now, but here for posterity */
|
4
|
+
void Shutdown_xmlsecrb() {
|
5
|
+
xmlSecCryptoShutdown();
|
6
|
+
xmlSecCryptoAppShutdown();
|
7
|
+
xmlSecShutdown();
|
8
|
+
xsltCleanupGlobals();
|
9
|
+
#ifndef XMLSEC_NO_XSLT
|
10
|
+
xsltCleanupGlobals();
|
11
|
+
#endif /* XMLSEC_NO_XSLT */
|
12
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#ifndef XMLSECRB_H
|
2
|
+
#define XMLSECRB_H
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
|
6
|
+
#include <libxml/tree.h>
|
7
|
+
#include <libxml/xmlmemory.h>
|
8
|
+
#include <libxml/parser.h>
|
9
|
+
#include <libxml/xmlstring.h>
|
10
|
+
|
11
|
+
#include <libxslt/xslt.h>
|
12
|
+
|
13
|
+
#include <xmlsec/xmlsec.h>
|
14
|
+
#include <xmlsec/xmltree.h>
|
15
|
+
#include <xmlsec/xmldsig.h>
|
16
|
+
#include <xmlsec/xmlenc.h>
|
17
|
+
#include <xmlsec/templates.h>
|
18
|
+
#include <xmlsec/crypto.h>
|
19
|
+
#include <xmlsec/dl.h>
|
20
|
+
|
21
|
+
VALUE sign_with_key(VALUE self, VALUE rb_key_name, VALUE rb_rsa_key);
|
22
|
+
VALUE sign_with_certificate(VALUE self, VALUE rb_key_name, VALUE rb_rsa_key, VALUE rb_cert);
|
23
|
+
VALUE verify_signature_with_rsa_key(VALUE self, VALUE rb_rsa_key);
|
24
|
+
VALUE verify_signature_with_named_keys(VALUE self, VALUE rb_keys);
|
25
|
+
VALUE verify_signature_with_certificates(VALUE self, VALUE rb_certs);
|
26
|
+
VALUE encrypt_with_key(VALUE self, VALUE rb_key_name, VALUE rb_key);
|
27
|
+
VALUE decrypt_with_key(VALUE self, VALUE rb_key_name, VALUE rb_key);
|
28
|
+
VALUE set_id_attribute(VALUE self, VALUE rb_attr_name);
|
29
|
+
|
30
|
+
void Init_Nokogiri_ext(void);
|
31
|
+
|
32
|
+
extern VALUE rb_cNokogiri_XML_Document;
|
33
|
+
extern VALUE rb_eSigningError;
|
34
|
+
extern VALUE rb_eVerificationError;
|
35
|
+
extern VALUE rb_eKeystoreError;
|
36
|
+
extern VALUE rb_eEncryptionError;
|
37
|
+
extern VALUE rb_eDecryptionError;
|
38
|
+
|
39
|
+
#endif // XMLSECRB_H
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'xmlsec'
|
data/lib/xmlsec.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require "xmlsec/version"
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'nokogiri_ext_xmlsec'
|
4
|
+
|
5
|
+
class Nokogiri::XML::Document
|
6
|
+
# Signs this document, and then returns it.
|
7
|
+
#
|
8
|
+
# Examples:
|
9
|
+
#
|
10
|
+
# doc.sign! key: 'rsa-private-key'
|
11
|
+
# doc.sign! key: 'rsa-private-key', name: 'key-name'
|
12
|
+
# doc.sign! x509: 'x509 certificate', key: 'cert private key'
|
13
|
+
# doc.sign! x509: 'x509 certificate', key: 'cert private key',
|
14
|
+
# name: 'key-name'
|
15
|
+
#
|
16
|
+
# You can also use `:cert` or `:certificate` as aliases for `:x509`.
|
17
|
+
#
|
18
|
+
def sign! opts
|
19
|
+
if (cert = opts[:x509]) || (cert = opts[:cert]) || (cert = opts[:certificate])
|
20
|
+
raise "need a private :key" unless opts[:key]
|
21
|
+
sign_with_certificate opts[:name].to_s, opts[:key], cert
|
22
|
+
elsif opts[:key]
|
23
|
+
sign_with_key opts[:name].to_s, opts[:key]
|
24
|
+
else
|
25
|
+
raise "No private :key was given"
|
26
|
+
end
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
# Verifies the signature on the current document.
|
31
|
+
#
|
32
|
+
# Returns `true` if the signature is valid, `false` otherwise.
|
33
|
+
#
|
34
|
+
# Examples:
|
35
|
+
#
|
36
|
+
# # Try to validate with the given public or private key
|
37
|
+
# doc.verify_with key: 'rsa-key'
|
38
|
+
#
|
39
|
+
# # Try to validate with a set of keys. It will try to match
|
40
|
+
# # based on the contents of the `KeyName` element.
|
41
|
+
# doc.verify_with({
|
42
|
+
# 'key-name' => 'x509 certificate',
|
43
|
+
# 'another-key-name' => 'rsa-public-key'
|
44
|
+
# })
|
45
|
+
#
|
46
|
+
# # Try to validate with a trusted certificate
|
47
|
+
# doc.verify_with(x509: 'certificate')
|
48
|
+
#
|
49
|
+
# # Try to validate with a set of certificates, any one of which
|
50
|
+
# # can match
|
51
|
+
# doc.verify_with(x509: ['cert1', 'cert2'])
|
52
|
+
#
|
53
|
+
# You can also use `:cert` or `:certificate` or `:certs` or
|
54
|
+
# `:certificates` as aliases for `:x509`.
|
55
|
+
#
|
56
|
+
def verify_with opts_or_keys
|
57
|
+
if (certs = opts_or_keys[:x509]) ||
|
58
|
+
(certs = opts_or_keys[:cert]) ||
|
59
|
+
(certs = opts_or_keys[:certs]) ||
|
60
|
+
(certs = opts_or_keys[:certificate]) ||
|
61
|
+
(certs = opts_or_keys[:certificates])
|
62
|
+
certs = [certs] unless certs.kind_of?(Array)
|
63
|
+
verify_with_certificates certs
|
64
|
+
elsif opts_or_keys[:key]
|
65
|
+
verify_with_rsa_key opts_or_keys[:key]
|
66
|
+
else
|
67
|
+
verify_with_named_keys opts_or_keys
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Attempts to verify the signature of this document using only certificates
|
72
|
+
# installed on the system. This is equivalent to calling
|
73
|
+
# `verify_with certificates: []` (that is, an empty array).
|
74
|
+
#
|
75
|
+
def verify_signature
|
76
|
+
verify_with_certificates []
|
77
|
+
end
|
78
|
+
|
79
|
+
# Encrypts the current document, then returns it.
|
80
|
+
#
|
81
|
+
# Examples:
|
82
|
+
#
|
83
|
+
# # encrypt with a public key and optional key name
|
84
|
+
# doc.encrypt! key: 'public-key', name: 'name'
|
85
|
+
#
|
86
|
+
def encrypt! opts
|
87
|
+
if opts[:key]
|
88
|
+
encrypt_with_key opts[:name].to_s, opts[:key]
|
89
|
+
else
|
90
|
+
raise "public :key is required for encryption"
|
91
|
+
end
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
# Decrypts the current document, then returns it.
|
96
|
+
#
|
97
|
+
# Examples:
|
98
|
+
#
|
99
|
+
# # decrypt with a specific private key
|
100
|
+
# doc.decrypt! key: 'private-key'
|
101
|
+
#
|
102
|
+
def decrypt! opts
|
103
|
+
if opts[:key]
|
104
|
+
decrypt_with_key opts[:name].to_s, opts[:key]
|
105
|
+
else
|
106
|
+
raise 'inadequate options specified for decryption'
|
107
|
+
end
|
108
|
+
self
|
109
|
+
end
|
110
|
+
end
|