xml-kit 0.1.14 → 0.5.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +23 -5
  3. data/.travis.yml +7 -5
  4. data/CHANGELOG.md +60 -0
  5. data/README.md +14 -22
  6. data/bin/cibuild +1 -1
  7. data/lib/xml/kit.rb +11 -2
  8. data/lib/xml/kit/certificate.rb +6 -4
  9. data/lib/xml/kit/crypto.rb +14 -0
  10. data/lib/xml/kit/crypto/oaep_cipher.rb +5 -2
  11. data/lib/xml/kit/crypto/rsa_cipher.rb +4 -2
  12. data/lib/xml/kit/crypto/symmetric_cipher.rb +30 -9
  13. data/lib/xml/kit/crypto/unknown_cipher.rb +6 -1
  14. data/lib/xml/kit/decryption.rb +29 -20
  15. data/lib/xml/kit/document.rb +5 -4
  16. data/lib/xml/kit/encrypted_data.rb +51 -0
  17. data/lib/xml/kit/encrypted_key.rb +35 -0
  18. data/lib/xml/kit/encryption.rb +27 -18
  19. data/lib/xml/kit/fingerprint.rb +1 -1
  20. data/lib/xml/kit/key_info.rb +71 -0
  21. data/lib/xml/kit/key_info/key_value.rb +19 -0
  22. data/lib/xml/kit/key_info/retrieval_method.rb +19 -0
  23. data/lib/xml/kit/key_info/rsa_key_value.rb +15 -0
  24. data/lib/xml/kit/key_pair.rb +8 -3
  25. data/lib/xml/kit/namespaces.rb +12 -12
  26. data/lib/xml/kit/self_signed_certificate.rb +16 -3
  27. data/lib/xml/kit/signature.rb +9 -2
  28. data/lib/xml/kit/signatures.rb +4 -1
  29. data/lib/xml/kit/templatable.rb +75 -24
  30. data/lib/xml/kit/templates/certificate.builder +1 -5
  31. data/lib/xml/kit/templates/encrypted_data.builder +9 -0
  32. data/lib/xml/kit/templates/encrypted_key.builder +9 -0
  33. data/lib/xml/kit/templates/key_info.builder +14 -0
  34. data/lib/xml/kit/templates/key_value.builder +5 -0
  35. data/lib/xml/kit/templates/retrieval_method.builder +3 -0
  36. data/lib/xml/kit/templates/rsa_key_value.builder +6 -0
  37. data/lib/xml/kit/templates/signature.builder +1 -1
  38. data/lib/xml/kit/version.rb +1 -1
  39. data/xml-kit.gemspec +4 -4
  40. metadata +29 -18
  41. data/.rubocop_todo.yml +0 -22
  42. data/lib/xml/kit/templates/encryption.builder +0 -16
@@ -3,9 +3,11 @@
3
3
  module Xml
4
4
  module Kit
5
5
  class SelfSignedCertificate
6
- SUBJECT = '/C=CA/ST=AB/L=Calgary/O=XmlKit/OU=XmlKit/CN=XmlKit'.freeze
6
+ SUBJECT = '/C=CA/ST=AB/L=Calgary/O=XmlKit/OU=XmlKit/CN=XmlKit'
7
7
 
8
- def create(algorithm: 'AES-256-CBC', passphrase: nil, key_pair: OpenSSL::PKey::RSA.new(2048))
8
+ def create(algorithm: 'AES-256-CBC',
9
+ passphrase: nil,
10
+ key_pair: OpenSSL::PKey::RSA.new(2048))
9
11
  certificate = certificate_for(key_pair.public_key)
10
12
  certificate.sign(key_pair, OpenSSL::Digest::SHA256.new)
11
13
  [certificate.to_pem, export(key_pair, algorithm, passphrase)]
@@ -24,14 +26,25 @@ module Xml
24
26
 
25
27
  def certificate_for(public_key)
26
28
  certificate = OpenSSL::X509::Certificate.new
27
- certificate.subject = certificate.issuer = OpenSSL::X509::Name.parse(SUBJECT)
29
+ certificate.subject =
30
+ certificate.issuer = OpenSSL::X509::Name.parse(SUBJECT)
28
31
  certificate.not_before = Time.now
29
32
  certificate.not_after = certificate.not_before + 30 * 24 * 60 * 60 # 30 days
30
33
  certificate.public_key = public_key
31
34
  certificate.serial = 0x0
32
35
  certificate.version = 2
36
+ apply_ski_extension_to(certificate)
33
37
  certificate
34
38
  end
39
+
40
+ def apply_ski_extension_to(certificate)
41
+ extensions = OpenSSL::X509::ExtensionFactory.new
42
+ extensions.subject_certificate = certificate
43
+ extensions.issuer_certificate = certificate
44
+ certificate.add_extension(
45
+ extensions.create_extension('subjectKeyIdentifier', 'hash', false)
46
+ )
47
+ end
35
48
  end
36
49
  end
37
50
  end
@@ -2,6 +2,10 @@
2
2
 
3
3
  module Xml
4
4
  module Kit
5
+ # An implementation of the Signature element.
6
+ # https://www.w3.org/TR/xmldsig-core1/#sec-Signature
7
+ #
8
+ # @since 0.1.0
5
9
  class Signature
6
10
  SIGNATURE_METHODS = {
7
11
  SHA1: 'http://www.w3.org/2000/09/xmldsig#rsa-sha1',
@@ -11,7 +15,7 @@ module Xml
11
15
  SHA512: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512',
12
16
  }.freeze
13
17
  DIGEST_METHODS = {
14
- SHA1: 'http://www.w3.org/2000/09/xmldsig#SHA1',
18
+ SHA1: 'http://www.w3.org/2000/09/xmldsig#sha1',
15
19
  SHA224: 'http://www.w3.org/2001/04/xmldsig-more#sha224',
16
20
  SHA256: 'http://www.w3.org/2001/04/xmlenc#sha256',
17
21
  SHA384: 'http://www.w3.org/2001/04/xmldsig-more#sha384',
@@ -23,7 +27,10 @@ module Xml
23
27
  attr_reader :reference_id
24
28
  attr_reader :signature_method
25
29
 
26
- def initialize(reference_id, signature_method: :SH256, digest_method: :SHA256, certificate:)
30
+ def initialize(reference_id,
31
+ signature_method: :SH256,
32
+ digest_method: :SHA256,
33
+ certificate:)
27
34
  @certificate = certificate
28
35
  @digest_method = DIGEST_METHODS[digest_method]
29
36
  @reference_id = reference_id
@@ -39,7 +39,10 @@ module Xml
39
39
  end
40
40
 
41
41
  # @!visibility private
42
- def self.sign(xml: ::Builder::XmlMarkup.new, key_pair:, signature_method: :SHA256, digest_method: :SHA256)
42
+ def self.sign(xml: ::Builder::XmlMarkup.new,
43
+ key_pair:,
44
+ signature_method: :SHA256,
45
+ digest_method: :SHA256)
43
46
  signatures = new(
44
47
  key_pair: key_pair,
45
48
  signature_method: signature_method,
@@ -17,22 +17,79 @@ module Xml
17
17
  # The [Xml::Kit::Certificate] that contains the public key to use for encrypting the document.
18
18
  attr_accessor :encryption_certificate
19
19
 
20
+ # Allows you to specify the digest method algorithm. (Default: SHA256)
21
+ # A list of digest methods can be found in [Xml::Kit::Signature].
22
+ attr_accessor :digest_method
23
+
24
+ # Allows you to specify the signature method algorithm. (Default: SHA256)
25
+ # A list of signature methods can be found in [Xml::Kit::Signature].
26
+ attr_accessor :signature_method
27
+
20
28
  # Returns the generated XML document with an XML Digital Signature and XML Encryption.
21
- def to_xml(xml: ::Builder::XmlMarkup.new)
22
- signatures.complete(render(self, xml: xml))
29
+ def to_xml(xml: ::Builder::XmlMarkup.new, pretty: false)
30
+ result = signatures.complete(render(self, xml: xml))
31
+ pretty ? Nokogiri::XML(result).to_xml(indent: 2) : result
32
+ end
33
+
34
+ # Generates an {#Xml::Kit::EncryptedKey} section. https://www.w3.org/TR/xmlenc-core1/#sec-EncryptedKey
35
+ #
36
+ # @since 0.3.0
37
+ # @param xml [Builder::XmlMarkup] the xml builder instance
38
+ # @param id [String] the id of EncryptedKey element
39
+ def encrypt_key_for(xml:, id:, key_info: nil)
40
+ ::Xml::Kit::EncryptedKey.new(
41
+ id: id,
42
+ asymmetric_cipher: asymmetric_cipher,
43
+ symmetric_cipher: symmetric_cipher,
44
+ key_info: key_info
45
+ ).to_xml(xml: xml)
46
+ end
47
+
48
+ # @deprecated Use {#encrypt_data_for} instead of this
49
+ def encryption_for(*args, &block)
50
+ ::Xml::Kit.deprecate(
51
+ 'encryption_for is deprecated. Use encrypt_data_for instead.'
52
+ )
53
+ encrypt_data_for(*args, &block)
54
+ end
55
+
56
+ # Generates an {#Xml::Kit::EncryptedData} section. https://www.w3.org/TR/xmlenc-core1/#sec-EncryptedData
57
+ #
58
+ # @since 0.3.0
59
+ # @param xml [Builder::XmlMarkup] the xml builder instance
60
+ # @param key_info [Xml::Kit::KeyInfo] the key info to render in the EncryptedData
61
+ def encrypt_data_for(xml:, key_info: nil)
62
+ return yield xml unless encrypt?
63
+
64
+ temp = ::Builder::XmlMarkup.new
65
+ yield temp
66
+ ::Xml::Kit::EncryptedData.new(
67
+ signatures.complete(temp.target!),
68
+ symmetric_cipher: symmetric_cipher,
69
+ asymmetric_cipher: asymmetric_cipher,
70
+ key_info: key_info
71
+ ).to_xml(xml: xml)
72
+ end
73
+
74
+ # Provides a default RSA asymmetric cipher. Can be overridden to provide custom ciphers.
75
+ #
76
+ # @abstract
77
+ # @since 0.3.0
78
+ def asymmetric_cipher(algorithm: Crypto::RsaCipher::ALGORITHM)
79
+ raise Xml::Kit::Error, 'encryption_certificate is not specified.' unless encryption_certificate
80
+
81
+ @asymmetric_cipher ||= Crypto.cipher_for(
82
+ algorithm,
83
+ encryption_certificate.public_key
84
+ )
23
85
  end
24
86
 
25
- def encryption_for(xml:)
26
- if encrypt?
27
- temp = ::Builder::XmlMarkup.new
28
- yield temp
29
- ::Xml::Kit::Encryption.new(
30
- signatures.complete(temp.target!),
31
- encryption_certificate.public_key
32
- ).to_xml(xml: xml)
33
- else
34
- yield xml
35
- end
87
+ # Provides a default aes256-cbc symmetric cipher. Can be overridden to provide custom ciphers.
88
+ #
89
+ # @abstract
90
+ # @since 0.3.0
91
+ def symmetric_cipher
92
+ @symmetric_cipher ||= Crypto::SymmetricCipher.new
36
93
  end
37
94
 
38
95
  def render(model, options)
@@ -48,9 +105,11 @@ module Xml
48
105
  # Allows you to specify which key pair to use for generating an XML digital signature.
49
106
  #
50
107
  # @param key_pair [Xml::Kit::KeyPair] the key pair to use for signing.
51
- def sign_with(key_pair)
108
+ def sign_with(key_pair, signature_method: :SHA256, digest_method: :SHA256)
52
109
  self.signing_key_pair = key_pair
53
110
  self.embed_signature = true
111
+ self.signature_method = signature_method
112
+ self.digest_method = digest_method
54
113
  signatures.sign_with(key_pair)
55
114
  end
56
115
 
@@ -72,19 +131,11 @@ module Xml
72
131
  def signatures
73
132
  @signatures ||= ::Xml::Kit::Signatures.new(
74
133
  key_pair: signing_key_pair,
75
- digest_method: digest_method,
76
- signature_method: signature_method
134
+ digest_method: digest_method || :SHA256,
135
+ signature_method: signature_method || :SHA256
77
136
  )
78
137
  end
79
138
 
80
- def digest_method
81
- :SHA256
82
- end
83
-
84
- def signature_method
85
- :SHA256
86
- end
87
-
88
139
  # @!visibility private
89
140
  def encrypt?
90
141
  encrypt && encryption_certificate
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  xml.KeyDescriptor use ? { use: use } : {} do
4
- xml.KeyInfo "xmlns": ::Xml::Kit::Namespaces::XMLDSIG do
5
- xml.X509Data do
6
- xml.X509Certificate stripped
7
- end
8
- end
4
+ render key_info, xml: xml
9
5
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ xml.EncryptedData xmlns: ::Xml::Kit::Namespaces::XMLENC do
4
+ xml.EncryptionMethod Algorithm: symmetric_cipher.algorithm
5
+ render key_info, xml: xml
6
+ xml.CipherData do
7
+ xml.CipherValue symmetric_cipher_value
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ xml.EncryptedKey Id: id, xmlns: ::Xml::Kit::Namespaces::XMLENC do
4
+ xml.EncryptionMethod Algorithm: asymmetric_cipher.algorithm
5
+ render(key_info, xml: xml) if key_info
6
+ xml.CipherData do
7
+ xml.CipherValue cipher_value
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ xml.KeyInfo xmlns: ::Xml::Kit::Namespaces::XMLDSIG do
4
+ xml.KeyName key_name if key_name
5
+ render(key_value, xml: xml) if @key_value
6
+ render(retrieval_method, xml: xml) if @retrieval_method
7
+ if x509_data
8
+ xml.X509Data do
9
+ xml.X509SKI subject_key_identifier
10
+ xml.X509Certificate ::Xml::Kit::Certificate.strip(x509_data.to_pem)
11
+ end
12
+ end
13
+ render(encrypted_key, xml: xml) if encrypted_key
14
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ xml.KeyValue do
4
+ render(rsa, xml: xml) if @rsa
5
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ xml.RetrievalMethod xmlns: ::Xml::Kit::Namespaces::XMLDSIG, URI: uri, Type: type
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ xml.RSAKeyValue do
4
+ xml.Modulus modulus
5
+ xml.Exponent exponent
6
+ end
@@ -6,7 +6,7 @@ xml.Signature 'xmlns' => ::Xml::Kit::Namespaces::XMLDSIG do
6
6
  xml.SignatureMethod Algorithm: signature_method
7
7
  xml.Reference URI: "##{reference_id}" do
8
8
  xml.Transforms do
9
- xml.Transform Algorithm: "#{::Xml::Kit::Namespaces::XMLDSIG}enveloped-signature"
9
+ xml.Transform Algorithm: ::Xml::Kit::Namespaces::ENVELOPED_SIG
10
10
  xml.Transform Algorithm: ::Xml::Kit::Namespaces::CANONICALIZATION
11
11
  end
12
12
  xml.DigestMethod Algorithm: digest_method
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Xml
4
4
  module Kit
5
- VERSION = '0.1.14'.freeze
5
+ VERSION = '0.5.0'
6
6
  end
7
7
  end
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.description = 'A simple toolkit for working with XML.'
15
15
  spec.homepage = 'https://github.com/saml-kit/xml-kit'
16
16
  spec.license = 'MIT'
17
- spec.required_ruby_version = '>= 2.2.0'
17
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
18
18
 
19
19
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
20
20
  f.match(%r{^(test|spec|features)/})
@@ -26,13 +26,13 @@ Gem::Specification.new do |spec|
26
26
 
27
27
  spec.add_dependency 'activemodel', '>= 4.2.0'
28
28
  spec.add_dependency 'builder', '~> 3.2'
29
- spec.add_dependency 'nokogiri', '>= 1.8.5'
29
+ spec.add_dependency 'nokogiri', '~> 1.10'
30
30
  spec.add_dependency 'tilt', '>= 1.4.1'
31
31
  spec.add_dependency 'xmldsig', '~> 0.6'
32
- spec.add_development_dependency 'bundler', '~> 1.16'
32
+ spec.add_development_dependency 'bundler', '~> 2.0'
33
33
  spec.add_development_dependency 'bundler-audit', '~> 0.6'
34
34
  spec.add_development_dependency 'ffaker', '~> 2.7'
35
- spec.add_development_dependency 'rake', '~> 10.0'
35
+ spec.add_development_dependency 'rake', '~> 13.0'
36
36
  spec.add_development_dependency 'rspec', '~> 3.0'
37
37
  spec.add_development_dependency 'rubocop', '~> 0.52'
38
38
  spec.add_development_dependency 'rubocop-rspec', '~> 1.22'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xml-kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.14
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - mo khan
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-21 00:00:00.000000000 Z
11
+ date: 2021-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: nokogiri
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.8.5
47
+ version: '1.10'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.8.5
54
+ version: '1.10'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: tilt
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '1.16'
89
+ version: '2.0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '1.16'
96
+ version: '2.0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: bundler-audit
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +128,14 @@ dependencies:
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '10.0'
131
+ version: '13.0'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '10.0'
138
+ version: '13.0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rspec
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -203,9 +203,10 @@ files:
203
203
  - ".gitlab-ci.yml"
204
204
  - ".rspec"
205
205
  - ".rubocop.yml"
206
- - ".rubocop_todo.yml"
207
206
  - ".travis.yml"
207
+ - CHANGELOG.md
208
208
  - Gemfile
209
+ - Gemfile.lock
209
210
  - LICENSE.txt
210
211
  - README.md
211
212
  - Rakefile
@@ -225,9 +226,15 @@ files:
225
226
  - lib/xml/kit/decryption.rb
226
227
  - lib/xml/kit/decryption_error.rb
227
228
  - lib/xml/kit/document.rb
229
+ - lib/xml/kit/encrypted_data.rb
230
+ - lib/xml/kit/encrypted_key.rb
228
231
  - lib/xml/kit/encryption.rb
229
232
  - lib/xml/kit/fingerprint.rb
230
233
  - lib/xml/kit/id.rb
234
+ - lib/xml/kit/key_info.rb
235
+ - lib/xml/kit/key_info/key_value.rb
236
+ - lib/xml/kit/key_info/retrieval_method.rb
237
+ - lib/xml/kit/key_info/rsa_key_value.rb
231
238
  - lib/xml/kit/key_pair.rb
232
239
  - lib/xml/kit/namespaces.rb
233
240
  - lib/xml/kit/self_signed_certificate.rb
@@ -236,8 +243,13 @@ files:
236
243
  - lib/xml/kit/templatable.rb
237
244
  - lib/xml/kit/template.rb
238
245
  - lib/xml/kit/templates/certificate.builder
239
- - lib/xml/kit/templates/encryption.builder
246
+ - lib/xml/kit/templates/encrypted_data.builder
247
+ - lib/xml/kit/templates/encrypted_key.builder
248
+ - lib/xml/kit/templates/key_info.builder
249
+ - lib/xml/kit/templates/key_value.builder
240
250
  - lib/xml/kit/templates/nil_class.builder
251
+ - lib/xml/kit/templates/retrieval_method.builder
252
+ - lib/xml/kit/templates/rsa_key_value.builder
241
253
  - lib/xml/kit/templates/signature.builder
242
254
  - lib/xml/kit/version.rb
243
255
  - xml-kit.gemspec
@@ -246,7 +258,7 @@ licenses:
246
258
  - MIT
247
259
  metadata:
248
260
  yard.run: yri
249
- post_install_message:
261
+ post_install_message:
250
262
  rdoc_options: []
251
263
  require_paths:
252
264
  - lib
@@ -254,16 +266,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
254
266
  requirements:
255
267
  - - ">="
256
268
  - !ruby/object:Gem::Version
257
- version: 2.2.0
269
+ version: 2.5.0
258
270
  required_rubygems_version: !ruby/object:Gem::Requirement
259
271
  requirements:
260
272
  - - ">="
261
273
  - !ruby/object:Gem::Version
262
274
  version: '0'
263
275
  requirements: []
264
- rubyforge_project:
265
- rubygems_version: 2.7.6
266
- signing_key:
276
+ rubygems_version: 3.2.3
277
+ signing_key:
267
278
  specification_version: 4
268
279
  summary: A simple toolkit for working with XML.
269
280
  test_files: []