From fd3c0e0e66aa547b1593dc7b8ba68e0c488de22b Mon Sep 17 00:00:00 2001 From: Chris Barth Date: Wed, 7 Jun 2023 20:19:49 -0400 Subject: [PATCH 1/2] Lint code for new linting rules --- .eslintrc.json | 2 +- lib/c14n-canonicalization.js | 8 +-- lib/enveloped-signature.js | 5 +- lib/exclusive-canonicalization.js | 9 ++- lib/signed-xml.js | 106 +++++++++++++++--------------- lib/utils.js | 22 +++---- package.json | 4 +- 7 files changed, 78 insertions(+), 78 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index b3a85705..b3b6a4cf 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -17,7 +17,7 @@ "no-duplicate-imports": "error", "no-use-before-define": "error", "curly": "warn", - "eqeqeq": ["error", "smart"], + "eqeqeq": ["warn", "smart"], "no-var": "warn", "prefer-const":"warn" } diff --git a/lib/c14n-canonicalization.js b/lib/c14n-canonicalization.js index 0e4ba696..38937a8b 100644 --- a/lib/c14n-canonicalization.js +++ b/lib/c14n-canonicalization.js @@ -1,9 +1,6 @@ /* jshint laxcomma: true */ var utils = require("./utils"); -exports.C14nCanonicalization = C14nCanonicalization; -exports.C14nCanonicalizationWithComments = C14nCanonicalizationWithComments; - function C14nCanonicalization() { this.includeComments = false; } @@ -278,8 +275,6 @@ C14nCanonicalization.prototype.getAlgorithmName = function () { }; // Add c14n#WithComments here (very simple subclass) -exports.C14nCanonicalizationWithComments = C14nCanonicalizationWithComments; - function C14nCanonicalizationWithComments() { C14nCanonicalization.call(this); this.includeComments = true; @@ -292,3 +287,6 @@ C14nCanonicalizationWithComments.prototype.constructor = C14nCanonicalizationWit C14nCanonicalizationWithComments.prototype.getAlgorithmName = function () { return "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"; }; + +exports.C14nCanonicalization = C14nCanonicalization; +exports.C14nCanonicalizationWithComments = C14nCanonicalizationWithComments; diff --git a/lib/enveloped-signature.js b/lib/enveloped-signature.js index c438e0d6..7296f92c 100644 --- a/lib/enveloped-signature.js +++ b/lib/enveloped-signature.js @@ -1,8 +1,6 @@ var xpath = require("xpath"); var utils = require("./utils"); -exports.EnvelopedSignature = EnvelopedSignature; - function EnvelopedSignature() {} EnvelopedSignature.prototype.process = function (node, options) { @@ -41,3 +39,6 @@ EnvelopedSignature.prototype.process = function (node, options) { EnvelopedSignature.prototype.getAlgorithmName = function () { return "http://www.w3.org/2000/09/xmldsig#enveloped-signature"; }; + +exports.EnvelopedSignature = EnvelopedSignature; + diff --git a/lib/exclusive-canonicalization.js b/lib/exclusive-canonicalization.js index 758ea474..50bbf88f 100644 --- a/lib/exclusive-canonicalization.js +++ b/lib/exclusive-canonicalization.js @@ -1,9 +1,6 @@ /* jshint laxcomma: true */ var utils = require("./utils"); -exports.ExclusiveCanonicalization = ExclusiveCanonicalization; -exports.ExclusiveCanonicalizationWithComments = ExclusiveCanonicalizationWithComments; - function ExclusiveCanonicalization() { this.includeComments = false; } @@ -330,8 +327,6 @@ ExclusiveCanonicalization.prototype.getAlgorithmName = function () { }; // Add c14n#WithComments here (very simple subclass) -exports.ExclusiveCanonicalizationWithComments = ExclusiveCanonicalizationWithComments; - function ExclusiveCanonicalizationWithComments() { ExclusiveCanonicalization.call(this); this.includeComments = true; @@ -346,3 +341,7 @@ ExclusiveCanonicalizationWithComments.prototype.constructor = ExclusiveCanonical ExclusiveCanonicalizationWithComments.prototype.getAlgorithmName = function () { return "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"; }; + +exports.ExclusiveCanonicalization = ExclusiveCanonicalization; +exports.ExclusiveCanonicalizationWithComments = ExclusiveCanonicalizationWithComments; + diff --git a/lib/signed-xml.js b/lib/signed-xml.js index 7d26d726..cdaabbd4 100644 --- a/lib/signed-xml.js +++ b/lib/signed-xml.js @@ -8,10 +8,6 @@ var xpath = require("xpath"), FileKeyInfo = require("./file-key-info"), crypto = require("crypto"); -exports.SignedXml = SignedXml; -exports.StringKeyInfo = StringKeyInfo; -exports.FileKeyInfo = FileKeyInfo; - /** * Hash algorithm implementation * @@ -177,6 +173,32 @@ function HMACSHA1() { }; } +function collectAncestorNamespaces(node, nsArray) { + if (!nsArray) { + nsArray = []; + } + + var parent = node.parentNode; + + if (!parent) { + return nsArray; + } + + if (parent.attributes && parent.attributes.length > 0) { + for (var i = 0; i < parent.attributes.length; i++) { + var attr = parent.attributes[i]; + if (attr && attr.nodeName && attr.nodeName.search(/^xmlns:/) !== -1) { + nsArray.push({ + prefix: attr.nodeName.replace(/^xmlns:/, ""), + namespaceURI: attr.nodeValue, + }); + } + } + } + + return collectAncestorNamespaces(parent, nsArray); +} + /** * Extract ancestor namespaces in order to import it to root of document subset * which is being canonicalized for non-exclusive c14n. @@ -233,30 +255,36 @@ function findAncestorNs(doc, docSubsetXpath, namespaceResolver) { return returningNs; } -function collectAncestorNamespaces(node, nsArray) { - if (!nsArray) { - nsArray = []; +function validateDigestValue(digest, expectedDigest) { + var buffer, expectedBuffer; + + var majorVersion = /^v(\d+)/.exec(process.version)[1]; + + if (+majorVersion >= 6) { + buffer = Buffer.from(digest, "base64"); + expectedBuffer = Buffer.from(expectedDigest, "base64"); + } else { + // Compatibility with Node < 5.10.0 + buffer = new Buffer(digest, "base64"); + expectedBuffer = new Buffer(expectedDigest, "base64"); } - var parent = node.parentNode; + if (typeof buffer.equals === "function") { + return buffer.equals(expectedBuffer); + } - if (!parent) { - return nsArray; + // Compatibility with Node < 0.11.13 + if (buffer.length !== expectedBuffer.length) { + return false; } - if (parent.attributes && parent.attributes.length > 0) { - for (var i = 0; i < parent.attributes.length; i++) { - var attr = parent.attributes[i]; - if (attr && attr.nodeName && attr.nodeName.search(/^xmlns:/) !== -1) { - nsArray.push({ - prefix: attr.nodeName.replace(/^xmlns:/, ""), - namespaceURI: attr.nodeValue, - }); - } + for (var i = 0; i < buffer.length; i++) { + if (buffer[i] !== expectedBuffer[i]) { + return false; } } - return collectAncestorNamespaces(parent, nsArray); + return true; } /** @@ -540,38 +568,6 @@ SignedXml.prototype.validateReferences = function (doc) { return true; }; -function validateDigestValue(digest, expectedDigest) { - var buffer, expectedBuffer; - - var majorVersion = /^v(\d+)/.exec(process.version)[1]; - - if (+majorVersion >= 6) { - buffer = Buffer.from(digest, "base64"); - expectedBuffer = Buffer.from(expectedDigest, "base64"); - } else { - // Compatibility with Node < 5.10.0 - buffer = new Buffer(digest, "base64"); - expectedBuffer = new Buffer(expectedDigest, "base64"); - } - - if (typeof buffer.equals === "function") { - return buffer.equals(expectedBuffer); - } - - // Compatibility with Node < 0.11.13 - if (buffer.length !== expectedBuffer.length) { - return false; - } - - for (var i = 0; i < buffer.length; i++) { - if (buffer[i] !== expectedBuffer[i]) { - return false; - } - } - - return true; -} - SignedXml.prototype.loadSignature = function (signatureNode) { if (typeof signatureNode === "string") { this.signatureNode = signatureNode = new Dom().parseFromString(signatureNode); @@ -1132,3 +1128,9 @@ SignedXml.prototype.getOriginalXmlWithIds = function () { SignedXml.prototype.getSignedXml = function () { return this.signedXml; }; + + +exports.SignedXml = SignedXml; +exports.StringKeyInfo = StringKeyInfo; +exports.FileKeyInfo = FileKeyInfo; + diff --git a/lib/utils.js b/lib/utils.js index 33b8d381..1925e9b5 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,5 +1,16 @@ var select = require("xpath").select; +function attrEqualsExplicitly(attr, localName, namespace) { + return attr.localName == localName && (attr.namespaceURI == namespace || !namespace); +} + +function attrEqualsImplicitly(attr, localName, namespace, node) { + return ( + attr.localName == localName && + ((!attr.namespaceURI && node.namespaceURI == namespace) || !namespace) + ); +} + function findAttr(node, localName, namespace) { for (var i = 0; i < node.attributes.length; i++) { var attr = node.attributes[i]; @@ -32,17 +43,6 @@ function findChilds(node, localName, namespace) { return res; } -function attrEqualsExplicitly(attr, localName, namespace) { - return attr.localName == localName && (attr.namespaceURI == namespace || !namespace); -} - -function attrEqualsImplicitly(attr, localName, namespace, node) { - return ( - attr.localName == localName && - ((!attr.namespaceURI && node.namespaceURI == namespace) || !namespace) - ); -} - var xml_special_to_encoded_attribute = { "&": "&", "<": "<", diff --git a/package.json b/package.json index dfdffd54..da8141af 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ }, "scripts": { "changelog": "gren changelog --override --generate --head master", - "lint": "eslint --ext .js \"**/*.js\" --cache && npm run prettier-check", - "lint:fix": "eslint --ext .js --fix \"**/*.js\" && npm run prettier-format", + "lint": "eslint --ext .js \"{lib,test}/*.js\" --cache && npm run prettier-check", + "lint:fix": "eslint --ext .js --fix \"{lib,test}/*.js\" && npm run prettier-format", "prettier-check": "prettier --config .prettierrc.json --check .", "prettier-format": "prettier --config .prettierrc.json --write .", "prerelease": "git clean -xfd && npm ci && npm test", From 79b3920075358031275ecb93fd959b1bfb64130f Mon Sep 17 00:00:00 2001 From: Chris Barth Date: Wed, 7 Jun 2023 20:27:03 -0400 Subject: [PATCH 2/2] more linting and formatting --- .eslintrc.json | 4 +- lib/enveloped-signature.js | 1 - lib/exclusive-canonicalization.js | 1 - lib/signed-xml.js | 2 - test/signature-integration-tests.js | 68 +++--- test/signature-unit-tests.js | 365 ++++++++++++++-------------- 6 files changed, 219 insertions(+), 222 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index b3b6a4cf..0a0a638d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -19,6 +19,6 @@ "curly": "warn", "eqeqeq": ["warn", "smart"], "no-var": "warn", - "prefer-const":"warn" + "prefer-const": "warn" } -} \ No newline at end of file +} diff --git a/lib/enveloped-signature.js b/lib/enveloped-signature.js index 7296f92c..47a1acde 100644 --- a/lib/enveloped-signature.js +++ b/lib/enveloped-signature.js @@ -41,4 +41,3 @@ EnvelopedSignature.prototype.getAlgorithmName = function () { }; exports.EnvelopedSignature = EnvelopedSignature; - diff --git a/lib/exclusive-canonicalization.js b/lib/exclusive-canonicalization.js index 50bbf88f..144759d3 100644 --- a/lib/exclusive-canonicalization.js +++ b/lib/exclusive-canonicalization.js @@ -344,4 +344,3 @@ ExclusiveCanonicalizationWithComments.prototype.getAlgorithmName = function () { exports.ExclusiveCanonicalization = ExclusiveCanonicalization; exports.ExclusiveCanonicalizationWithComments = ExclusiveCanonicalizationWithComments; - diff --git a/lib/signed-xml.js b/lib/signed-xml.js index cdaabbd4..523bfdf9 100644 --- a/lib/signed-xml.js +++ b/lib/signed-xml.js @@ -1129,8 +1129,6 @@ SignedXml.prototype.getSignedXml = function () { return this.signedXml; }; - exports.SignedXml = SignedXml; exports.StringKeyInfo = StringKeyInfo; exports.FileKeyInfo = FileKeyInfo; - diff --git a/test/signature-integration-tests.js b/test/signature-integration-tests.js index 4d69143c..af493a70 100644 --- a/test/signature-integration-tests.js +++ b/test/signature-integration-tests.js @@ -6,6 +6,40 @@ var xpath = require("xpath"), var expect = require("chai").expect; describe("Signature integration tests", function () { + function verifySignature(xml, expected, xpath) { + var sig = new SignedXml(); + sig.signingKey = fs.readFileSync("./test/static/client.pem"); + sig.keyInfo = null; + + xpath.map(function (n) { + sig.addReference(n); + }); + + sig.computeSignature(xml); + var signed = sig.getSignedXml(); + + //fs.writeFileSync("./test/validators/XmlCryptoUtilities/XmlCryptoUtilities/bin/Debug/signedExample.xml", signed) + var expectedContent = fs.readFileSync(expected).toString(); + expect(signed, "signature xml different than expected").to.equal(expectedContent); + /* + var spawn = require('child_process').spawn + var proc = spawn('./test/validators/XmlCryptoUtilities/XmlCryptoUtilities/bin/Debug/XmlCryptoUtilities.exe', ['verify']) + + proc.stdout.on('data', function (data) { + console.log('stdout: ' + data); + }); + + proc.stderr.on('data', function (data) { + console.log('stderr: ' + data); + }); + + proc.on('exit', function (code) { + test.equal(0, code, "signature validation failed") + test.done() + }); + */ + } + it("verify signature", function () { var xml = ''; @@ -188,37 +222,3 @@ describe("Signature integration tests", function () { ).to.equal(2); }); }); - -function verifySignature(xml, expected, xpath) { - var sig = new SignedXml(); - sig.signingKey = fs.readFileSync("./test/static/client.pem"); - sig.keyInfo = null; - - xpath.map(function (n) { - sig.addReference(n); - }); - - sig.computeSignature(xml); - var signed = sig.getSignedXml(); - - //fs.writeFileSync("./test/validators/XmlCryptoUtilities/XmlCryptoUtilities/bin/Debug/signedExample.xml", signed) - var expectedContent = fs.readFileSync(expected).toString(); - expect(signed, "signature xml different than expected").to.equal(expectedContent); - /* - var spawn = require('child_process').spawn - var proc = spawn('./test/validators/XmlCryptoUtilities/XmlCryptoUtilities/bin/Debug/XmlCryptoUtilities.exe', ['verify']) - - proc.stdout.on('data', function (data) { - console.log('stdout: ' + data); - }); - - proc.stderr.on('data', function (data) { - console.log('stderr: ' + data); - }); - - proc.on('exit', function (code) { - test.equal(0, code, "signature validation failed") - test.done() - }); - */ -} diff --git a/test/signature-unit-tests.js b/test/signature-unit-tests.js index e911abb0..043993fb 100644 --- a/test/signature-unit-tests.js +++ b/test/signature-unit-tests.js @@ -7,6 +7,189 @@ var select = require("xpath").select, var expect = require("chai").expect; describe("Signature unit tests", function () { + function verifySignature(xml, mode) { + var doc = new dom().parseFromString(xml); + var node = select( + "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", + doc + )[0]; + + var sig = new SignedXml(mode); + sig.keyInfoProvider = new FileKeyInfo("./test/static/client_public.pem"); + sig.loadSignature(node); + var res = sig.checkSignature(xml); + + return res; + } + + function passValidSignature(file, mode) { + var xml = fs.readFileSync(file).toString(); + var res = verifySignature(xml, mode); + expect(res, "expected signature to be valid, but it was reported invalid").to.equal(true); + } + + function passLoadSignature(file, toString) { + var xml = fs.readFileSync(file).toString(); + var doc = new dom().parseFromString(xml); + var node = select( + "/*//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", + doc + )[0]; + var sig = new SignedXml(); + sig.loadSignature(toString ? node.toString() : node); + + expect(sig.canonicalizationAlgorithm, "wrong canonicalization method").to.equal( + "http://www.w3.org/2001/10/xml-exc-c14n#" + ); + + expect(sig.signatureAlgorithm, "wrong signature method").to.equal( + "http://www.w3.org/2000/09/xmldsig#rsa-sha1" + ); + + expect(sig.signatureValue, "wrong signature value").to.equal( + "PI2xGt3XrVcxYZ34Kw7nFdq75c7Mmo7J0q7yeDhBprHuJal/KV9KyKG+Zy3bmQIxNwkPh0KMP5r1YMTKlyifwbWK0JitRCSa0Fa6z6+TgJi193yiR5S1MQ+esoQT0RzyIOBl9/GuJmXx/1rXnqrTxmL7UxtqKuM29/eHwF0QDUI=" + ); + + var keyInfo = select( + "//*[local-name(.)='KeyInfo']/*[local-name(.)='dummyKey']", + sig.keyInfo[0] + )[0]; + expect(keyInfo.firstChild.data, "keyInfo clause not correctly loaded").to.equal("1234"); + + expect(sig.references.length).to.equal(3); + + var digests = [ + "b5GCZ2xpP5T7tbLWBTkOl4CYupQ=", + "K4dI497ZCxzweDIrbndUSmtoezY=", + "sH1gxKve8wlU8LlFVa2l6w3HMJ0=", + ]; + + for (var i = 0; i < sig.references.length; i++) { + var ref = sig.references[i]; + var expectedUri = "#_" + i; + expect( + ref.uri, + "wrong uri for index " + i + ". expected: " + expectedUri + " actual: " + ref.uri + ).to.equal(expectedUri); + expect(ref.transforms.length).to.equal(1); + expect(ref.transforms[0]).to.equal("http://www.w3.org/2001/10/xml-exc-c14n#"); + expect(ref.digestValue).to.equal(digests[i]); + expect(ref.digestAlgorithm).to.equal("http://www.w3.org/2000/09/xmldsig#sha1"); + } + } + + function failInvalidSignature(file, mode) { + var xml = fs.readFileSync(file).toString(); + var res = verifySignature(xml, mode); + expect(res, "expected signature to be invalid, but it was reported valid").to.equal(false); + } + + function verifyDoesNotDuplicateIdAttributes(mode, prefix) { + var xml = + ""; + var sig = new SignedXml(mode); + sig.signingKey = fs.readFileSync("./test/static/client.pem"); + sig.addReference("//*[local-name(.)='x']"); + sig.computeSignature(xml); + var signedXml = sig.getOriginalXmlWithIds(); + var doc = new dom().parseFromString(signedXml); + var attrs = select("//@*", doc); + expect(attrs.length, "wrong number of attributes").to.equal(2); + } + + function nodeExists(doc, xpath) { + if (!doc && !xpath) return; + var node = select(xpath, doc); + expect(node.length, "xpath " + xpath + " not found").to.equal(1); + } + + function verifyAddsId(mode, nsMode) { + var xml = ''; + var sig = new SignedXml(mode); + sig.signingKey = fs.readFileSync("./test/static/client.pem"); + + sig.addReference("//*[local-name(.)='x']"); + sig.addReference("//*[local-name(.)='y']"); + sig.addReference("//*[local-name(.)='w']"); + + sig.computeSignature(xml); + var signedXml = sig.getOriginalXmlWithIds(); + var doc = new dom().parseFromString(signedXml); + + var op = nsMode == "equal" ? "=" : "!="; + + var xpath = + "//*[local-name(.)='{elem}' and '_{id}' = @*[local-name(.)='Id' and namespace-uri(.)" + + op + + "'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd']]"; + + //verify each of the signed nodes now has an "Id" attribute with the right value + nodeExists(doc, xpath.replace("{id}", "0").replace("{elem}", "x")); + nodeExists(doc, xpath.replace("{id}", "1").replace("{elem}", "y")); + nodeExists(doc, xpath.replace("{id}", "2").replace("{elem}", "w")); + } + + function verifyAddsAttrs() { + var xml = 'xml-cryptogithub'; + var sig = new SignedXml(); + var attrs = { + Id: "signatureTest", + data: "dataValue", + xmlns: "http://custom-xmlns#", + }; + + sig.signingKey = fs.readFileSync("./test/static/client.pem"); + + sig.addReference("//*[local-name(.)='name']"); + + sig.computeSignature(xml, { + attrs: attrs, + }); + + var signedXml = sig.getSignatureXml(); + var doc = new dom().parseFromString(signedXml); + var signatureNode = doc.documentElement; + + expect( + attrs.Id, + 'Id attribute is not equal to the expected value: "' + attrs.Id + '"' + ).to.equal(signatureNode.getAttribute("Id")); + expect( + attrs.data, + 'data attribute is not equal to the expected value: "' + attrs.data + '"' + ).to.equal(signatureNode.getAttribute("data")); + expect(attrs.xmlns, "xmlns attribute can not be overridden").not.to.equal( + signatureNode.getAttribute("xmlns") + ); + expect( + signatureNode.getAttribute("xmlns"), + 'xmlns attribute is not equal to the expected value: "http://www.w3.org/2000/09/xmldsig#"' + ).to.equal("http://www.w3.org/2000/09/xmldsig#"); + } + + function verifyReferenceNS() { + var xml = + 'xml-cryptogithub'; + var sig = new SignedXml("wssecurity"); + + sig.signingKey = fs.readFileSync("./test/static/client.pem"); + + sig.addReference("//*[@wsu:Id]"); + + sig.computeSignature(xml, { + existingPrefixes: { + wsu: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", + }, + }); + + var signedXml = sig.getSignatureXml(); + var doc = new dom().parseFromString(signedXml); + var references = select("//*[local-name(.)='Reference']", doc); + expect(references.length).to.equal(2); + } + it("signer adds increasing id attributes to elements", function () { verifyAddsId("wssecurity", "equal"); verifyAddsId(null, "different"); @@ -834,185 +1017,3 @@ describe("Signature unit tests", function () { ).to.equal("custom-value"); }); }); - -function passValidSignature(file, mode) { - var xml = fs.readFileSync(file).toString(); - var res = verifySignature(xml, mode); - expect(res, "expected signature to be valid, but it was reported invalid").to.equal(true); -} - -function passLoadSignature(file, toString) { - var xml = fs.readFileSync(file).toString(); - var doc = new dom().parseFromString(xml); - var node = select( - "/*//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", - doc - )[0]; - var sig = new SignedXml(); - sig.loadSignature(toString ? node.toString() : node); - - expect(sig.canonicalizationAlgorithm, "wrong canonicalization method").to.equal( - "http://www.w3.org/2001/10/xml-exc-c14n#" - ); - - expect(sig.signatureAlgorithm, "wrong signature method").to.equal( - "http://www.w3.org/2000/09/xmldsig#rsa-sha1" - ); - - expect(sig.signatureValue, "wrong signature value").to.equal( - "PI2xGt3XrVcxYZ34Kw7nFdq75c7Mmo7J0q7yeDhBprHuJal/KV9KyKG+Zy3bmQIxNwkPh0KMP5r1YMTKlyifwbWK0JitRCSa0Fa6z6+TgJi193yiR5S1MQ+esoQT0RzyIOBl9/GuJmXx/1rXnqrTxmL7UxtqKuM29/eHwF0QDUI=" - ); - - var keyInfo = select( - "//*[local-name(.)='KeyInfo']/*[local-name(.)='dummyKey']", - sig.keyInfo[0] - )[0]; - expect(keyInfo.firstChild.data, "keyInfo clause not correctly loaded").to.equal("1234"); - - expect(sig.references.length).to.equal(3); - - var digests = [ - "b5GCZ2xpP5T7tbLWBTkOl4CYupQ=", - "K4dI497ZCxzweDIrbndUSmtoezY=", - "sH1gxKve8wlU8LlFVa2l6w3HMJ0=", - ]; - - for (var i = 0; i < sig.references.length; i++) { - var ref = sig.references[i]; - var expectedUri = "#_" + i; - expect( - ref.uri, - "wrong uri for index " + i + ". expected: " + expectedUri + " actual: " + ref.uri - ).to.equal(expectedUri); - expect(ref.transforms.length).to.equal(1); - expect(ref.transforms[0]).to.equal("http://www.w3.org/2001/10/xml-exc-c14n#"); - expect(ref.digestValue).to.equal(digests[i]); - expect(ref.digestAlgorithm).to.equal("http://www.w3.org/2000/09/xmldsig#sha1"); - } -} - -function failInvalidSignature(file, mode) { - var xml = fs.readFileSync(file).toString(); - var res = verifySignature(xml, mode); - expect(res, "expected signature to be invalid, but it was reported valid").to.equal(false); -} - -function verifySignature(xml, mode) { - var doc = new dom().parseFromString(xml); - var node = select( - "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", - doc - )[0]; - - var sig = new SignedXml(mode); - sig.keyInfoProvider = new FileKeyInfo("./test/static/client_public.pem"); - sig.loadSignature(node); - var res = sig.checkSignature(xml); - - return res; -} - -function verifyDoesNotDuplicateIdAttributes(mode, prefix) { - var xml = - ""; - var sig = new SignedXml(mode); - sig.signingKey = fs.readFileSync("./test/static/client.pem"); - sig.addReference("//*[local-name(.)='x']"); - sig.computeSignature(xml); - var signedXml = sig.getOriginalXmlWithIds(); - var doc = new dom().parseFromString(signedXml); - var attrs = select("//@*", doc); - expect(attrs.length, "wrong number of attributes").to.equal(2); -} - -function verifyAddsId(mode, nsMode) { - var xml = ''; - var sig = new SignedXml(mode); - sig.signingKey = fs.readFileSync("./test/static/client.pem"); - - sig.addReference("//*[local-name(.)='x']"); - sig.addReference("//*[local-name(.)='y']"); - sig.addReference("//*[local-name(.)='w']"); - - sig.computeSignature(xml); - var signedXml = sig.getOriginalXmlWithIds(); - var doc = new dom().parseFromString(signedXml); - - var op = nsMode == "equal" ? "=" : "!="; - - var xpath = - "//*[local-name(.)='{elem}' and '_{id}' = @*[local-name(.)='Id' and namespace-uri(.)" + - op + - "'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd']]"; - - //verify each of the signed nodes now has an "Id" attribute with the right value - nodeExists(doc, xpath.replace("{id}", "0").replace("{elem}", "x")); - nodeExists(doc, xpath.replace("{id}", "1").replace("{elem}", "y")); - nodeExists(doc, xpath.replace("{id}", "2").replace("{elem}", "w")); -} - -function verifyAddsAttrs() { - var xml = 'xml-cryptogithub'; - var sig = new SignedXml(); - var attrs = { - Id: "signatureTest", - data: "dataValue", - xmlns: "http://custom-xmlns#", - }; - - sig.signingKey = fs.readFileSync("./test/static/client.pem"); - - sig.addReference("//*[local-name(.)='name']"); - - sig.computeSignature(xml, { - attrs: attrs, - }); - - var signedXml = sig.getSignatureXml(); - var doc = new dom().parseFromString(signedXml); - var signatureNode = doc.documentElement; - - expect(attrs.Id, 'Id attribute is not equal to the expected value: "' + attrs.Id + '"').to.equal( - signatureNode.getAttribute("Id") - ); - expect( - attrs.data, - 'data attribute is not equal to the expected value: "' + attrs.data + '"' - ).to.equal(signatureNode.getAttribute("data")); - expect(attrs.xmlns, "xmlns attribute can not be overridden").not.to.equal( - signatureNode.getAttribute("xmlns") - ); - expect( - signatureNode.getAttribute("xmlns"), - 'xmlns attribute is not equal to the expected value: "http://www.w3.org/2000/09/xmldsig#"' - ).to.equal("http://www.w3.org/2000/09/xmldsig#"); -} - -function verifyReferenceNS() { - var xml = - 'xml-cryptogithub'; - var sig = new SignedXml("wssecurity"); - - sig.signingKey = fs.readFileSync("./test/static/client.pem"); - - sig.addReference("//*[@wsu:Id]"); - - sig.computeSignature(xml, { - existingPrefixes: { - wsu: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", - }, - }); - - var signedXml = sig.getSignatureXml(); - var doc = new dom().parseFromString(signedXml); - var references = select("//*[local-name(.)='Reference']", doc); - expect(references.length).to.equal(2); -} - -function nodeExists(doc, xpath) { - if (!doc && !xpath) return; - var node = select(xpath, doc); - expect(node.length, "xpath " + xpath + " not found").to.equal(1); -}