signed_xml 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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