XML-Dsig and the Chile SII

In this page we look at creating digital signatures in XML documents (XML-Dsig) using the standards for electronic invoices set by the Servicio de Impuestos Internos (SII) of Chile ("Internal Revenue Service"). We show how you could use our CryptoSys PKI Toolkit to do the cryptographic operations to sign, read and verify the necessary files, and we give some hints on how to do the [expletive deleted] canonicalization.

New New 2013-09-04: Added VB6 and C# code to create the signatureValue using a test RSA encrypted key. See Even More Code below.

Contents

Introduction

This is a long, complicated document; not for the faint-hearted. It is partly a "how-to" instruction set to carry out the cryptography operations for a Chilean SII XML invoice. It is partly a critique of the XML-Dsig standard, and partly a blatant plug for our own cryptographic product CryptoSys PKI Toolkit. We have a simpler page How to create a digital signature in XML and another example on Accented characters and UTF-8 in XML-DSIG signatures.

Our two main reference documents from the Chile SII are Instructivo Técnico Factura Electrónica , 08/09/2004 (instructivo_emision.pdf, 176 kB) [SII-INSTR-2004] and Manual Para Empresas Usuarias Ambiente De Certificación Factura Electronica , 26 November 2003, [SII-MANUAL-20033]. The originals of these documents were last accessed on the SII web site in January 2009. See the References at the end of this page for links.

To illustrate our workings, we will use their sample file F60T33-ejemplo.xml dated 13 October 2003 (zipped, 4 kB). The SII original was last accessed January 2009 at:
http://www.sii.cl/factura_electronica/ejemplo_xml.zip.

We show here how you can verify the two XML digital signatures in the example SII XML document, and how you can use the private key provided on page 25 of the manual [SII-MANUAL-20033] to re-create the FRMT signature. We also show what we believe is an error in the October 2003 version of the sample XML document, where the X.509 certificate does not match the public key value given.

Note that we do not show how to format the final XML document (adding line-breaks every 76 characters for the sello and certificado fields, correct xsi references, and the like). It's up to you to format the final XML document properly as per SII requirements. We just look at the cryptography issues.

There is a new version of Instructivo Técnico Factura Electrónica issued 15 October 2009. This page does not incorporate changes made in that document.

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.

And we do not speak Spanish very well. In fact, not at all. Sorry. No hablamos español. Nos disculpamos. We understand enough to figure out technical documents (with lots of help from Google Translate).

The Code

The full set of VB6 code used on this page is available here (zipped, 11 kB). No warranties. Use at your own risk, etc. This VB6 code can be easily be adapted to work in VB.NET, C# or C++ instead. The .NET code is more concise.

New July 2010: Here is the code converted to VB.NET (VB200x) (TestChile.vb.zip, 14 kB) and the same code in C Sharp (TestChile.cs.zip, 15kB). The zipped files include the test file data.canon.ok.txt. Note that these .NET programs are meant to be compiled as "Console" programs.

New September 2013: See Even More Code below for VB6 and C# code to create a signatureValue using a test private key.

You can download a fully-functional trial verson of CryptoSys PKI to carry out these tests yourself.

The code carries out a lot of complicated tests that demonstrate that certain values are equal when extracted from the XML document or derived in other ways. The point is that you have to do this with the data that is exactly correct or it will fail. If you can make it work just once, you are almost certainly doing it correctly. You need to have a good understanding of the mechanics of public key signatures and message digest hashes to make sense of this. If you can figure out what the code is doing, you should be able to adapt it to make your own Chile-SII-Invoicing-compatible software.

Please note that we do not have access to the SII validation service, so what you see on this page is everything we know about the process. We know that some people have successfully used CryptoSys PKI to create applications that work, so it can be done. But it's up to the user to work out the details.

We'll happily answer quick questions on this topic. See the contact details at the bottom of the page. If you want more detailed work or programming carried out, we offer consulting services in cryptography.

The Process

The final invoice is an XML document signed multiple times. The process of signing an XML document, or a fragment of such a document, is tricky. Signing XML documents is fraught with problems because of the underlying design of XML digital signatures.

The theory of XML digital signatures is explained in RFC 3275: XML-Signature Syntax and Processing [XML-DSIG]. The ghastly principles of canonicalizing XML before signing is in RFC 3076: Canonical XML Version 1.0 [XML-C14N]. To make you feel better when trying to implement this stuff, an alternative view on the topic is in Peter Gutmann's Why XML Security is Broken. That said, we show how we managed to do it.

For an SII invoice, there are multiple layers that need to be signed, and different methods are used for different layers.

There are three signatures to be created or verified. In each case we need to

  1. isolate the data we need to sign from the original XML file
  2. canonicalize this data - that is, format it in a specific way so we always get the same result. This is very tricky for XML!
  3. create a message digest of the canonicalized data
  4. create or verify a digital signature of this digest

The Layers

Let's break down the structure of the final SII XML document into four layers.

Outer XML layer
<?xml version="1.0" encoding="ISO-8859-1"?>
<EnvioDTE xmlns="http://www.sii.cl/SiiDte" ... version="1.0">
  <SetDTE ID="SetDoc">...</SetDTE>
  <Signature>...</Signature>
</EnvioDTE>
Inner XML layer
<DTE version="1.0">
  <Documento ID="F60T33">...</Documento>
  <Signature>...</Signature>
</DTE>
FRMT
<TED version="1.0">
  <DD>...</DD>
  <FRMT algoritmo="SHA1withRSA">...</FRMT>
</TED>
FRMA
<CAF version="1.0">
  <DA>...</DA>
  <FRMA algoritmo="SHA1withRSA">...</FRMA>
</CAF>

In each case we have an enveloping element that includes two sub-elements: the data-to-be-signed and a signature.

FRMA

At the inner-most layer, we have the FRMA signature of a <DA> element enclosed inside a <CAF> element. As far as we know, this is provided by the SII and you need to include the whole thing in your XML document. You can effectively treat it as a "blob" of characters to include in the final document. Since first publishing this page, we have obtained the certificate used by the signer of this data and we show how to use that certificate to verify the signature.

First we compute the SHA-1 digest of the "flattened" <DA> element, using the rules explained further below for FRMT. The input to the digest function is the string:

<DA><RE>97975000-5</RE><RS>RUT DE PRUEBA</RS><TD>33</TD><RNG><D>1</D><H>200</H></RNG><FA>2003-09-04</FA><RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK><IDK>100</IDK></DA>

The SHA-1 message digest of this string is (0x)9A2115CC03E05F99A996FBCE47C4554905D75D1D or miEVzAPgX5mplvvOR8RVSQXXXR0= in base64 format.

We extract the 512-bit RSA public key from the X.509 certificate of the signer

-----BEGIN CERTIFICATE-----
MIICTzCCAfmgAwIBAwIBZDANBgkqhkiG9w0BAQQFADCBrzELMAkGA1UEBhMCQ0wx
CzAJBgNVBAgTAkNTMQswCQYDVQQHEwJDczEnMCUGA1UEChMeU2VydmljaW8gZGUg
SW1wdWVzdG9zIEludGVybm9zMRkwFwYDVQQLExBPZmljaW5hIEludGVybmV0MScw
JQYDVQQDEx5TZXJ2aWNpbyBkZSBJbXB1ZXN0b3MgSW50ZXJub3MxGTAXBgkqhkiG
9w0BCQEWCnNpaUBzaWkuY2wwHhcNMDMwNDI5MjAxNDA1WhcNMDQwNDIzMjAxNDA1
WjCBrzELMAkGA1UEBhMCQ0wxCzAJBgNVBAgTAkNTMQswCQYDVQQHEwJDczEnMCUG
A1UEChMeU2VydmljaW8gZGUgSW1wdWVzdG9zIEludGVybm9zMRkwFwYDVQQLExBP
ZmljaW5hIEludGVybmV0MScwJQYDVQQDEx5TZXJ2aWNpbyBkZSBJbXB1ZXN0b3Mg
SW50ZXJub3MxGTAXBgkqhkiG9w0BCQEWCnNpaUBzaWkuY2wwXDANBgkqhkiG9w0B
AQEFAANLADBIAkEAyPvwDcshpVAApYVSLF3lKKc+DOFswDqx5ep95LKigRHjUvrv
jct9UeNJq9SxBdzU9nz54TEVBYyfAVQpG4xxUwIDAQABMA0GCSqGSIb3DQEBBAUA
A0EADvJX1C7hUFD2Eq9jNZpeJ/YBOZx1SBmAHSeXud6fTw98+AR4X3YDmzO9D4Kd
hEFi3NK4anpjiPOKbA8fBWyyBA==
-----END CERTIFICATE-----

This public key, in XML RSAKeyValue form, is

<RSAKeyValue>
  <Modulus>yPvwDcshpVAApYVSLF3lKKc+DOFswDqx5ep95LKigRHjUvrvjct9UeNJq9SxBdzU9nz54TEVBYyfAVQpG4xxUw==</Modulus>
  <Exponent>AQAB</Exponent>
</RSAKeyValue>

Then we use this public key to decrypt the signature value

<FRMA algoritmo="SHA1withRSA">g1AQX0sy8NJugX52k2hTJEZAE9Cuul6pqYBdFxj1N17umW7zG/hAavCALKByHzdYAfZ3LhGTXCai5zNxOo4lDQ==</FRMA>

and we obtain the message digest value: 9a2115cc03e05f99a996fbce47c4554905d75d1d which matches exactly the value we obtained by computing the digest independently. Thus we have verified the signature.

Apparently there are two certificates issued by the SII to sign the FRMA element: 100.cer and 300.cer. The number matches the IDK number in the <DA> element and is also the serial number of the certificate. We are told that the 100 certificate is used for testing and the 300 certificate for production.

FRMT

At the next level up, we have the FRMT signature. Note that this is not an XML-Dsig signature. It is created by computing the SHA-1 digest of the "flattened" <DD> element. We remove all the white-space between all the elements inside the <DD> element to form a string and then signing the digest using an RSA private key. The string is

<DD><RE>97975000-5</RE><TD>33</TD><F>60</F><FE>2003-10-13</FE><RR>77777777-7</RR><RSR>EMPRESA  LTDA</RSR><MNT>119000</MNT><IT1>Parlantes Multimedia 180W.</IT1><CAF version="1.0"><DA><RE>97975000-5</RE><RS>RUT DE PRUEBA</RS><TD>33</TD><RNG><D>1</D><H>200</H></RNG><FA>2003-09-04</FA><RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK><IDK>100</IDK></DA><FRMA algoritmo="SHA1withRSA">g1AQX0sy8NJugX52k2hTJEZAE9Cuul6pqYBdFxj1N17umW7zG/hAavCALKByHzdYAfZ3LhGTXCai5zNxOo4lDQ==</FRMA></CAF><TSTED>2003-10-13T09:33:20</TSTED></DD>

The first character of this string is a '<' character, and the last is a '>'. To summarize the rules:

In this example, there are no "predefined entities" or accented characters to deal with. Here is a zipped file of the exact 592 bytes that must be input to the SHA-1 hash function; and the same data in hexdump format.

The SHA-1 message digest of this string is (0x)35F9C699D6A2911CA05205570DD2CE753B881AC8 or NfnGmdaikRygUgVXDdLOdTuIGsg= in base64 format.

This is signed with the RSA key. In this case, we have the private key, provided in [SII-MANUAL-2003] in PEM format:

-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBANGuDuim8fEI9yuIlkj+MOyp3mWHifoP6a4oWLSBKJSrd3MpEsZd
czvL0l7t/e0IU5rF+0gRLnU1Mfvtsw1wYWcCAQMCQQCLyV9FxKFLW09yWw7bVCCd
xpRDr7FRX/EexZB4VhsNxm/vtJfDZyYle0Lfy42LlcsXxPm1w6Q6NnjuW+AeBy67
AiEA7iMi5q5xjswqq+49RP55o//jqdZL/pC9rdnUKxsNRMMCIQDhaHdIctErN2hC
IP9knS3+9zra4R+5jSXOvI+3xVhWjQIhAJ7CF0R0S7SIHHKe04NUURf/7RvkMqm1
08k74sdnXi3XAiEAlkWk2vc2HM+a1sCqQxNz/098ketqe7NuidMKeoOQObMCIQCk
FAMS9IcPcMjk7zI2r/4EEW63PSXyN7MFAX7TYe25mw==
-----END RSA PRIVATE KEY-----

We can use this RSA private key to sign the flattened <DD> data above, using the SHA1withRSA algorithm. The input in hex format to the RSA private key encryption function, encoded for PKCS#1 V1.5, is

0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003021300906052B0E03021A0500041435F9C699D6A2911CA05205570DD2CE753B881AC8

The resulting signature value in hexadecimal and base64 format, respectively, is:

19B983712F5EFE3542D8BB0B21ED62455D7605FEA5C6C20BB5B4220A487A99B8DC905089EDF8FF91A9054D2D3A268F224B81D7BC98F7A1866E7B2E772AB9E27B
GbmDcS9e/jVC2LsLIe1iRV12Bf6lxsILtbQiCkh6mbjckFCJ7fj/kakFTS06Jo8iS4HXvJj3oYZuey53Krniew==

Some VB6 Code

Here are some procedures in the VB6 Code. There are more references below.

Creating an XML digital signature

First, a useful outline from the theory in [XML-DSIG].

XML digital signatures are represented by the Signature element which has the following structure (where "?" denotes zero or one occurrence; "+" denotes one or more occurrences; and "*" denotes zero or more occurrences):
<Signature ID?>
   <SignedInfo>
     <CanonicalizationMethod/>
     <SignatureMethod/>
     (<Reference URI? >
       (<Transforms>)?
       <DigestMethod>
       <DigestValue>
     </Reference>)+
   </SignedInfo>
   <SignatureValue>
  (<KeyInfo>)?
  (<Object ID?>)*
</Signature>

Hint: There is not an <Object> element in this case. Search in the sample XML document for <Reference URI="#XXXX"> and then see which element is called "XXXX".

Creating an XML digital signature is a two-part process.

  1. Compose the data-to-be-signed in canonicalized form and compute its message digest value.
  2. Include this message digest value (in the clear) in a canonicalized <SignedInfo> element and then sign that element to produce the final signature value.

To create a signature

  1. Compute the message digest value of the canonicalized data-to-be-signed.
  2. Compose a <SignedInfo> XML fragment, in canonicalized form, which contains the message digest value from step 1.
  3. Compute the message digest of the canonicalized <SignedInfo> element.
  4. Sign this message digest using your private key to produce a signature value.

Steps 3 and 4 could be combined into one operation, depending on the features offered in your cryptography toolkit.

To verify a signature

  1. Extract and canonicalize the data-to-be-signed from the XML document.
  2. Compute the message digest of the canonicalized data-to-be-signed.
  3. If the message digest value encapsulated in the <SignedInfo> element does not match the value obtained in the previous step, indicate failure and stop.
  4. Canonicalize the <SignedInfo> element from the signed XML document.
  5. Compute the message digest of the canonicalized <SignedInfo> element.
  6. Recover the message digest value from the signature value using the public key contained in the document (or provided to you separately).
  7. If these two message digests do not match, indicate failure and stop.

If you fail to reproduce the canonicalized data in steps 1 and 4 in exactly the same way as they were done in the signing process, the signature will show as invalid. And when we say exactly, we mean exactly, byte-for-byte, bit-for-bit. Needless to say, this canonicalization process is the hardest part to get right.

The trendy short term for canonicalization is C14N, which is meant to indicate that there are 14 characters between the "C" and the "N". A better word might be B-I-T-C-H.

The XML signatures in an SII invoice

We show here how we verify the two XML-Dsig signatures in the example SII XML document. We do not have the private keys used to create the signatures.

The hard part is to canonicalize the data. We did this off-line to create text files containing the canonicalized text. We found the -c14n option of the XMLStarlet Command Line XML Toolkit utility most useful for this. We still had to experiment with the attributes for the parent element and we had problems creating and keeping a "Unix-style" file in Windows.

Here is a zip file (23 kB) containing the original text, the canonicalized text and a hexdump of the c14n'd text for the two sets of data to be signed. If you compute the SHA-1 message digest of the "-canon.unix.txt" files, you should get the exact values used in the XML document.

Canonicalizing the SII elements

The important bits:

Now get just one byte wrong in the above set of rules, and you will get the wrong signature. There are lots of other gotchas, too. If you can truly claim that you understand the [XML-C14N] reference, you have our respect. We have to admit that we initially just experimented with alternatives until we stumbled across the correct input to get the required SHA-1 message digest value in the examples. We then assume that if it works once, it will work everytime. (We also assume that the people who made the example got it right themselves; not necessarily a valid assumption. But, hey, if they are validating your input, who are you to complain?)

Inner XML layer

In the "inner" layer, the data-to-be-signed (and verified) is the <Documento> element. Here are the original element fragment and the canonicalized version as text files. The 2781 exact bytes we require as input to the hash function are shown in this hexdump. The SHA-1 message digest of the canonicalized data is (0x)865990B6EFC0CA35234C384CDFCE76C2F442AFCC or hlmQtu/AyjUjTDhM3852wvRCr8w= in base64 format. You can see the base64 form as a <DigestValue> in clear text in the XML document.

The canonicalized <SignedInfo> for this is

<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
<Reference URI="#F60T33">
<Transforms>
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></Transform>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
<DigestValue>hlmQtu/AyjUjTDhM3852wvRCr8w=</DigestValue>
</Reference>
</SignedInfo>

The SHA-1 message digest of this is (0x)353CABFE369AAD9BEA21F5FA06CB367960FFB7D4. The PKCS#1v1.5-encoded input to the RSA encryption function is

0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003021300906052B0E03021A05000414353CABFE369AAD9BEA21F5FA06CB367960FFB7D4

The resulting signature value in hexadecimal and base64 format, respectively, is the 1024 bits or 128 bytes:

246D48834A6F4881FCE6420A1916548E4C97E8235A634F18F788F851E8138037BCFB097AD46CEA8DD475ADF38AF411A7F7700C3A8E9A880828956D24FD7925355B4CFD9CE934D4B777F7D855AD6AE74F6600C4976DE97148CDDB8E86BB1FA5B377F995D4FA50F332B9830EE680C30FE082B11F24BDD86F3518482E4A6CDC4260
JG1Ig0pvSIH85kIKGRZUjkyX6CNaY08Y94j4UegTgDe8+wl61GzqjdR1rfOK9BGn93AMOo6aiAgolW0k/XklNVtM/ZzpNNS3d/fYVa1q509mAMSXbelxSM3bjoa7H6Wzd/mV1PpQ8zK5gw7mgMMP4IKxHyS92G81GEguSmzcQmA=

Outer XML layer

In the "outer" layer, the data-to-be-signed (and verified) is the <SetDTE> element. Here are the original element fragment and the canonicalized version as text files. The 5971 exact bytes we require as input to the hash function are shown in this hexdump. The SHA-1 message digest of the canonicalized data is (0x)E0E4D65F2465E5FC3786D8D3C995D0B5812C0B71 or 4OTWXyRl5fw3htjTyZXQtYEsC3E= in base64 format. Again, you can see this <DigestValue> in clear text in the XML document.

The canonicalized <SignedInfo> for this is

<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
<Reference URI="#SetDoc">
<Transforms>
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></Transform>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
<DigestValue>4OTWXyRl5fw3htjTyZXQtYEsC3E=</DigestValue>
</Reference>
</SignedInfo>

The SHA-1 message digest of this is (0x)98B466FFE6A5E73B85962BC7300841C5F1693D3A. The PKCS#1v1.5-encoded input to the RSA encryption function is

0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003021300906052B0E03021A0500041498B466FFE6A5E73B85962BC7300841C5F1693D3A

The resulting signature value in hexadecimal and base64 format, respectively, is the 1024 bits or 128 bytes:

B019EBF18AB5E2F54072B37FA4A2C3FC1AEA50573328C5B7CB5B7724EADDB31861ABA231BD2D774A0C8C5DB20DFD3F5C89168580D69BB37A62EF7D9785CA5E892983D64B736D172D11B488B33624149638F64D1E07E4D5CEADDE55A42BE0836BCA67EE3A75A3EFC0597302AE5EF0F2E2201CC7AFD305B00090F17030FF6A976B
sBnr8Yq14vVAcrN/pKLD/BrqUFczKMW3y1t3JOrdsxhhq6IxvS13SgyMXbIN/T9ciRaFgNabs3pi732XhcpeiSmD1ktzbRctEbSIszYkFJY49k0eB+TVzq3eVaQr4INrymfuOnWj78BZcwKuXvDy4iAcx6/TBbAAkPFwMP9ql2s=

OK, got it? Test on Monday.

More VB6 Code

You will have to figure out how this code works. But it should be sufficient to reproduce the values shown on this page. See also VB6 Code above.

Even More Code

New New 2013-09-04: We have added some code in both VB6 and C# that shows how to create the signatureValue of the SignedInfo element. We don't have the original private keys used in the SII examples, so we've used a test 1024-bit RSA private key AlicePrivRSASign.key derived from RFC 4134. This is a PKCS#8 encrypted private key with password password.

All the above code plus Alice's private key and X509 certificate are in this zip file (8 kB). The output from the test using the function SignSignedInfo() is as follows:

SHA-1 message digest of <SignedInfo> = 353CABFE369AAD9BEA21F5FA06CB367960FFB7D4
  Key is 128 bytes long
  Digest=353CABFE369AAD9BEA21F5FA06CB367960FFB7D4
  RSA_EncodeMsg returns 0 (expected 0)
  EM: 0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003021300906052B0E03021A05000414353CABFE369AAD9BEA21F5FA06CB367960FFB7D4
  SG: 45054693C680F35B4E62D532D9E0C5B55368C4A0243186B763C3CDD7C182E611980165B9E02751FF8091B2715451C151E79A4E1AF3133974DC6C996249C4E327DB435914DAF7856654EDA5CD23CF189D84937BD7D9B4AA45478C948B620687135CB7FBECE006B9E9A680A714340C2A4837BCA7551074A563BF461EDE9C8C89FA
SignatureValue=RQVGk8aA81tOYtUy2eDFtVNoxKAkMYa3Y8PN18GC5hGYAWW54CdR/4CRsnFUUcFR55pOGvMTOXTcbJliScTjJ9tDWRTa94VmVO2lzSPPGJ2Ek3vX2bSqRUeMlItiBocTXLf77OAGuemmgKcUNAwqSDe8p1UQdKVjv0Ye3pyMifo=

The error in the XML document

You can provide the Key Info required to verify the signature in two forms, all wrapped in a <KeyInfo> element:

<KeyInfo>
  <KeyValue>
    <RSAKeyValue>...</RSAKeyValue>
  </KeyValue>
  <X509Data>
    <X509Certificate>...</X509Certificate>
  </X509Data>
</KeyInfo>

The <RSAKeyValue> element contains the public key explicitly in <Modulus> and <Exponent> form. While the <X509Certificate> is meant to include the same public key together with other information such as the name of the subject, who issued it, serial number and expiry date.

We have two example XML documents provided by the SII, with the Key Info provided in both <RSAKeyValue> and in <X509Certificate> form. These were in the ejemplo.xml document and the example on pages 23-4 of the manual [SII-MANUAL-2003]. The certificates are reproduced in this zip file (3 kB). They were both issued by "E-CERTCHILE CA" on 1 October 2002 and 2 October 2003, respectively, with serial numbers 0x02018A and 0x010000A7.

Unfortunately, the public key in the <X509Certificate> does not match the public key in the <RSAKeyValue> in either case. You can use the key in the <RSAKeyValue> to decrypt the signature value, but you cannot use the public key in either of the certificates.

The public key in the certificate in the example XML document, issued October 2003, has a 1024-bit public key modulus

BC59955875C6BF6C2902010C5FFA55AFA5B074121B90009825AFB4D4C839737713D1100B2EE938F1EB0E0E84BACBE81F27AC6522896DCD139C8157669EFCABB99B7478A3CCAAAF326CAFC1B74FECA2BC2D07F07FCE16E2FF4EF0C25E50795B246968E671400AB3C0793B4E35B1DA45ECB378C0EFD8481A9CD10325CF5CF9435F

but the modulus in the associated <RSAKeyValue> is

B4D1249E46F5907883D4E3805A52CA91C1FF50FE5419AE95E8C62CA3EF8907EBD8320D8E5C544E005EC6F0134514F4318AE4BFEF2D5ACD9963376C6AF9B5B76C0A2ED5B5B68A3EDFC525D64C960564C0329DD6CBC861CCD5EDE7566C29804A71047859CCFBF02DBE79B2DD7071EB8A8ECD8E9ED6F5DC9DF7B146FB6DB24C5A1D

The public key in the certificate in the [SII-MANUAL-2003], issued October 2002, has a public key modulus of only 512 bits

BCD43268B3DDDDC42506BD1F416A2800A5D215A9FF59B685B43E4FED00F3704D69048BCA63652FEAE89DBABFE619507D212E05ABFD714485F2D771459B12F04D

but the modulus in the associated <RSAKeyValue> is 1024 bits (and is the same as in the first example).

B4D1249E46F5907883D4E3805A52CA91C1FF50FE5419AE95E8C62CA3EF8907EBD8320D8E5C544E005EC6F0134514F4318AE4BFEF2D5ACD9963376C6AF9B5B76C0A2ED5B5B68A3EDFC525D64C960564C0329DD6CBC861CCD5EDE7566C29804A71047859CCFBF02DBE79B2DD7071EB8A8ECD8E9ED6F5DC9DF7B146FB6DB24C5A1D

Woops! The full code to analyze this is in

Handling accented characters

A common problem seems to be signing XML documents which include accented characters like áéíóúñ.

There is an example on Accented characters and UTF-8 in XML-DSIG signatures.

Comment

This page started as a simple "how-to" after we were contacted by a Chilean customer asking for help on implementing a package. We took the opportunity to take a few swipes at the horrendous effort required to make XML-Dsig work. The difficulties should be obvious to anyone who can wade through our attempts to explain and the frightful code we provide.

Our sympathies go to the SII for having to deal with XML-Dsig. They have probably released corrections and better examples than we have used, but we couldn't find them [at the time we first wrote this]. Not speaking decent Spanish does not help. But given our experience with other cryptographic standards (e.g. X.9.42), it would not surprise us that an error could remain undetected and uncorrected.

References

Contact

For more information or to comment on this page, please send us a message.

This page first published by DI Management 27 January 2009. Last updated 7 September 2013