PeculiarVentures / xadesjs

A pure Typescript/Javascript implementation of XAdES based on XMLDSIGjs. (Keywords: WebCrypto, XMLDSIG, XADES, eIDAS, Trust List, X.509, CRL, OCSP)
https://xadesjs.com
MIT License
141 stars 49 forks source link

Adding a reference to the KeyInfo element #86

Open Zephidel opened 5 years ago

Zephidel commented 5 years ago

Hello

I'm having a couple of problems right now and to be honest I don't know to solve them. I'm trying to sign an XML file and I'm still a bit new to this.

  1. The standard used for these xml files demands that on the KeyInfo element the only allowed value is the x509 certificate, ¿How can I make sure that xadesjs can create the KeyInfo element without the KeyValue element?.

  2. According to the standard established for this documents (Here in Colombia) it needs 3 references inside, I have 2 of them but I'm missing the third, a sha256 reference to the KeyInfo element (Algorithm = http://www.w3.org/2001/04/xmlenc#sha256).

Here is my sign method in NodeJs:

/**
 * @param {string} xmlString XML to sign
 * @param {string} certificate Base64 Certificate
 * @param {string} publicKeyPem Base64 PublicKey pem
 * @param {string} privateKeyPem Base64 PrivateKey pem
*/
const signXML = async (xmlString, certificate, publicKeyPem, privateKeyPem) => {
  try {
    const sha256 = "SHA-256";
    const algorithm = {
      name: "RSASSA-PKCS1-v1_5",
      hash: sha256,
      publicExponent: new Uint8Array([1, 0, 1]),
      modulusLength: 2048,
    }
    // Read cert
    // const certDer = Convert.FromBase64(certificate);

    // Read public key
    const publicKeyDer = Convert.FromBase64(privateKeyPem);
    const publicKey = await crypto.subtle.importKey("spki", publicKeyDer, algorithm, true, ["verify"]);

    // Read private key
    const keyDer = Convert.FromBase64(publicKeyPem);
    const key = await crypto.subtle.importKey("pkcs8", keyDer, algorithm, false, ["sign"]);

    // XAdES-EPES
    const xml = xades.Parse(xmlString);
    const xadesXml = new xades.SignedXml(xml);
    const x509 = certificate;
    const referenceId = "Signature-ddb543c7";

    // Set the policy values
    xadesXml.SignedProperties.SignedSignatureProperties.SignaturePolicyIdentifier.SignaturePolicyId.SigPolicyId.Identifier.Value = "https://facturaelectronica.dian.gov.co/politicadefirma/v1/politicadefirmav2.pdf";
    xadesXml.SignedProperties.SignedSignatureProperties.SignaturePolicyIdentifier.SignaturePolicyId.SigPolicyHash.DigestMethod.Algorithm = "http://www.w3.org/2001/04/xmlenc#sha256";
    xadesXml.SignedProperties.SignedSignatureProperties.SignaturePolicyIdentifier.SignaturePolicyId.SigPolicyHash.DigestValue = [116, 202, 12, 190, 215, 6, 229, 162, 51, 129, 138, 52, 180, 139, 18, 65, 229, 73, 4, 57, 212, 157, 244, 142, 124, 26, 113, 94, 185, 168, 175, 70];

    // Create signature
    const signature = await xadesXml.Sign(   // Signing document
      algorithm,                             // algorithm
      key,                                   // key
      xml,                                   // document
      {                                      // options
        keyValue: publicKey,
        references: [
          {
            id: "xmldsig-0e79b719-635c-476f-a59e-8ac3ba14365d-ref0",
            uri: "",
            hash: sha256,
            transforms: ["enveloped"]
          },
        ],
        signerRole: {
          claimed: ["Supplier"]
        },
        x509: [x509],
        signingCertificate: x509,
    });

    // add Id to Signature
    const signatureXml = signature.GetXml();
    signatureXml.setAttribute("Id", referenceId);

    const xmlElem = xml.getElementById(referenceId);

    if (!xmlElem) {
      throw new Error("Cannot get XML element by Id `Signature-ddb543c7-ea0c-4b00-95b9-d4bfa2b4e411`");
    }

    // append signature
    xmlElem.appendChild(signature.GetXml());

    // serialize XML
    const sXML = xmlCore.Stringify(xml);
    const signedXml = Buffer.from(sXML).toString().replace(" id=\"Signature-ddb543c7\"", "");//"base64");
    return signedXml;

  } catch (err) {
    throw err;
  }
}

(Based on the solution by Andres Castillo @aazcast)

microshine commented 5 years ago

xadesjs classes describe XML schema. You can change values without getElementById. For examples see apply functions