Skip to content

Commit 33f6a59

Browse files
committed
Fix default canonicalization to be non-exclusive and apply whenever the output of transforms returns a node-set rather than an octet stream, which is whenever there are no transforms or the last transform is enveloped signature. Add back test for when canonicalization method is not specified in transforms
1 parent e0fe511 commit 33f6a59

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)