Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix transform processing regression #379

Merged
merged 1 commit into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions src/c14n-canonicalization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,14 @@
return { rendered: res.join(""), newDefaultNs };
}

processInner(node: Node, prefixesInScope, defaultNs, defaultNsForPrefix, ancestorNamespaces) {
/**
* @param node Node
*/
processInner(node, prefixesInScope, defaultNs, defaultNsForPrefix, ancestorNamespaces) {
if (xpath.isComment(node)) {
return this.renderComment(node);
}
if (xpath.isComment(node)) {
if (node.data) {
return utils.encodeSpecialCharactersInText(node.data);
}

Expand All @@ -198,7 +201,7 @@
return res.join("");
}

return "";
throw new Error(`Unable to canonicalize node type: ${node.nodeType}`);

Check warning on line 204 in src/c14n-canonicalization.ts

View check run for this annotation

Codecov / codecov/patch

src/c14n-canonicalization.ts#L204

Added line #L204 was not covered by tests
}

// Thanks to deoxxa/xml-c14n for comment renderer
Expand Down Expand Up @@ -247,7 +250,7 @@
* @param node
* @api public
*/
process(node: Node, options: CanonicalizationOrTransformationAlgorithmProcessOptions) {
process(node: Node, options: CanonicalizationOrTransformationAlgorithmProcessOptions): string {
options = options || {};
const defaultNs = options.defaultNs || "";
const defaultNsForPrefix = options.defaultNsForPrefix || {};
Expand Down
2 changes: 1 addition & 1 deletion src/enveloped-signature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {

export class EnvelopedSignature implements CanonicalizationOrTransformationAlgorithm {
includeComments = false;
process(node: Node, options: CanonicalizationOrTransformationAlgorithmProcessOptions) {
process(node: Node, options: CanonicalizationOrTransformationAlgorithmProcessOptions): Node {
if (null == options.signatureNode) {
const signature = xpath.select1(
"./*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']",
Expand Down
65 changes: 35 additions & 30 deletions src/exclusive-canonicalization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@
return { rendered: res.join(""), newDefaultNs: newDefaultNs };
}

/**
* @param node Node
*/
processInner(
node,
prefixesInScope,
Expand All @@ -181,32 +184,36 @@
return utils.encodeSpecialCharactersInText(node.data);
}

let i;
let pfxCopy;
const ns = this.renderNs(
node,
prefixesInScope,
defaultNs,
defaultNsForPrefix,
inclusiveNamespacesPrefixList,
);
const res = ["<", node.tagName, ns.rendered, this.renderAttrs(node), ">"];

for (i = 0; i < node.childNodes.length; ++i) {
pfxCopy = prefixesInScope.slice(0);
res.push(
this.processInner(
node.childNodes[i],
pfxCopy,
ns.newDefaultNs,
defaultNsForPrefix,
inclusiveNamespacesPrefixList,
),
if (xpath.isElement(node)) {
let i;
let pfxCopy;
const ns = this.renderNs(
node,
prefixesInScope,
defaultNs,
defaultNsForPrefix,
inclusiveNamespacesPrefixList,
);
const res = ["<", node.tagName, ns.rendered, this.renderAttrs(node), ">"];

for (i = 0; i < node.childNodes.length; ++i) {
pfxCopy = prefixesInScope.slice(0);
res.push(
this.processInner(
node.childNodes[i],
pfxCopy,
ns.newDefaultNs,
defaultNsForPrefix,
inclusiveNamespacesPrefixList,
),
);
}

res.push("</", node.tagName, ">");
return res.join("");
}

res.push("</", node.tagName, ">");
return res.join("");
throw new Error(`Unable to exclusive canonicalize node type: ${node.nodeType}`);

Check warning on line 216 in src/exclusive-canonicalization.ts

View check run for this annotation

Codecov / codecov/patch

src/exclusive-canonicalization.ts#L216

Added line #L216 was not covered by tests
}

// Thanks to deoxxa/xml-c14n for comment renderer
Expand Down Expand Up @@ -250,13 +257,11 @@
}

/**
* Perform canonicalization of the given node
* Perform canonicalization of the given element node
*
* @param {Node} node
* @return {String}
* @api public
*/
process(node, options: CanonicalizationOrTransformationAlgorithmProcessOptions) {
process(elem: Element, options: CanonicalizationOrTransformationAlgorithmProcessOptions): string {
options = options || {};
let inclusiveNamespacesPrefixList = options.inclusiveNamespacesPrefixList || [];
const defaultNs = options.defaultNs || "";
Expand All @@ -267,7 +272,7 @@
* If the inclusiveNamespacesPrefixList has not been explicitly provided then look it up in CanonicalizationMethod/InclusiveNamespaces
*/
if (!utils.isArrayHasLength(inclusiveNamespacesPrefixList)) {
const CanonicalizationMethod = utils.findChildren(node, "CanonicalizationMethod");
const CanonicalizationMethod = utils.findChildren(elem, "CanonicalizationMethod");
if (CanonicalizationMethod.length !== 0) {
const inclusiveNamespaces = utils.findChildren(
CanonicalizationMethod[0],
Expand All @@ -289,7 +294,7 @@
if (ancestorNamespaces) {
ancestorNamespaces.forEach(function (ancestorNamespace) {
if (prefix === ancestorNamespace.prefix) {
node.setAttributeNS(
elem.setAttributeNS(
"http://www.w3.org/2000/xmlns/",
`xmlns:${prefix}`,
ancestorNamespace.namespaceURI,
Expand All @@ -301,7 +306,7 @@
}

const res = this.processInner(
node,
elem,
[],
defaultNs,
defaultNsForPrefix,
Expand Down
70 changes: 34 additions & 36 deletions src/signed-xml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,12 +471,11 @@
}

validateReferences(doc: Document) {
for (const ref of this.references) {
if (!this.validateReference(ref, doc)) {
return false;
}
}
return true;
return (
Array.isArray(this.references) &&
this.references.length > 0 &&
this.references.every((ref) => this.validateReference(ref, doc))
);
}

/**
Expand Down Expand Up @@ -595,39 +594,38 @@
.flatMap((namespace) => (namespace.getAttribute("PrefixList") ?? "").split(" "))
.filter((value) => value.length > 0);
}
}

if (utils.isArrayHasLength(this.implicitTransforms)) {
this.implicitTransforms.forEach(function (t) {
transforms.push(t);
});
}

/**
* DigestMethods take an octet stream rather than a node set. If the output of the last transform is a node set, we
* need to canonicalize the node set to an octet stream using non-exclusive canonicalization. If there are no
* transforms, we need to canonicalize because URI dereferencing for a same-document reference will return a node-set.
* @see:
* 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-Same-Document
*/
if (
transforms.length === 0 ||
transforms[transforms.length - 1] ===
"http://www.w3.org/2000/09/xmldsig#enveloped-signature"
) {
transforms.push("http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
}

this.addReference({
transforms,
digestAlgorithm: digestAlgo,
uri: xpath.isElement(refNode) ? utils.findAttr(refNode, "URI")?.value : undefined,
digestValue,
inclusiveNamespacesPrefixList,
isEmptyUri: false,
if (utils.isArrayHasLength(this.implicitTransforms)) {
this.implicitTransforms.forEach(function (t) {
transforms.push(t);

Check warning on line 601 in src/signed-xml.ts

View check run for this annotation

Codecov / codecov/patch

src/signed-xml.ts#L600-L601

Added lines #L600 - L601 were not covered by tests
});
}

/**
* DigestMethods take an octet stream rather than a node set. If the output of the last transform is a node set, we
* need to canonicalize the node set to an octet stream using non-exclusive canonicalization. If there are no
* transforms, we need to canonicalize because URI dereferencing for a same-document reference will return a node-set.
* @see:
* 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-Same-Document
*/
if (
transforms.length === 0 ||
transforms[transforms.length - 1] === "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
) {
transforms.push("http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
}

this.addReference({
transforms,
digestAlgorithm: digestAlgo,
uri: xpath.isElement(refNode) ? utils.findAttr(refNode, "URI")?.value : undefined,
digestValue,
inclusiveNamespacesPrefixList,
isEmptyUri: false,
});
}

/**
Expand Down
9 changes: 6 additions & 3 deletions test/c14nWithComments-unit-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ const compare = function (xml, xpathArg, expected, inclusiveNamespacesPrefixList
const doc = new xmldom.DOMParser().parseFromString(xml);
const elem = xpath.select1(xpathArg, doc);
const can = new c14nWithComments();
const result = can.process(elem, { inclusiveNamespacesPrefixList }).toString();

expect(result).to.equal(expected);
if (xpath.isElement(elem)) {
const result = can.process(elem, { inclusiveNamespacesPrefixList }).toString();
expect(result).to.equal(expected);
} else {
throw new Error("Element not found.");
}
};

describe("Exclusive canonicalization with comments", function () {
Expand Down
20 changes: 12 additions & 8 deletions test/canonicalization-unit-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@ const compare = function (
const doc = new xmldom.DOMParser().parseFromString(xml);
const elem = xpath.select1(xpathArg, doc);
const can = new ExclusiveCanonicalization();
const result = can
.process(elem, {
inclusiveNamespacesPrefixList,
defaultNsForPrefix,
})
.toString();

expect(expected).to.equal(result);
if (xpath.isElement(elem)) {
const result = can
.process(elem, {
inclusiveNamespacesPrefixList,
defaultNsForPrefix,
})
.toString();

expect(expected).to.equal(result);
} else {
throw new Error("Invalid element");
}
};

describe("Canonicalization unit tests", function () {
Expand Down
8 changes: 8 additions & 0 deletions test/signature-unit-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,10 @@ describe("Signature unit tests", function () {
passValidSignature("./test/static/valid_signature_with_unused_prefixes.xml");
});

it("verifies valid signature without transforms element", function () {
passValidSignature("./test/static/valid_signature_without_transforms_element.xml");
});

it("fails invalid signature - signature value", function () {
failInvalidSignature("./test/static/invalid_signature - signature value.xml");
});
Expand Down Expand Up @@ -918,6 +922,10 @@ describe("Signature unit tests", function () {
);
});

it("fails invalid signature without transforms element", function () {
failInvalidSignature("./test/static/invalid_signature_without_transforms_element.xml");
});

it("allow empty reference uri when signing", function () {
const xml = "<root><x /></root>";
const sig = new SignedXml();
Expand Down
4 changes: 4 additions & 0 deletions test/static/invalid_signature_without_transforms_element.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0"?>
<library><book ID="bookid"><name>some tampered text</name></book><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="#bookid"><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>LsMoqo1d6Sqh8DKLp00MK0fSBDA=</DigestValue></Reference></SignedInfo><SignatureValue>OR1SYcyU18qELj+3DX/bW/r5DqueuyPAnNFEh3hNKFaj8ZKLB/mdsR9w8GDBCmZ2
lsCTEvJqWC37oF8rm2eBSonNbdBnA+TM6Y22C8rffVzaoM3zpNoeWMH2LwFmpdKB
UXOMWVExEaz/s4fOcyv1ajVuk42I3nl0xcD95+i7PjY=</SignatureValue></Signature></library>
4 changes: 4 additions & 0 deletions test/static/valid_signature_without_transforms_element.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0"?>
<library><book ID="bookid"><name>some text</name></book><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="#bookid"><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>LsMoqo1d6Sqh8DKLp00MK0fSBDA=</DigestValue></Reference></SignedInfo><SignatureValue>OR1SYcyU18qELj+3DX/bW/r5DqueuyPAnNFEh3hNKFaj8ZKLB/mdsR9w8GDBCmZ2
lsCTEvJqWC37oF8rm2eBSonNbdBnA+TM6Y22C8rffVzaoM3zpNoeWMH2LwFmpdKB
UXOMWVExEaz/s4fOcyv1ajVuk42I3nl0xcD95+i7PjY=</SignatureValue></Signature></library>