Skip to content

[BUG] EnvelopedSignature transform fails when signature is nested in child elementΒ #525

@shunkica

Description

@shunkica

Description

The library produces invalid signatures when using the enveloped-signature transform with nested signature placement using location.

Reproduction

import { SignedXml } from "../src/index";
import { generateKeyPairSync } from "crypto";
import { expect } from "chai";
import * as xpath from "xpath";
import * as xmldom from "@xmldom/xmldom";
import * as isDomNode from "@xmldom/is-dom-node";

describe("EnvelopedSignature with nested signature location", function () {
  it("should verify signature when signature is nested in a child element", function () {
    // Generate keys
    const { privateKey, publicKey } = generateKeyPairSync("rsa", {
      modulusLength: 2048,
      publicKeyEncoding: { type: "spki", format: "pem" },
      privateKeyEncoding: { type: "pkcs8", format: "pem" },
    });

    const xml = "<root><SignatureInformation/></root>";

    // Sign
    const sig = new SignedXml();
    sig.privateKey = privateKey;

    sig.addReference({
      xpath: "/*",
      transforms: [
        "http://www.w3.org/2000/09/xmldsig#enveloped-signature",
        "http://www.w3.org/2001/10/xml-exc-c14n#",
      ],
      digestAlgorithm: "http://www.w3.org/2001/04/xmlenc#sha256",
    });

    sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
    sig.signatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";

    // Place signature inside SignatureInformation (not as direct child of root)
    sig.computeSignature(xml, {
      location: {
        action: "append",
        reference: "//*[local-name()='SignatureInformation']",
      },
    });

    const signedXml = sig.getSignedXml();

    // Verify
    const doc = new xmldom.DOMParser().parseFromString(signedXml);
    const signatureNode = xpath.select1(
      "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']",
      doc,
    );
    isDomNode.assertIsNodeLike(signatureNode);

    const verifier = new SignedXml();
    verifier.publicCert = publicKey;
    verifier.loadSignature(signatureNode);

    const result = verifier.checkSignature(signedXml);

    expect(result, "Signature verification should succeed").to.be.true;
  });
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions