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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +12 -0
- data/Guardfile +24 -0
- data/LICENSE +22 -0
- data/README.md +80 -0
- data/Rakefile +10 -0
- data/lib/xmldsig.rb +20 -0
- data/lib/xmldsig/canonicalizer.rb +30 -0
- data/lib/xmldsig/reference.rb +80 -0
- data/lib/xmldsig/signature.rb +93 -0
- data/lib/xmldsig/signed_document.rb +26 -0
- data/lib/xmldsig/transforms.rb +26 -0
- data/lib/xmldsig/transforms/canonicalize.rb +25 -0
- data/lib/xmldsig/transforms/enveloped_signature.rb +10 -0
- data/lib/xmldsig/transforms/transform.rb +18 -0
- data/lib/xmldsig/version.rb +3 -0
- data/signing_service.rb +133 -0
- data/spec/fixtures/certificate.cer +16 -0
- data/spec/fixtures/certificate2.cer +16 -0
- data/spec/fixtures/key.pem +15 -0
- data/spec/fixtures/signed.xml +23 -0
- data/spec/fixtures/signed/ideal.cert +18 -0
- data/spec/fixtures/signed/ideal.txt +41 -0
- data/spec/fixtures/unsigned.xml +21 -0
- data/spec/fixtures/unsigned/canonicalizer_1_0.xml +19 -0
- data/spec/fixtures/unsigned/canonicalizer_1_1.xml +19 -0
- data/spec/fixtures/unsigned/canonicalizer_exc.xml +21 -0
- data/spec/fixtures/unsigned/digest_sha1.xml +21 -0
- data/spec/fixtures/unsigned/with_soap_envelope.xml +33 -0
- data/spec/fixtures/unsigned/without_canonicalization.xml +18 -0
- data/spec/fixtures/unsigned/without_namespace_prefix.xml +19 -0
- data/spec/fixtures/unsigned/without_reference_uri.xml +21 -0
- data/spec/fixtures/unsigned_multiple_references.xml +38 -0
- data/spec/fixtures/unsigned_nested_signature.xml +40 -0
- data/spec/lib/xmldsig/reference_spec.rb +65 -0
- data/spec/lib/xmldsig/signature_spec.rb +100 -0
- data/spec/lib/xmldsig/signed_document_spec.rb +94 -0
- data/spec/lib/xmldsig/transforms/enveloped_signature_spec.rb +18 -0
- data/spec/lib/xmldsig/transforms/transform_spec.rb +10 -0
- data/spec/lib/xmldsig_spec.rb +47 -0
- data/spec/spec_helper.rb +22 -0
- data/xmldsig.gemspec +20 -0
- 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
|