signed_xml 0.0.1 → 1.0.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.
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "1.9.3"
5
+ - "2.0.0"
6
+ - rbx-19mode
data/README.md CHANGED
@@ -1,26 +1,56 @@
1
- # SignedXmlDocument
1
+ SignedXml [![Build Status](https://travis-ci.org/toddthomas/signed_xml.png)](https://travis-ci.org/toddthomas/signed_xml)
2
+ =========
2
3
 
3
- TODO: Write a gem description
4
+ SignedXml is a Ruby implementation of [XML Signatures](http://www.w3.org/TR/xmldsig-core).
4
5
 
5
- ## Installation
6
+ Dependencies
7
+ ------------
8
+
9
+ SignedXml requires and is in love with [Nokogiri](http://nokogiri.org).
10
+
11
+ Limitations
12
+ -----------
13
+
14
+ They are legion. Currently only verification of signed documents is supported.
15
+ Allowed transformations are enveloped-signature and c14n. Only same-document
16
+ Reference URIs are supported, and of those only the null URI (URI="", or
17
+ the whole document) and fragment URIs which specify a literal ID are supported.
18
+ XPointer expressions are not supported.
19
+
20
+ Installation
21
+ ------------
6
22
 
7
23
  Add this line to your application's Gemfile:
8
24
 
9
- gem 'signed_xml_document'
25
+ ```ruby
26
+ gem 'signed_xml'
27
+ ```
10
28
 
11
29
  And then execute:
12
30
 
13
- $ bundle
31
+ ```shell
32
+ bundle
33
+ ```
14
34
 
15
35
  Or install it yourself as:
16
36
 
17
- $ gem install signed_xml_document
37
+ ```shell
38
+ gem install signed_xml
39
+ ```
40
+
41
+ Usage
42
+ -----
18
43
 
19
- ## Usage
44
+ ```ruby
45
+ require 'signed_xml'
20
46
 
21
- TODO: Write usage instructions here
47
+ doc = Nokogiri::XML(File.read 'some_signed_doc.xml')
48
+ signed_doc = SignedXml::Document.new(doc)
49
+ signed_doc.is_verified?
50
+ ```
22
51
 
23
- ## Contributing
52
+ Contributing
53
+ ------------
24
54
 
25
55
  1. Fork it
26
56
  2. Create your feature branch (`git checkout -b my-new-feature`)
data/Rakefile CHANGED
@@ -1 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -3,7 +3,7 @@ require 'base64'
3
3
  module SignedXml
4
4
  class Base64Transform
5
5
  def apply(input)
6
- Base64.encode64(input)
6
+ Base64.encode64(input).chomp
7
7
  end
8
8
  end
9
9
  end
@@ -11,14 +11,14 @@ module SignedXml
11
11
  when "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" then XML_C14N_1_0
12
12
  when "http://www.w3.org/2001/10/xml-exc-c14n" then XML_C14N_EXCLUSIVE_1_0
13
13
  when "http://www.w3.org/2006/12/xml-c14n11" then XML_C14N_1_1
14
- else raise ArgumentError.new("unknown canonicalization method #{method}")
14
+ else raise ArgumentError, "unknown canonicalization method #{method}"
15
15
  end
16
16
 
17
17
  @with_comments = !!with_comments
18
18
  end
19
19
 
20
20
  def apply(input)
21
- raise ArgumentError.new("input #{input.inspect}:#{input.class} is not canonicalizable") unless input.respond_to?(:canonicalize)
21
+ raise ArgumentError, "input #{input.inspect}:#{input.class} is not canonicalizable" unless input.respond_to?(:canonicalize)
22
22
 
23
23
  input.canonicalize(method, nil, with_comments)
24
24
  end
@@ -4,11 +4,12 @@ module SignedXml
4
4
  module DigestMethodResolution
5
5
  include OpenSSL
6
6
 
7
- def digester_for_id(id)
7
+ def new_digester_for_id(id)
8
8
  case id
9
9
  when "http://www.w3.org/2000/09/xmldsig#sha1","http://www.w3.org/2000/09/xmldsig#rsa-sha1"
10
10
  Digest::SHA1.new
11
- else raise ArgumentError.new("unknown digest method #{id}")
11
+ else
12
+ raise ArgumentError, "unknown digest method #{id}"
12
13
  end
13
14
  end
14
15
  end
@@ -7,7 +7,7 @@ module SignedXml
7
7
  attr_reader :digest
8
8
 
9
9
  def initialize(method_id)
10
- @digest = digester_for_id(method_id)
10
+ @digest = new_digester_for_id(method_id)
11
11
  end
12
12
 
13
13
  def apply(input)
@@ -3,22 +3,48 @@ require "options"
3
3
 
4
4
  module SignedXml
5
5
  class Document
6
+ include Logging
7
+
6
8
  attr_reader :doc
7
9
 
8
- def initialize(doc)
9
- @doc = doc
10
+ def initialize(thing)
11
+ if thing.is_a? Nokogiri::XML::Document
12
+ @doc = thing
13
+ else
14
+ @doc = Nokogiri::XML(thing)
15
+ end
10
16
  end
11
17
 
12
18
  def is_verifiable?
13
19
  signatures.any?
14
20
  end
15
21
 
16
- def is_verified?(opts = {})
17
- return false unless is_verifiable?
22
+ def is_verified?(arg = nil)
23
+ unless is_verifiable?
24
+ logger.warn "document cannot be verified because it contains no <Signature> elements"
25
+ return false
26
+ end
27
+
28
+ if arg.respond_to? :public_key
29
+ set_public_key_for_signatures(arg)
30
+ elsif arg.respond_to? :[]
31
+ set_certificate_store_for_signatures(arg)
32
+ elsif !arg.nil?
33
+ raise ArgumentError, "#{arg.inspect}:#{arg.class} must have a public key or be a hash of public keys"
34
+ end
18
35
 
19
36
  signatures.all?(&:is_verified?)
20
37
  end
21
38
 
39
+ def sign(private_key, certificate = nil)
40
+ signatures.each { |sig| sig.sign(private_key, certificate) }
41
+ self
42
+ end
43
+
44
+ def to_xml
45
+ doc.to_xml
46
+ end
47
+
22
48
  private
23
49
 
24
50
  def signatures
@@ -32,5 +58,15 @@ module SignedXml
32
58
  end
33
59
  signatures
34
60
  end
61
+
62
+ def set_public_key_for_signatures(certificate)
63
+ signatures.each { |sig| sig.public_key = certificate.public_key }
64
+ end
65
+
66
+ def set_certificate_store_for_signatures(cert_store)
67
+ raise "#{cert_store.inspect} doesn't implement []" unless cert_store.respond_to? :[]
68
+
69
+ signatures.each { |sig| sig.certificate_store = cert_store }
70
+ end
35
71
  end
36
72
  end
@@ -0,0 +1,9 @@
1
+ require 'digest'
2
+
3
+ module SignedXml
4
+ module Fingerprinting
5
+ def fingerprint(data)
6
+ Digest::SHA1.hexdigest(data)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module SignedXml
2
+ # Logging stuff borrowed from https://github.com/pezra/saml-sp
3
+
4
+ module Logging
5
+ def logger
6
+ SignedXml.logger
7
+ end
8
+
9
+ def self.included(base)
10
+ base.extend(self)
11
+ end
12
+ end
13
+ end
@@ -1,6 +1,7 @@
1
1
  module SignedXml
2
2
  class Reference
3
3
  include Transformable
4
+ include Logging
4
5
 
5
6
  attr_reader :here, :start
6
7
 
@@ -13,18 +14,26 @@ module SignedXml
13
14
  @start = here.document.root
14
15
  when /^#/
15
16
  id = uri.split('#').last
16
- raise ArgumentError.new("XPointer expressions like #{id} are not yet supported") if id =~ /^xpointer/
17
+ raise ArgumentError, "XPointer expressions like #{id} are not yet supported" if id =~ /^xpointer/
17
18
  # TODO: handle ID attrs with names other than 'ID'
18
19
  @start = here.document.at_xpath("//*[@ID='#{id}']")
19
- raise ArgumentError.new("no match found for ID #{id}") if @start.nil?
20
- else raise ArgumentError.new("unsupported Reference URI #{uri}")
20
+ raise ArgumentError, "no match found for ID #{id}" if @start.nil?
21
+ else
22
+ raise ArgumentError, "unsupported Reference URI #{uri}"
21
23
  end
22
24
 
23
25
  @transforms = init_transforms
24
26
  end
25
27
 
26
28
  def is_verified?
27
- apply_transforms.chomp == digest_value
29
+ result = apply_transforms == digest_value
30
+ logger.info "verification failed for digest value [#{digest_value}]" unless result
31
+ result
32
+ end
33
+
34
+ def compute_and_set_digest_value
35
+ digest_value_node.content = apply_transforms
36
+ logger.debug "set digest value to [#{digest_value}]"
28
37
  end
29
38
 
30
39
  private
@@ -39,7 +48,8 @@ module SignedXml
39
48
  transforms << EnvelopedSignatureTransform.new
40
49
  when %r{^http://.*c14n}
41
50
  transforms << C14NTransform.new(method)
42
- else raise ArgumentError.new("unknown transform method #{method}")
51
+ else
52
+ raise ArgumentError, "unknown transform method #{method}"
43
53
  end
44
54
  end
45
55
 
@@ -53,7 +63,11 @@ module SignedXml
53
63
  end
54
64
 
55
65
  def digest_value
56
- @digest_value ||= here.at_xpath('ds:DigestValue', ds: XMLDSIG_NS).text.strip
66
+ @digest_value ||= digest_value_node.text.strip
67
+ end
68
+
69
+ def digest_value_node
70
+ @digest_value_node ||= here.at_xpath('ds:DigestValue', ds: XMLDSIG_NS)
57
71
  end
58
72
  end
59
73
  end
@@ -3,8 +3,12 @@ require 'base64'
3
3
  module SignedXml
4
4
  class Signature
5
5
  include DigestMethodResolution
6
+ include Fingerprinting
7
+ include Logging
6
8
 
7
9
  attr_accessor :here
10
+ attr_accessor :public_key
11
+ attr_accessor :certificate_store
8
12
 
9
13
  def initialize(here)
10
14
  @here = here
@@ -14,16 +18,46 @@ module SignedXml
14
18
  is_signed_info_verified? && are_reference_digests_verified?
15
19
  end
16
20
 
21
+ def sign(private_key, certificate = nil)
22
+ compute_digests_for_references
23
+ sign_signed_info(private_key)
24
+ set_certificate_data(certificate)
25
+ end
26
+
17
27
  private
18
28
 
19
29
  def is_signed_info_verified?
20
- public_key.verify(digester_for_id(signed_info.signature_method), decoded_value, signed_info.apply_transforms)
30
+ return false if public_key.nil?
31
+
32
+ result = public_key.verify(new_digester_for_id(signed_info.signature_method), decoded_value, signed_info.apply_transforms)
33
+ logger.info "verification of signature value [#{value}] failed" unless result
34
+ result
21
35
  end
22
36
 
23
37
  def are_reference_digests_verified?
24
38
  references.all?(&:is_verified?)
25
39
  end
26
40
 
41
+ def sign_signed_info(private_key)
42
+ data = signed_info.apply_transforms
43
+ logger.debug "data to sign: [#{data}]"
44
+ digester = new_digester_for_id(signed_info.signature_method)
45
+ logger.debug "digester: #{digester.inspect}"
46
+ sig_value = private_key.sign(digester, data)
47
+ logger.debug "signature value (before Base64 encoding): [#{sig_value}]"
48
+ value_node.content = Base64Transform.new.apply(sig_value)
49
+ logger.debug "SignatureValue set to [#{value}]"
50
+ end
51
+
52
+ def compute_digests_for_references
53
+ references.each(&:compute_and_set_digest_value)
54
+ end
55
+
56
+ def set_certificate_data(certificate)
57
+ x509_cert_data_node.content = certificate.to_pem.split("\n")[1..-2].join("\n") if certificate
58
+ logger.debug "set certificate data to [#{x509_cert_data}]"
59
+ end
60
+
27
61
  def references
28
62
  @references ||= init_references
29
63
  end
@@ -43,23 +77,52 @@ module SignedXml
43
77
  end
44
78
 
45
79
  def value
46
- @value ||= here.at_xpath('//ds:SignatureValue', ds: XMLDSIG_NS).text.strip
80
+ @value ||= value_node.text.strip
81
+ end
82
+
83
+ def value_node
84
+ @value_node ||= here.at_xpath('//ds:SignatureValue', ds: XMLDSIG_NS)
47
85
  end
48
86
 
49
87
  def signed_info
50
88
  @signed_info ||= SignedInfo.new(here.at_xpath("//ds:SignedInfo", ds: XMLDSIG_NS))
51
89
  end
52
90
 
91
+ def certificate_store
92
+ @certificate_store ||= {}
93
+ end
94
+
53
95
  def public_key
54
- @public_key ||= x509_certificate.public_key
96
+ # If the user provided a certificate store, we MUST only use a
97
+ # key which matches the one in the signature's KeyInfo. Otherwise,
98
+ # use the key in the signature.
99
+ @public_key ||= if certificate_store.any?
100
+ logger.debug "using cert store #{certificate_store}"
101
+ if certificate_store.has_key? x509_cert_fingerprint
102
+ certificate_store[x509_cert_fingerprint].public_key
103
+ else
104
+ logger.warn "Store has no certificate with fingerprint #{x509_cert_fingerprint}. Signature validation will fail."
105
+ nil
106
+ end
107
+ else
108
+ x509_certificate.public_key
109
+ end
55
110
  end
56
111
 
57
112
  def x509_certificate
58
- @x509_certificate ||= OpenSSL::X509::Certificate.new(certificate(x509_cert_data))
113
+ OpenSSL::X509::Certificate.new(certificate(x509_cert_data))
114
+ end
115
+
116
+ def x509_cert_fingerprint
117
+ @x509_cert_fingerprint ||= fingerprint(x509_certificate.to_der)
59
118
  end
60
119
 
61
120
  def x509_cert_data
62
- @x509_cert_data ||= here.at_xpath("//ds:X509Certificate", ds: XMLDSIG_NS).text
121
+ x509_cert_data_node.text
122
+ end
123
+
124
+ def x509_cert_data_node
125
+ @x509_cert_data_node ||= here.at_xpath("//ds:X509Certificate", ds: XMLDSIG_NS)
63
126
  end
64
127
 
65
128
  def certificate(data)
@@ -1,12 +1,19 @@
1
1
  module SignedXml
2
2
  module Transformable
3
+ include Logging
4
+
3
5
  def transforms
4
6
  @transforms ||= []
5
7
  end
6
8
 
7
9
  def apply_transforms
8
10
  transforms.reduce(start) do |input, transform|
9
- transform.apply(input)
11
+ logger.debug "applying transform #{transform.inspect}"
12
+ logger.debug "input: [#{input}]"
13
+
14
+ result = transform.apply(input)
15
+ logger.debug "output: [#{result}]"
16
+ result
10
17
  end
11
18
  end
12
19
  end
@@ -1,3 +1,3 @@
1
1
  module SignedXml
2
- VERSION = "0.0.1"
2
+ VERSION = "1.0.0"
3
3
  end
data/lib/signed_xml.rb CHANGED
@@ -1,8 +1,30 @@
1
+ require 'logger'
1
2
  require 'nokogiri'
2
3
 
3
4
  module SignedXml
4
5
  XMLDSIG_NS = "http://www.w3.org/2000/09/xmldsig#"
5
6
 
7
+ def self.Document(thing)
8
+ Document.new(thing)
9
+ end
10
+
11
+ # Logger that does nothing
12
+ BITBUCKET_LOGGER = Logger.new(nil)
13
+ class << BITBUCKET_LOGGER
14
+ def add(*args)
15
+ end
16
+ end
17
+
18
+ # The logger signed_xml should use
19
+ def self.logger
20
+ @@logger ||= BITBUCKET_LOGGER
21
+ end
22
+
23
+ # Set the logger for signed_xml
24
+ def self.logger=(a_logger)
25
+ @@logger = a_logger
26
+ end
27
+
6
28
  autoload :Transformable, 'signed_xml/transformable'
7
29
  autoload :Document, 'signed_xml/document'
8
30
  autoload :Signature, 'signed_xml/signature'
@@ -13,4 +35,6 @@ module SignedXml
13
35
  autoload :Base64Transform, 'signed_xml/base64_transform'
14
36
  autoload :C14NTransform, 'signed_xml/c14n_transform'
15
37
  autoload :EnvelopedSignatureTransform, 'signed_xml/enveloped_signature_transform'
38
+ autoload :Fingerprinting, 'signed_xml/fingerprinting'
39
+ autoload :Logging, 'signed_xml/logging'
16
40
  end
@@ -0,0 +1,28 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEujCCA6KgAwIBAgIJAL+8HkFCI7nBMA0GCSqGSIb3DQEBBQUAMIGZMQswCQYD
3
+ VQQGEwJVUzEWMBQGA1UECBMNQW5vdGhlciBTdGF0ZTEUMBIGA1UEBxMLU2hlbGJ5
4
+ dmlsbGUxDTALBgNVBAoTBEFDTUUxFDASBgNVBAsTC1NrdW5rIFdvcmtzMRUwEwYD
5
+ VQQDEwxTb21lb25lIEVsc2UxIDAeBgkqhkiG9w0BCQEWEWFsaWNlQGV4YW1wbGUu
6
+ b3JnMB4XDTEzMDQxMjE0MjMwOVoXDTQwMDgyODE0MjMwOVowgZkxCzAJBgNVBAYT
7
+ AlVTMRYwFAYDVQQIEw1Bbm90aGVyIFN0YXRlMRQwEgYDVQQHEwtTaGVsYnl2aWxs
8
+ ZTENMAsGA1UEChMEQUNNRTEUMBIGA1UECxMLU2t1bmsgV29ya3MxFTATBgNVBAMT
9
+ DFNvbWVvbmUgRWxzZTEgMB4GCSqGSIb3DQEJARYRYWxpY2VAZXhhbXBsZS5vcmcw
10
+ ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD8Q3VU7TN85VWWiOs0VaGC
11
+ DWyspwTlaCEoBHZlncmYr3bzwZGuLr0fzG8XQJbyfh7kM2As9fDSmnf6p2ARfqJq
12
+ 2KFk5JPzRoY8HzU6VI0HmY57SzltABAzfHnnjL8sfQI7ZlttmXIwva1Zao+1L63X
13
+ +m5JZEAKeKoA5mNe3Fu3YGwbQRZXi5lpxeh9OpDvPo37MSpAK8nTwjpn4VwA/EPB
14
+ TPLkZa6yhdzT6YWe0FKqWnXc4XvWxu+ivfR82HytZMnHxwkX3QjJVY4MgFlhTXN6
15
+ 0jLgwLMksxF72P+yrCbPz+w3cG76tOWCBL3O/SAHUFEKHoJ6EqnQNsfb2xdNaSmn
16
+ AgMBAAGjggEBMIH+MB0GA1UdDgQWBBTumQKrYT5TZNHp6I2bEtpBqthL+zCBzgYD
17
+ VR0jBIHGMIHDgBTumQKrYT5TZNHp6I2bEtpBqthL+6GBn6SBnDCBmTELMAkGA1UE
18
+ BhMCVVMxFjAUBgNVBAgTDUFub3RoZXIgU3RhdGUxFDASBgNVBAcTC1NoZWxieXZp
19
+ bGxlMQ0wCwYDVQQKEwRBQ01FMRQwEgYDVQQLEwtTa3VuayBXb3JrczEVMBMGA1UE
20
+ AxMMU29tZW9uZSBFbHNlMSAwHgYJKoZIhvcNAQkBFhFhbGljZUBleGFtcGxlLm9y
21
+ Z4IJAL+8HkFCI7nBMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKNY
22
+ yM7gr63/l6kWL8fgkXidelF4S9JOzi5QUY8rzexPxRPv8UfGzGg2CReIlHbAQmzH
23
+ uYkUdV4k3Is7EYzNlkO/EvhCaajIRNDUFn0BEmJLUBSB1hpQQWRxc5LH/9j0lT/f
24
+ nodmDMpfId7R66X6lDGHVSWhPFbAJ559/8TI8FOkKFnMTdVGon2/M/hu9lZ659Kb
25
+ Quhl1Slbi03AtxqT//IH3926aRjkd77pWWBKJ5W4L/8lOZjkHIQdlyjOtSO/Yhgc
26
+ cd7BdioIrLXUMBNaa0Jzb7j8P5IW8RgJRIyKKQuFppIrILhCyFW6ic7ZcCX5mmG2
27
+ lP2S5xTyx7cyd7XjBF4=
28
+ -----END CERTIFICATE-----
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpQIBAAKCAQEA/EN1VO0zfOVVlojrNFWhgg1srKcE5WghKAR2ZZ3JmK9288GR
3
+ ri69H8xvF0CW8n4e5DNgLPXw0pp3+qdgEX6iatihZOST80aGPB81OlSNB5mOe0s5
4
+ bQAQM3x554y/LH0CO2ZbbZlyML2tWWqPtS+t1/puSWRACniqAOZjXtxbt2BsG0EW
5
+ V4uZacXofTqQ7z6N+zEqQCvJ08I6Z+FcAPxDwUzy5GWusoXc0+mFntBSqlp13OF7
6
+ 1sbvor30fNh8rWTJx8cJF90IyVWODIBZYU1zetIy4MCzJLMRe9j/sqwmz8/sN3Bu
7
+ +rTlggS9zv0gB1BRCh6CehKp0DbH29sXTWkppwIDAQABAoIBAQCNLxgQ4vypDxVa
8
+ veCdlrtgtTC4ZHWqCyBbbDvzXV8B1FpHzHNDQCdbD6ixI9YXe5zAbTyLjU4uIIO7
9
+ xkdPI0e1cu7JL+DaDAN+zJyWu9F+imOi/5PxPFLU7fqwLCamuIQySHQtH+839kB5
10
+ xdkON9QdB60H6FKrSaMkA81jvwKZ2wHRenD9SQ9gJMf33Xl0yISbHsYB2tVAC3BE
11
+ xKf7ofAGWjQjiy4CqrlHrXFnnglhvAPABwtOTrRjWbk6yG4vSupyjGRozwuPECLR
12
+ tyjqzY2QfJZGCuN7iSUsrR7LKp0RkOSRxyXmFvWKHrH3a7xTufkiZR0WyWF2HTLv
13
+ dGkmdj5pAoGBAP5nP2jH6GHGk6pE+T+mmTMgaov0mmMP1XbDC3cJUu1eZk2D0qDx
14
+ s9std34fiTvruEMxB8wdkZdVHA+NQIK3hEQIMjLO6+vkcbyeeHA76jDDX0MXVnpV
15
+ LFWfMvuPI40ZadRk5V40IGihLKMS5T0MojBwNMclkr39rYzk22NrNu5jAoGBAP3Y
16
+ xcir110C2Uu/mRM8BveRMhSSZ1s6p6FhVmxPsa/x40WAhGn1xoL6GnF+dUBGLBEn
17
+ 0/7uV8/KmVq2AF5a53gGAyluEcf880V+EeMPab+7i3wyA98NPAG061cIL2h8K1pW
18
+ zmC3hrveElj2f+V+3ofsOF23Ew+Gov3AFPqWJSjtAoGAbjV+M78+fXUQLVgZ/igH
19
+ AC4P2jeJ1lZarEtMoTHJ2gjmGrh7u7tZph6pQFsbEXlJZtpLvXIly0BUmqwfgUFN
20
+ LEe8r2QSsitR1lt0Y3KhPqS0lRT8IpzZSvJfnLjittKGlTtsXgYI8Cq6cp7R7kOV
21
+ 05QYWRl+242U7I+MNyKQNm8CgYEArb0LCaCLg05q2QxmwaJpBlJrG2dktCz+BFcx
22
+ pmoZLFn6+lvOxRMBbi2toZYyu+4LRSakUyxgD4kT0uEUeX/wQtainV2HcABxpFN3
23
+ /JdVAnRjMHqu6aAOPQDNvkCM6g9qQKd/EvUpkzWYCymTOcjOl+sWXRXrRsoYjmJE
24
+ OYpAHrUCgYEA2mYFv9PV9WCTCLEIJEWL1yvWDm2UqJU5pen6dUee6djCQHiZD8+w
25
+ qFmlIKVQn+8/Ov6g3KSZABhVF5ispNo4iERDhjR1ItyYUs3M8dR0sFhAfRe1cfQl
26
+ msO/cWkdJQ1IDPs2RxIWE8KWIgs6Dg9DqJwfjlnzSJxvvHh5kuSdBjY=
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,47 @@
1
+ <?xml version="1.0"?>
2
+ <Response xmlns="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" IssueInstant="2003-04-17T00:46:02Z" Version="2.0" ID="_c7055387-af61-4fce-8b98-e2927324b306">
3
+ <saml:Issuer>https://www.opensaml.org/IDP"</saml:Issuer>
4
+ <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
5
+ <ds:SignedInfo>
6
+ <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
7
+ <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
8
+ <ds:Reference URI="">
9
+ <ds:Transforms>
10
+ <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
11
+ </ds:Transforms>
12
+ <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
13
+ <ds:DigestValue>otynz9RFK0/mrkztml+POU0P4Rw=</ds:DigestValue>
14
+ </ds:Reference>
15
+ </ds:SignedInfo>
16
+ <ds:SignatureValue>fMniqoW/jSH7isH7ka+79+WYeiE4O63mA7TdrqOTrh8Q+JZQMsYsbAnx5E7Fo4Fy
17
+ +2yE/6XgCnEUFUvyWK9J5vaS+qzoOH5RZeSDcaSZeM5rP2hW5lf7iTQG/9wLsQUX
18
+ KQRm1/pFgm7yetYr+gfK8yvUMR0pQc4h+vo4wKyQQYpHMlS97BWFoPEvi9F1M0Ld
19
+ 7NxHSHUFGTLqm+664ZTYI3z1k2kcgsuZpwHYCYOx185U383jnW1DruwLD8KE6Nxn
20
+ Wd9imhxAiCV2CMQkjxIkrBM8du47rm+kDToYVgOn9gU15gYAmXUN/4MwF/yvYpQE
21
+ sAs0VcNWD5PRjIviKbRh2Q==</ds:SignatureValue>
22
+ </ds:Signature>
23
+ <Status>
24
+ <StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
25
+ </Status>
26
+ <Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="_a75adf55-01d7-40cc-929f-dbd8372ebdfc" IssueInstant="2003-04-17T00:46:02Z" Version="2.0">
27
+ <Issuer>https://www.opensaml.org/IDP</Issuer>
28
+ <Subject>
29
+ <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
30
+ scott@example.org
31
+ </NameID>
32
+ <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"/>
33
+ </Subject>
34
+ <Conditions NotBefore="2003-04-17T00:46:02Z" NotOnOrAfter="2003-04-17T00:51:02Z">
35
+ <AudienceRestriction>
36
+ <Audience>http://www.opensaml.org/SP</Audience>
37
+ </AudienceRestriction>
38
+ </Conditions>
39
+ <AuthnStatement AuthnInstant="2003-04-17T00:46:00Z">
40
+ <AuthnContext>
41
+ <AuthnContextClassRef>
42
+ urn:oasis:names:tc:SAML:2.0:ac:classes:Password
43
+ </AuthnContextClassRef>
44
+ </AuthnContext>
45
+ </AuthnStatement>
46
+ </Assertion>
47
+ </Response>
@@ -0,0 +1,54 @@
1
+ <Response
2
+ IssueInstant="2003-04-17T00:46:02Z" Version="2.0"
3
+ ID="_c7055387-af61-4fce-8b98-e2927324b306"
4
+ xmlns="urn:oasis:names:tc:SAML:2.0:protocol"
5
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
6
+ <saml:Issuer>https://www.opensaml.org/IDP"</saml:Issuer>
7
+ <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
8
+ <ds:SignedInfo>
9
+ <ds:CanonicalizationMethod
10
+ Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
11
+ <ds:SignatureMethod
12
+ Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
13
+ <ds:Reference URI="">
14
+ <ds:Transforms>
15
+ <ds:Transform
16
+ Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
17
+ </ds:Transforms>
18
+ <ds:DigestMethod
19
+ Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
20
+ <ds:DigestValue/>
21
+ </ds:Reference>
22
+ </ds:SignedInfo>
23
+ <ds:SignatureValue/>
24
+ </ds:Signature>
25
+ <Status>
26
+ <StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
27
+ </Status>
28
+ <Assertion ID="_a75adf55-01d7-40cc-929f-dbd8372ebdfc"
29
+ IssueInstant="2003-04-17T00:46:02Z" Version="2.0"
30
+ xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
31
+ <Issuer>https://www.opensaml.org/IDP</Issuer>
32
+ <Subject>
33
+ <NameID
34
+ Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
35
+ scott@example.org
36
+ </NameID>
37
+ <SubjectConfirmation
38
+ Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"/>
39
+ </Subject>
40
+ <Conditions NotBefore="2003-04-17T00:46:02Z"
41
+ NotOnOrAfter="2003-04-17T00:51:02Z">
42
+ <AudienceRestriction>
43
+ <Audience>http://www.opensaml.org/SP</Audience>
44
+ </AudienceRestriction>
45
+ </Conditions>
46
+ <AuthnStatement AuthnInstant="2003-04-17T00:46:00Z">
47
+ <AuthnContext>
48
+ <AuthnContextClassRef>
49
+ urn:oasis:names:tc:SAML:2.0:ac:classes:Password
50
+ </AuthnContextClassRef>
51
+ </AuthnContext>
52
+ </AuthnStatement>
53
+ </Assertion>
54
+ </Response>
@@ -0,0 +1,78 @@
1
+ <?xml version="1.0"?>
2
+ <Response xmlns="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" IssueInstant="2003-04-17T00:46:02Z" Version="2.0" ID="_c7055387-af61-4fce-8b98-e2927324b306">
3
+ <saml:Issuer>https://www.opensaml.org/IDP"</saml:Issuer>
4
+ <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
5
+ <ds:SignedInfo>
6
+ <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
7
+ <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
8
+ <ds:Reference URI="">
9
+ <ds:Transforms>
10
+ <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
11
+ </ds:Transforms>
12
+ <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
13
+ <ds:DigestValue>otynz9RFK0/mrkztml+POU0P4Rw=</ds:DigestValue>
14
+ </ds:Reference>
15
+ </ds:SignedInfo>
16
+ <ds:SignatureValue>fMniqoW/jSH7isH7ka+79+WYeiE4O63mA7TdrqOTrh8Q+JZQMsYsbAnx5E7Fo4Fy
17
+ +2yE/6XgCnEUFUvyWK9J5vaS+qzoOH5RZeSDcaSZeM5rP2hW5lf7iTQG/9wLsQUX
18
+ KQRm1/pFgm7yetYr+gfK8yvUMR0pQc4h+vo4wKyQQYpHMlS97BWFoPEvi9F1M0Ld
19
+ 7NxHSHUFGTLqm+664ZTYI3z1k2kcgsuZpwHYCYOx185U383jnW1DruwLD8KE6Nxn
20
+ Wd9imhxAiCV2CMQkjxIkrBM8du47rm+kDToYVgOn9gU15gYAmXUN/4MwF/yvYpQE
21
+ sAs0VcNWD5PRjIviKbRh2Q==</ds:SignatureValue>
22
+ <ds:KeyInfo>
23
+ <ds:X509Data>
24
+
25
+ <ds:X509Certificate>MIIEujCCA6KgAwIBAgIJAL+8HkFCI7nBMA0GCSqGSIb3DQEBBQUAMIGZMQswCQYD
26
+ VQQGEwJVUzEWMBQGA1UECBMNQW5vdGhlciBTdGF0ZTEUMBIGA1UEBxMLU2hlbGJ5
27
+ dmlsbGUxDTALBgNVBAoTBEFDTUUxFDASBgNVBAsTC1NrdW5rIFdvcmtzMRUwEwYD
28
+ VQQDEwxTb21lb25lIEVsc2UxIDAeBgkqhkiG9w0BCQEWEWFsaWNlQGV4YW1wbGUu
29
+ b3JnMB4XDTEzMDQxMjE0MjMwOVoXDTQwMDgyODE0MjMwOVowgZkxCzAJBgNVBAYT
30
+ AlVTMRYwFAYDVQQIEw1Bbm90aGVyIFN0YXRlMRQwEgYDVQQHEwtTaGVsYnl2aWxs
31
+ ZTENMAsGA1UEChMEQUNNRTEUMBIGA1UECxMLU2t1bmsgV29ya3MxFTATBgNVBAMT
32
+ DFNvbWVvbmUgRWxzZTEgMB4GCSqGSIb3DQEJARYRYWxpY2VAZXhhbXBsZS5vcmcw
33
+ ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD8Q3VU7TN85VWWiOs0VaGC
34
+ DWyspwTlaCEoBHZlncmYr3bzwZGuLr0fzG8XQJbyfh7kM2As9fDSmnf6p2ARfqJq
35
+ 2KFk5JPzRoY8HzU6VI0HmY57SzltABAzfHnnjL8sfQI7ZlttmXIwva1Zao+1L63X
36
+ +m5JZEAKeKoA5mNe3Fu3YGwbQRZXi5lpxeh9OpDvPo37MSpAK8nTwjpn4VwA/EPB
37
+ TPLkZa6yhdzT6YWe0FKqWnXc4XvWxu+ivfR82HytZMnHxwkX3QjJVY4MgFlhTXN6
38
+ 0jLgwLMksxF72P+yrCbPz+w3cG76tOWCBL3O/SAHUFEKHoJ6EqnQNsfb2xdNaSmn
39
+ AgMBAAGjggEBMIH+MB0GA1UdDgQWBBTumQKrYT5TZNHp6I2bEtpBqthL+zCBzgYD
40
+ VR0jBIHGMIHDgBTumQKrYT5TZNHp6I2bEtpBqthL+6GBn6SBnDCBmTELMAkGA1UE
41
+ BhMCVVMxFjAUBgNVBAgTDUFub3RoZXIgU3RhdGUxFDASBgNVBAcTC1NoZWxieXZp
42
+ bGxlMQ0wCwYDVQQKEwRBQ01FMRQwEgYDVQQLEwtTa3VuayBXb3JrczEVMBMGA1UE
43
+ AxMMU29tZW9uZSBFbHNlMSAwHgYJKoZIhvcNAQkBFhFhbGljZUBleGFtcGxlLm9y
44
+ Z4IJAL+8HkFCI7nBMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKNY
45
+ yM7gr63/l6kWL8fgkXidelF4S9JOzi5QUY8rzexPxRPv8UfGzGg2CReIlHbAQmzH
46
+ uYkUdV4k3Is7EYzNlkO/EvhCaajIRNDUFn0BEmJLUBSB1hpQQWRxc5LH/9j0lT/f
47
+ nodmDMpfId7R66X6lDGHVSWhPFbAJ559/8TI8FOkKFnMTdVGon2/M/hu9lZ659Kb
48
+ Quhl1Slbi03AtxqT//IH3926aRjkd77pWWBKJ5W4L/8lOZjkHIQdlyjOtSO/Yhgc
49
+ cd7BdioIrLXUMBNaa0Jzb7j8P5IW8RgJRIyKKQuFppIrILhCyFW6ic7ZcCX5mmG2
50
+ lP2S5xTyx7cyd7XjBF4=</ds:X509Certificate>
51
+ </ds:X509Data>
52
+ </ds:KeyInfo>
53
+ </ds:Signature>
54
+ <Status>
55
+ <StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
56
+ </Status>
57
+ <Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="_a75adf55-01d7-40cc-929f-dbd8372ebdfc" IssueInstant="2003-04-17T00:46:02Z" Version="2.0">
58
+ <Issuer>https://www.opensaml.org/IDP</Issuer>
59
+ <Subject>
60
+ <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
61
+ scott@example.org
62
+ </NameID>
63
+ <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"/>
64
+ </Subject>
65
+ <Conditions NotBefore="2003-04-17T00:46:02Z" NotOnOrAfter="2003-04-17T00:51:02Z">
66
+ <AudienceRestriction>
67
+ <Audience>http://www.opensaml.org/SP</Audience>
68
+ </AudienceRestriction>
69
+ </Conditions>
70
+ <AuthnStatement AuthnInstant="2003-04-17T00:46:00Z">
71
+ <AuthnContext>
72
+ <AuthnContextClassRef>
73
+ urn:oasis:names:tc:SAML:2.0:ac:classes:Password
74
+ </AuthnContextClassRef>
75
+ </AuthnContext>
76
+ </AuthnStatement>
77
+ </Assertion>
78
+ </Response>
@@ -2,21 +2,18 @@ require 'spec_helper'
2
2
 
3
3
  describe SignedXml::Document do
4
4
  include SignedXml::DigestMethodResolution
5
+ include SignedXml::Fingerprinting
5
6
 
6
7
  let(:resources_path) { File.join(File.dirname(__FILE__), 'resources') }
7
8
 
8
- let(:unsigned_doc_nodes) do
9
- xml_doc_from_file(File.join(resources_path, 'unsigned_saml_response.xml'))
9
+ let(:unsigned_doc) do
10
+ SignedXml::Document(File.read(File.join(resources_path, 'unsigned_saml_response.xml')))
10
11
  end
11
12
 
12
- let(:unsigned_doc) { SignedXml::Document.new(unsigned_doc_nodes) }
13
-
14
- let(:signed_doc_nodes) do
15
- xml_doc_from_file(File.join(resources_path, 'signed_saml_response.xml'))
13
+ let(:signed_doc) do
14
+ SignedXml::Document(File.read(File.join(resources_path, 'signed_saml_response.xml')))
16
15
  end
17
16
 
18
- let(:signed_doc) { SignedXml::Document.new(signed_doc_nodes) }
19
-
20
17
  it "knows which documents can be verified" do
21
18
  unsigned_doc.is_verifiable?.should be false
22
19
  signed_doc.is_verifiable?.should be true
@@ -26,7 +23,7 @@ describe SignedXml::Document do
26
23
  unsigned_doc.is_verified?.should be false
27
24
  end
28
25
 
29
- let(:test_certificate) { OpenSSL::X509::Certificate.new IO.read(File.join(resources_path, 'test_cert.pem')) }
26
+ let(:test_certificate) { OpenSSL::X509::Certificate.new File.read(File.join(resources_path, 'test_cert.pem')) }
30
27
 
31
28
  it "can read an embedded X.509 certificate" do
32
29
  signed_doc.send(:signatures).first.send(:x509_certificate).to_pem.should eq test_certificate.to_pem
@@ -37,7 +34,7 @@ describe SignedXml::Document do
37
34
  end
38
35
 
39
36
  it "knows the signature method of the signed info" do
40
- digester_for_id(signed_doc.send(:signatures).first.send(:signed_info).signature_method).class.should == OpenSSL::Digest::SHA1
37
+ new_digester_for_id(signed_doc.send(:signatures).first.send(:signed_info).signature_method).class.should == OpenSSL::Digest::SHA1
41
38
  end
42
39
 
43
40
  it "knows how to canonicalize its signed info" do
@@ -52,43 +49,88 @@ describe SignedXml::Document do
52
49
  signed_doc.is_verified?.should be true
53
50
  end
54
51
 
55
- let(:same_doc_ref_nodes) do
56
- xml_doc_from_file(File.join(resources_path, 'same_doc_reference.xml'))
52
+ let(:passed_in_nokogiri_doc) do
53
+ SignedXml::Document(Nokogiri::XML(File.read(File.join(resources_path, 'signed_saml_response.xml'))))
57
54
  end
58
55
 
59
- let(:same_doc_ref_doc) { SignedXml::Document.new(same_doc_ref_nodes) }
56
+ it "works when passed a Nokogiri::XML::Document instead of a string" do
57
+ passed_in_nokogiri_doc.is_verified?.should be true
58
+ end
59
+
60
+ let(:same_doc_ref_doc) do
61
+ SignedXml::Document(File.read(File.join(resources_path, 'same_doc_reference.xml')))
62
+ end
60
63
 
61
64
  it "verifies docs with same-document references" do
62
65
  same_doc_ref_doc.is_verified?.should be true
63
66
  end
64
67
 
65
- let(:two_sig_nodes) do
66
- xml_doc_from_file(File.join(resources_path, 'two_sig_doc.xml'))
68
+ let(:two_sig_doc) do
69
+ SignedXml::Document(File.read(File.join(resources_path, 'two_sig_doc.xml')))
67
70
  end
68
71
 
69
- let(:two_sig_doc) { SignedXml::Document.new(two_sig_nodes) }
70
-
71
72
  it "verifies docs with more than one signature" do
72
73
  two_sig_doc.is_verified?.should be true
73
74
  end
74
75
 
75
- let(:badly_signed_doc_nodes) do
76
- xml_doc_from_file(File.join(resources_path, 'badly_signed_saml_response.xml'))
76
+ let(:no_key_doc) do
77
+ SignedXml::Document(File.read(File.join(resources_path, 'no_key_doc.xml')))
78
+ end
79
+
80
+ it "verifies docs lacking keys if X.509 cert is provided at runtime" do
81
+ no_key_doc.is_verified? test_certificate
82
+ end
83
+
84
+ let(:test_cert_fingerprint) { fingerprint(test_certificate.to_der) }
85
+ let(:cert_store) { {test_cert_fingerprint => test_certificate} }
86
+
87
+ it "uses a key matching the embedded key if a cert store is provided" do
88
+ signed_doc.is_verified?(cert_store).should be true
77
89
  end
78
90
 
79
- let(:badly_signed_doc) { SignedXml::Document.new(badly_signed_doc_nodes) }
91
+ let(:another_test_cert) { OpenSSL::X509::Certificate.new File.read(File.join(resources_path, 'another_test_cert.pem')) }
92
+ let(:another_test_cert_fp) { Digest::SHA1.hexdigest(test_certificate.to_der) }
93
+ let(:another_cert_store) { {another_test_cert_fp => another_test_cert} }
94
+
95
+ it "fails validation if provided cert store does not contain a key matching the embedded key" do
96
+ signed_doc.is_verified?(another_cert_store).should be false
97
+ end
98
+
99
+ let(:wrong_key_doc) do
100
+ SignedXml::Document(File.read(File.join(resources_path, 'wrong_key_doc.xml')))
101
+ end
102
+
103
+ it "fails validation of a doc with the wrong key" do
104
+ wrong_key_doc.is_verified?.should be false
105
+ end
106
+
107
+ it "uses provided cert instead of embedded cert" do
108
+ wrong_key_doc.is_verified? test_certificate
109
+ end
110
+
111
+ let(:badly_signed_doc) do
112
+ SignedXml::Document(File.read(File.join(resources_path, 'badly_signed_saml_response.xml')))
113
+ end
80
114
 
81
115
  it "fails verification of a badly-signed doc" do
82
116
  badly_signed_doc.is_verified?.should be false
83
117
  end
84
118
 
85
- let(:incorrect_digest_doc_nodes) do
86
- xml_doc_from_file(File.join(resources_path, 'incorrect_digest_saml_response.xml'))
119
+ let(:incorrect_digest_doc) do
120
+ SignedXml::Document(File.read(File.join(resources_path, 'incorrect_digest_saml_response.xml')))
87
121
  end
88
122
 
89
- let(:incorrect_digest_doc) { SignedXml::Document.new(incorrect_digest_doc_nodes) }
90
-
91
123
  it "fails verification of a doc with an incorrect Resource digest" do
92
124
  incorrect_digest_doc.is_verified?.should be false
93
125
  end
126
+
127
+ let(:signed_doc_template) do
128
+ SignedXml::Document(File.read(File.join(resources_path, 'saml_response_template.xml')))
129
+ end
130
+
131
+ let(:test_private_key) { OpenSSL::PKey::RSA.new File.read(File.join(resources_path, 'test_key.pem')) }
132
+
133
+ it "signs template documents" do
134
+ signed_doc_template.sign(test_private_key, test_certificate).is_verified?.should be true
135
+ end
94
136
  end
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1 @@
1
1
  require 'signed_xml'
2
-
3
- def xml_doc_from_file(path)
4
- file = File.open(path)
5
- doc = Nokogiri::XML(file)
6
- file.close
7
- doc
8
- end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: signed_xml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-12 00:00:00.000000000 Z
12
+ date: 2013-04-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -83,6 +83,7 @@ extensions: []
83
83
  extra_rdoc_files: []
84
84
  files:
85
85
  - .gitignore
86
+ - .travis.yml
86
87
  - Gemfile
87
88
  - LICENSE.txt
88
89
  - README.md
@@ -94,14 +95,20 @@ files:
94
95
  - lib/signed_xml/digest_transform.rb
95
96
  - lib/signed_xml/document.rb
96
97
  - lib/signed_xml/enveloped_signature_transform.rb
98
+ - lib/signed_xml/fingerprinting.rb
99
+ - lib/signed_xml/logging.rb
97
100
  - lib/signed_xml/reference.rb
98
101
  - lib/signed_xml/signature.rb
99
102
  - lib/signed_xml/signed_info.rb
100
103
  - lib/signed_xml/transformable.rb
101
104
  - lib/signed_xml/version.rb
102
105
  - signed_xml.gemspec
106
+ - spec/resources/another_test_cert.pem
107
+ - spec/resources/another_test_key.pem
103
108
  - spec/resources/badly_signed_saml_response.xml
104
109
  - spec/resources/incorrect_digest_saml_response.xml
110
+ - spec/resources/no_key_doc.xml
111
+ - spec/resources/no_key_template.xml
105
112
  - spec/resources/same_doc_reference.xml
106
113
  - spec/resources/same_doc_reference_template.xml
107
114
  - spec/resources/saml_response_template.xml
@@ -110,6 +117,7 @@ files:
110
117
  - spec/resources/test_key.pem
111
118
  - spec/resources/two_sig_doc.xml
112
119
  - spec/resources/unsigned_saml_response.xml
120
+ - spec/resources/wrong_key_doc.xml
113
121
  - spec/signed_xml_document_spec.rb
114
122
  - spec/spec_helper.rb
115
123
  homepage: ''
@@ -126,7 +134,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
126
134
  version: '0'
127
135
  segments:
128
136
  - 0
129
- hash: -2293715516306633631
137
+ hash: 299573032670506091
130
138
  required_rubygems_version: !ruby/object:Gem::Requirement
131
139
  none: false
132
140
  requirements:
@@ -135,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
143
  version: '0'
136
144
  segments:
137
145
  - 0
138
- hash: -2293715516306633631
146
+ hash: 299573032670506091
139
147
  requirements: []
140
148
  rubyforge_project:
141
149
  rubygems_version: 1.8.25
@@ -143,8 +151,12 @@ signing_key:
143
151
  specification_version: 3
144
152
  summary: Provides [incomplete] support for verification of XML Signatures <http://www.w3.org/TR/xmldsig-core>.
145
153
  test_files:
154
+ - spec/resources/another_test_cert.pem
155
+ - spec/resources/another_test_key.pem
146
156
  - spec/resources/badly_signed_saml_response.xml
147
157
  - spec/resources/incorrect_digest_saml_response.xml
158
+ - spec/resources/no_key_doc.xml
159
+ - spec/resources/no_key_template.xml
148
160
  - spec/resources/same_doc_reference.xml
149
161
  - spec/resources/same_doc_reference_template.xml
150
162
  - spec/resources/saml_response_template.xml
@@ -153,5 +165,6 @@ test_files:
153
165
  - spec/resources/test_key.pem
154
166
  - spec/resources/two_sig_doc.xml
155
167
  - spec/resources/unsigned_saml_response.xml
168
+ - spec/resources/wrong_key_doc.xml
156
169
  - spec/signed_xml_document_spec.rb
157
170
  - spec/spec_helper.rb