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 +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 [![Build Status](https://travis-ci.org/toddthomas/signed_xml.png)](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
|