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,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
|