CryptoSys Home > PKI > XML-DSIG and the Chile SII - Revisited 2020

XML-DSIG and the Chile SII - Revisited 2020


This page is a complete rewrite of the original page written in 2009. It takes a fresh look at using CryptoSys PKI Pro to sign EnvioDTE and EnvioBOLETA documents using the standards for electronic invoices set by the Servicio de Impuestos Internos (SII) of Chile ("Internal Revenue Service"). New2020-11-11: Added code for VBA/VB6 users. New2021-03-03: New Version 1.2 of source code.

We have new tools available since we first published our old page on the subject in 2009 (original 2009 page kept for historical reference). In particular, we can do all the canonicalization and cryptographic operations in memory and avoid using intermediate canonicalized files like we had to do before. These new tools include SC14N and xmlsq. See New tools since 2009.

This page includes the full working code, written in both C# and VBA, for a program to sign either of these documents. There is also a program to verify an existing signed document, and code to extract your X.509 certificate from the PFX/P12 file provided by your e-certificate issuer.

We emphasise that we have no connection whatsoever with the Chilean Servicio de Impuestos Internos, and this site is in no way endorsed by them.

Document Structure

We look at two XML document specifications here: EnvioDTE and EnvioBOLETA (see xsd references). For signing purposes, these can be considered the same. Their structure is almost identical, just a few different nodes and different allowable TipoDTE values. We'll refer to these generically as an Envio document. The overall structure is as follows.

<EnvioDTE> or <EnvioBOLETA>
  <SetDTE ID="...">
    <Caratula>
    (<DTE>)+
  <Signature>
</EnvioDTE>

<DTE>
  <Documento ID="...">
  <Signature>
</DTE>

<Documento>
  ...
  <TED version="1.0">
    <DD>
    <FRMT>
  </TED>
  ...
</Documento>

The outer Envio document contains a set of DTE documents, each of which is individually signed using XML-DSIG. Inside each DTE document is a special FRMT signature described below. The complete outer Envio document once assembled is then signed using XML-DSIG.

Signing Procedure

There are three parts to sign, which must be done in the correct order, working outwards.

  1. Each DTE document has an TED element signed using a special RSA private key. This is currently a small 512-bit key provided to you in an Autorizacion file, one for each TipoDTE (see below). The signature is computed over the DD element, which contains your 512-bit public key hardcoded as an RSAPK element. This FRMT signature value is computed using a different method (explained below) and is inserted in the FRMT element.
  2. Each DTE document is signed individually using XML-DSIG with a larger RSA signing key, currently 1024 bits, usually issued to you by an E-certificate provider. This signature is computed over the Documento element referenced by its ID attribute. It seems to be important that there are no xmlns attributes in the individual DTE document when it is signed. See the notes in the code.
  3. The combined Envio document is then signed using the same signing key as in (2). This signature is computed over the SetDTE element.

Code to process and sign an Envio document

The function MakeEnvio.ProcessEnvioDoc in the C# code module MakeEnvio.cs creates a complete signed Envio document ready for submission to SII. For VBA/VB6 users, the function ProcessEnvioDoc in the VBA module basMakeEnvio.bas does the same thing.

The function takes as input a set of one or more template DTE documents prepared by the user plus an outer template for the EnvioDTE or EnvioBOLETA document. Inside these templates are placeholders to be completed by the signing program. These are in the form @!...!@. The program also requires the user's private signing key file, its password, the user's X.509 certificate, and CAF private key.

The input parameters for MakeEnvio.ProcessEnvioDoc are:

outputxmlFile
Name of output file to create.
certFile
Signer's X.509 certificate file (.cer). Extracted from the PFX file as explained below.
keyFile
Signer's private key file (.pfx). The original PFX file issued by your E-Cert provider, or your private signing key in any other supported form.
password
Password for private key file ("" if unencrypted).
cafKeyFile
CAF private key file. Extracted from the Autorizacion file as described below.
outerTemplate
XML template for outer Envio document. See Outer template.
dtedocs
List of DTE XML documents to be signed (comma-separated list of filenames). See DTE templates.
If the program runs successfully, the output file specified in outputxmlFile will be created. This should be in the correct format to be submitted to the SII. As an extra check, use the VerifyDoc.VerifySignedEnvio function.

Example:

string envioDoc = MakeEnvio.ProcessEnvioDoc("output-enviodte.xml", // Output XML file to create
	"user.cer", // User's signing certificate
	"user.pfx", // User's private key file
	"password", // Password for private key file
	"caf33.key", // Private key for CAF
	"template-enviodte.xml", // Template for outer document, completed as necessary
	// (params) variable-length list of base DTE documents to be signed...
	"dte-33-1.xml", "dte-33-2.xml");
All the test files used here are available in the downloads below.

White space is important! Do not reformat or pretty-print your document after signing - it will invalidate the signatures. Note also that the signatures will be different each time you run the program even on the same base documents, because the timestamp changes each time.

Notes on the MakeEnvio code

Please refer to the comments in the code modules MakeEnvio.cs and basMakeEnvio.bas. Here are some of the main points.

The base template XML documents

Prepare an outer template XML document for your Envio document and separate individual DTE template documents, as shown below.

You fill in the specific details marked in green. The placeholders shown as @!...!@ will be completed by the program.

Outer template

<?xml version="1.0" encoding="ISO-8859-1"?>
<EnvioDTE xmlns="http://www.sii.cl/SiiDte" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://www.sii.cl/SiiDte EnvioDTE_v10.xsd" 
  version="1.0">
<SetDTE ID="SetDoc">
<Caratula version="1.0">
<RutEmisor>11111111-1</RutEmisor>
<RutEnvia>11111111-1</RutEnvia>
<RutReceptor>60803000-K</RutReceptor>
<FchResol>2020-07-31</FchResol>
<NroResol>0</NroResol>
<TmstFirmaEnv>@!TIMESTAMP!@</TmstFirmaEnv>
<SubTotDTE>
<TpoDTE>33</TpoDTE>
<NroDTE>@!NUM-DTE!@</NroDTE>
</SubTotDTE>
</Caratula>
<DTE>@!SET-OF-DTE!@</DTE>
</SetDTE>
<Signature>@!SIGNATURE!@</Signature>
</EnvioDTE>

DTE templates

Prepare a set of separate DTE template files for processing similar to the following. The CAF element marked in blue should be copied verbatim from your Autorizacion file.

<DTE version="1.0">
<Documento ID="Ejemplo_F72T33">
<Encabezado>
<IdDoc>
<TipoDTE>33</TipoDTE>
<Folio>72</Folio>
<FchEmis>@!FECHA!@</FchEmis>
</IdDoc>
<Emisor>
<RUTEmisor>11111111-1</RUTEmisor>
<RznSocEmisor>EJEMPLO S.A.</RznSocEmisor>
</Emisor>
<Receptor>
<RUTRecep>12345678-2</RUTRecep>
<RznSocRecep>Empresa A&amp;B el año 1999 Limitada</RznSocRecep>
</Receptor>
<Totales>
<MntTotal>100000</MntTotal>
<TasaIVA>19</TasaIVA>
<IVA>19000</IVA>
<MntTotal>119000</MntTotal>
</Totales>
</Encabezado>
<Detalle>
<NroLinDet>1</NroLinDet>
<CdgItem>
<TpoCodigo>INT1</TpoCodigo>
<VlrCodigo>011</VlrCodigo>
</CdgItem>
<NmbItem>Parlantes Multimedia 180W.</NmbItem>
<DscItem/>
<QtyItem>20</QtyItem>
<PrcItem>4500</PrcItem>
<MontoItem>90000</MontoItem>
</Detalle>
<Detalle>
...
</Detalle>
<TED version="1.0">
<DD>
<RE>11111111-1</RE>
<TD>33</TD>
<F>72</F>
<FE>@!FECHA!@</FE>
<RR>12345678-2</RR>
<RSR>Empresa A&amp;B el año 1999 Limitada</RSR>
<MNT>119000</MNT>
<IT1>Parlantes Multimedia 180W.</IT1>
<CAF version="1.0">
<DA>
<RE>11111111-1</RE>
<RS>EJEMPLO S.A.</RS>
<TD>33</TD>
<RNG><D>1</D><H>200</H></RNG>
<FA>2020-05-31</FA>
<RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK>
<IDK>100</IDK>
</DA>
<FRMA algoritmo="SHA1withRSA">s8jKW4d5E9NR/gaVkllgzJGwAQmtn35v0ZIQEO99pFITXLOmmX/M0TL2uLQZL/b4FYLj2uWZhG3AZ8TOjGs0WQ==</FRMA>
</CAF>
<TSTED>@!TIMESTAMP!@</TSTED>
</DD>
<FRMT algoritmo="SHA1withRSA">@!FRMT-SIG!@</FRMT>
</TED>
<TmstFirma>@!TIMESTAMP!@</TmstFirma>
</Documento>
<Signature>@!SIGNATURE!@</Signature>
</DTE>

The Documento ID must be unique for each DTE document in the set.

The example above contains a node with a couple of gotchas. The recipient's business name (RznSocRecep/RSR) is "Empresa A&B el año 1999 Limitada". This contains an ampersand symbol (&) which needs to be escaped in all your XML text files as A&amp;B. The company name also contains the non-ASCII character (ñ) which we need to treat carefully because of encoding issues.

The Signature template

The Signature template is hard-coded in the code. This is the same for both the inner DTE and outer Envio templates. If any of the algorithms change, you will need to change this template and the default algorithms in the source code.

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="#@!DOCID!@">
<Transforms>
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>@!DIGVAL!@</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>@!SIGVAL!@</SignatureValue>
<KeyInfo>
<KeyValue>
<RSAKeyValue><Modulus>@!RSA-MOD!@</Modulus><Exponent>@!RSA-EXP!@</Exponent></RSAKeyValue>
</KeyValue>
<X509Data>
<X509Certificate>@!CERTIFICATE!@</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>

If you wish, you can replace the placeholders @!CERTIFICATE!@, @!RSA-MOD!@ and @!RSA-EXP!@ with your specific base64 values.

Verifying the signed Envio document

Use the VerifyDoc.VerifySignedEnvio function in the C# code module VerifyDoc.cs.

string s = VerifyDoc.VerifySignedEnvio("F60T33-ejemplo.xml");
Console.WriteLine(s);
Debug.Assert("OK" == s, "VerifyDoc failed");

The Autorizacion file

You should have been provided with one or more AUTORIZACION files similar to the following, probably with a filename like FOLIOSSIIXXX.XML.

 1 <AUTORIZACION>
 2 <CAF version="1.0">
 3 <DA>
 4 <RE>11111111-1</RE>
 5 <RS>EJEMPLO S.A.</RS>
 6 <TD>33</TD>
 7 <RNG><D>1</D><H>200</H></RNG>
 8 <FA>2020-05-31</FA>
 9 <RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK>
10 <IDK>100</IDK>
11 </DA>
12 <FRMA algoritmo="SHA1withRSA">s8jKW4d5E9NR/gaVkllgzJGwAQmtn35v0ZIQEO99pFITXLOmmX/M0TL2uLQZL/b4FYLj2uWZhG3AZ8TOjGs0WQ==</FRMA>
13 </CAF>
14 <RSASK>
15 -----BEGIN RSA PRIVATE KEY-----
16 MIIBOwIBAAJBANGuDuim8fEI9yuIlkj+MOyp3mWHifoP6a4oWLSBKJSrd3MpEsZd
17 czvL0l7t/e0IU5rF+0gRLnU1Mfvtsw1wYWcCAQMCQQCLyV9FxKFLW09yWw7bVCCd
18 xpRDr7FRX/EexZB4VhsNxm/vtJfDZyYle0Lfy42LlcsXxPm1w6Q6NnjuW+AeBy67
19 AiEA7iMi5q5xjswqq+49RP55o//jqdZL/pC9rdnUKxsNRMMCIQDhaHdIctErN2hC
20 IP9knS3+9zra4R+5jSXOvI+3xVhWjQIhAJ7CF0R0S7SIHHKe04NUURf/7RvkMqm1
21 08k74sdnXi3XAiEAlkWk2vc2HM+a1sCqQxNz/098ketqe7NuidMKeoOQObMCIQCk
22 FAMS9IcPcMjk7zI2r/4EEW63PSXyN7MFAX7TYe25mw==
23 -----END RSA PRIVATE KEY-----
24 </RSASK>
25 <RSAPUBK>
26 -----BEGIN PUBLIC KEY-----
27 MFowDQYJKoZIhvcNAQEBBQADSQAwRgJBANGuDuim8fEI9yuIlkj+MOyp3mWHifoP
28 6a4oWLSBKJSrd3MpEsZdczvL0l7t/e0IU5rF+0gRLnU1Mfvtsw1wYWcCAQM=
29 -----END PUBLIC KEY-----
30 </RSAPUBK>
31 </AUTORIZACION>
Process this file as follows.
  1. The CAF element (lines 2-13) you copy verbatim into each DTE document (shown shaded blue in the DTE template).
  2. Copy the contents of the RSASK element (lines 15-23) into a separate text file - in our example we've named it caf33.key. This is the cafKeyFile argument to be passed to the program. The first line should begin with -----BEGIN RSA PRIVATE KEY----- with no leading spaces. This is an unencrypted private key used to create the FRMT signature element. Keep it secret.

Extracting your X.509 certficate

The program needs your signing X.509 certificate as a separate file (the certFile argument). This is included in your PFX file. To extract it, use the GetCertsFromPfx.GetCerts function in the C# code module GetCertsFromPfx.cs. VBA/VB6 users can use the GetCertsFromPFX function in the module basGetCertsFromPFX.bas.

GetCertsFromPfx.GetCerts("user.pfx", "password");

This function will extract all the X.509 certificates in your PFX file (there may be more than one). You want your individual .cer file, the one issued to you. Double-click on each CER file to see the details in Windows Certificate Manager.

Ejemplo certificate

The FRMT signature

The FRMT signature is computed in a different way to the XML-DSIG signatures. It's actually easier to do. You extract the <DD> element and "flatten" it. That is, remove all white space between the elements to form a one-line string. The FRMT signature is computed over this string using SHA1withRSA with your 512-bit "caf" private RSA key.

<DD><RE>11111111-1</RE><TD>33</TD><F>72</F><FE>2020-09-27</FE><RR>12345678-2</RR><RSR>Empresa A&amp;B el año 1999 Limitada</RSR><MNT>119000</MNT><IT1>Parlantes Multimedia 180W.</IT1><CAF version="1.0"><DA><RE>11111111-1</RE><RS>EJEMPLO S.A.</RS><TD>33</TD><RNG><D>1</D><H>200</H></RNG><FA>2020-05-31</FA><RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK><IDK>100</IDK></DA><FRMA algoritmo="SHA1withRSA">s8jKW4d5E9NR/gaVkllgzJGwAQmtn35v0ZIQEO99pFITXLOmmX/M0TL2uLQZL/b4FYLj2uWZhG3AZ8TOjGs0WQ==</FRMA></CAF><TSTED>2020-09-27T18:37:31</TSTED></DD>

To summarize the rules:

To compute the signature, given the base DTE XML document in the string xmlStr, we do the following.
// Use regex to extract the <DD> element.
Match match = Regex.Match(xmlStr, @"(<DD.*?</DD>)", RegexOptions.Singleline);
if (!match.Success) { 
    // Handle error...
}
ddelem = match.Value;
// Now flatten it - this is the input for the FRMT signature
ddelem = Regex.Replace(ddelem, @">\s+<", @"><");

// Convert to bytes in Latin-1 encoding
byte[] b = System.Text.Encoding.GetEncoding("iso-8859-1").GetBytes(ddelem);

// Compute FRMT signature in base64 over the flattened, Latin-1-encoded <DD> element
string frmtSig = Pki.Sig.SignData(b, sbCafKey.ToString(), "", Pki.SigAlgorithm.Rsa_Sha1);

Observant readers will notice that we can form a signature in two ways. We can use Sig.SignData and pass the data to be signed directly as a byte array (as we have done above). Alternatively, we can compute the digest value of the data to be signed and pass this value to Sig.SignDigest (we do this in the source code). Both ways work. Sometimes it's handy when debugging to check the digest value.

XSD files and references

These are the latest relevant XSD files we know of as at 1 October 2020: chilesii-xsd.zip (31 kB), with their SHA-1 digest values.

2017/12/12 18:18:10 GMT      233408 bytes DTE_v10.xsd              74460a0126cd2061521cc3c4d7ae8faabe573442
2020/09/03 09:02:38 GMT       53809 bytes EnvioBOLETA_v11.xsd      9e59658c1c5c1a14700c474cb720240272e24693
2011/05/27 14:38:06 GMT        4738 bytes EnvioDTE_v10.xsd         5de95b2d1d263e0e3c14491c89bdf196ea4077d3
2017/12/14 15:38:52 GMT       31096 bytes SiiTypes_v10.xsd         b69b473e6bc609634e692731d3d1f5762a7c7141
2017/07/02 01:18:22 GMT       10293 bytes xmldsignature_v10.xsd    6e61b4fb62b292090b796b17b25e8215bca8e187

Downloads and test files

Revisions

Version 1.2: Fixed MakeEnvio and VerifyDoc to cope with &apos; and &quot; entities in FRMT <DD> elements. The original code used Xpath in xmlsq to extract and flatten the DD element. Unfortunately Xpath converts XML entities &apos; and &quot; to literal characters, ' and " (which is normal behaviour for XML processors). So in the rare event that the DD element had text content with a quote or apostrophe in it, for example <RS>BERNADETTE O&apos;CONNOR</RS>, this change would invalidate the signature. The solution is to use a regex instead, as in the code above.

New tools available since 2009

New tools now available:

CryptoSys PKI Pro
CryptoSys PKI Pro has the added SIG functions and .NET Sig class to create the required base64 SignatureValue element directly given either the data to be signed or its digest value. No need to use the "Raw" RSA functions. The latest CryptoSys PKI Pro is available here.
SC14N, XML canonicalization
SC14N performs the canonicalization (C14N) transformations you need to do when creating signed XML documents using XML-DSIG. We use SC14N here to canonicalize the data we need directly from the XML document in memory. No need to create intermediate text files. SC14N is available here.
xmlsq, XML Simple Query
xmlsq is a simple lightweight utility to query XML documents using XPath 1.0. We use xmlsq here to extract values we need from the template XML documents. We use a simple template file and read in the values we need. xmlsq is free and available here.

Contact us

To contact us or comment on this page, please send us a message.

[Go to top]

This page last updated 15 November 2022