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 +6 -0
- data/README.md +39 -9
- data/Rakefile +5 -0
- data/lib/signed_xml/base64_transform.rb +1 -1
- data/lib/signed_xml/c14n_transform.rb +2 -2
- data/lib/signed_xml/digest_method_resolution.rb +3 -2
- data/lib/signed_xml/digest_transform.rb +1 -1
- data/lib/signed_xml/document.rb +40 -4
- data/lib/signed_xml/fingerprinting.rb +9 -0
- data/lib/signed_xml/logging.rb +13 -0
- data/lib/signed_xml/reference.rb +20 -6
- data/lib/signed_xml/signature.rb +68 -5
- data/lib/signed_xml/transformable.rb +8 -1
- data/lib/signed_xml/version.rb +1 -1
- data/lib/signed_xml.rb +24 -0
- data/spec/resources/another_test_cert.pem +28 -0
- data/spec/resources/another_test_key.pem +27 -0
- data/spec/resources/no_key_doc.xml +47 -0
- data/spec/resources/no_key_template.xml +54 -0
- data/spec/resources/wrong_key_doc.xml +78 -0
- data/spec/signed_xml_document_spec.rb +66 -24
- data/spec/spec_helper.rb +0 -7
- metadata +17 -4
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,26 +1,56 @@
|
|
1
|
-
|
1
|
+
SignedXml [](https://travis-ci.org/toddthomas/signed_xml)
|
2
|
+
=========
|
2
3
|
|
3
|
-
|
4
|
+
SignedXml is a Ruby implementation of [XML Signatures](http://www.w3.org/TR/xmldsig-core).
|
4
5
|
|
5
|
-
|
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
|
-
|
25
|
+
```ruby
|
26
|
+
gem 'signed_xml'
|
27
|
+
```
|
10
28
|
|
11
29
|
And then execute:
|
12
30
|
|
13
|
-
|
31
|
+
```shell
|
32
|
+
bundle
|
33
|
+
```
|
14
34
|
|
15
35
|
Or install it yourself as:
|
16
36
|
|
17
|
-
|
37
|
+
```shell
|
38
|
+
gem install signed_xml
|
39
|
+
```
|
40
|
+
|
41
|
+
Usage
|
42
|
+
-----
|
18
43
|
|
19
|
-
|
44
|
+
```ruby
|
45
|
+
require 'signed_xml'
|
20
46
|
|
21
|
-
|
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
|
-
|
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
@@ -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
|
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
|
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
|
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
|
11
|
+
else
|
12
|
+
raise ArgumentError, "unknown digest method #{id}"
|
12
13
|
end
|
13
14
|
end
|
14
15
|
end
|
data/lib/signed_xml/document.rb
CHANGED
@@ -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(
|
9
|
-
|
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?(
|
17
|
-
|
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
|
data/lib/signed_xml/reference.rb
CHANGED
@@ -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
|
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
|
20
|
-
else
|
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
|
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
|
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 ||=
|
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
|
data/lib/signed_xml/signature.rb
CHANGED
@@ -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
|
-
|
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 ||=
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
data/lib/signed_xml/version.rb
CHANGED
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(:
|
9
|
-
|
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(:
|
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
|
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
|
-
|
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(:
|
56
|
-
|
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
|
-
|
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(:
|
66
|
-
|
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(:
|
76
|
-
|
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(:
|
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(:
|
86
|
-
|
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
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
|
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
|
+
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:
|
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:
|
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
|