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

Include UBL extension in my signed document #73

Open
jerojasol opened this issue Sep 6, 2018 · 7 comments
Open

Include UBL extension in my signed document #73

jerojasol opened this issue Sep 6, 2018 · 7 comments

Comments

@jerojasol
Copy link

Hi, I use xadesjs to generate signed documents, when I add the signature to the document like in the example xml.documentElement.appendChild(signature.GetXml());, the verify() function works fine and the signature is added in the root tag, for example:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <content>....</content>
  <ds:Signature Id="id-fea3a1cabb60">...</ds:Signature>
</root>

But my documents have UBL format so I need to include the signature in an UBL Extension tag, for example:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <ext:Extensions>
    <ext:Extension>
      <ext:Extensioncontent>
          <ds:Signature Id="id-fea3a1cabb60">...</ds:Signature>
      <ext:Extensioncontent>
    <ext:Extension>
  <ext:Extensions>
<content>....</content>
</root>

But when the signature is added in that way, the verify() function shows the next error message:

message: 'XMLJS0013: Cryptographic error: Invalid digest for uri '#xades-id-fea3a1cabb60'. Calculated digest is rZyuhWUmuiAHQLuQSX9tl8PEcPFrjcpJ2Iz2nwDKcZo= but the xml to validate supplies digest nIflO2RU6U8+d8Y+wrKAFTU9cE9pjcwbaFPp5879RxA='

It seems the original XML is modified and the digest is different. How can I add the signature in a UBL extension tag so that the verify() function works fine?

I really appreciate your help. Thanks in advance.

@microshine
Copy link
Contributor

microshine commented Sep 7, 2018

Example

// TypeScript
import OsslCrypto from "node-webcrypto-ossl";
import * as xades from "xadesjs";
import * as xmlCore from "xml-core";

const RSA_ALG: RsaHashedKeyGenParams = {
  name: "RSASSA-PKCS1-v1_5",
  hash: "SHA-256",
  publicExponent: new Uint8Array([1, 0, 1]),
  modulusLength: 2048,
}

const XML_DOC = `
<?xml version="1.0" encoding="utf-8"?>
<root>
  <ext:Extensions>
    <ext:Extension>
      <ext:Extensioncontent id="xades-signature">
      </ext:Extensioncontent>
    </ext:Extension>
  </ext:Extensions>
<content>....</content>
</root>
`

async function sign(xml: Document) {
  var signedXml = new xades.SignedXml();

  const crypto = xades.Application.crypto;
  const keys = await crypto.subtle.generateKey(RSA_ALG, false, ["sign", "verify"]);

  const signature = await signedXml.Sign(               // Signing document
    RSA_ALG,                                // algorithm
    keys.privateKey,                        // key
    xml,                                 // document
    {                                       // options
      keyValue: keys.publicKey,
      references: [
        { hash: "SHA-256", transforms: ["enveloped"] }
      ],
    });

  // add Id to Signature
  const signatureXml = signature.GetXml()!;
  signatureXml.setAttribute("Id", "xades-1234567890");

  // Add signature to document
  const xmlEl = xml.getElementById("xades-signature");
  if (!xmlEl) {
    throw new Error("Cannot get XML element by Id `xades-signature`");
  }
  xmlEl.appendChild(signature.GetXml()!);

  return xml;
}

async function verify(xml: Document) {
  var signedXml = new xades.SignedXml(xml);
  signedXml.LoadXml(xml.getElementsByTagName("ds:Signature")[0]);
  const ok = await signedXml.Verify();
  return ok;
}

async function main() {
  // Set crypto engine
  xades.Application.setEngine("OpenSSL", new OsslCrypto() as any);

  var xmlDoc = xades.Parse(XML_DOC);
  console.log(`--------------XML--------------\n${XML_DOC}\n--------------------------------\n`);

  const signedXml = await sign(xmlDoc);
  console.log(`----------XML Signature----------\n${xmlCore.Stringify(signedXml)}\n--------------------------------\n`);

  console.log("Signature:", (await verify(signedXml)) ? "Valid" : "Invalid");
}

main().catch((err) => { console.error(err); });

Output

--------------XML--------------

<?xml version="1.0" encoding="utf-8"?>
<root>
  <ext:Extensions>
    <ext:Extension>
      <ext:Extensioncontent id="xades-signature">
      </ext:Extensioncontent>
    </ext:Extension>
  </ext:Extensions>
<content>....</content>
</root>

--------------------------------

----------XML Signature----------

<?xml version="1.0" encoding="utf-8"?>
<root>
  <ext:Extensions xmlns:ext="">
    <ext:Extension>
      <ext:Extensioncontent id="xades-signature">
      <ds:Signature Id="xades-1234567890" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>PXl01v2DAwSB6Lp1BkIoG3yvstd0t5PMJM6Br/Wet3U=</ds:DigestValue></ds:Reference><ds:Reference URI="#xades-id-7c4875c4cd27" Type="http://uri.etsi.org/01903#SignedProperties"><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>VY0TSO976h5vzls+ppNf/RAU9AAXKth2aRmVPDoIrlc=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>YL5yiKCrAkB0O1CXn6eDJ7H7Cxyiq6cuiVPRQ+P9JLbkqzAlUQRl5x9b1hXZQ/mMGJ1vmGjhHUSrreH0CHoLv/APJE3EiOu0GjYyHxjSoLUM9yfX/CCtbKL/lvg22q/Yt1M7m5fYaK1T+63Cie6zDot7nKOeoxkDYl8PysD5XHpEEscn6/3jOLbt07vWpeXOW7eE0Gh1UIzHiC24FpPluZaa814fmbGRnMeMlNwP+bIS8kIKIqzDQatoaGGCWQRTQgzy5DCNjhih3PWGkiSwwTfec56ETsj+5Jju89LUo4nLHujXAbXTyErhKEzHj88mc3t18+HUZza2/zPhxWR+aw==</ds:SignatureValue><ds:KeyInfo><ds:KeyValue><ds:RSAKeyValue><ds:Modulus>x9KKOtI2hY6Qw3WJScwngTUuXXJmpRpTGqx2BJySpU5Q6Amtl4TgQK2YAiG6hNt621hA4bzhJ4wwxRUZpmuKRuNnnzXKYOIOpWqKjf6uQORlif3gGgy19aKmgXSD8qjXGvrU9i2cV8O67hABInjj6hOepADuztIVEebev0QUvw6pQnPN4QbwkeG6FveDVTQJoYDEs7tz93KtpUrjgwAhxCF2DjNTKAnv7HdUc/TqgqfL9wtI85c6JcV2SBCmVMplfF9XfTY3YetDA59EoOzXCi4Ss32TNg25ByanAUHjxb4M7+CXig9gcmV29KKwhJBuMu/RGNa3x2Q0vFXW1NVObw==</ds:Modulus><ds:Exponent>AQAB</ds:Exponent></ds:RSAKeyValue></ds:KeyValue></ds:KeyInfo><ds:Object><xades:QualifyingProperties Target="#id-7c4875c4cd27" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#"><xades:SignedProperties Id="xades-id-7c4875c4cd27"><xades:SignedSignatureProperties><xades:SigningTime>2018-09-07T05:41:15.265Z</xades:SigningTime><xades:SignaturePolicyIdentifier><xades:SignaturePolicyImplied/></xades:SignaturePolicyIdentifier></xades:SignedSignatureProperties></xades:SignedProperties></xades:QualifyingProperties></ds:Object></ds:Signature></ext:Extensioncontent>
    </ext:Extension>
  </ext:Extensions>
<content>....</content>
</root>
--------------------------------

Signature: Valid

@gponceleon
Copy link

Hello @microshine, sorry bother, but I cand add this xsd: xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#
in the QualifyingProperties, I have tried in the core code, but the sign fails.
Thanks

@microshine
Copy link
Contributor

You can add this code after Id adding to Signature

const props = signatureXml.getElementsByTagName("xades:QualifyingProperties");
props[0].setAttribute("xmlns:xades141","http://uri.etsi.org/01903/v1.4.1#");

@gponceleon
Copy link

After this line? signedXml.XmlSignature.KeyInfo.Id = keyInfoId;

@microshine
Copy link
Contributor

After

// add Id to Signature
const signatureXml = signature.GetXml()!;
signatureXml.setAttribute("Id", "xades-1234567890");

@gponceleon
Copy link

I already placed it after the signature, but it gets damaged. There is no way to place it before the signature in the CreateQualifyingProperties method?

@microshine
Copy link
Contributor

image

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

3 participants