xmldsig-fiscalizer 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/CHANGELOG.md +4 -0
  6. data/Gemfile +12 -0
  7. data/Guardfile +24 -0
  8. data/LICENSE +22 -0
  9. data/README.md +80 -0
  10. data/Rakefile +10 -0
  11. data/lib/xmldsig.rb +20 -0
  12. data/lib/xmldsig/canonicalizer.rb +30 -0
  13. data/lib/xmldsig/reference.rb +80 -0
  14. data/lib/xmldsig/signature.rb +93 -0
  15. data/lib/xmldsig/signed_document.rb +26 -0
  16. data/lib/xmldsig/transforms.rb +26 -0
  17. data/lib/xmldsig/transforms/canonicalize.rb +25 -0
  18. data/lib/xmldsig/transforms/enveloped_signature.rb +10 -0
  19. data/lib/xmldsig/transforms/transform.rb +18 -0
  20. data/lib/xmldsig/version.rb +3 -0
  21. data/signing_service.rb +133 -0
  22. data/spec/fixtures/certificate.cer +16 -0
  23. data/spec/fixtures/certificate2.cer +16 -0
  24. data/spec/fixtures/key.pem +15 -0
  25. data/spec/fixtures/signed.xml +23 -0
  26. data/spec/fixtures/signed/ideal.cert +18 -0
  27. data/spec/fixtures/signed/ideal.txt +41 -0
  28. data/spec/fixtures/unsigned.xml +21 -0
  29. data/spec/fixtures/unsigned/canonicalizer_1_0.xml +19 -0
  30. data/spec/fixtures/unsigned/canonicalizer_1_1.xml +19 -0
  31. data/spec/fixtures/unsigned/canonicalizer_exc.xml +21 -0
  32. data/spec/fixtures/unsigned/digest_sha1.xml +21 -0
  33. data/spec/fixtures/unsigned/with_soap_envelope.xml +33 -0
  34. data/spec/fixtures/unsigned/without_canonicalization.xml +18 -0
  35. data/spec/fixtures/unsigned/without_namespace_prefix.xml +19 -0
  36. data/spec/fixtures/unsigned/without_reference_uri.xml +21 -0
  37. data/spec/fixtures/unsigned_multiple_references.xml +38 -0
  38. data/spec/fixtures/unsigned_nested_signature.xml +40 -0
  39. data/spec/lib/xmldsig/reference_spec.rb +65 -0
  40. data/spec/lib/xmldsig/signature_spec.rb +100 -0
  41. data/spec/lib/xmldsig/signed_document_spec.rb +94 -0
  42. data/spec/lib/xmldsig/transforms/enveloped_signature_spec.rb +18 -0
  43. data/spec/lib/xmldsig/transforms/transform_spec.rb +10 -0
  44. data/spec/lib/xmldsig_spec.rb +47 -0
  45. data/spec/spec_helper.rb +22 -0
  46. data/xmldsig.gemspec +20 -0
  47. metadata +127 -0
@@ -0,0 +1,21 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <foo:Foo ID="foo" xmlns:foo="http://example.com/foo#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#">
3
+ <foo:Bar>bar</foo:Bar>
4
+ <ds:Signature>
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="#foo">
9
+ <ds:Transforms>
10
+ <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
11
+ <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
12
+ <ec:InclusiveNamespaces PrefixList="foo"/>
13
+ </ds:Transform>
14
+ </ds:Transforms>
15
+ <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
16
+ <ds:DigestValue></ds:DigestValue>
17
+ </ds:Reference>
18
+ </ds:SignedInfo>
19
+ <ds:SignatureValue></ds:SignatureValue>
20
+ </ds:Signature>
21
+ </foo:Foo>
@@ -0,0 +1,33 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3
+ <soapenv:Body>
4
+ <samlp:ArtifactResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" ID="_91e79cb2e8cded9a7fd4d68dc480b49d2d1adf88" Version="2.0" IssueInstant="2013-01-17T09:02:44Z">
5
+ <ds:Signature>
6
+ <ds:SignedInfo>
7
+ <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
8
+ <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
9
+ <ds:Reference>
10
+ <ds:Transforms>
11
+ <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
12
+ <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
13
+ <ec:InclusiveNamespaces PrefixList="ds saml samlp xs"/>
14
+ </ds:Transform>
15
+ </ds:Transforms>
16
+ <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
17
+ <ds:DigestValue></ds:DigestValue>
18
+ </ds:Reference>
19
+ </ds:SignedInfo>
20
+ <ds:SignatureValue></ds:SignatureValue>
21
+ <ds:KeyInfo/>
22
+ </ds:Signature>
23
+ <samlp:Status>
24
+ <samlp:StatusCode/>
25
+ </samlp:Status>
26
+ <samlp:Response ID="_5a88b4aeb1d290c86073874278e5ef302da66739" Version="2.0" IssueInstant="2013-01-17T09:02:44Z">
27
+ <samlp:Status>
28
+ <samlp:StatusCode/>
29
+ </samlp:Status>
30
+ </samlp:Response>
31
+ </samlp:ArtifactResponse>
32
+ </soapenv:Body>
33
+ </soapenv:Envelope>
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <foo:Foo ID="foo" xmlns:foo="http://example.com/foo#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#">
3
+ <foo:Bar>bar</foo:Bar>
4
+ <ds:Signature>
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="#foo">
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></ds:DigestValue>
14
+ </ds:Reference>
15
+ </ds:SignedInfo>
16
+ <ds:SignatureValue></ds:SignatureValue>
17
+ </ds:Signature>
18
+ </foo:Foo>
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <foo:Foo ID="foo" xmlns:foo="http://example.com/foo#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#">
3
+ <foo:Bar>bar</foo:Bar>
4
+ <ds:Signature>
5
+ <ds:SignedInfo>
6
+ <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
7
+ <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
8
+ <ds:Reference URI="#foo">
9
+ <ds:Transforms>
10
+ <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
11
+ <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
12
+ </ds:Transforms>
13
+ <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
14
+ <ds:DigestValue></ds:DigestValue>
15
+ </ds:Reference>
16
+ </ds:SignedInfo>
17
+ <ds:SignatureValue></ds:SignatureValue>
18
+ </ds:Signature>
19
+ </foo:Foo>
@@ -0,0 +1,21 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <foo:Foo ID="foo" xmlns:foo="http://example.com/foo#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#">
3
+ <foo:Bar>bar</foo:Bar>
4
+ <ds:Signature>
5
+ <ds:SignedInfo>
6
+ <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
7
+ <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
8
+ <ds:Reference>
9
+ <ds:Transforms>
10
+ <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
11
+ <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
12
+ <ec:InclusiveNamespaces PrefixList="foo"/>
13
+ </ds:Transform>
14
+ </ds:Transforms>
15
+ <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
16
+ <ds:DigestValue></ds:DigestValue>
17
+ </ds:Reference>
18
+ </ds:SignedInfo>
19
+ <ds:SignatureValue></ds:SignatureValue>
20
+ </ds:Signature>
21
+ </foo:Foo>
@@ -0,0 +1,38 @@
1
+ <?xml version="1.0"?>
2
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
3
+ <soapenv:Header></soapenv:Header>
4
+ <soapenv:Body>
5
+
6
+ <SomeMethod ID="Data-1">
7
+ <Data>some Content</Data>
8
+ </SomeMethod>
9
+
10
+ <Timestamp ID="Timestamp-1">
11
+ <Created>2010-10-25T12:09:44Z</Created>
12
+ <Expires>2010-10-25T12:14:44Z</Expires>
13
+ </Timestamp>
14
+
15
+ <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
16
+ <SignedInfo>
17
+ <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
18
+ <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
19
+ <Reference URI="#Timestamp-1">
20
+ <Transforms>
21
+ <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
22
+ </Transforms>
23
+ <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
24
+ <DigestValue></DigestValue>
25
+ </Reference>
26
+ <Reference URI="#Data-1">
27
+ <Transforms>
28
+ <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
29
+ </Transforms>
30
+ <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
31
+ <DigestValue></DigestValue>
32
+ </Reference>
33
+ </SignedInfo>
34
+ <SignatureValue></SignatureValue>
35
+ </Signature>
36
+
37
+ </soapenv:Body>
38
+ </soapenv:Envelope>
@@ -0,0 +1,40 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <foo:Foo ID="foo" xmlns:foo="http://example.com/foo#" xmlns:baz="http://example.com/baz#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#">
3
+ <foo:Bar>bar</foo:Bar>
4
+ <ds:Signature>
5
+ <ds:SignedInfo>
6
+ <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
7
+ <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
8
+ <ds:Reference URI="#foo">
9
+ <ds:Transforms>
10
+ <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
11
+ <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
12
+ <ec:InclusiveNamespaces PrefixList="foo baz"/>
13
+ </ds:Transform>
14
+ </ds:Transforms>
15
+ <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
16
+ <ds:DigestValue></ds:DigestValue>
17
+ </ds:Reference>
18
+ </ds:SignedInfo>
19
+ <ds:SignatureValue></ds:SignatureValue>
20
+ </ds:Signature>
21
+ <baz:Baz ID="baz">
22
+ <ds:Signature>
23
+ <ds:SignedInfo>
24
+ <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
25
+ <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
26
+ <ds:Reference URI="#baz">
27
+ <ds:Transforms>
28
+ <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
29
+ <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
30
+ <ec:InclusiveNamespaces PrefixList="foo baz"/>
31
+ </ds:Transform>
32
+ </ds:Transforms>
33
+ <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
34
+ <ds:DigestValue></ds:DigestValue>
35
+ </ds:Reference>
36
+ </ds:SignedInfo>
37
+ <ds:SignatureValue></ds:SignatureValue>
38
+ </ds:Signature>
39
+ </baz:Baz>
40
+ </foo:Foo>
@@ -0,0 +1,65 @@
1
+ require "spec_helper"
2
+
3
+ describe Xmldsig::Reference do
4
+ let(:document) { Nokogiri::XML::Document.parse File.read("spec/fixtures/signed.xml") }
5
+ let(:reference) { Xmldsig::Reference.new(document.at_xpath('//ds:Reference', Xmldsig::NAMESPACES)) }
6
+
7
+ describe "#digest_value" do
8
+ it "returns the digest value in the xml" do
9
+ reference.digest_value.should == Base64.decode64("ftoSYFdze1AWgGHF5N9i9SFKThXkqH2AdyzA3/epbJw=")
10
+ end
11
+ end
12
+
13
+ describe "#document" do
14
+ it "returns the document" do
15
+ reference.document.should == document
16
+ end
17
+ end
18
+
19
+ describe "#sign" do
20
+ let(:document) { Nokogiri::XML::Document.parse File.read("spec/fixtures/unsigned.xml") }
21
+
22
+ it "sets the correct digest value" do
23
+ reference.sign
24
+ reference.digest_value.should == Base64.decode64("ftoSYFdze1AWgGHF5N9i9SFKThXkqH2AdyzA3/epbJw=")
25
+ end
26
+ end
27
+
28
+ describe "#referenced_node" do
29
+ it "returns the referenced_node by id" do
30
+ reference.referenced_node.to_s.should ==
31
+ document.at_xpath("//*[@ID='foo']").to_s
32
+ end
33
+
34
+ it "returns the referenced node by parent" do
35
+ reference.stub(:reference_uri).and_return("")
36
+ reference.referenced_node.to_s.should ==
37
+ document.root.to_s
38
+ end
39
+
40
+ it "returns the reference node when using WS-Security style id attribute" do
41
+ node = document.at_xpath('//*[@ID]')
42
+ node.add_namespace('wsu', Xmldsig::NAMESPACES['wsu'])
43
+ node['wsu:Id'] = node['ID']
44
+ node.remove_attribute('ID')
45
+
46
+ reference.referenced_node.
47
+ attribute_with_ns('Id', Xmldsig::NAMESPACES['wsu']).value.
48
+ should == 'foo'
49
+ end
50
+
51
+ it "raises ReferencedNodeNotFound when the refenced node is not present" do
52
+ node = document.at_xpath('//*[@ID]')
53
+ node.remove_attribute('ID')
54
+
55
+ expect { reference.referenced_node }.
56
+ to raise_error(Xmldsig::Reference::ReferencedNodeNotFound)
57
+ end
58
+ end
59
+
60
+ describe "#reference_uri" do
61
+ it "returns the reference uri" do
62
+ reference.reference_uri.should == "#foo"
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xmldsig::Signature do
4
+ let(:certificate) { OpenSSL::X509::Certificate.new(File.read("spec/fixtures/certificate.cer")) }
5
+ let(:other_certificate) { OpenSSL::X509::Certificate.new(File.read("spec/fixtures/certificate2.cer")) }
6
+ let(:private_key) { OpenSSL::PKey::RSA.new(File.read("spec/fixtures/key.pem")) }
7
+ let(:document) { Nokogiri::XML::Document.parse File.read("spec/fixtures/signed.xml") }
8
+ let(:signature_node) { document.at_xpath("//ds:Signature", Xmldsig::NAMESPACES) }
9
+ let(:signature) { Xmldsig::Signature.new(signature_node) }
10
+
11
+ describe "#sign" do
12
+ let(:document) { Nokogiri::XML::Document.parse File.read("spec/fixtures/unsigned.xml") }
13
+ let(:signature_node) { document.at_xpath("//ds:Signature", Xmldsig::NAMESPACES) }
14
+ let(:signature) { Xmldsig::Signature.new(signature_node) }
15
+
16
+ before :each do
17
+ signature.sign(private_key)
18
+ end
19
+
20
+ it "sets the digest value" do
21
+ signature.references.first.digest_value.should == Base64.decode64("ftoSYFdze1AWgGHF5N9i9SFKThXkqH2AdyzA3/epbJw=")
22
+ end
23
+
24
+ it "sets the signature value" do
25
+ signature.signature_value.should == Base64.decode64("
26
+ E3yyqsSoxRkhYEuaEtR+SLg85gU5B4a7xUXA+d2Zn6j7F6z73dOd8iYHOusB
27
+ Ty3C/3ujbmPhHKg8uX9kUE8b+YoOqZt4z9pdxAq44nJEuijwi4doIPpHWirv
28
+ BnSoP5IoL0DYzGVrgj8udRzfAw5nNeV7wSrBZEn+yrxmUPJoUZc=
29
+ ")
30
+ end
31
+
32
+ it "accepts a block" do
33
+ signature.sign do |data, signature_algorithm|
34
+ signature_algorithm.should == "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
35
+ private_key.sign(OpenSSL::Digest::SHA256.new, data)
36
+ end
37
+ signature.signature_value.should == Base64.decode64("
38
+ E3yyqsSoxRkhYEuaEtR+SLg85gU5B4a7xUXA+d2Zn6j7F6z73dOd8iYHOusB
39
+ Ty3C/3ujbmPhHKg8uX9kUE8b+YoOqZt4z9pdxAq44nJEuijwi4doIPpHWirv
40
+ BnSoP5IoL0DYzGVrgj8udRzfAw5nNeV7wSrBZEn+yrxmUPJoUZc=
41
+ ")
42
+ end
43
+
44
+ describe "multiple references" do
45
+ let(:document) { Nokogiri::XML::Document.parse File.read("spec/fixtures/unsigned_multiple_references.xml") }
46
+
47
+ it "can sign the document" do
48
+ signature.sign(private_key)
49
+ signature.should be_valid(certificate)
50
+ end
51
+
52
+ it "gets a digest per reference" do
53
+ signature.references.count.should be == 2
54
+ signature.sign(private_key)
55
+ signature.references[0].digest_value.should be == Base64.decode64("P1nUq8Y/LPmd+EON/mcNMNRjT78=")
56
+ signature.references[1].digest_value.should be == Base64.decode64("RoGAaQeuNJuDMWcgsD7RuGbFACo=")
57
+ end
58
+ end
59
+ end
60
+
61
+ describe "#signed_info" do
62
+ it "returns the canonicalized signed info element" do
63
+ signature.signed_info.to_s.should ==
64
+ document.at_xpath("//ds:SignedInfo", Xmldsig::NAMESPACES).to_s
65
+ end
66
+ end
67
+
68
+ describe "#signature_value" do
69
+ it "returns the signature value" do
70
+ signature.signature_value.should ==
71
+ Base64.decode64(document.at_xpath("//ds:SignatureValue", Xmldsig::NAMESPACES).content)
72
+ end
73
+ end
74
+
75
+ describe "#valid?" do
76
+ it "returns true with the correct certificate" do
77
+ signature.valid?(certificate).should be_true
78
+ end
79
+
80
+ it "returns false if the xml changed" do
81
+ signature.references.first.stub(:document).and_return(
82
+ Nokogiri::XML::Document.parse(File.read("spec/fixtures/signed.xml").gsub("\s\s", "\s"))
83
+ )
84
+ signature.valid?(certificate)
85
+ signature.errors.should include(:digest_value)
86
+ end
87
+
88
+ it "returns false with a difference certificate" do
89
+ signature.valid?(other_certificate).should be_false
90
+ end
91
+
92
+ it "accepts a block" do
93
+ signature.valid? do |signature_value, data, signature_algorithm|
94
+ signature_algorithm.should == "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
95
+ certificate.public_key.verify(OpenSSL::Digest::SHA256.new, signature_value, data)
96
+ end
97
+ signature.errors.should be_empty
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe Xmldsig::SignedDocument do
4
+ let(:signed_xml) { File.read("spec/fixtures/signed.xml") }
5
+ let(:signed_document) { Xmldsig::SignedDocument.new(signed_xml) }
6
+ let(:unsigned_xml) { File.read("spec/fixtures/unsigned.xml") }
7
+ let(:unsigned_document) { Xmldsig::SignedDocument.new(unsigned_xml) }
8
+ let(:private_key) { OpenSSL::PKey::RSA.new(File.read("spec/fixtures/key.pem")) }
9
+ let(:certificate) { OpenSSL::X509::Certificate.new(File.read("spec/fixtures/certificate.cer")) }
10
+ let(:other_certificate) { OpenSSL::X509::Certificate.new(File.read("spec/fixtures/certificate2.cer")) }
11
+
12
+ describe "#initialize" do
13
+ it "sets the document to a nokogiri document" do
14
+ document = described_class.new(signed_xml)
15
+ document.document.should be_a(Nokogiri::XML::Document)
16
+ end
17
+ end
18
+
19
+ describe "#signatures" do
20
+ let(:unsigned_xml) { File.read("spec/fixtures/unsigned_nested_signature.xml") }
21
+ let(:unsigned_document) { Xmldsig::SignedDocument.new(unsigned_xml) }
22
+
23
+ it "returns only the signed nodes" do
24
+ signed_document.signatures.should be_all { |signature| signature.is_a?(Xmldsig::Signature) }
25
+ end
26
+
27
+ it "returns the nested signatures first" do
28
+ unsigned_document.signatures.first.references.first.reference_uri.should == '#baz'
29
+ end
30
+ end
31
+
32
+ describe "#signed_nodes" do
33
+ it "returns only the signed nodes" do
34
+ signed_document.signed_nodes.collect(&:name).should == %w(Foo)
35
+ end
36
+ end
37
+
38
+ describe "#validate" do
39
+ it "returns true if the signature and digest value are correct" do
40
+ signed_document.validate(certificate).should be_true
41
+ end
42
+
43
+ it "returns false if the certificate is not valid" do
44
+ signed_document.validate(other_certificate).should be_false
45
+ end
46
+
47
+ it "returns false if there are no signatures and validation is strict" do
48
+ xml_without_signature = Xmldsig::SignedDocument.new('<foo></foo>')
49
+ xml_without_signature.validate(certificate).should be_false
50
+ end
51
+
52
+ it "accepts a block" do
53
+ signed_document.validate do |signature_value, data|
54
+ certificate.public_key.verify(OpenSSL::Digest::SHA256.new, signature_value, data)
55
+ end.should be_true
56
+ end
57
+ end
58
+
59
+ describe "#sign" do
60
+ it "returns a signed document" do
61
+ signed_document = unsigned_document.sign(private_key)
62
+ Xmldsig::SignedDocument.new(signed_document).validate(certificate).should be_true
63
+ end
64
+
65
+ it "accepts a block" do
66
+ signed_document = unsigned_document.sign do |data|
67
+ private_key.sign(OpenSSL::Digest::SHA256.new, data)
68
+ end
69
+ Xmldsig::SignedDocument.new(signed_document).validate(certificate).should be_true
70
+ end
71
+ end
72
+
73
+
74
+ describe "Nested Signatures" do
75
+ let(:unsigned_xml) { File.read("spec/fixtures/unsigned_nested_signature.xml") }
76
+ let(:unsigned_document) { Xmldsig::SignedDocument.new(unsigned_xml) }
77
+ let(:signed_document) { unsigned_document.sign(private_key) }
78
+
79
+ it "when signed should be valid" do
80
+ Xmldsig::SignedDocument.new(signed_document).validate(certificate).should be_true
81
+ end
82
+
83
+ it "should sign 2 elements" do
84
+ unsigned_document.signed_nodes.count.should == 2
85
+ end
86
+
87
+ it "allows individual signs" do
88
+ unsigned_document.signatures.last.sign(private_key)
89
+ unsigned_document.validate(certificate).should be_false
90
+ unsigned_document.signatures.last.valid?(certificate).should be_true
91
+ end
92
+ end
93
+
94
+ end