Skip to content

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

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;
  });
});

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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