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

Invalid signature when signing a SAML response #81

Open
markusahlstrand opened this issue Sep 9, 2024 · 0 comments
Open

Invalid signature when signing a SAML response #81

markusahlstrand opened this issue Sep 9, 2024 · 0 comments

Comments

@markusahlstrand
Copy link

I'm trying to migrate over from xml-crypto to xmldsigjs for our SAML service to get it running on Cloudflare Workers and it seems to almost be working, but for some reason the signature isn't valid.

For reference, this is the settings we're using with web-crypto:

    const xpath = "/*[local-name(.)='Response']/*[local-name(.)='Assertion']";
    const issuerXPath =
      '/*[local-name(.)="Issuer" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:assertion"]';

    const sig = new SignedXml({ privateKey, publicCert });
    sig.addReference({
      xpath,
      digestAlgorithm: 'http://www.w3.org/2000/09/xmldsig#sha1',
      transforms: ['http://www.w3.org/2001/10/xml-exc-c14n#'],
    });
    sig.canonicalizationAlgorithm = 'http://www.w3.org/2001/10/xml-exc-c14n#';
    sig.signatureAlgorithm = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
    sig.computeSignature(xmlContent, {
      location: { reference: xpath + issuerXPath, action: 'after' },
    });

    return sig.getSignedXml();

This is my attempt to do the same with xmldsigjs:

const xmlDoc = XmlDSigJs.Parse(xmlContent);

  const assertionNode = xmlDoc.getElementsByTagNameNS(
    "urn:oasis:names:tc:SAML:2.0:assertion",
    "Assertion",
  )[0];

  const assertionId = assertionNode.getAttribute("ID");

  const signedXml = new XmlDSigJs.SignedXml();    
  signedXml.XmlSignature.SignedInfo.CanonicalizationMethod.Algorithm =
    "http://www.w3.org/2001/10/xml-exc-c14n#";
  const signatureElement = await signedXml.Sign(
    { name: "RSASSA-PKCS1-v1_5" },
    privateKey,
    assertionNode,
    {
      x509: [importedCert.toString("base64")],
      references: [
        {
          hash: "SHA-1",
          transforms: ["enveloped", "exc-c14n"],
          uri: `#${assertionId}`,
        },
      ],
    },
  );
  
   // Import the signature element into the original document
  const importedSignatureNode = xmlDoc.importNode(signatureXml!, true);

  const issuerElement = assertionNode.getElementsByTagNameNS(
    "urn:oasis:names:tc:SAML:2.0:assertion",
    "Issuer",
  )[0];

  // Append the signature to the assertion
  assertionNode.insertBefore(
    importedSignatureNode,
    issuerElement.nextSibling,
  );
  
  return xmlDoc.toString();

There are a few things I'm uncertain about. First I'm getting a document not found error when trying to set the uri of the reference to #${assertionId}. I tried getting around this by doing the following, but get the feeling that I might be using the library the wrong way?

    const referenceElement = importedSignatureNode.getElementsByTagNameNS(
    "http://www.w3.org/2000/09/xmldsig#",
    "Reference",
  )[0];
  referenceElement.setAttribute("URI", `#${assertionId}`);

Another part I'm not sure about is the Canonicalization. Do I need to format the XML into the correct format before calling the Sign function?

Finally I'm not sure if the adding of the signature to the document is correct? It seems to generate a xml format that validates against the XSD but maybe this way of doing it isn't right?

Appreciating any pointers or ideas to get me on the right track!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant