Signing and verifying XML with xmlsec1

Let’s say we have a certification path like the following:

  • Root CA
    • Intermediate CA 1
      • Intermediate CA 2
        • End entity signer

And we want to sign sample.xml:

<?xml version="1.0" encoding="UTF-8"?>
<sample>
    <data>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</data>
</sample>

You will need to modify sample.xml adding to it the highlighted signature template:

<?xml version="1.0" encoding="UTF-8"?>
<sample>
    <data>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</data>
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
            <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
            <Reference>
                <Transforms>
                    <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </Transforms>
                <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <DigestValue/>
            </Reference>
        </SignedInfo>
        <SignatureValue/>
        <KeyInfo>
            <X509Data/>
        </KeyInfo>
    </Signature>
</sample>

Then you can sign it using the following command:

$ xmlsec1 --sign --privkey-pem end_entity_privkey.pem,end_entity_cert.pem --output sample-signed.xml sample.xml

And verify the signature with the following command:

$ xmlsec1 --verify --trusted-pem root_ca.pem --untrusted-pem intermediate_ca_1.pem --untrusted-pem intermediate_ca_2.pem sample-signed.xml
OK
SignedInfo References (ok/all): 1/1
Manifests References (ok/all): 0/0

From the previous command note that you have to add only one --trusted-pem for the root CA and one --untrusted-pem for each intermediate CA.

It is very important to realize that xmlsec1 is expecting only one certificate in each PEM file, irrespective of the common practice to group several certificates in one PEM file and because of this --untrusted-pem is repeated for every intermediate CA.

Another useful post on this topic can be found on http://sgros.blogspot.pe/2013/01/signing-xml-document-using-xmlsec1.html.

Note: xmlsec1 in Windows

From some time already xmlsec1 can be easily installed on Windows as a regular Cygwin package:

See http://cygwin.1069669.n5.nabble.com/ANNOUNCEMENT-xmlsec1-1-2-22-1-td129718.html.

Problema con el certificado digital en Facturador SUNAT v1.5

Después de haber importado un certificado digital en el Facturador SUNAT v1.5 y al intentar generar un comprobante se podría obtener un error como el siguiente:

content[0] is not a valid X509Data type

En cuyo caso es posible que se deba a que la entrada de la clave en el PFX importado tiene un nombre que incluye espacios, como se muestra en el ejemplo a continuación, donde la entrada de clave posee el nombre “juan carlos perez diaz”:

>keytool -list -keystore certificado.pfx
...
juan carlos perez diaz, Jul 22, 2017, PrivateKeyEntry,
Certificate fingerprint (SHA1): D7:5C:99:FC:CE:00:90:D8:02:21:56:40:D5:A5:8E:7C:D7:55:1D:BC

Y esta condición explota un “bug” en el Facturador SUNAT v1.5, que no está soportando apropiadamente las entradas con espacios en su nombre.

De cualquier manera, un sencillo “workaround” consiste en reemplazar aquel nombre por uno que no contenga espacios, para nuestro ejemplo esto se obtendría con el siguiente comando:

>keytool -changealias -keystore certificado.pfx -alias "juan carlos perez diaz" -destalias "juancarlosperezdiaz"

Después de lo cual se debería importar el certificado nuevamente al Facturador SUNAT y volver a generar el comprobante.

Como mencioné anteriormente, esto se debe a un “bug” en la aplicación Facturador SUNAT y si resulta de interés para alguno, el problema se encuentra en el siguiente método, pe.gob.sunat.servicio2.registro.service.BandejaDocumentosServiceImpl#importarCertificado, específicamente donde se resalta a continuación:

salida = FacturadorUtil.executeCommand("keytool -importkeystore -srcalias " + aliasPfx + " -srckeystore " + rutaCertificado + " -srcstoretype pkcs12 -srcstorepass " + passPrivateKey + " -destkeystore " + this.comunesService.obtenerRutaTrabajo("ALMC") + "FacturadorKey.jks -deststoretype JKS -destalias certContribuyente -deststorepass **********");

Cuya solución (rápida pero lejos de lo ideal) podría ser envolver el valor de la variable aliasPfx en comillas dobles como se muestra a continuación:

salida = FacturadorUtil.executeCommand("keytool -importkeystore -srcalias \"" + aliasPfx + "\" -srckeystore " + rutaCertificado + " -srcstoretype pkcs12 -srcstorepass " + passPrivateKey + " -destkeystore " + this.comunesService.obtenerRutaTrabajo("ALMC") + "FacturadorKey.jks -deststoretype JKS -destalias certContribuyente -deststorepass **********");

Por último, me gustaría comunicar esta incidencia a SUNAT para que lo solucionen de su lado, pero no conozco el canal correcto de reporte de incidencias a SUNAT, por lo que agradecería aquella información.

Grid card for two-factor authentication

I’ve been asked to develop a demonstration of two-factor authentication using a grid card (aka. bingo card) so I started researching a little bit on this and the only thing I could find is the following fork for the phpSec project, https://github.com/multiwebinc/phpSec, which implements it.

So I downloaded the source code and assembled a very simple demonstration page hosted at http://gridcard.demo.blobfish.pe.

Some screenshots follows:

Source code at https://github.com/hablutzel1/phpsec_gridcard_demo.