xml-kit 0.1.0
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 +12 -0
- data/.gitlab-ci.yml +15 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/xml/kit.rb +40 -0
- data/lib/xml/kit/builders/encryption.rb +20 -0
- data/lib/xml/kit/builders/signature.rb +34 -0
- data/lib/xml/kit/builders/templates/certificate.builder +7 -0
- data/lib/xml/kit/builders/templates/encryption.builder +14 -0
- data/lib/xml/kit/builders/templates/nil_class.builder +0 -0
- data/lib/xml/kit/builders/templates/signature.builder +20 -0
- data/lib/xml/kit/certificate.rb +96 -0
- data/lib/xml/kit/crypto.rb +17 -0
- data/lib/xml/kit/crypto/oaep_cipher.rb +22 -0
- data/lib/xml/kit/crypto/rsa_cipher.rb +23 -0
- data/lib/xml/kit/crypto/simple_cipher.rb +34 -0
- data/lib/xml/kit/crypto/unknown_cipher.rb +18 -0
- data/lib/xml/kit/decryption.rb +44 -0
- data/lib/xml/kit/document.rb +75 -0
- data/lib/xml/kit/fingerprint.rb +50 -0
- data/lib/xml/kit/id.rb +13 -0
- data/lib/xml/kit/key_pair.rb +29 -0
- data/lib/xml/kit/namespaces.rb +17 -0
- data/lib/xml/kit/self_signed_certificate.rb +28 -0
- data/lib/xml/kit/signatures.rb +67 -0
- data/lib/xml/kit/templatable.rb +83 -0
- data/lib/xml/kit/template.rb +32 -0
- data/lib/xml/kit/version.rb +5 -0
- data/xml-kit.gemspec +36 -0
- metadata +220 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3a289752cbc49e2c74959f38b5b104ecbd02b4b8
|
4
|
+
data.tar.gz: 1475f47273a9d9483645c629517b3bf087f686c9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0576d38d7792ee436cfe335809516219730d817d5fc0a0d605affc897861e248ea07cc8ffe7e5312b77f2f1a85dd87b034a6d06e05a2b4c4f82afd8a655d8e0c
|
7
|
+
data.tar.gz: f7c764c6ff671e16b4992d0bea126819238ae766368d5c8b6215ca2cecbaa30890a5fad7ee2ba802be74de4f29bcfe63476cc6c0520a390c4c36bcf205a6e269
|
data/.gitignore
ADDED
data/.gitlab-ci.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
image: ruby:2.2
|
2
|
+
|
3
|
+
before_script:
|
4
|
+
- apt-get update && apt-get install -y locales
|
5
|
+
- echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
|
6
|
+
- locale-gen
|
7
|
+
- export LC_ALL=en_US.UTF-8
|
8
|
+
- ruby -v
|
9
|
+
- which ruby
|
10
|
+
- gem install bundler --no-ri --no-rdoc
|
11
|
+
- bundle install --jobs $(nproc) "${FLAGS[@]}"
|
12
|
+
|
13
|
+
rspec:
|
14
|
+
script:
|
15
|
+
- bundle exec rspec
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 mo
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Xml::Kit
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/xml/kit`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'xml-kit'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install xml-kit
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/saml-kit/xml-kit.
|
36
|
+
|
37
|
+
## License
|
38
|
+
|
39
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "xml/kit"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/xml/kit.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "active_model"
|
2
|
+
require "active_support/core_ext/numeric/time"
|
3
|
+
require "base64"
|
4
|
+
require "builder"
|
5
|
+
require "logger"
|
6
|
+
require "nokogiri"
|
7
|
+
require "openssl"
|
8
|
+
require "tilt"
|
9
|
+
require "xmldsig"
|
10
|
+
|
11
|
+
require "xml/kit/namespaces"
|
12
|
+
|
13
|
+
require "xml/kit/builders/encryption"
|
14
|
+
require "xml/kit/builders/signature"
|
15
|
+
require "xml/kit/certificate"
|
16
|
+
require "xml/kit/crypto"
|
17
|
+
require "xml/kit/decryption"
|
18
|
+
require "xml/kit/document"
|
19
|
+
require "xml/kit/fingerprint"
|
20
|
+
require "xml/kit/id"
|
21
|
+
require "xml/kit/key_pair"
|
22
|
+
require "xml/kit/self_signed_certificate"
|
23
|
+
require "xml/kit/signatures"
|
24
|
+
require "xml/kit/templatable"
|
25
|
+
require "xml/kit/template"
|
26
|
+
require "xml/kit/version"
|
27
|
+
|
28
|
+
module Xml
|
29
|
+
module Kit
|
30
|
+
class << self
|
31
|
+
def logger
|
32
|
+
@logger ||= Logger.new(STDOUT)
|
33
|
+
end
|
34
|
+
|
35
|
+
def logger=(logger)
|
36
|
+
@logger = logger
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
module Builders
|
4
|
+
class Encryption
|
5
|
+
attr_reader :public_key
|
6
|
+
attr_reader :key, :iv, :encrypted
|
7
|
+
|
8
|
+
def initialize(raw_xml, public_key)
|
9
|
+
@public_key = public_key
|
10
|
+
cipher = OpenSSL::Cipher.new('AES-256-CBC')
|
11
|
+
cipher.encrypt
|
12
|
+
@key = cipher.random_key
|
13
|
+
@iv = cipher.random_iv
|
14
|
+
@encrypted = cipher.update(raw_xml) + cipher.final
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
module Builders
|
4
|
+
class Signature
|
5
|
+
SIGNATURE_METHODS = {
|
6
|
+
SHA1: "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
|
7
|
+
SHA224: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha224",
|
8
|
+
SHA256: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
9
|
+
SHA384: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
|
10
|
+
SHA512: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
|
11
|
+
}.freeze
|
12
|
+
DIGEST_METHODS = {
|
13
|
+
SHA1: "http://www.w3.org/2000/09/xmldsig#SHA1",
|
14
|
+
SHA224: "http://www.w3.org/2001/04/xmldsig-more#sha224",
|
15
|
+
SHA256: "http://www.w3.org/2001/04/xmlenc#sha256",
|
16
|
+
SHA384: "http://www.w3.org/2001/04/xmldsig-more#sha384",
|
17
|
+
SHA512: "http://www.w3.org/2001/04/xmlenc#sha512",
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
attr_reader :certificate
|
21
|
+
attr_reader :digest_method
|
22
|
+
attr_reader :reference_id
|
23
|
+
attr_reader :signature_method
|
24
|
+
|
25
|
+
def initialize(reference_id, signature_method: :SH256, digest_method: :SHA256, certificate:)
|
26
|
+
@certificate = certificate
|
27
|
+
@digest_method = DIGEST_METHODS[digest_method]
|
28
|
+
@reference_id = reference_id
|
29
|
+
@signature_method = SIGNATURE_METHODS[signature_method]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
xml.EncryptedData xmlns: ::Xml::Kit::Namespaces::XMLENC do
|
2
|
+
xml.EncryptionMethod Algorithm: "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
|
3
|
+
xml.KeyInfo xmlns: ::Xml::Kit::Namespaces::XMLDSIG do
|
4
|
+
xml.EncryptedKey xmlns: ::Xml::Kit::Namespaces::XMLENC do
|
5
|
+
xml.EncryptionMethod Algorithm: "http://www.w3.org/2001/04/xmlenc#rsa-1_5"
|
6
|
+
xml.CipherData do
|
7
|
+
xml.CipherValue Base64.encode64(public_key.public_encrypt(key))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
xml.CipherData do
|
12
|
+
xml.CipherValue Base64.encode64(iv + encrypted)
|
13
|
+
end
|
14
|
+
end
|
File without changes
|
@@ -0,0 +1,20 @@
|
|
1
|
+
xml.Signature "xmlns" => ::Xml::Kit::Namespaces::XMLDSIG do
|
2
|
+
xml.SignedInfo do
|
3
|
+
xml.CanonicalizationMethod Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#"
|
4
|
+
xml.SignatureMethod Algorithm: signature_method
|
5
|
+
xml.Reference URI: "##{reference_id}" do
|
6
|
+
xml.Transforms do
|
7
|
+
xml.Transform Algorithm: "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
|
8
|
+
xml.Transform Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#"
|
9
|
+
end
|
10
|
+
xml.DigestMethod Algorithm: digest_method
|
11
|
+
xml.DigestValue ""
|
12
|
+
end
|
13
|
+
end
|
14
|
+
xml.SignatureValue ""
|
15
|
+
xml.KeyInfo do
|
16
|
+
xml.X509Data do
|
17
|
+
xml.X509Certificate certificate.stripped
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
# {include:file:spec/xml/certificate_spec.rb}
|
4
|
+
class Certificate
|
5
|
+
BEGIN_CERT=/-----BEGIN CERTIFICATE-----/
|
6
|
+
END_CERT=/-----END CERTIFICATE-----/
|
7
|
+
# The use can be `:signing` or `:encryption`
|
8
|
+
attr_reader :use
|
9
|
+
|
10
|
+
def initialize(value, use:)
|
11
|
+
@value = value
|
12
|
+
@use = use.downcase.to_sym
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Xml::Kit::Fingerprint] the certificate fingerprint.
|
16
|
+
def fingerprint
|
17
|
+
Fingerprint.new(value)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns true if this certificate is for the specified use.
|
21
|
+
#
|
22
|
+
# @param use [Symbol] `:signing` or `:encryption`.
|
23
|
+
# @return [Boolean] true or false.
|
24
|
+
def for?(use)
|
25
|
+
self.use == use.to_sym
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns true if this certificate is used for encryption.
|
29
|
+
#
|
30
|
+
# return [Boolean] true or false.
|
31
|
+
def encryption?
|
32
|
+
for?(:encryption)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns true if this certificate is used for signing.
|
36
|
+
#
|
37
|
+
# return [Boolean] true or false.
|
38
|
+
def signing?
|
39
|
+
for?(:signing)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the x509 form.
|
43
|
+
#
|
44
|
+
# return [OpenSSL::X509::Certificate] the OpenSSL equivalent.
|
45
|
+
def x509
|
46
|
+
self.class.to_x509(value)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns the public key.
|
50
|
+
#
|
51
|
+
# @return [OpenSSL::PKey::RSA] the RSA public key.
|
52
|
+
def public_key
|
53
|
+
x509.public_key
|
54
|
+
end
|
55
|
+
|
56
|
+
def ==(other)
|
57
|
+
self.fingerprint == other.fingerprint
|
58
|
+
end
|
59
|
+
|
60
|
+
def eql?(other)
|
61
|
+
self == other
|
62
|
+
end
|
63
|
+
|
64
|
+
def hash
|
65
|
+
value.hash
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_s
|
69
|
+
value
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_h
|
73
|
+
{ use: @use, fingerprint: fingerprint.to_s }
|
74
|
+
end
|
75
|
+
|
76
|
+
def inspect
|
77
|
+
to_h.inspect
|
78
|
+
end
|
79
|
+
|
80
|
+
def stripped
|
81
|
+
value.to_s.gsub(BEGIN_CERT, '').gsub(END_CERT, '').gsub(/\n/, '')
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.to_x509(value)
|
85
|
+
OpenSSL::X509::Certificate.new(Base64.decode64(value))
|
86
|
+
rescue OpenSSL::X509::CertificateError => error
|
87
|
+
::Xml::Kit.logger.warn(error)
|
88
|
+
OpenSSL::X509::Certificate.new(value)
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
attr_reader :value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'xml/kit/crypto/oaep_cipher'
|
2
|
+
require 'xml/kit/crypto/rsa_cipher'
|
3
|
+
require 'xml/kit/crypto/simple_cipher'
|
4
|
+
require 'xml/kit/crypto/unknown_cipher'
|
5
|
+
|
6
|
+
module Xml
|
7
|
+
module Kit
|
8
|
+
module Crypto
|
9
|
+
DECRYPTORS = [ SimpleCipher, RsaCipher, OaepCipher, UnknownCipher ]
|
10
|
+
|
11
|
+
# @!visibility private
|
12
|
+
def self.decryptor_for(algorithm, key)
|
13
|
+
DECRYPTORS.find { |x| x.matches?(algorithm) }.new(algorithm, key)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
module Crypto
|
4
|
+
class OaepCipher
|
5
|
+
ALGORITHMS = {
|
6
|
+
'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p' => true,
|
7
|
+
}
|
8
|
+
def initialize(algorithm, key)
|
9
|
+
@key = key
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.matches?(algorithm)
|
13
|
+
ALGORITHMS[algorithm]
|
14
|
+
end
|
15
|
+
|
16
|
+
def decrypt(cipher_text)
|
17
|
+
@key.private_decrypt(cipher_text, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
module Crypto
|
4
|
+
class RsaCipher
|
5
|
+
ALGORITHMS = {
|
6
|
+
'http://www.w3.org/2001/04/xmlenc#rsa-1_5' => true,
|
7
|
+
}
|
8
|
+
|
9
|
+
def initialize(algorithm, key)
|
10
|
+
@key = key
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.matches?(algorithm)
|
14
|
+
ALGORITHMS[algorithm]
|
15
|
+
end
|
16
|
+
|
17
|
+
def decrypt(cipher_text)
|
18
|
+
@key.private_decrypt(cipher_text)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
module Crypto
|
4
|
+
class SimpleCipher
|
5
|
+
ALGORITHMS = {
|
6
|
+
'http://www.w3.org/2001/04/xmlenc#tripledes-cbc' => 'DES-EDE3-CBC',
|
7
|
+
'http://www.w3.org/2001/04/xmlenc#aes128-cbc' => 'AES-128-CBC',
|
8
|
+
'http://www.w3.org/2001/04/xmlenc#aes192-cbc' => 'AES-192-CBC',
|
9
|
+
'http://www.w3.org/2001/04/xmlenc#aes256-cbc' => 'AES-256-CBC',
|
10
|
+
}
|
11
|
+
|
12
|
+
def initialize(algorithm, private_key)
|
13
|
+
@algorithm = algorithm
|
14
|
+
@private_key = private_key
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.matches?(algorithm)
|
18
|
+
ALGORITHMS[algorithm]
|
19
|
+
end
|
20
|
+
|
21
|
+
def decrypt(cipher_text)
|
22
|
+
cipher = OpenSSL::Cipher.new(ALGORITHMS[@algorithm])
|
23
|
+
cipher.decrypt
|
24
|
+
iv = cipher_text[0..cipher.iv_len-1]
|
25
|
+
data = cipher_text[cipher.iv_len..-1]
|
26
|
+
#cipher.padding = 0
|
27
|
+
cipher.key = @private_key
|
28
|
+
cipher.iv = iv
|
29
|
+
cipher.update(data) + cipher.final
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
# {include:file:spec/saml/xml_decryption_spec.rb}
|
4
|
+
class Decryption
|
5
|
+
# The list of private keys to use to attempt to decrypt the document.
|
6
|
+
attr_reader :private_keys
|
7
|
+
|
8
|
+
def initialize(private_keys:)
|
9
|
+
@private_keys = private_keys
|
10
|
+
end
|
11
|
+
|
12
|
+
# Decrypts an EncryptedData section of an XML document.
|
13
|
+
#
|
14
|
+
# @param data [Hash] the XML document converted to a [Hash] using Hash.from_xml.
|
15
|
+
def decrypt(data)
|
16
|
+
encrypted_data = data['EncryptedData']
|
17
|
+
symmetric_key = symmetric_key_from(encrypted_data)
|
18
|
+
cipher_text = Base64.decode64(encrypted_data["CipherData"]["CipherValue"])
|
19
|
+
to_plaintext(cipher_text, symmetric_key, encrypted_data["EncryptionMethod"]['Algorithm'])
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def symmetric_key_from(encrypted_data)
|
25
|
+
encrypted_key = encrypted_data['KeyInfo']['EncryptedKey']
|
26
|
+
cipher_text = Base64.decode64(encrypted_key['CipherData']['CipherValue'])
|
27
|
+
attempts = private_keys.count
|
28
|
+
private_keys.each do |private_key|
|
29
|
+
begin
|
30
|
+
attempts -= 1
|
31
|
+
return to_plaintext(cipher_text, private_key, encrypted_key["EncryptionMethod"]['Algorithm'])
|
32
|
+
rescue OpenSSL::PKey::RSAError => error
|
33
|
+
::Xml::Kit.logger.error(error)
|
34
|
+
raise if attempts.zero?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_plaintext(cipher_text, symmetric_key, algorithm)
|
40
|
+
Crypto.decryptor_for(algorithm, symmetric_key).decrypt(cipher_text)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
# {include:file:spec/saml/xml_spec.rb}
|
4
|
+
class Document
|
5
|
+
include ActiveModel::Validations
|
6
|
+
NAMESPACES = { "ds": ::Xml::Kit::Namespaces::XMLDSIG }.freeze
|
7
|
+
|
8
|
+
validate :validate_signatures
|
9
|
+
validate :validate_certificates
|
10
|
+
|
11
|
+
def initialize(raw_xml, namespaces: NAMESPACES)
|
12
|
+
@raw_xml = raw_xml
|
13
|
+
@namespaces = namespaces
|
14
|
+
@document = ::Nokogiri::XML(raw_xml)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the first XML node found by searching the document with the provided XPath.
|
18
|
+
#
|
19
|
+
# @param xpath [String] the XPath to use to search the document
|
20
|
+
def find_by(xpath)
|
21
|
+
document.at_xpath(xpath, namespaces)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns all XML nodes found by searching the document with the provided XPath.
|
25
|
+
#
|
26
|
+
# @param xpath [String] the XPath to use to search the document
|
27
|
+
def find_all(xpath)
|
28
|
+
document.search(xpath, namespaces)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Return the XML document as a [String].
|
32
|
+
#
|
33
|
+
# @param pretty [Boolean] return the XML string in a human readable format if true.
|
34
|
+
def to_xml(pretty: true)
|
35
|
+
pretty ? document.to_xml(indent: 2) : raw_xml
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
attr_reader :raw_xml, :document, :namespaces
|
41
|
+
|
42
|
+
def validate_signatures
|
43
|
+
invalid_signatures.flat_map(&:errors).uniq.each do |error|
|
44
|
+
errors.add(error, "is invalid")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def invalid_signatures
|
49
|
+
signed_document = Xmldsig::SignedDocument.new(document, id_attr: 'ID=$uri or @Id')
|
50
|
+
signed_document.signatures.find_all do |signature|
|
51
|
+
x509_certificates.all? do |certificate|
|
52
|
+
!signature.valid?(certificate)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate_certificates(now = Time.current)
|
58
|
+
return if find_by('//ds:Signature').nil?
|
59
|
+
|
60
|
+
x509_certificates.each do |certificate|
|
61
|
+
inactive = now < certificate.not_before
|
62
|
+
errors.add(:certificate, "Not valid before #{certificate.not_before}") if inactive
|
63
|
+
|
64
|
+
expired = now > certificate.not_after
|
65
|
+
errors.add(:certificate, "Not valid after #{certificate.not_after}") if expired
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def x509_certificates
|
70
|
+
xpath = "//ds:KeyInfo/ds:X509Data/ds:X509Certificate"
|
71
|
+
find_all(xpath).map { |item| Certificate.to_x509(item.text) }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
# This generates a fingerprint for an X509 Certificate.
|
4
|
+
#
|
5
|
+
# certificate, _ = Xml::Kit::SelfSignedCertificate.new("password").create
|
6
|
+
#
|
7
|
+
# puts Xml::Kit::Fingerprint.new(certificate).to_s
|
8
|
+
# # B7:AB:DC:BD:4D:23:58:65:FD:1A:99:0C:5F:89:EA:87:AD:F1:D7:83:34:7A:E9:E4:88:12:DD:46:1F:38:05:93
|
9
|
+
#
|
10
|
+
# {include:file:spec/saml/fingerprint_spec.rb}
|
11
|
+
class Fingerprint
|
12
|
+
# The OpenSSL::X509::Certificate
|
13
|
+
attr_reader :x509
|
14
|
+
|
15
|
+
def initialize(raw_certificate)
|
16
|
+
@x509 = Certificate.to_x509(raw_certificate)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Generates a formatted fingerprint using the specified hash algorithm.
|
20
|
+
#
|
21
|
+
# @param algorithm [OpenSSL::Digest] the openssl algorithm to use `OpenSSL::Digest::SHA256`, `OpenSSL::Digest::SHA1`.
|
22
|
+
# @return [String] in the format of `"BF:ED:C5:F1:6C:AB:F5:B2:15:1F:BF:BD:7D:68:1A:F9:A5:4E:4C:19:30:BC:6D:25:B1:8E:98:D4:23:FD:B4:09"`
|
23
|
+
def algorithm(algorithm)
|
24
|
+
pretty_fingerprint(algorithm.new.hexdigest(x509.to_der))
|
25
|
+
end
|
26
|
+
|
27
|
+
def ==(other)
|
28
|
+
self.to_s == other.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
def eql?(other)
|
32
|
+
self == other
|
33
|
+
end
|
34
|
+
|
35
|
+
def hash
|
36
|
+
to_s.hash
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
algorithm(OpenSSL::Digest::SHA256)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def pretty_fingerprint(fingerprint)
|
46
|
+
fingerprint.upcase.scan(/../).join(":")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/xml/kit/id.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
# This class is used primary for generating ID.
|
4
|
+
#https://www.w3.org/2001/XMLSchema.xsd
|
5
|
+
class Id
|
6
|
+
# Generate an ID that conforms to the XML Schema.
|
7
|
+
# https://www.w3.org/2001/XMLSchema.xsd
|
8
|
+
def self.generate
|
9
|
+
"_#{SecureRandom.uuid}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
class KeyPair # :nodoc:
|
4
|
+
attr_reader :certificate, :private_key, :use
|
5
|
+
|
6
|
+
def initialize(certificate, private_key, passphrase, use)
|
7
|
+
@use = use
|
8
|
+
@certificate = ::Xml::Kit::Certificate.new(certificate, use: use)
|
9
|
+
@private_key = OpenSSL::PKey::RSA.new(private_key, passphrase)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns true if the key pair is the designated use.
|
13
|
+
#
|
14
|
+
# @param use [Symbol] Can be either `:signing` or `:encryption`.
|
15
|
+
def for?(use)
|
16
|
+
@use == use
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a generated self signed certificate with private key.
|
20
|
+
#
|
21
|
+
# @param use [Symbol] Can be either `:signing` or `:encryption`.
|
22
|
+
# @param passphrase [String] the passphrase to use to encrypt the private key.
|
23
|
+
def self.generate(use:, passphrase: SecureRandom.uuid)
|
24
|
+
certificate, private_key = ::Xml::Kit::SelfSignedCertificate.new(passphrase).create
|
25
|
+
new(certificate, private_key, passphrase, use)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
module Namespaces
|
4
|
+
ENVELOPED_SIG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
|
5
|
+
RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
|
6
|
+
RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
|
7
|
+
RSA_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"
|
8
|
+
RSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
|
9
|
+
SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1"
|
10
|
+
SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256'
|
11
|
+
SHA384 = "http://www.w3.org/2001/04/xmldsig-more#sha384"
|
12
|
+
SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512'
|
13
|
+
XMLDSIG = "http://www.w3.org/2000/09/xmldsig#"
|
14
|
+
XMLENC = "http://www.w3.org/2001/04/xmlenc#"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
class SelfSignedCertificate
|
4
|
+
SUBJECT="/C=CA/ST=Alberta/L=Calgary/O=XmlKit/OU=XmlKit/CN=XmlKit"
|
5
|
+
|
6
|
+
def initialize(passphrase)
|
7
|
+
@passphrase = passphrase
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
rsa_key = OpenSSL::PKey::RSA.new(2048)
|
12
|
+
public_key = rsa_key.public_key
|
13
|
+
certificate = OpenSSL::X509::Certificate.new
|
14
|
+
certificate.subject = certificate.issuer = OpenSSL::X509::Name.parse(SUBJECT)
|
15
|
+
certificate.not_before = Time.now.to_i
|
16
|
+
certificate.not_after = (Date.today + 30).to_time.to_i
|
17
|
+
certificate.public_key = public_key
|
18
|
+
certificate.serial = 0x0
|
19
|
+
certificate.version = 2
|
20
|
+
certificate.sign(rsa_key, OpenSSL::Digest::SHA256.new)
|
21
|
+
[
|
22
|
+
certificate.to_pem,
|
23
|
+
rsa_key.to_pem(OpenSSL::Cipher.new('AES-256-CBC'), @passphrase)
|
24
|
+
]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
# @!visibility private
|
4
|
+
class Signatures # :nodoc:
|
5
|
+
attr_reader :key_pair, :signature_method, :digest_method
|
6
|
+
|
7
|
+
# @!visibility private
|
8
|
+
def initialize(key_pair:, signature_method:, digest_method:)
|
9
|
+
@digest_method = digest_method
|
10
|
+
@key_pair = key_pair
|
11
|
+
@signature_method = signature_method
|
12
|
+
end
|
13
|
+
|
14
|
+
# @!visibility private
|
15
|
+
def sign_with(key_pair)
|
16
|
+
@key_pair = key_pair
|
17
|
+
end
|
18
|
+
|
19
|
+
# @!visibility private
|
20
|
+
def build(reference_id)
|
21
|
+
return nil if key_pair.nil?
|
22
|
+
|
23
|
+
::Xml::Kit::Builders::Signature.new(
|
24
|
+
reference_id,
|
25
|
+
certificate: key_pair.certificate,
|
26
|
+
signature_method: signature_method,
|
27
|
+
digest_method: digest_method
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @!visibility private
|
32
|
+
def complete(raw_xml)
|
33
|
+
return raw_xml if key_pair.nil?
|
34
|
+
|
35
|
+
private_key = key_pair.private_key
|
36
|
+
Xmldsig::SignedDocument.new(raw_xml).sign(private_key)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @!visibility private
|
40
|
+
def self.sign(xml: ::Builder::XmlMarkup.new, key_pair:, signature_method: :SHA256, digest_method: :SHA256)
|
41
|
+
signatures = new(
|
42
|
+
key_pair: key_pair,
|
43
|
+
signature_method: signature_method,
|
44
|
+
digest_method: digest_method,
|
45
|
+
)
|
46
|
+
yield xml, XmlSignatureTemplate.new(xml, signatures)
|
47
|
+
signatures.complete(xml.target!)
|
48
|
+
end
|
49
|
+
|
50
|
+
class XmlSignatureTemplate # :nodoc:
|
51
|
+
# @!visibility private
|
52
|
+
attr_reader :signatures, :xml
|
53
|
+
|
54
|
+
# @!visibility private
|
55
|
+
def initialize(xml, signatures)
|
56
|
+
@signatures = signatures
|
57
|
+
@xml = xml
|
58
|
+
end
|
59
|
+
|
60
|
+
# @!visibility private
|
61
|
+
def template(reference_id)
|
62
|
+
Template.new(signatures.build(reference_id)).to_xml(xml: xml)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
module Templatable
|
4
|
+
# Can be used to disable embeding a signature.
|
5
|
+
# By default a signature will be embedded if a signing
|
6
|
+
# certificate is available.
|
7
|
+
attr_accessor :embed_signature
|
8
|
+
|
9
|
+
# Used to enable/disable encrypting the document.
|
10
|
+
attr_accessor :encrypt
|
11
|
+
|
12
|
+
# The [Xml::Kit::KeyPair] to use for generating a signature.
|
13
|
+
attr_accessor :signing_key_pair
|
14
|
+
|
15
|
+
# The [Xml::Kit::Certificate] that contains the public key to use for encrypting the document.
|
16
|
+
attr_accessor :encryption_certificate
|
17
|
+
|
18
|
+
# Returns the generated XML document with an XML Digital Signature and XML Encryption.
|
19
|
+
def to_xml(xml: ::Builder::XmlMarkup.new)
|
20
|
+
signatures.complete(render(self, xml: xml))
|
21
|
+
end
|
22
|
+
|
23
|
+
def encryption_for(xml:)
|
24
|
+
if encrypt?
|
25
|
+
temp = ::Builder::XmlMarkup.new
|
26
|
+
yield temp
|
27
|
+
signed_xml = signatures.complete(temp.target!)
|
28
|
+
xml_encryption = ::Xml::Kit::Builders::Encryption.new(
|
29
|
+
signed_xml,
|
30
|
+
encryption_certificate.public_key
|
31
|
+
)
|
32
|
+
render(xml_encryption, xml: xml)
|
33
|
+
else
|
34
|
+
yield xml
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def render(model, options)
|
39
|
+
::Xml::Kit::Template.new(model).to_xml(options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def signature_for(reference_id:, xml:)
|
43
|
+
return unless sign?
|
44
|
+
render(signatures.build(reference_id), xml: xml)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Allows you to specify which key pair to use for generating an XML digital signature.
|
48
|
+
#
|
49
|
+
# @param key_pair [Xml::Kit::KeyPair] the key pair to use for signing.
|
50
|
+
def sign_with(key_pair)
|
51
|
+
signatures.sign_with(key_pair)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def sign?
|
57
|
+
embed_signature
|
58
|
+
end
|
59
|
+
|
60
|
+
# @!visibility private
|
61
|
+
def signatures
|
62
|
+
@signatures ||= ::Xml::Kit::Signatures.new(
|
63
|
+
key_pair: signing_key_pair,
|
64
|
+
digest_method: digest_method,
|
65
|
+
signature_method: signature_method,
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
def digest_method
|
70
|
+
:SHA256
|
71
|
+
end
|
72
|
+
|
73
|
+
def signature_method
|
74
|
+
:SHA256
|
75
|
+
end
|
76
|
+
|
77
|
+
# @!visibility private
|
78
|
+
def encrypt?
|
79
|
+
encrypt && encryption_certificate
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Xml
|
2
|
+
module Kit
|
3
|
+
class Template
|
4
|
+
attr_reader :target
|
5
|
+
|
6
|
+
def initialize(target)
|
7
|
+
@target = target
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns the compiled template as a [String].
|
11
|
+
#
|
12
|
+
# @param options [Hash] The options hash to pass to the template engine.
|
13
|
+
def to_xml(options = {})
|
14
|
+
template.render(target, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def template_path
|
20
|
+
return target.template_path if target.respond_to?(:template_path)
|
21
|
+
|
22
|
+
root_path = File.expand_path(File.dirname(__FILE__))
|
23
|
+
template_name = "#{target.class.name.split("::").last.underscore}.builder"
|
24
|
+
File.join(root_path, "builders/templates/", template_name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def template
|
28
|
+
Tilt.new(template_path)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/xml-kit.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "xml/kit/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "xml-kit"
|
8
|
+
spec.version = Xml::Kit::VERSION
|
9
|
+
spec.authors = ["mo khan"]
|
10
|
+
spec.email = ["mo@mokhan.ca"]
|
11
|
+
|
12
|
+
spec.summary = %q{A simple toolkit for working with XML.}
|
13
|
+
spec.description = %q{A simple toolkit for working with XML.}
|
14
|
+
spec.homepage = "http://www.mokhan.ca"
|
15
|
+
spec.license = "MIT"
|
16
|
+
spec.required_ruby_version = '>= 2.2.0'
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
+
f.match(%r{^(test|spec|features)/})
|
20
|
+
end
|
21
|
+
spec.metadata["yard.run"] = "yri"
|
22
|
+
spec.bindir = "exe"
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_dependency "activemodel", ">= 4.2.0"
|
27
|
+
spec.add_dependency "builder", "~> 3.2"
|
28
|
+
spec.add_dependency "nokogiri", "~> 1.8"
|
29
|
+
spec.add_dependency "tilt", "~> 2.0"
|
30
|
+
spec.add_dependency "xmldsig", "~> 0.6"
|
31
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
32
|
+
spec.add_development_dependency "ffaker", "~> 2.7"
|
33
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
34
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
35
|
+
spec.add_development_dependency "simplecov", "~> 0.15.1"
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xml-kit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- mo khan
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-12-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activemodel
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: builder
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.8'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: tilt
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: xmldsig
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.6'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.6'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.16'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.16'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: ffaker
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.7'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.7'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '10.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '10.0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '3.0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '3.0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: simplecov
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 0.15.1
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 0.15.1
|
153
|
+
description: A simple toolkit for working with XML.
|
154
|
+
email:
|
155
|
+
- mo@mokhan.ca
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- ".gitignore"
|
161
|
+
- ".gitlab-ci.yml"
|
162
|
+
- ".rspec"
|
163
|
+
- ".travis.yml"
|
164
|
+
- Gemfile
|
165
|
+
- LICENSE.txt
|
166
|
+
- README.md
|
167
|
+
- Rakefile
|
168
|
+
- bin/console
|
169
|
+
- bin/setup
|
170
|
+
- lib/xml/kit.rb
|
171
|
+
- lib/xml/kit/builders/encryption.rb
|
172
|
+
- lib/xml/kit/builders/signature.rb
|
173
|
+
- lib/xml/kit/builders/templates/certificate.builder
|
174
|
+
- lib/xml/kit/builders/templates/encryption.builder
|
175
|
+
- lib/xml/kit/builders/templates/nil_class.builder
|
176
|
+
- lib/xml/kit/builders/templates/signature.builder
|
177
|
+
- lib/xml/kit/certificate.rb
|
178
|
+
- lib/xml/kit/crypto.rb
|
179
|
+
- lib/xml/kit/crypto/oaep_cipher.rb
|
180
|
+
- lib/xml/kit/crypto/rsa_cipher.rb
|
181
|
+
- lib/xml/kit/crypto/simple_cipher.rb
|
182
|
+
- lib/xml/kit/crypto/unknown_cipher.rb
|
183
|
+
- lib/xml/kit/decryption.rb
|
184
|
+
- lib/xml/kit/document.rb
|
185
|
+
- lib/xml/kit/fingerprint.rb
|
186
|
+
- lib/xml/kit/id.rb
|
187
|
+
- lib/xml/kit/key_pair.rb
|
188
|
+
- lib/xml/kit/namespaces.rb
|
189
|
+
- lib/xml/kit/self_signed_certificate.rb
|
190
|
+
- lib/xml/kit/signatures.rb
|
191
|
+
- lib/xml/kit/templatable.rb
|
192
|
+
- lib/xml/kit/template.rb
|
193
|
+
- lib/xml/kit/version.rb
|
194
|
+
- xml-kit.gemspec
|
195
|
+
homepage: http://www.mokhan.ca
|
196
|
+
licenses:
|
197
|
+
- MIT
|
198
|
+
metadata:
|
199
|
+
yard.run: yri
|
200
|
+
post_install_message:
|
201
|
+
rdoc_options: []
|
202
|
+
require_paths:
|
203
|
+
- lib
|
204
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: 2.2.0
|
209
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
210
|
+
requirements:
|
211
|
+
- - ">="
|
212
|
+
- !ruby/object:Gem::Version
|
213
|
+
version: '0'
|
214
|
+
requirements: []
|
215
|
+
rubyforge_project:
|
216
|
+
rubygems_version: 2.6.14
|
217
|
+
signing_key:
|
218
|
+
specification_version: 4
|
219
|
+
summary: A simple toolkit for working with XML.
|
220
|
+
test_files: []
|