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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions