nokogiri-xmlsec-instructure 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -0
  5. data/Gemfile +4 -0
  6. data/Guardfile +13 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +124 -0
  9. data/Rakefile +30 -0
  10. data/ext/nokogiri_ext_xmlsec/common.h +13 -0
  11. data/ext/nokogiri_ext_xmlsec/extconf.rb +27 -0
  12. data/ext/nokogiri_ext_xmlsec/init.c +76 -0
  13. data/ext/nokogiri_ext_xmlsec/nokogiri_decrypt_with_key.c +82 -0
  14. data/ext/nokogiri_ext_xmlsec/nokogiri_encrypt_with_key.c +169 -0
  15. data/ext/nokogiri_ext_xmlsec/nokogiri_helpers_set_attribute_id.c +94 -0
  16. data/ext/nokogiri_ext_xmlsec/nokogiri_init.c +30 -0
  17. data/ext/nokogiri_ext_xmlsec/nokogiri_sign.c +252 -0
  18. data/ext/nokogiri_ext_xmlsec/nokogiri_verify_with.c +259 -0
  19. data/ext/nokogiri_ext_xmlsec/options.c +166 -0
  20. data/ext/nokogiri_ext_xmlsec/options.h +36 -0
  21. data/ext/nokogiri_ext_xmlsec/shutdown.c +12 -0
  22. data/ext/nokogiri_ext_xmlsec/util.c +139 -0
  23. data/ext/nokogiri_ext_xmlsec/util.h +42 -0
  24. data/ext/nokogiri_ext_xmlsec/xmlsecrb.h +42 -0
  25. data/lib/nokogiri-xmlsec.rb +1 -0
  26. data/lib/xmlsec.rb +102 -0
  27. data/lib/xmlsec/version.rb +3 -0
  28. data/nokogiri-xmlsec-instructure.gemspec +39 -0
  29. data/spec/fixtures/cert/server.crt +14 -0
  30. data/spec/fixtures/cert/server.csr +11 -0
  31. data/spec/fixtures/cert/server.key.decrypted +15 -0
  32. data/spec/fixtures/cert/server.key.encrypted +18 -0
  33. data/spec/fixtures/hate.xml +7 -0
  34. data/spec/fixtures/pwned.xml +1 -0
  35. data/spec/fixtures/rsa.pem +15 -0
  36. data/spec/fixtures/rsa.pub +6 -0
  37. data/spec/fixtures/sign2-doc.xml +6 -0
  38. data/spec/fixtures/sign2-result.xml +25 -0
  39. data/spec/fixtures/sign3-result.xml +38 -0
  40. data/spec/lib/nokogiri/xml/document/encryption_and_decryption_spec.rb +34 -0
  41. data/spec/lib/nokogiri/xml/document/signing_and_verifying_spec.rb +122 -0
  42. data/spec/lib/nokogiri/xml/document/unsafe_xml_spec.rb +61 -0
  43. data/spec/spec_helper.rb +10 -0
  44. metadata +211 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ed59b79032290908cffa12a20deb7b0d5c2195e45a817e430d49bfc404243bee
4
+ data.tar.gz: b315b63fe30ab7760719bce3e435b36c3565b658eb0ac42d1fb6d6f48c65b974
5
+ SHA512:
6
+ metadata.gz: 660d2ff3242177e1e6fd09112afed32ae5507d331c3c2fedd7c920a75cf09b58115ca14d3915fa76297ee7879594b314caacef967b5b90903d3fd1b9b36a4aff
7
+ data.tar.gz: d96e85677b8f9c34b3df00ae1d878d1de8c8f69d7ed5d78f76a680a504e8afcee4d55c398ccdc6e766a773a1bb45466bbe507985930839c4591dd2c452d8153d
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ spec/old
19
+ *.so
20
+ *.sw[opn]
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+
@@ -0,0 +1,3 @@
1
+ before_install:
2
+ - sudo apt-get update -qq
3
+ - sudo apt-get install -y libxmlsec1-dev
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in xmlsec.gemspec
4
+ gemspec
@@ -0,0 +1,13 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rake', :task => 'default' do
5
+ watch(/^ext\//)
6
+ end
7
+
8
+ guard 'rspec' do
9
+ watch(%r{^spec/.+_spec\.rb$})
10
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
11
+ watch('spec/spec_helper.rb') { "spec" }
12
+ # watch(/^ext\//) { "spec" }
13
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,124 @@
1
+ # nokogiri-xmlsec
2
+
3
+ [![Build Status](https://travis-ci.org/omb-awong/xmlsec.svg)](https://travis-ci.org/omb-awong/xmlsec)
4
+
5
+ Adds support to Ruby for encrypting, decrypting, signing and validating
6
+ the signatures of XML documents, according to the [XML Encryption Syntax and
7
+ Processing](http://www.w3.org/TR/xmlenc-core/) standard, by wrapping around the
8
+ [xmlsec](http://www.aleksey.com/xmlsec) C library and adding relevant methods
9
+ to `Nokogiri::XML::Document`.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'nokogiri-xmlsec'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install nokogiri-xmlsec
24
+
25
+ ## Usage
26
+
27
+ Several methods are added to `Nokogiri::XML::Document` which expose this gem's
28
+ functionality.
29
+
30
+ ### Signing
31
+
32
+ The `sign!` method adds a digital signature to the XML document so that it can
33
+ later be determined whether the document itself has been tampered with. If the
34
+ document changes, the signature will be invalid.
35
+
36
+ Signing a document will add XML nodes directly to the document itself, and
37
+ then returns itself.
38
+
39
+ # First, get an XML document
40
+ doc = Nokogiri::XML("<doc><greeting>Hello, World!</greeting></doc>")
41
+
42
+ # Sign the document with a certificate, a key, and a key name
43
+ doc.sign! cert: 'certificate data',
44
+ key: 'private key data',
45
+ name: 'private key name',
46
+ digest_alg: 'sha256',
47
+ signature_alg: 'rsa-sha256'
48
+
49
+ If you pass `cert`, the certificate will be included as part of the signature,
50
+ so that it can be later verified by certificate instead of by key.
51
+
52
+ `name` can be used to verify the signature with any of a set of keys, as in the
53
+ following example:
54
+
55
+ ### Signature verification
56
+
57
+ Verification of signatures always returns `true` if successful, `false`
58
+ otherwise.
59
+
60
+ # Verify the document's signature to ensure it has not been tampered with
61
+ doc.verify_with({
62
+ 'key-name-1' => 'public key contents',
63
+ 'key-name-2' => 'another public key content'
64
+ })
65
+
66
+ In the above example, the `name` field from the signing process will be used
67
+ to determine which key to validate with. If you plan to always verify with the
68
+ same key, you can do it like so, effectively ignoring the `name` value:
69
+
70
+ # Verify the document's signature with a specific key
71
+ doc.verify_with key: 'public key contents'
72
+
73
+ Finally, you can also verify with a certificate:
74
+
75
+ # Verify the document's signature with a single certificate
76
+ doc.verify_with cert: 'certificate data'
77
+
78
+ # Verify the document's signature with multiple certificates. Any one match
79
+ # will pass verification.
80
+ doc.verify_with certs: [ 'cert1', 'cert2', 'cert3' ]
81
+
82
+ If the certificate has been installed to your system certificates, then you can
83
+ verify signatures like so:
84
+
85
+ # Verify with installed CA certificates
86
+ doc.verify_signature
87
+
88
+ ### Encryption & Decryption
89
+
90
+ Encrypted documents can only be decrypted with the private key that corresponds
91
+ to the public key that was used to encrypt it. Thus, the party that encrypted
92
+ the document can be sure that the document will only be readable by its intended
93
+ recipient.
94
+
95
+ Both encryption and decryption of a document manipulates the XML nodes of the
96
+ document in-place. Both methods return the original document, after the changes
97
+ have been made to it.
98
+
99
+ To encrypt a document, use a public key:
100
+
101
+ doc.encrypt! key: 'public key content'
102
+
103
+ To decrypt a document, use a private key:
104
+
105
+ doc.decrypt! key: 'private key content'
106
+
107
+
108
+ ## Limitations and Known Issues
109
+
110
+ Following is a list of limitations and/or issues I know about, but have no
111
+ immediate plan to resolve. This is probably because I haven't needed the
112
+ functionality, and no one has sent a pull request. (Hint, hint!)
113
+
114
+ - Currently, it is not possible to encrypt/decrypt individual XML nodes. The
115
+ `nokogiri-xmlsec` operations must be performed on the entire document.
116
+ You _can_ sign an individual node.
117
+
118
+ ## Contributing
119
+
120
+ 1. Fork it
121
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
122
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
123
+ 4. Push to the branch (`git push origin my-new-feature`)
124
+ 5. Create new Pull Request
@@ -0,0 +1,30 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/extensiontask'
3
+ require 'rspec/core/rake_task'
4
+
5
+ Rake::ExtensionTask.new('nokogiri_ext_xmlsec')
6
+
7
+ RSpec::Core::RakeTask.new :rspec
8
+
9
+ desc 'clean out build files'
10
+ task :clean do
11
+ rm_rf File.expand_path('../tmp', __FILE__)
12
+ end
13
+
14
+ task :default => [:clean, :compile, :rspec]
15
+
16
+ desc 'code statistics, cause im a stats junky'
17
+ task :stats do
18
+ def count(glob)
19
+ Dir[glob].inject(0) do |count, fi|
20
+ next unless File.file?(fi)
21
+ count + File.read(fi).lines.length
22
+ end
23
+ end
24
+
25
+ rb_lines = count 'lib/**/*.rb'
26
+ c_lines = count 'ext/**/*.{c,h}'
27
+
28
+ puts "Lines of Ruby: #{rb_lines}"
29
+ puts "Lines of C: #{c_lines}"
30
+ end
@@ -0,0 +1,13 @@
1
+ #ifndef NOKOGIRI_EXT_XMLSEC_COMMON_H
2
+ #define NOKOGIRI_EXT_XMLSEC_COMMON_H
3
+
4
+ #ifndef TRUE
5
+ #define TRUE 1
6
+ #endif
7
+ #ifndef FALSE
8
+ #define FALSE 0
9
+ #endif
10
+
11
+ typedef int BOOL;
12
+
13
+ #endif // NOKOGIRI_EXT_XMLSEC_COMMON_H
@@ -0,0 +1,27 @@
1
+ require 'mkmf'
2
+
3
+ def barf message = 'dependencies not met'
4
+ raise message
5
+ end
6
+
7
+ barf unless have_header('ruby.h')
8
+
9
+ pkg_config('xmlsec1')
10
+ $CFLAGS << " " + `xmlsec1-config --cflags`.strip
11
+ $CFLAGS << " -fvisibility=hidden"
12
+
13
+ if $CFLAGS =~ /\-DXMLSEC_CRYPTO=\\\\\\"openssl\\\\\\"/
14
+ puts "Changing escaping: #{$CFLAGS}"
15
+ $CFLAGS['-DXMLSEC_CRYPTO=\\\\\\"openssl\\\\\\"'] =
16
+ '-DXMLSEC_CRYPTO=\\"openssl\\"'
17
+ end
18
+
19
+ if $CFLAGS =~ /\-DXMLSEC_CRYPTO="openssl"/
20
+ puts "Ensure we escaping: #{$CFLAGS}"
21
+ $CFLAGS['-DXMLSEC_CRYPTO="openssl"'] =
22
+ '-DXMLSEC_CRYPTO=\\"openssl\\"'
23
+ end
24
+
25
+ puts "Clfags: #{$CFLAGS}"
26
+ $libs = `xmlsec1-config --libs`.strip
27
+ create_makefile('nokogiri_ext_xmlsec')
@@ -0,0 +1,76 @@
1
+ #include "xmlsecrb.h"
2
+ #include "util.h"
3
+
4
+ #include <xmlsec/dl.h>
5
+ #include <xmlsec/errors.h>
6
+
7
+ #ifndef XMLSEC_NO_XSLT
8
+ #include <libxslt/xslt.h>
9
+ #include <libxslt/security.h>
10
+ #endif /* XMLSEC_NO_XSLT */
11
+
12
+ EXTENSION_EXPORT
13
+ void Init_nokogiri_ext_xmlsec() {
14
+ #ifndef XMLSEC_NO_XSLT
15
+ xsltSecurityPrefsPtr xsltSecPrefs = NULL;
16
+ #endif /* XMLSEC_NO_XSLT */
17
+
18
+ /* xmlsec proper */
19
+ // libxml
20
+ xmlInitParser();
21
+ LIBXML_TEST_VERSION
22
+ xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
23
+ xmlSubstituteEntitiesDefault(1);
24
+ // xslt
25
+
26
+ #ifndef XMLSEC_NO_XSLT
27
+ xmlIndentTreeOutput = 1;
28
+
29
+ /* Disable all XSLT options that give filesystem and network access. */
30
+ xsltSecPrefs = xsltNewSecurityPrefs();
31
+ xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid);
32
+ xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid);
33
+ xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid);
34
+ xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid);
35
+ xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid);
36
+ xsltSetDefaultSecurityPrefs(xsltSecPrefs);
37
+ #endif /* XMLSEC_NO_XSLT */
38
+
39
+ // xmlsec
40
+
41
+ if (xmlSecInit() < 0) {
42
+ rb_raise(rb_eRuntimeError, "xmlsec initialization failed");
43
+ return;
44
+ }
45
+ if (xmlSecCheckVersion() != 1) {
46
+ rb_raise(rb_eRuntimeError, "xmlsec version is not compatible");
47
+ return;
48
+ }
49
+ // load crypto
50
+ #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
51
+ if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
52
+ rb_raise(rb_eRuntimeError,
53
+ "Error: unable to load default xmlsec-crypto library. Make sure"
54
+ "that you have it installed and check shared libraries path\n"
55
+ "(LD_LIBRARY_PATH) envornment variable.\n");
56
+ return;
57
+ }
58
+ #endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */
59
+ // init crypto
60
+ if (xmlSecCryptoAppInit(NULL) < 0) {
61
+ rb_raise(rb_eRuntimeError, "unable to initialize crypto engine");
62
+ return;
63
+ }
64
+ // init xmlsec-crypto library
65
+ if (xmlSecCryptoInit() < 0) {
66
+ rb_raise(rb_eRuntimeError, "xmlsec-crypto initialization failed");
67
+ }
68
+
69
+ // Set Error callback catcher last because various modules also call this.
70
+ // This way we always win.
71
+ xmlSecErrorsSetCallback(storeErrorCallback);
72
+
73
+ /* ruby classes & objects */
74
+ Init_Nokogiri_ext();
75
+ }
76
+
@@ -0,0 +1,82 @@
1
+ #include "xmlsecrb.h"
2
+ #include "util.h"
3
+
4
+ VALUE decrypt_with_key(VALUE self, VALUE rb_key_name, VALUE rb_key) {
5
+ VALUE rb_exception_result = Qnil;
6
+ const char* exception_message = NULL;
7
+
8
+ xmlNodePtr node = NULL;
9
+ xmlSecEncCtxPtr encCtx = NULL;
10
+ xmlSecKeysMngrPtr keyManager = NULL;
11
+ char *key = NULL;
12
+ char *keyName = NULL;
13
+ unsigned int keyLength = 0;
14
+
15
+ resetXmlSecError();
16
+
17
+ Check_Type(rb_key, T_STRING);
18
+ Check_Type(rb_key_name, T_STRING);
19
+ Data_Get_Struct(self, xmlNode, node);
20
+ key = RSTRING_PTR(rb_key);
21
+ keyLength = RSTRING_LEN(rb_key);
22
+ keyName = StringValueCStr(rb_key_name);
23
+
24
+ keyManager = createKeyManagerWithSingleKey(key, keyLength, keyName,
25
+ &rb_exception_result,
26
+ &exception_message);
27
+ if (keyManager == NULL) {
28
+ // Propagate the exception.
29
+ goto done;
30
+ }
31
+
32
+ // create encryption context
33
+ encCtx = xmlSecEncCtxCreate(keyManager);
34
+ if(encCtx == NULL) {
35
+ rb_exception_result = rb_eDecryptionError;
36
+ exception_message = "failed to create encryption context";
37
+ goto done;
38
+ }
39
+ // don't let xmlsec free the node we're looking at out from under us
40
+ encCtx->flags |= XMLSEC_ENC_RETURN_REPLACED_NODE;
41
+
42
+ // decrypt the data
43
+ if((xmlSecEncCtxDecrypt(encCtx, node) < 0) || (encCtx->result == NULL)) {
44
+ rb_exception_result = rb_eDecryptionError;
45
+ exception_message = "decryption failed";
46
+ goto done;
47
+ }
48
+
49
+ if(encCtx->resultReplaced == 0) {
50
+ rb_exception_result = rb_eDecryptionError;
51
+ exception_message = "Not implemented: don't know how to handle decrypted, non-XML data yet";
52
+ goto done;
53
+ }
54
+
55
+ done:
56
+ // cleanup
57
+ if(encCtx != NULL) {
58
+ // the replaced node is orphaned, but not freed; let Nokogiri
59
+ // own it now
60
+ if(encCtx->replacedNodeList != NULL) {
61
+ nokogiri_root_node(encCtx->replacedNodeList);
62
+ // no really, please don't free it
63
+ encCtx->replacedNodeList = NULL;
64
+ }
65
+ xmlSecEncCtxDestroy(encCtx);
66
+ }
67
+
68
+ if (keyManager != NULL) {
69
+ xmlSecKeysMngrDestroy(keyManager);
70
+ }
71
+
72
+ if(rb_exception_result != Qnil) {
73
+ if (hasXmlSecLastError()) {
74
+ rb_raise(rb_exception_result, "%s, XmlSec error: %s", exception_message,
75
+ getXmlSecLastError());
76
+ } else {
77
+ rb_raise(rb_exception_result, "%s", exception_message);
78
+ }
79
+ }
80
+
81
+ return Qnil;
82
+ }
@@ -0,0 +1,169 @@
1
+ #include "xmlsecrb.h"
2
+ #include "options.h"
3
+ #include "util.h"
4
+
5
+ // Encrypes the XML Document document using XMLEnc.
6
+ //
7
+ // Expects 3 positional arguments:
8
+ // rb_rsa_key_name - String with name of the rsa key. May be the empty.
9
+ // rb_rsa_key - A PEM encoded rsa key for signing.
10
+ // rb_opts - An ruby hash that configures the encryption options.
11
+ // See XmlEncOptions struct for possible values.
12
+ VALUE encrypt_with_key(VALUE self, VALUE rb_rsa_key_name, VALUE rb_rsa_key,
13
+ VALUE rb_opts) {
14
+ VALUE rb_exception_result = Qnil;
15
+ const char* exception_message = NULL;
16
+
17
+ xmlDocPtr doc = NULL;
18
+ xmlNodePtr encDataNode = NULL;
19
+ xmlNodePtr encKeyNode = NULL;
20
+ xmlNodePtr keyInfoNode = NULL;
21
+ xmlSecEncCtxPtr encCtx = NULL;
22
+ xmlSecKeysMngrPtr keyManager = NULL;
23
+ char *keyName = NULL;
24
+ char *key = NULL;
25
+ unsigned int keyLength = 0;
26
+
27
+ resetXmlSecError();
28
+
29
+ Check_Type(rb_rsa_key, T_STRING);
30
+ Check_Type(rb_rsa_key_name, T_STRING);
31
+ Check_Type(rb_opts, T_HASH);
32
+
33
+ key = RSTRING_PTR(rb_rsa_key);
34
+ keyLength = RSTRING_LEN(rb_rsa_key);
35
+ keyName = StringValueCStr(rb_rsa_key_name);
36
+
37
+ XmlEncOptions options;
38
+ if (!GetXmlEncOptions(rb_opts, &options, &rb_exception_result,
39
+ &exception_message)) {
40
+ goto done;
41
+ }
42
+
43
+ Data_Get_Struct(self, xmlDoc, doc);
44
+
45
+ // create encryption template to encrypt XML file and replace
46
+ // its content with encryption result
47
+ encDataNode = xmlSecTmplEncDataCreate(doc, options.block_encryption, NULL,
48
+ xmlSecTypeEncElement, NULL, NULL);
49
+ if(encDataNode == NULL) {
50
+ rb_exception_result = rb_eEncryptionError;
51
+ exception_message = "failed to create encryption template";
52
+ goto done;
53
+ }
54
+
55
+ // we want to put encrypted data in the <enc:CipherValue/> node
56
+ if(xmlSecTmplEncDataEnsureCipherValue(encDataNode) == NULL) {
57
+ rb_exception_result = rb_eEncryptionError;
58
+ exception_message = "failed to add CipherValue node";
59
+ goto done;
60
+ }
61
+
62
+ // add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to put key name in the
63
+ // signed document
64
+ keyInfoNode = xmlSecTmplEncDataEnsureKeyInfo(encDataNode, NULL);
65
+ if(keyInfoNode == NULL) {
66
+ rb_exception_result = rb_eEncryptionError;
67
+ exception_message = "failed to add key info";
68
+ goto done;
69
+ }
70
+
71
+ if(xmlSecTmplKeyInfoAddKeyName(keyInfoNode, NULL) == NULL) {
72
+ rb_exception_result = rb_eEncryptionError;
73
+ exception_message = "failed to add key name";
74
+ goto done;
75
+ }
76
+
77
+ if ((keyManager = createKeyManagerWithSingleKey(
78
+ key, keyLength, keyName,
79
+ &rb_exception_result,
80
+ &exception_message)) == NULL) {
81
+ // Propagate the exception.
82
+ goto done;
83
+ }
84
+
85
+ // create encryption context, we don't need keys manager in this example
86
+ encCtx = xmlSecEncCtxCreate(keyManager);
87
+ if(encCtx == NULL) {
88
+ rb_exception_result = rb_eEncryptionError;
89
+ exception_message = "failed to create encryption context";
90
+ goto done;
91
+ }
92
+
93
+ // Generate the symmetric key.
94
+ encCtx->encKey = xmlSecKeyGenerateByName(BAD_CAST options.key_type, options.key_bits,
95
+ xmlSecKeyDataTypeSession);
96
+
97
+ if(encCtx->encKey == NULL) {
98
+ rb_exception_result = rb_eDecryptionError;
99
+ exception_message = "failed to generate session key";
100
+ goto done;
101
+ }
102
+
103
+ // Set key name.
104
+ if(xmlSecKeySetName(encCtx->encKey, (xmlSecByte *)keyName) < 0) {
105
+ rb_exception_result = rb_eEncryptionError;
106
+ exception_message = "failed to set key name";
107
+ goto done;
108
+ }
109
+
110
+ // Add <enc:EncryptedKey/> node to the <dsig:KeyInfo/> tag to include
111
+ // the session key.
112
+ encKeyNode = xmlSecTmplKeyInfoAddEncryptedKey(keyInfoNode,
113
+ options.key_transport, // encMethodId encryptionMethod
114
+ NULL, // xmlChar *idAttribute
115
+ NULL, // xmlChar *typeAttribute
116
+ NULL // xmlChar *recipient
117
+ );
118
+ if (encKeyNode == NULL) {
119
+ rb_exception_result = rb_eEncryptionError;
120
+ exception_message = "failed to add encrypted key node";
121
+ goto done;
122
+ }
123
+ if (xmlSecTmplEncDataEnsureCipherValue(encKeyNode) == NULL) {
124
+ rb_exception_result = rb_eEncryptionError;
125
+ exception_message = "failed to add encrypted cipher value";
126
+ goto done;
127
+ }
128
+
129
+ // encrypt the data
130
+ if(xmlSecEncCtxXmlEncrypt(encCtx, encDataNode, xmlDocGetRootElement(doc)) < 0) {
131
+ rb_exception_result = rb_eEncryptionError;
132
+ exception_message = "encryption failed";
133
+ goto done;
134
+ }
135
+
136
+ // the template is inserted in the doc, so don't free it
137
+ encDataNode = NULL;
138
+ encKeyNode = NULL;
139
+
140
+ done:
141
+
142
+ /* cleanup */
143
+ if(encCtx != NULL) {
144
+ xmlSecEncCtxDestroy(encCtx);
145
+ }
146
+
147
+ if (encKeyNode != NULL) {
148
+ xmlFreeNode(encKeyNode);
149
+ }
150
+
151
+ if(encDataNode != NULL) {
152
+ xmlFreeNode(encDataNode);
153
+ }
154
+
155
+ if (keyManager != NULL) {
156
+ xmlSecKeysMngrDestroy(keyManager);
157
+ }
158
+
159
+ if(rb_exception_result != Qnil) {
160
+ if (hasXmlSecLastError()) {
161
+ rb_raise(rb_exception_result, "%s, XmlSec error: %s", exception_message,
162
+ getXmlSecLastError());
163
+ } else {
164
+ rb_raise(rb_exception_result, "%s", exception_message);
165
+ }
166
+ }
167
+
168
+ return Qnil;
169
+ }