node.jsxml-crypto

Signed xml with xml-crypto node.js library produces an error


I'm use xml-crypto node.js package to sign xml. When I use signed xml document in saml 2.0 I am getting an error: org.opensaml.xmlsec.signature.support.SignatureException: Signature cryptographic validation not successful My metthod full code:

import { Injectable, Optional } from "@nestjs/common";
import { SignedXml } from "xml-crypto";
import * as p12 from "p12-pem";

  async getAuthRequest(): Promise<any> {
    const date = new Date();

    const xml = `<?xml version="1.0" encoding="utf-8" ?>
<saml2p:AuthnRequest Destination="${this.config.url}SingleSignOnService" AssertionConsumerServiceURL="https://url/artifactResolves" IssueInstant="${date.toISOString()}" Version="2.0" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:eidas="http://eidas.europa.eu/saml-extensions">
    <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://izzinakarte.pl</saml2:Issuer>
    <saml2p:NameIDPolicy  AllowCreate="true" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"/>
    <saml2p:RequestedAuthnContext Comparison="minimum">
        <saml2:AuthnContextClassRef xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://eidas.europa.eu/LoA/high</saml2:AuthnContextClassRef>
    </saml2p:RequestedAuthnContext>
</saml2p:AuthnRequest>`;

    const {pemKey, pemCertificate, commonName} = p12.getPemFromP12("certs/sign.p12", this.config.signPassword);

    const sign = new SignedXml();
    sign.addReference(
      "//*[local-name(.)='AuthnRequest']",
      [
        "http://www.w3.org/2000/09/xmldsig#enveloped-signature",
        "http://www.w3.org/2001/10/xml-exc-c14n#",
      ],
      "http://www.w3.org/2001/04/xmlenc#sha256"
    );
    sign.signingKey = pemKey
        .replace("-----BEGIN RSA PRIVATE KEY-----", "-----BEGIN RSA PRIVATE KEY-----\n")
        .replace("-----END RSA PRIVATE KEY-----", "\n-----END RSA PRIVATE KEY-----")

    // @ts-ignore
    sign.keyInfoProvider = new KeyInfoProvider(pemCertificate);
    sign.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
    sign.signatureAlgorithm =
      "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";

    sign.computeSignature(xml, {
      prefix: "ds",
      location: { reference: "//*[local-name(.)='Issuer']", action: "after" },
    });

    const signedXml = sign.getSignedXml().replace("Id=", "ID=");
    const buff = Buffer.from(signedXml);
    const base64data = buff.toString("base64");

    return base64data;
  }

Solution

  • Problem solved. I had to explicitly insert the identifier so that _0 would not be inserted.

    <saml2p:AuthnRequest ID="ID-${Guid.raw()}"