xmldsig-fiscalizer 0.2.4

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.
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