xml_signature 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +11 -0
- data/Guardfile +11 -0
- data/README.md +54 -0
- data/features/step_definitions/verify_steps.rb +61 -0
- data/features/support/env.rb +4 -0
- data/features/verify.feature +7 -0
- data/lib/xml_signature.rb +96 -0
- data/lib/xml_signature/version.rb +3 -0
- data/xml_signature.gemspec +23 -0
- metadata +69 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
guard 'bundler' do
|
2
|
+
watch('Gemfile')
|
3
|
+
watch(/^.+\.gemspec/)
|
4
|
+
end
|
5
|
+
|
6
|
+
guard 'cucumber' do
|
7
|
+
watch(%r{^features/.+\.feature$})
|
8
|
+
watch(%r{^features/support/.+$}) { 'features' }
|
9
|
+
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
10
|
+
end
|
11
|
+
|
data/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
[![Build Status](https://secure.travis-ci.org/kjellm/xml_signature.png?branch=master)](http://travis-ci.org/kjellm/xml_signature)
|
2
|
+
|
3
|
+
XML Signature
|
4
|
+
=============
|
5
|
+
|
6
|
+
A (partial) Ruby implementation of the XML Signature standard.
|
7
|
+
|
8
|
+
So far it can only be used to verify signed xml documents.
|
9
|
+
|
10
|
+
|
11
|
+
Install
|
12
|
+
-------
|
13
|
+
|
14
|
+
gem install xml_signature
|
15
|
+
|
16
|
+
Usage
|
17
|
+
-----
|
18
|
+
|
19
|
+
require 'xml_signature'
|
20
|
+
foo = REXML::Document.new(...)
|
21
|
+
expected_certificate = "..."
|
22
|
+
XMLSignature.new(foo).verify(expected_certificate)
|
23
|
+
|
24
|
+
Author
|
25
|
+
------
|
26
|
+
|
27
|
+
Kjell-Magne Øierud (kjellm AT oierud DOT net)
|
28
|
+
|
29
|
+
Bugs
|
30
|
+
----
|
31
|
+
|
32
|
+
Report bugs to http://github.com/kjellm/xml_signature/issues
|
33
|
+
|
34
|
+
License
|
35
|
+
-------
|
36
|
+
|
37
|
+
(The MIT License)
|
38
|
+
|
39
|
+
Copyright © 2012 Kjell-Magne Øierud
|
40
|
+
|
41
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
42
|
+
associated documentation files (the ‘Software’), to deal in the Software without restriction, including
|
43
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
44
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to
|
45
|
+
the following conditions:
|
46
|
+
|
47
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
48
|
+
portions of the Software.
|
49
|
+
|
50
|
+
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
51
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
52
|
+
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
53
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
54
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'rexml/document'
|
3
|
+
|
4
|
+
# With a lot of help from http://users.dcc.uchile.cl/~pcamacho/tutorial/web/xmlsec/xmlsec.html
|
5
|
+
xml = <<'EOT'
|
6
|
+
<?xml version="1.0"?>
|
7
|
+
<References>
|
8
|
+
<Book xml:id="id1">
|
9
|
+
<Author>
|
10
|
+
<FirstName>Bruce</FirstName> <LastName>Schneier</LastName>
|
11
|
+
</Author>
|
12
|
+
<Title>Applied Cryptography</Title>
|
13
|
+
</Book> <Web>
|
14
|
+
<Title>XMLSec</Title>
|
15
|
+
<Url>http://www.aleksey.com/xmlsec/</Url>
|
16
|
+
</Web>
|
17
|
+
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
18
|
+
<SignedInfo>
|
19
|
+
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
20
|
+
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
21
|
+
<Reference URI="#id1">
|
22
|
+
<Transforms>
|
23
|
+
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
24
|
+
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
25
|
+
</Transforms>
|
26
|
+
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
27
|
+
<DigestValue>U5zbRpFUOzL1gfjfyd73KMVb0KU=</DigestValue>
|
28
|
+
</Reference>
|
29
|
+
</SignedInfo>
|
30
|
+
<SignatureValue>
|
31
|
+
DGVFyoNcf+nepI8eBj2xr7hNFaBEvRDfCQPXPgOryt9iF8bMN1J0LgMnw+Fm3ykSVrv/p+i3PFiAhbdbdRWTtS4dyYqHY7vK4TqrOdRXLgvwAmgbDVlRtfStXzWGlddOGyj2fWzOd1slHn+MPbGGrh6L02l0/cxDshtoX2Yehd4=
|
32
|
+
</SignatureValue>
|
33
|
+
<KeyInfo>
|
34
|
+
<X509Data>
|
35
|
+
<X509Certificate>
|
36
|
+
MIIC6DCCAlGgAwIBAgICAR4wDQYJKoZIhvcNAQEFBQAwgYcxCzAJBgNVBAYTAkNMMQswCQYDVQQIEwJSTTERMA8GA1UEBxMIU2FudGlhZ28xHDAaBgNVBAoTE2xpdHRsZWNyeXB0b2dyYXBoZXIxGTAXBgNVBAMTEFBoaWxpcHBlIENhbWFjaG8xHzAdBgkqhkiG9w0BCQEWEGxvc3RpbG9zQGZyZWUuZnIwHhcNMDgwMTE5MTI1MjM3WhcNMDkwMTE4MTI1MjM3WjBuMQswCQYDVQQGEwJDTDELMAkGA1UECBMCUk0xHDAaBgNVBAoTE2xpdHRsZWNyeXB0b2dyYXBoZXIxEzARBgNVBAMTCkpvaG4gU21pdGgxHzAdBgkqhkiG9w0BCQEWEGpzbWl0aEBoZWxsby5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALwShIDVij20XFC8V3Bs8Xn6b3uRa8rnPgkMCc92LoxNc/IzCriw9gu9NGps/bwanWgZbK5va46Y27axFhHo2uNk9ZE2lj0UQegFdBGlEIOt9hlpHFSqTnmXAKraSHd2yxhVe+JqGIrtyTQluWVNPOCKXd8zubFgWqlUMXMrn8JzAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBQ08GE4h2jHJZOGkDUyQE9EEPMqlDAfBgNVHSMEGDAWgBT+y1YLKOsq6cec6uU61UxVhNvUajANBgkqhkiG9w0BAQUFAAOBgQAVZMDaKVhvX2qOMlcjX7i6DESF7SDyEbjfPk+bYIDm+al45lmzixkFeYUUQcFJMG0s152AkFd/fTVMfz/j37OQYxUYwwZQlMW3dVnC+CvjtMlSrReeHThhQFQpO16i21aDitON1TFsvO8T+21YGB4kne44vry6O4JJPy8EZBsfbw==
|
37
|
+
</X509Certificate>
|
38
|
+
</X509Data>
|
39
|
+
</KeyInfo>
|
40
|
+
</Signature>
|
41
|
+
</References>
|
42
|
+
EOT
|
43
|
+
|
44
|
+
cert = 'MIIC6DCCAlGgAwIBAgICAR4wDQYJKoZIhvcNAQEFBQAwgYcxCzAJBgNVBAYTAkNMMQswCQYDVQQIEwJSTTERMA8GA1UEBxMIU2FudGlhZ28xHDAaBgNVBAoTE2xpdHRsZWNyeXB0b2dyYXBoZXIxGTAXBgNVBAMTEFBoaWxpcHBlIENhbWFjaG8xHzAdBgkqhkiG9w0BCQEWEGxvc3RpbG9zQGZyZWUuZnIwHhcNMDgwMTE5MTI1MjM3WhcNMDkwMTE4MTI1MjM3WjBuMQswCQYDVQQGEwJDTDELMAkGA1UECBMCUk0xHDAaBgNVBAoTE2xpdHRsZWNyeXB0b2dyYXBoZXIxEzARBgNVBAMTCkpvaG4gU21pdGgxHzAdBgkqhkiG9w0BCQEWEGpzbWl0aEBoZWxsby5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALwShIDVij20XFC8V3Bs8Xn6b3uRa8rnPgkMCc92LoxNc/IzCriw9gu9NGps/bwanWgZbK5va46Y27axFhHo2uNk9ZE2lj0UQegFdBGlEIOt9hlpHFSqTnmXAKraSHd2yxhVe+JqGIrtyTQluWVNPOCKXd8zubFgWqlUMXMrn8JzAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBQ08GE4h2jHJZOGkDUyQE9EEPMqlDAfBgNVHSMEGDAWgBT+y1YLKOsq6cec6uU61UxVhNvUajANBgkqhkiG9w0BAQUFAAOBgQAVZMDaKVhvX2qOMlcjX7i6DESF7SDyEbjfPk+bYIDm+al45lmzixkFeYUUQcFJMG0s152AkFd/fTVMfz/j37OQYxUYwwZQlMW3dVnC+CvjtMlSrReeHThhQFQpO16i21aDitON1TFsvO8T+21YGB4kne44vry6O4JJPy8EZBsfbw=='
|
45
|
+
|
46
|
+
Given /^a signed XML document$/ do
|
47
|
+
@doc = REXML::Document.new(%q{<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_7f1bf800d7fb2c6380a81df68b07ebc0422018c1b5" Version="2.0" IssueInstant="2012-06-19T12:18:37Z" Destination="http://localhost/feide/mellon/endpoint/postResponse" InResponseTo="cda19580-9c36-012f-fc85-388d120849f6"><saml:Issuer>https://idp-test.feide.no</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_ee3a7c1ef76e7bb8a96e4480342f7171a615a92cbe" Version="2.0" IssueInstant="2012-06-19T12:18:37Z"><saml:Issuer>https://idp-test.feide.no</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
48
|
+
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
49
|
+
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
50
|
+
<ds:Reference URI="#_ee3a7c1ef76e7bb8a96e4480342f7171a615a92cbe"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>fGialLR9Z03EPTPegi8EFHVabJg=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>umIL/zWzfaid4alX5MEaET10eqMfwvaal9p0jzimj7GVicyaGB8iHGwUDOQHd3R1TO7bpqhBJIA6BPcytGu5oFtclSWMoH2y7gygkbARQxZz1WvWnEVPAsJxrn2plnvqf8qM87RjSNAE8heoCUgB97cKCXaIBlsHPsS0WcwMUmnaqVlC6jLZXNRAwuuqR/z5Ww1XKCzl2vz3D//FDX6EhtpmikBZzu0is4YtQ4aAFuJdQYOLltR33pnMrDoG9AzuoS6pgOA9CsK6sB8cak9duQX0208CdJbWFMcK5P4mbM3brRfyedUGXQcYaOTHHdtoiuZee7CJY9drndwJ8As11w==</ds:SignatureValue>
|
51
|
+
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDkDCCAngCCQCoO7l98RIRDzANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAcTCVRyb25kaGVpbTETMBEGA1UEChMKVW5pbmV0dCBBUzEOMAwGA1UECxMFRkVJREUxGjAYBgNVBAMTEWlkcC10ZXN0LmZlaWRlLm5vMSUwIwYJKoZIhvcNAQkBFhZtb3JpYS1kcmlmdEB1bmluZXR0Lm5vMB4XDTA4MDkwNTExNTIzOFoXDTE4MDcxNTExNTIzOFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQHEwlUcm9uZGhlaW0xEzARBgNVBAoTClVuaW5ldHQgQVMxDjAMBgNVBAsTBUZFSURFMRowGAYDVQQDExFpZHAtdGVzdC5mZWlkZS5ubzElMCMGCSqGSIb3DQEJARYWbW9yaWEtZHJpZnRAdW5pbmV0dC5ubzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMzbnp+fdJ4nkgXS+EqnfHUqYOnbxMuJga+ZWJUoKQ/X2DAkZI1rPkJgi50K2mKk3me4JjN8+qEV3XLd326XALJnra8yf07l3gE2aDlR+3pMe1fhhSANVjEzY8x6kROJMq9bxreDQjimcjvdFX69FLgxjqtcwWoGcRyn2HZUYuuoWmvqFlX+985lOfLa/PJjaFbdy7XWtucMw6dDTrA+UWK4yjbenZaT/HHyn29kYQ4MKu4Mn0cYasrfrZrVSHG5L7fySVAaXEgaxToH/fVa40Z5ltHWOw2PiDOCsC1CcQFTmKDq1Gkhi1dMhm/CECJFlAR9ML7tG1Ort9q487kSNxUCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAhf/4EsLnq7EYrvW2gBjJobhweYjjjBng0gXx3yQ/ivHbApcWcbaBLyVIokiGTf7XFhxbeZaT9+vrS+yhKCrcjAfoaXbx/xVVlKLsSMZmOr1g8+4yq6v4ax6orPrsDsmRhutoAUL8AnsGIxbyG/FbjmzEYudnbR44vUnfLD2ffnIGjGLuJHZ0OPMFkPM2V2QPiJlyngrd1xvqBfnsWmWO5pDWlXa/WkxyOBiyIGcmXFJRAPtjJzxUo1CsE2PjdBIqt1bk5UDmuW8qxbDJo1kIKeqVonuAbihZzNXyAFEqV118S4IpCNF7QqBBmlgFE25RMDktiwFk2ymdM680WFBftw==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml:Subject><saml:NameID SPNameQualifier="urn:mace:feide.no:services:http.localhost.boklink.no.restrictedservice" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_792ba75671ac729f6878af5a478f2613c08dc646aa</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2012-06-19T12:23:37Z" Recipient="http://localhost/feide/mellon/endpoint/postResponse" InResponseTo="cda19580-9c36-012f-fc85-388d120849f6"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2012-06-19T12:18:07Z" NotOnOrAfter="2012-06-19T12:23:37Z"><saml:AudienceRestriction><saml:Audience>urn:mace:feide.no:services:http.localhost.boklink.no.restrictedservice</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2012-06-19T12:18:36Z" SessionNotOnOrAfter="2012-06-19T20:18:37Z" SessionIndex="_6b56557e0c70873720ffd134de0a2ab22f18b377e9"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement><saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">member</saml:AttributeValue><saml:AttributeValue xsi:type="xs:string">student</saml:AttributeValue></saml:Attribute><saml:Attribute Name="eduPersonPrincipalName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">test@feide.no</saml:AttributeValue></saml:Attribute><saml:Attribute Name="cn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">FEIDE Test User (cn) øæåØÆÅ</saml:AttributeValue></saml:Attribute><saml:Attribute Name="sn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">FEIDE Test User (sn) øæåØÆÅ</saml:AttributeValue></saml:Attribute><saml:Attribute Name="givenName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">FEIDE Test User (givenName) øæåØÆÅ</saml:AttributeValue></saml:Attribute><saml:Attribute Name="eduPersonEntitlement" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">urn:mace:feide.no:domain.no:testvalue</saml:AttributeValue><saml:AttributeValue xsi:type="xs:string">urn:mace:feide.no:GREP:testvalue</saml:AttributeValue></saml:Attribute><saml:Attribute Name="displayName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">Feide Test User (displayName) æøåÆØÅ</saml:AttributeValue></saml:Attribute><saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">support@feide.no</saml:AttributeValue></saml:Attribute><saml:Attribute Name="eduPersonOrgDN:norEduOrgNIN" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">NO968100211</saml:AttributeValue></saml:Attribute><saml:Attribute Name="eduPersonOrgDN:norEduOrgSchemaVersion" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">1.5</saml:AttributeValue></saml:Attribute><saml:Attribute Name="eduPersonOrgUnitDN:norEduOrgUnitUniqueIdentifier" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">350200</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response>})
|
52
|
+
end
|
53
|
+
|
54
|
+
When /^I check it's validity$/ do #'
|
55
|
+
@sig = XMLSignature.new(@doc)
|
56
|
+
@valid = @sig.verify('MIIDkDCCAngCCQCoO7l98RIRDzANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAcTCVRyb25kaGVpbTETMBEGA1UEChMKVW5pbmV0dCBBUzEOMAwGA1UECxMFRkVJREUxGjAYBgNVBAMTEWlkcC10ZXN0LmZlaWRlLm5vMSUwIwYJKoZIhvcNAQkBFhZtb3JpYS1kcmlmdEB1bmluZXR0Lm5vMB4XDTA4MDkwNTExNTIzOFoXDTE4MDcxNTExNTIzOFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQHEwlUcm9uZGhlaW0xEzARBgNVBAoTClVuaW5ldHQgQVMxDjAMBgNVBAsTBUZFSURFMRowGAYDVQQDExFpZHAtdGVzdC5mZWlkZS5ubzElMCMGCSqGSIb3DQEJARYWbW9yaWEtZHJpZnRAdW5pbmV0dC5ubzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMzbnp+fdJ4nkgXS+EqnfHUqYOnbxMuJga+ZWJUoKQ/X2DAkZI1rPkJgi50K2mKk3me4JjN8+qEV3XLd326XALJnra8yf07l3gE2aDlR+3pMe1fhhSANVjEzY8x6kROJMq9bxreDQjimcjvdFX69FLgxjqtcwWoGcRyn2HZUYuuoWmvqFlX+985lOfLa/PJjaFbdy7XWtucMw6dDTrA+UWK4yjbenZaT/HHyn29kYQ4MKu4Mn0cYasrfrZrVSHG5L7fySVAaXEgaxToH/fVa40Z5ltHWOw2PiDOCsC1CcQFTmKDq1Gkhi1dMhm/CECJFlAR9ML7tG1Ort9q487kSNxUCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAhf/4EsLnq7EYrvW2gBjJobhweYjjjBng0gXx3yQ/ivHbApcWcbaBLyVIokiGTf7XFhxbeZaT9+vrS+yhKCrcjAfoaXbx/xVVlKLsSMZmOr1g8+4yq6v4ax6orPrsDsmRhutoAUL8AnsGIxbyG/FbjmzEYudnbR44vUnfLD2ffnIGjGLuJHZ0OPMFkPM2V2QPiJlyngrd1xvqBfnsWmWO5pDWlXa/WkxyOBiyIGcmXFJRAPtjJzxUo1CsE2PjdBIqt1bk5UDmuW8qxbDJo1kIKeqVonuAbihZzNXyAFEqV118S4IpCNF7QqBBmlgFE25RMDktiwFk2ymdM680WFBftw==')
|
57
|
+
end
|
58
|
+
|
59
|
+
Then /^it should pass$/ do
|
60
|
+
@valid.should == true
|
61
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require "digest/sha1"
|
4
|
+
require "openssl"
|
5
|
+
require "xmlcanonicalizer"
|
6
|
+
|
7
|
+
class XMLSignature
|
8
|
+
|
9
|
+
# xml - A REXML document
|
10
|
+
def initialize(xml)
|
11
|
+
@xml = xml.dup
|
12
|
+
@ds_signature = xpath(@xml, '//ds:Signature')
|
13
|
+
@ds_signature.remove
|
14
|
+
end
|
15
|
+
|
16
|
+
def verify(expected_certificate)
|
17
|
+
raise "Certificate mismatch" if expected_certificate != given_certificate
|
18
|
+
|
19
|
+
REXML::XPath.each(@ds_signature, "//ds:Reference") do |ref|
|
20
|
+
raise "Digest mismatch!" if computed_digest_value(ref) != given_digest_value(ref)
|
21
|
+
end
|
22
|
+
|
23
|
+
raise "Signature mismatch" \
|
24
|
+
unless certificate.public_key.verify(signature_algorithm_class.new,
|
25
|
+
signature,
|
26
|
+
c14n(xpath(@ds_signature, "//ds:SignedInfo")))
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def given_digest_value(ds_reference)
|
33
|
+
xpath(ds_reference, "//ds:DigestValue").text
|
34
|
+
end
|
35
|
+
|
36
|
+
def computed_digest_value(ds_reference)
|
37
|
+
signed_element_in_canonical_representation = c14n(signed_element(ds_reference))
|
38
|
+
Base64.encode64(algorithm_class(ds_reference).digest(signed_element_in_canonical_representation)).chop
|
39
|
+
end
|
40
|
+
|
41
|
+
def c14n(node)
|
42
|
+
with_comments = false
|
43
|
+
exclusive = true
|
44
|
+
XML::Util::XmlCanonicalizer.new(with_comments, exclusive).canonicalize(node)
|
45
|
+
end
|
46
|
+
|
47
|
+
def signature
|
48
|
+
Base64.decode64(xpath(@ds_signature, "//ds:SignatureValue").text.strip)
|
49
|
+
end
|
50
|
+
|
51
|
+
def certificate_text
|
52
|
+
xpath(@ds_signature, "//ds:X509Certificate").text.strip
|
53
|
+
end
|
54
|
+
|
55
|
+
alias :given_certificate :certificate_text
|
56
|
+
|
57
|
+
def certificate
|
58
|
+
OpenSSL::X509::Certificate.new(Base64.decode64(certificate_text))
|
59
|
+
end
|
60
|
+
|
61
|
+
def signed_element(ds_reference)
|
62
|
+
id = reference_uri_to_id(ds_reference.attributes['URI'])
|
63
|
+
xpath(@xml, "//[@ID='#{id}']")
|
64
|
+
end
|
65
|
+
|
66
|
+
def reference_uri_to_id(uri)
|
67
|
+
uri[1..-1] # remove the '#' prefix
|
68
|
+
end
|
69
|
+
|
70
|
+
def algorithm_class(ds_reference)
|
71
|
+
# Legal algorithm URIs: http://www.w3.org/TR/xmlsec-algorithms/#digest-method-uris
|
72
|
+
digest_method = xpath(ds_reference, "//ds:DigestMethod").attributes['Algorithm']
|
73
|
+
case digest_method
|
74
|
+
when 'http://www.w3.org/2000/09/xmldsig#sha1'
|
75
|
+
OpenSSL::Digest::SHA1
|
76
|
+
else
|
77
|
+
raise "Do not support digest method: #{digest_method}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def signature_algorithm_class
|
82
|
+
# Legal algorithm URIs: http://www.w3.org/TR/xmlsec-algorithms/#signature-method-uris
|
83
|
+
signature_method = xpath(@ds_signature, "//ds:SignatureMethod").attributes['Algorithm']
|
84
|
+
case signature_method
|
85
|
+
when 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
|
86
|
+
OpenSSL::Digest::SHA1
|
87
|
+
else
|
88
|
+
raise "Do not support signature method: #{digest_method}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def xpath(node, path)
|
93
|
+
REXML::XPath.first(node, path, {'ds' => 'http://www.w3.org/2000/09/xmldsig#'})
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "xml_signature/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "xml_signature"
|
7
|
+
s.version = XMLSignature::VERSION
|
8
|
+
s.author = "Kjell-Magne Øierud"
|
9
|
+
s.email = ["kjellm@oierud.net"]
|
10
|
+
s.homepage = "https://github.com/kjellm/xml_signature"
|
11
|
+
s.license = "MIT"
|
12
|
+
s.summary = %q{A (partial) implementation of the XML Signature standard}
|
13
|
+
s.description = %q{A (partial) implementation of the XML Signature standard}
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
#s.test_files = `git ls-files -- spec/*`.split("\n")
|
17
|
+
#s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.required_ruby_version = '>= 1.8.7'
|
21
|
+
|
22
|
+
s.add_runtime_dependency 'xmlcanonicalizer'
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xml_signature
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Kjell-Magne Øierud
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: xmlcanonicalizer
|
16
|
+
requirement: &70318916634040 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70318916634040
|
25
|
+
description: A (partial) implementation of the XML Signature standard
|
26
|
+
email:
|
27
|
+
- kjellm@oierud.net
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- .travis.yml
|
34
|
+
- Gemfile
|
35
|
+
- Guardfile
|
36
|
+
- README.md
|
37
|
+
- features/step_definitions/verify_steps.rb
|
38
|
+
- features/support/env.rb
|
39
|
+
- features/verify.feature
|
40
|
+
- lib/xml_signature.rb
|
41
|
+
- lib/xml_signature/version.rb
|
42
|
+
- xml_signature.gemspec
|
43
|
+
homepage: https://github.com/kjellm/xml_signature
|
44
|
+
licenses:
|
45
|
+
- MIT
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.8.7
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 1.8.17
|
65
|
+
signing_key:
|
66
|
+
specification_version: 3
|
67
|
+
summary: A (partial) implementation of the XML Signature standard
|
68
|
+
test_files: []
|
69
|
+
has_rdoc:
|