Skip to content

Commit bcccb80

Browse files
authored
Merge pull request #4 from Asana/megandaly-fix-auto-canonicalization
Fix default canonicalization Summary: According to the Digest Method Spec [1], the DigestMethod takes a octet stream, ad if the output of the URI dereference is a node set instead, it needs to be converted as described in the Reference Processing Spec [2] to an octet stream. The Reference Processing Spec says to use Canonical XML. Enveloped Signature returns a node-set, as does dereferencing a same-document reference [3], [4]. Canonicalization algorithms are the only other transforms we support, and they all return an octet stream, so the only times we need to add canonicalization are if we haven't done any transforms or if the last one is enveloped signature. https://www.w3.org/TR/xmldsig-core1/#sec-DigestMethod https://www.w3.org/TR/xmldsig-core1/#sec-ReferenceProcessingModel https://www.w3.org/TR/xmldsig-core1/#sec-EnvelopedSignature https://www.w3.org/TR/xmldsig-core1/#sec-Same-Document Tests: Added back the test from when this was implemented slightly differently for Windows Mobile, checked against a SamlResponse without a canonicalization method in the transforms Reviewer: @srir
2 parents e0fe511 + 33f6a59 commit bcccb80

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

lib/signed-xml.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,19 @@ SignedXml.prototype.loadReference = function(ref) {
570570
});
571571
}
572572

573+
/**
574+
* DigestMethods take an octet stream rather than a node set. If the output of the last transform is a node set, we
575+
* need to canonicalize the node set to an octet stream using non-exclusive canonicalization. If there are no
576+
* transforms, we need to canonicalize because URI dereferencing for a same-document reference will return a node-set.
577+
* See:
578+
* https://www.w3.org/TR/xmldsig-core1/#sec-DigestMethod
579+
* https://www.w3.org/TR/xmldsig-core1/#sec-ReferenceProcessingModel
580+
* https://www.w3.org/TR/xmldsig-core1/#sec-Same-Document
581+
*/
582+
if (transforms.length === 0 || transforms[transforms.length - 1] === "http://www.w3.org/2000/09/xmldsig#enveloped-signature") {
583+
transforms.push("http://www.w3.org/TR/2001/REC-xml-c14n-20010315")
584+
}
585+
573586
this.addReference(null, transforms, digestAlgo, utils.findAttr(ref, "URI").value, digestValue, inclusiveNamespacesPrefixList, false)
574587
}
575588

test/signature-integration-tests.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,28 @@ module.exports = {
5858
var sig = new crypto.SignedXml()
5959
sig.keyInfoProvider = new crypto.FileKeyInfo("./test/static/client_public.pem")
6060
sig.loadSignature(signature);
61-
61+
var result = sig.checkSignature(xml);
62+
test.equal(result, true);
63+
test.done();
64+
},
65+
66+
"add canonicalization if output of transforms will be a node-set rather than an octet stream": function(test) {
67+
68+
var xml = fs.readFileSync('./test/static/windows_store_signature.xml', 'utf-8');
69+
70+
// Make sure that whitespace in the source document is removed -- see xml-crypto issue #23 and post at
71+
// http://webservices20.blogspot.co.il/2013/06/validating-windows-mobile-app-store.html
72+
// This regex is naive but works for this test case; for a more general solution consider
73+
// the xmldom-fork-fixed library which can pass {ignoreWhiteSpace: true} into the Dom constructor.
74+
xml = xml.replace(/>\s*</g, '><');
75+
76+
var doc = new Dom().parseFromString(xml);
77+
xml = doc.firstChild.toString();
78+
79+
var signature = crypto.xpath(doc, "//*//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];
80+
var sig = new crypto.SignedXml();
81+
sig.keyInfoProvider = new crypto.FileKeyInfo("./test/static/windows_store_certificate.pem");
82+
sig.loadSignature(signature);
6283
var result = sig.checkSignature(xml);
6384
test.equal(result, true);
6485
test.done();

0 commit comments

Comments
 (0)