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

XADES-EPES Signature Example #54

Closed oliveryepez closed 5 years ago

oliveryepez commented 6 years ago

Hi a love this package!!! but I'm newbie on this stuff of digital signatures... Can guys give us an example of generate a XADES-EPES signature with xadesjs.

Thanks in advance for your colaboration

microshine commented 6 years ago

policies option is not implemented in current version of xadesjs https://github.com/PeculiarVentures/xadesjs/blob/master/index.d.ts#L24

But you can set you own values before Sign function calling

Here is example of signing XML document and adding XADES properties like SigningTime, SigningCertificate, SignerRole via options and SignaturePolicyIdentifier programmatically

//@ts-check

const asn1js = require("asn1js");
const pkijs = require("pkijs");
const xades = require("xadesjs");
const xmldsig = require("xmldsigjs");
const CryptoOSSL = require("node-webcrypto-ossl");
const crypto = new CryptoOSSL();

const commonName = "Test self-signed certificate";
const alg = {
    name: "RSASSA-PKCS1-v1_5",
    hash: { name: "SHA-256" },
    publicExponent: new Uint8Array([1, 0, 1]),
    modulusLength: 2048,
};

async function CreateCertificate(commonName, keys, alg) {
    // Generate new certificate
    const certificate = new pkijs.Certificate();

    certificate.version = 2;
    certificate.serialNumber = new asn1js.Integer({ value: 1 });
    certificate.issuer.typesAndValues.push(new pkijs.AttributeTypeAndValue({
        type: "2.5.4.6", // Country name
        value: new asn1js.PrintableString({ value: "EN" })
    }));
    certificate.issuer.typesAndValues.push(new pkijs.AttributeTypeAndValue({
        type: "2.5.4.3", // Common name
        value: new asn1js.BmpString({ value: commonName })
    }));
    certificate.subject.typesAndValues.push(new pkijs.AttributeTypeAndValue({
        type: "2.5.4.6", // Country name
        value: new asn1js.PrintableString({ value: "EN" })
    }));
    certificate.subject.typesAndValues.push(new pkijs.AttributeTypeAndValue({
        type: "2.5.4.3", // Common name
        value: new asn1js.BmpString({ value: commonName })
    }));

    certificate.notBefore.value = new Date();
    certificate.notAfter.value = new Date();
    certificate.notAfter.value.setFullYear(certificate.notAfter.value.getFullYear() + 1);

    certificate.extensions = []; // Extensions are not a part of certificate by default, it's an optional array
    await certificate.subjectPublicKeyInfo.importKey(keys.publicKey);
    await certificate.sign(keys.privateKey, alg.hash.name);

    // Convert certificate to DER
    const derCert = certificate.toSchema(true).toBER(false);
    // const pem = DerToPem(derCert, "CERTIFICATE");
    const pem = Buffer.from(derCert).toString("base64");
    console.log(pem);
    // import key to crypto
    return pem;
}

async function GenerateKeys(alg) {
    return await crypto.subtle.generateKey(alg, false, ["sign", "verify"]);
}

async function main() {
    // set crypto engine
    xades.Application.setEngine("OpenSSL", crypto);
    pkijs.setEngine("OpenSSL", crypto, new pkijs.CryptoEngine({ name: "OpenSSL", crypto, subtle: crypto.subtle }));

    const keys = await GenerateKeys(alg);
    const cert = await CreateCertificate(commonName, keys, alg);

    var xmlString = '<player bats="left" id="10012" throws="right">\n\t<!-- Here\'s a comment -->\n\t<name>Alfonso Soriano</name>\n\t<position>2B</position>\n\t<team>New York Yankees</team>\n</player>';
    var xmlDoc = xades.Parse(xmlString);
    const xml = new xades.SignedXml(xmlDoc);

    // If you need custom data you can add it manually
    xml.SignedProperties.SignedSignatureProperties.SignaturePolicyIdentifier.SignaturePolicyId.SigPolicyId.Identifier.Qualifier = "OIDAsURI";
    xml.SignedProperties.SignedSignatureProperties.SignaturePolicyIdentifier.SignaturePolicyId.SigPolicyId.Identifier.Value = "my.uti.oid";
    xml.SignedProperties.SignedSignatureProperties.SignaturePolicyIdentifier.SignaturePolicyId.SigPolicyHash.DigestMethod.Algorithm = "SHA-1";
    xml.SignedProperties.SignedSignatureProperties.SignaturePolicyIdentifier.SignaturePolicyId.SigPolicyHash.DigestValue = new Uint8Array(20);

    const signedXml = await xml.Sign(               // Signing document 
        alg,                              // algorithm  
        keys.privateKey,                        // key  
        xmlDoc,                                 // document 
        {                                       // options 
            keyValue: keys.publicKey,
            x509: [cert],
            signingCertificate: cert,
            references: [
                { hash: "SHA-256", transforms: ["enveloped"] }
            ],
            productionPlace: {
                country: "Country",
                state: "State",
                city: "City",
                code: "Code",
            },
            signerRole: {
                claimed: ["Some role"]
            }
        }
    );

    console.log(signedXml.toString());
}

main()
    .catch((err) => {
        console.log(err);
    })
oliveryepez commented 6 years ago

Hi @microshine thanks for your quick reponse, Damn! that was fast!!!... I got another question and I hope you can help me... I got and p12 crypto key and I need to sign and xml just the way you showed me on the last comment, but How can I import the cert and key pairs for do that?... I opened the crypto and it have at least 3 PEM certs.

Thanks in advance for your cooperation

Regards!

microshine commented 6 years ago

@oliveryepez You can use PKIjs for PKCS#12. Here is example of it https://pkijs.org/examples/PKCS12SimpleExample.html

rmhrisk commented 6 years ago

@oliveryepez see unmitigatedrisk.com/?p=543 for some details on PKCS#12 in the browser using PKIjs. We have since made some improvements that allow the use of the weaker cryptographic constructs but currently, it only works in Node where those algorithms are available.

oliveryepez commented 6 years ago

Thank you guys, for your responses, I'm compelled to use this type of keys @rmhrisk because is the key that I have for sign an xml with XADES-EPES signature, but I don't need to do this in browser, can be a simple js file running with node, this package was the only package that I found for do this type of signatures.

I follow you example @microshine but a think I do something wrong because I'm trying to parse the key like this.

    let file_buffered = fs.readFileSync(filepath);
    const password_buffered = pvutils.stringToArrayBuffer(password);
    const asn1 = asn1js.fromBER(file_buffered);
    const pkcs12 = new pkijs.PFX({schema: asn1.result});

And i got the following error (node:22078) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Object's schema was not verified against input data for PFX

What I'm doing wrong, I'm trying to get X509 Certificate and Public key for create XADES-EPES signature with xadesjs

Thank you for all your help guys

rmhrisk commented 6 years ago

@oliveryepez take a look at this example. https://github.com/PeculiarVentures/PKI.js/tree/master/examples/NodePKCS12Example

It will be easier to support PKIjs issues in the PKIjs repository.

Please post your final solution here for others but move discussions to PKCS#12/PFX support to that repository.

microshine commented 6 years ago

I think the problem is here

let file_buffered = fs.readFileSync(filepath);

ASN1js and PKIjs work with ArrayBuffer. fs.readFileSync returns Buffer. You need to convert Buffer to ArrayBuffer.

let file_buffered = new Uint8Array(fs.readFileSync(filepath)).buffer;

NOTE: You must be sure that PFX has DER format and you use BINARY Buffer, otherwise you must to convert PEB to DER

PEM to DER

https://support.quovadisglobal.com/kb/a37/what-is-pem-format.aspx

degaray commented 6 years ago

@oliveryepez Were you able to create a Xades-EPES signature? Can you post an example please?

jorgeacaballero commented 6 years ago

Hey @oliveryepez any updates on this? Could you figure out what you where looking for?

aazcast commented 6 years ago

Hi @oliveryepez, do you create Xades-EPES with this solution?

variux commented 6 years ago

@oliveryepez did you find a solution?

microshine commented 6 years ago

ETSI TS 101 903 V1.4.1

Open PDF

                                XMLDSIG
                                   |
<ds:Signature ID?>- - - - - - - - -+- - - - -+
  <ds:SignedInfo>                  |         |
    <ds:CanonicalizationMethod/>   |         |
    <ds:SignatureMethod/>          |         |
    (<ds:Reference URI? >          |         |
      (<ds:Transforms>)?           |         |
      <ds:DigestMethod/>           |         |
      <ds:DigestValue/>            |         |
    </ds:Reference>)+              |         |
  </ds:SignedInfo>                 |         |
  <ds:SignatureValue/>             |         |
  (<ds:KeyInfo>)?- - - - - - - - - +         |
                                             |
  <ds:Object>                                |
                                             |
    <QualifyingProperties>                   |
                                             |
      <SignedProperties>                     |
                                             |
                                             |
        <SignedSignatureProperties>          |
          (SigningTime)?                     |
          (SigningCertificate)?              |
          (SignaturePolicyIdentifier)        |
          (SignatureProductionPlace)?        |
          (SignerRole)?                      |
        </SignedSignatureProperties>         |
                                             |
        <SignedDataObjectProperties>         |
          (DataObjectFormat)*                |
          (CommitmentTypeIndication)*        |
          (AllDataObjectsTimeStamp)*         |
          (IndividualDataObjectsTimeStamp)*  |
        </SignedDataObjectProperties>        |
                                             |
      </SignedProperties>                    |
                                             |
      <UnsignedProperties>                   |
                                             |
        <UnsignedSignatureProperties>        |
          (CounterSignature)*                |
        </UnsignedSignatureProperties>       |
                                             |
      </UnsignedProperties>                  |
                                             |
    </QualifyingProperties>                  |
                                             |
  </ds:Object>                               |
                                             |
</ds:Signature>- - - - - - - - - - - - - - - +
                                             |
                                        XAdES-EPES 

xadesjs module allows has simple API to create Signature with a list of SignedSignatureProperties via Sign method with Options

You can find type definition for Options here

Create OpenSSL slef-signed certificate

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

XAdES EPES example

https://gist.github.com/microshine/f853759219452d4d397e38b972eaee78

Signed XML

<Test><Document attr="Hello"/><ds:Signature Id="id-62d6abd24e1c" 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:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>tg2dxbUKpoX43m9Unsu0gPiXIbJXtS54EZWpWznQigE=</ds:DigestValue></ds:Reference><ds:Reference URI="#xades-id-62d6abd24e1c" Type="http://uri.etsi.org/01903#SignedProperties"><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>oL93BXgu5sd730AZ7aGTHriHlDzcnLNUqWpeasWjz/w=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>ct4W+J8u9MUrRKgalGQtq7iH85gXiOVAl+Bk/Nj3jn29zQc1U7Mn5axf+tryLO34VpwQArf7lwY8H/TanepG2ya3c+4nCs/wZThnggh/IyZ14wJECYYP5bdQqelTu0asCTJPpomx5CcWNbadAKPKqZ0bzFA7Zjlzny7TFbTLHtZJ+sfVZPKI0ik1rdy8rHSZdAdx2sXoRGme7Iki7TNDPJO9/1pyTGoABWpyGA7eBKyN0kdHYaq1VcBCSbICMzxBZCmwOW+VgMRX5Mvwe7V/QOB2gjkYQmLuGeViBgaU1v9y7Qx3Ts8tJKono4uQSRQbSxJ+Fd6KBVL4gJudBlUZXp1Dfl+TCxujwqez4tY+T+JnztRCQE8tLrciuvMxUbpLfpyE1Co8TOEca9PCkNrYhx63z8aW8v8zMIHWp7hAEl7den2KokN7vYof0oaV5vfePCSFN0v1QwK5BM1m0lSO324IaH1QZl0z+81x8KVztNgl8vPrHR/gN0nYDZLmm+a7Ff6k1yBuTicdj26a5S/S20jGKqDnnnHbqlOw0ug90tYwup8SbfIrYZxe86EwAWGppJJrjetQurGVd8Fjh7JiZ4iFwHWK5YAuzDHyLTXuzopwVA3XcAcAfT0350MuVWdOlKzg1bMxsceX+wJkGNoYHXpBr4qMLfFn2rxpcS6q6eM=</ds:SignatureValue><ds:Object><xades:QualifyingProperties Target="#id-62d6abd24e1c" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#"><xades:SignedProperties Id="xades-id-62d6abd24e1c"><xades:SignedSignatureProperties><xades:SigningTime>2018-01-09T14:00:54.006Z</xades:SigningTime><xades:SigningCertificate><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>bu+t1r/OsLb0uLiKhFHDQvO/P2WlzLW1td48ji/qeM0=</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>C=RU, ST=Marj El, L=Yoshkar-Ola, O=PeculiarVentures, CN=microshine, E=microshine@mail.ru</ds:X509IssuerName><ds:X509SerialNumber>12630331543579879860</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert></xades:SigningCertificate><xades:SignaturePolicyIdentifier><xades:SignaturePolicyId><xades:SigPolicyId><xades:Identifier Qualifier="OIDAsURI">quilifier.uri</xades:Identifier></xades:SigPolicyId><xades:SigPolicyHash><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>Ilnj+FSn0X9MCRXFGIkHkMozR2P2rrS3UruywJVCBEg=</ds:DigestValue></xades:SigPolicyHash><xades:SigPolicyQualifiers><xades:SigPolicyQualifier><xades:SPUserNotice><xades:NoticeRef><xades:Organization>PeculiarVentures</xades:Organization><xades:IntegerList><xades:int>1</xades:int><xades:int>2</xades:int><xades:int>3</xades:int><xades:int>4</xades:int><xades:int>5</xades:int></xades:IntegerList></xades:NoticeRef></xades:SPUserNotice></xades:SigPolicyQualifier></xades:SigPolicyQualifiers></xades:SignaturePolicyId></xades:SignaturePolicyIdentifier><xades:SignatureProductionPlace><xades:City>Yoshkar-Ola</xades:City><xades:StateOrProvince>Marij El</xades:StateOrProvince><xades:PostalCode>424000</xades:PostalCode><xades:CountryName>Russia</xades:CountryName></xades:SignatureProductionPlace></xades:SignedSignatureProperties></xades:SignedProperties></xades:QualifyingProperties></ds:Object></ds:Signature></Test>

XMLSEC verification

xmlsec1 verify --pubkey-cert-pem cert.pem  sig.xml

output

OK
SignedInfo References (ok/all): 2/2
Manifests References (ok/all): 0/0
variux commented 6 years ago

Thank you @microshine the solution is working, for those who have a .p12 file first need to extract into two separated files.

Extract public and private key from pkcs12 file

After extracting your private key and cert you need to decrypt the private key for usage Then you need to delete the headers generated by that separations in public cert.

Decrypting a private key

Delete all before -----BEGIN CERTIFICATE-----

So in cert.pem in line 31, you need to put the cert without the header (step above) and in line 35 you need to put the Unencrypted RSA key

In my personal case I require some modifications to the @microshine gist, specifically on line 78 Replace:
xml.firstChild.appendChild(signature.GetXml());
With: xml.documentElement.appendChild(signature.GetXml());

NOTE: This is the first time that I work with p12 files, specifically with "Ministerio de Hacienda Costa Rica" digital sign so I don't know actually if those steps are required with other p12 files.

rmhrisk commented 6 years ago

@variux you can use PKCS#12 also, see - https://github.com/PeculiarVentures/PKI.js/blob/7b953ee08ee342d085328ec02152c087dae74917/examples/NodePKCS12Example/es6.js

variux commented 6 years ago

Thank you @rmhrisk I will try using PKI.js, will be useful for me!

variux commented 6 years ago

Hi @microshine when I use xmlsec1 command it returns me a "Invalid data: data and digest do not match" I think that is a wrong calculated digest but I don't know why, also I require the X509Data and isn't in my xml

rmhrisk commented 6 years ago

Did you edit the file after the signature was applied?

variux commented 6 years ago

No, It was not edited, I don't know if deleting the headers of cert.pem and key.pem could change the results, but I sign the document without the headers, also I wrote the string to an xml file, I don't know if its also affects

microshine commented 6 years ago

@variux For X509Data you need to add x509 option

const signature = await xadesXml.Sign(   // Signing document
        alg,                                    // algorithm
        key,                                    // key
        xml,                                    // document
        {                                       // options
            references: [
                { hash, transforms: ["c14n", "enveloped"] }
            ],
            x509: [x509],
            policy: {
microshine commented 6 years ago

@variux Could you share your signed xml and cert.pem? Email: microshine@mail.ru

variux commented 6 years ago

@microshine sure, thank you, has been sent, I added the x509 data

microshine commented 6 years ago

@variux could you sign xml one more time? Add console.log("Hash:\n%s\n", xml); before node_modules/xmldsigjs/dist/index.js:550

        return Promise.resolve().then(function () {
            var buf;
            if (typeof xml === "string") {
                console.log("Hash:\n%s\n", xml);
                buf = XmlCore.Convert.FromString(xml, "utf8");

Run your script Send me Hash log

variux commented 6 years ago

Sent to your email

microshine commented 6 years ago

@variux Do you have the lates version of xadesjs, xmldsigjs, and xml-core? Is see difference in xml canonicalization. I fixed some issues in xmldsigjs

Can you run npm update and sign again?

xadesjs@2.0.11
xmldsigjs@2.0.18
xml-core@1.0.12
variux commented 6 years ago

Yeah, I'm using the latest versions

https://gist.github.com/variux/8044b9ceb2896facd88d09241b12393b

This is my code if you want to check it

microshine commented 6 years ago

@variux thank you I'll do some tests tomorrow. It can be XML Canonicalization bug

variux commented 6 years ago

@microshine thanks to you for the help, I'll be waiting for your test

microshine commented 6 years ago

@variux I found problem. I need time to fix it. I'll notify you when it's done

variux commented 6 years ago

Thank you @microshine I'm gonna be waiting for that!

microshine commented 6 years ago

@variux I published new version of xmldsigjs@2.0.20 Can you check it?

variux commented 6 years ago

Thank you thank you thank you @microshine, that was really fast, it's working!

I have some questions, I need to established more nodes, that I didn't see at Options, specifically SignedDataObjectProperties, I can access them but by other ways but I don't know really how to configure them and set the DataCollectionItems

Also I need the modulus node, the exponent node

microshine commented 6 years ago

@variux You can use xadesjs API for it

Add this code before Sign method

const dataFormat = new xadesjs.xml.DataObjectFormat();
dataFormat.ObjectReference = "ojbRef";
dataFormat.Description = "description";
dataFormat.MimeType = "mime-type";
dataFormat.Encoding = "enc";

xadesXml.SignedProperties.SignedDataObjectProperties.DataObjectFormats.Add(dataFormat);

Output

xades:SignedDataObjectProperties><xades:DataObjectFormat ObjectReference="ojbRef"><xades:Description>description</xades:Description><xades:MimeType>mime-type</xades:MimeType><xades:Encoding>enc</xades:Encoding></xades:DataObjectFormat></xades:SignedDataObjectProperties>

Do you use xadesjs type definition? https://github.com/PeculiarVentures/xadesjs/blob/master/index.d.ts

microshine commented 6 years ago

If you need KeyValue in Signature you need to parse signing Certificate (PKIjs) and export public key from it. Then you can add public key to signing options like keyValue Example with keyValue

variux commented 6 years ago

Thank you @microshine, can the reference and keyinfo have and id and URI?

Examples:

<ds:Reference Id="xmldsig-5aa63746-c7f0-4627-a0c6-109043e3a003-ref0" URI="">

<ds:Reference URI="#xmldsig-5aa63746-c7f0-4627-a0c6-109043e3a003-keyinfo">

<ds:KeyInfo Id="xmldsig-5aa63746-c7f0-4627-a0c6-109043e3a003-keyinfo">

Here's an example that I need to follow and the why I'm looking for those options, this is signed with xades4j in Java

XML Example

microshine commented 6 years ago

Reference option supports id and uri https://github.com/PeculiarVentures/xmldsigjs/blob/master/index.d.ts#L971

image

But you cannot add Id for KeyInfo from options. You need to do it from script

microshine commented 6 years ago

Source code for KeyInfo adding https://github.com/PeculiarVentures/xmldsigjs/blob/master/src/signed_xml.ts#L494-L501

You just need to add

keyValue.Id = "xmldsig-5aa63746-c7f0-4627-a0c6-109043e3a003-keyinfo";

NOTE: all Signature objects modifications must be completed before Sign method

variux commented 6 years ago

Thank you @microshine for all the help given, my software is working now, last question, which IDE are you using?

microshine commented 6 years ago

VisualStudio Code

calvarezm70 commented 6 years ago

Hi @variux. I am also trying to sign an XML document with Xades-Epes according to the requirements established by the Ministry of Finance of Costa Rica.

When I send the signed file to the DGT, the document is rejected due to problems with the signature.

From the code in https://gist.github.com/variux/8044b9ceb2896facd88d09241b12393b I try to generate the signed XML, however I have a problem with the calculation of the digest.

When validating the XML in https://xadesjs.com/ I get the error "XMLJS0013: Cryptographic error: Invalid digest for uri ''. Calculated digest is a / F0 / Dnhn6EUANbmeyrzXy84sxR / Rr7aj7aQ9zvnliE = but the xml to validate supplies digest cft9G9yayijVVdg3ilM3sIYqu1l67IU / jl0isrrLwCM = ".

Could you share your final code after you applied the suggestions from @microshine and @rmhrisk?

These are the versions of the npm packages that I am working with:

xadesjs@2.0.11 xmldsigjs@2.0.20 xml-core@1.0.12

rmhrisk commented 6 years ago

@charlienux can you provide us a working and broken document based on the same origin document so we can help.

calvarezm70 commented 6 years ago

@rmhrisk Thank you very much for your help.

I attach a zip file with the documents. sign.zip

variux commented 6 years ago

Hi @charlienux some people are working on a complete SDK for Ministry of Finance in Costa Rica using this library, search at Facebook for crlibre.org

I didn't get any errors but when I sent to Ministry Of Finance they reject the document sign due to an incorrect reference.

This is what the technical personnel of Finance Ministry told me

"The reference to the data to sign is incorrectly referenced"

But I have been bussy and I have not had time to check what is.

rmhrisk commented 6 years ago

@microshine when you have time please take a look at @charlienux's samples

rmhrisk commented 6 years ago

@variux @charlienux you may want to show your Ministry Of Finance https://fortifyapp.com also

microshine commented 6 years ago

@charlienux I ran your JS script from ZIP and validated signed xml with xmlsec1 application. It has valid signature.

> xmlsec1 --verify signedDocument2.xml
OK
SignedInfo References (ok/all): 2/2
Manifests References (ok/all): 0/0

You have error on xadesjs.com because it had old JS library. I updated it image

microshine commented 6 years ago

I published new version v2.0.12. It has the latest working Web version

variux commented 6 years ago

Could someone help me with this

"The reference to the data to sign is incorrectly referenced"

I look at some signatures made by others languages and libraries use a "reference-id" I assume that this is what ministry of finance is telling me, but how to do that with xadesjs?

rmhrisk commented 6 years ago

@variux do you have an example document that they like?

calvarezm70 commented 6 years ago

Example of the signature label and its content:

example.zip

calvarezm70 commented 6 years ago

In example.zip I attach a file with the wrong name. Instead of signatureSchema.xsd, it must be invoiceSchema.xsd.

Now, I attach a pdf with the schema of the invoice and the signature. Invoice&SignatureSchema.pdf

Thank you in advance for your help.