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

Remove default canonicalization algorithm #405

Merged
merged 2 commits into from
Oct 18, 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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ by default the following algorithms are used:

_Canonicalization/Transformation Algorithm:_ Exclusive Canonicalization <http://www.w3.org/2001/10/xml-exc-c14n#>

_Hashing Algorithm:_ SHA1 digest <http://www.w3.org/2000/09/xmldsig#sha1>
_Hashing/Digest Algorithm:_ SHA1 digest <http://www.w3.org/2000/09/xmldsig#sha1>

_Signature Algorithm:_ RSA-SHA1 <http://www.w3.org/2000/09/xmldsig#rsa-sha1>

Expand Down Expand Up @@ -244,7 +244,7 @@ The `SignedXml` constructor provides an abstraction for sign and verify xml docu
- `privateKey` - string or Buffer - default `null` - the private key to use for signing
- `publicCert` - string or Buffer - default `null` - the public certificate to use for verifying
- `signatureAlgorithm` - string - default `http://www.w3.org/2000/09/xmldsig#rsa-sha1` - the signature algorithm to use
- `canonicalizationAlgorithm` - string - default `http://www.w3.org/TR/2001/REC-xml-c14n-20010315` - the canonicalization algorithm to use
- `canonicalizationAlgorithm` - string - default `undefined` - the canonicalization algorithm to use
- `inclusiveNamespacesPrefixList` - string - default `null` - a list of namespace prefixes to include during canonicalization
- `implicitTransforms` - string[] - default `[]` - a list of implicit transforms to use during verification
- `keyInfoAttributes` - object - default `{}` - a hash of attributes and values `attrName: value` to add to the KeyInfo node
Expand Down Expand Up @@ -313,7 +313,7 @@ function MyDigest() {
}
```

A custom signing algorithm. The default is RSA-SHA1.
A custom signing algorithm.

```javascript
function MySignatureAlgorithm() {
Expand All @@ -328,7 +328,7 @@ function MySignatureAlgorithm() {
}
```

Custom transformation algorithm. The default is exclusive canonicalization.
Custom transformation algorithm.

```javascript
function MyTransformation() {
Expand Down
6 changes: 5 additions & 1 deletion src/c14n-canonicalization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import * as utils from "./utils";
import * as isDomNode from "@xmldom/is-dom-node";

export class C14nCanonicalization implements CanonicalizationOrTransformationAlgorithm {
includeComments = false;
protected includeComments = false;

constructor() {
this.includeComments = false;
}

attrCompare(a, b) {
if (!a.namespaceURI && b.namespaceURI) {
Expand Down
7 changes: 6 additions & 1 deletion src/enveloped-signature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import type {
} from "./types";

export class EnvelopedSignature implements CanonicalizationOrTransformationAlgorithm {
includeComments = false;
protected includeComments = false;

constructor() {
this.includeComments = false;
}

process(node: Node, options: CanonicalizationOrTransformationAlgorithmProcessOptions): Node {
if (null == options.signatureNode) {
const signature = xpath.select1(
Expand Down
6 changes: 5 additions & 1 deletion src/exclusive-canonicalization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ function isPrefixInScope(prefixesInScope, prefix, namespaceURI) {
}

export class ExclusiveCanonicalization implements CanonicalizationOrTransformationAlgorithm {
includeComments = false;
protected includeComments = false;

constructor() {
this.includeComments = false;
}

attrCompare(a, b) {
if (!a.namespaceURI && b.namespaceURI) {
Expand Down
26 changes: 18 additions & 8 deletions src/signed-xml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@
/**
* Rules used to convert an XML document into its canonical form.
*/
canonicalizationAlgorithm: CanonicalizationAlgorithmType =
"http://www.w3.org/2001/10/xml-exc-c14n#";
canonicalizationAlgorithm?: CanonicalizationAlgorithmType = undefined;
/**
* It specifies a list of namespace prefixes that should be considered "inclusive" during the canonicalization process.
*/
Expand Down Expand Up @@ -140,7 +139,7 @@
this.privateKey = privateKey;
this.publicCert = publicCert;
this.signatureAlgorithm = signatureAlgorithm ?? this.signatureAlgorithm;
this.canonicalizationAlgorithm = canonicalizationAlgorithm ?? this.canonicalizationAlgorithm;
this.canonicalizationAlgorithm = canonicalizationAlgorithm;
if (typeof inclusiveNamespacesPrefixList === "string") {
this.inclusiveNamespacesPrefixList = inclusiveNamespacesPrefixList.split(" ");
} else if (utils.isArrayHasLength(inclusiveNamespacesPrefixList)) {
Expand Down Expand Up @@ -286,6 +285,9 @@
if (this.signatureNode == null) {
throw new Error("No signature found.");
}
if (typeof this.canonicalizationAlgorithm !== "string") {
throw new Error("Missing canonicalizationAlgorithm when trying to get signed info for XML");

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

View check run for this annotation

Codecov / codecov/patch

src/signed-xml.ts#L289

Added line #L289 was not covered by tests
}

const signedInfo = utils.findChildren(this.signatureNode, "SignedInfo");
if (signedInfo.length === 0) {
Expand All @@ -312,6 +314,7 @@
const c14nOptions = {
ancestorNamespaces: ancestorNamespaces,
};

return this.getCanonXml([this.canonicalizationAlgorithm], signedInfo[0], c14nOptions);
}

Expand Down Expand Up @@ -354,12 +357,14 @@
}

private findCanonicalizationAlgorithm(name: CanonicalizationOrTransformAlgorithmType) {
const algo = this.CanonicalizationAlgorithms[name];
if (algo) {
return new algo();
} else {
throw new Error(`canonicalization algorithm '${name}' is not supported`);
if (name != null) {
const algo = this.CanonicalizationAlgorithms[name];
if (algo) {
return new algo();
}
}

throw new Error(`canonicalization algorithm '${name}' is not supported`);

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

View check run for this annotation

Codecov / codecov/patch

src/signed-xml.ts#L367

Added line #L367 was not covered by tests
}

private findHashAlgorithm(name: HashAlgorithmType) {
Expand Down Expand Up @@ -1024,6 +1029,11 @@
*
*/
private createSignedInfo(doc, prefix) {
if (typeof this.canonicalizationAlgorithm !== "string") {
throw new Error(
"Missing canonicalizationAlgorithm when trying to create signed info for XML",
);
}
const transform = this.findCanonicalizationAlgorithm(this.canonicalizationAlgorithm);
const algo = this.findSignatureAlgorithm(this.signatureAlgorithm);
let currentPrefix;
Expand Down
2 changes: 0 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,6 @@ export interface CanonicalizationOrTransformationAlgorithm {
): Node | string;

getAlgorithmName(): CanonicalizationOrTransformAlgorithmType;

includeComments: boolean;
}

/** Implement this to create a new HashAlgorithm */
Expand Down
1 change: 1 addition & 0 deletions test/hmac-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ describe("HMAC tests", function () {
sig.privateKey = fs.readFileSync("./test/static/hmac.key");
sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#hmac-sha1";
sig.addReference({ xpath: "//*[local-name(.)='book']" });
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.computeSignature(xml);

const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml());
Expand Down
2 changes: 2 additions & 0 deletions test/key-info-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe("KeyInfo tests", function () {
const sig = new SignedXml();
sig.privateKey = fs.readFileSync("./test/static/client.pem");
sig.publicCert = fs.readFileSync("./test/static/client_public.pem");
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.computeSignature(xml);
const signedXml = sig.getSignedXml();
const doc = new xmldom.DOMParser().parseFromString(signedXml);
Expand All @@ -28,6 +29,7 @@ describe("KeyInfo tests", function () {
sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#hmac-sha1";
sig.enableHMAC();
sig.addReference({ xpath: "//*[local-name(.)='book']" });
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.computeSignature(xml);

const doc = new xmldom.DOMParser().parseFromString(sig.getSignedXml());
Expand Down
24 changes: 15 additions & 9 deletions test/signature-integration-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import { expect } from "chai";
import * as isDomNode from "@xmldom/is-dom-node";

describe("Signature integration tests", function () {
function verifySignature(xml, expected, xpath) {
function verifySignature(xml, expected, xpath, canonicalizationAlgorithm) {
const sig = new SignedXml();
sig.privateKey = fs.readFileSync("./test/static/client.pem");

xpath.map(function (n) {
sig.addReference({ xpath: n });
});

sig.canonicalizationAlgorithm = canonicalizationAlgorithm;
sig.computeSignature(xml);
const signed = sig.getSignedXml();

Expand All @@ -24,11 +25,12 @@ describe("Signature integration tests", function () {
it("verify signature", function () {
const xml =
'<root><x xmlns="ns"></x><y z_attr="value" a_attr1="foo"></y><z><ns:w ns:attr="value" xmlns:ns="myns"></ns:w></z></root>';
verifySignature(xml, "./test/static/integration/expectedVerify.xml", [
"//*[local-name(.)='x']",
"//*[local-name(.)='y']",
"//*[local-name(.)='w']",
]);
verifySignature(
xml,
"./test/static/integration/expectedVerify.xml",
["//*[local-name(.)='x']", "//*[local-name(.)='y']", "//*[local-name(.)='w']"],
"http://www.w3.org/2001/10/xml-exc-c14n#",
);
});

it("verify signature of complex element", function () {
Expand All @@ -43,9 +45,12 @@ describe("Signature integration tests", function () {
"</book>" +
"</library>";

verifySignature(xml, "./test/static/integration/expectedVerifyComplex.xml", [
"//*[local-name(.)='book']",
]);
verifySignature(
xml,
"./test/static/integration/expectedVerifyComplex.xml",
["//*[local-name(.)='book']"],
"http://www.w3.org/2001/10/xml-exc-c14n#",
);
});

it("empty URI reference should consider the whole document", function () {
Expand Down Expand Up @@ -168,6 +173,7 @@ describe("Signature integration tests", function () {
const sig = new SignedXml();
sig.addReference({ xpath: "//*[local-name(.)='book']" });
sig.privateKey = fs.readFileSync("./test/static/client.pem");
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.computeSignature(xml);

const signed = sig.getSignedXml();
Expand Down
Loading