xmldsig-fiscalizer 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|