Uso de XSL para transformar la factura electronica XML

Contenido/contents:
Introducion
Cadena Original
Verificacion de sello
Impresion
Pagina anterior/Previous page

Introduccion
Este es un ejemplo para trabajar con la factura electronica (CFD) usando la linea de comandos.
Aqui en la empresa para el trabajo diario NO usamos este codigo, lo que tenemos en produccion es el programa satxmlsv33.php desarrollado en PHP usando la extension openssl.
Este conjunto de pasos me sirvio en su momento para verificar que lo prograame en PHP fue correcto.
Cadena Original
Antes aqui mostraba una plantilla XSLT que yo genere a mano, pero como el SAT ya tiene publicada en su portal la plantilla oficial retiro la mia y cambio el ejemplo a usar la oficial.
Les recomiendo dos cosas:
Descargen los archivos necesarios del sitio oficial del SAT y tenganlos en su servidor local, no intenten accesar el sitio del SAT para cada validacion, de por si ya esta lento ...
Modifiquenlo con cuidado, por ejemplo yo le cambie la version="2.0" a version "1.0" para que no mande warnings el PHP ...
Vamor a aplicar las reglas de transformacion anteriores al siguiente archivo XML.
Para aplicar las reglas usamos el comando xsltproc dando como primer argumento el archivo con las reglas de transformacion XSLT y como segundo el nombre del archivo con la factura XML.
$ xsltproc cadenaoriginal_3_3.xslt fact.xml
||3.3|FEXA|188584|2017-08-18T16:47:57|00001000000401555105|593.22|MXN|1|688.14|I|55348|FJC780315E91|FABRICA DE JABON LA CORONA SA DE CV|601|XAXX010101000|VENTAS MOSTRADOR XALOSTOC|P01|42151909|7501026009396|2|XBX|Caja|BRIDEN 25P 100 ML|296.61|593.22|593.22|002|Tasa|0.160000|94.92|002|Tasa|0.160000|94.92|94.92||
Ya con esa cadena original podemos aplicar las reglas para calcular el sello. El primer paso es calcular el hash sha256.
$ xsltproc cadenaoriginal_3_3.xslt fact.xml | sha256sum | cut -f1 -d \ 
4c12c61dc10452aacfdf00d2db670a7a832a7c1a6272a3b437f2f299fda88500
Este hash ya se puede sellar con el certificado (que ya tengo convertido en formato PEM) y ademas codificarlo en formato base64 porque el sello lo deja en binario.
Openssl tiene la facilidad de calcular el sh256 y de sellarlo en un mismo paso, por lo cual ya no hace falta calcular el sha256 en un paso previo.
$ xsltproc cadenaoriginal_3_3.xslt fact.xml | openssl dgst -sha256 -sign /home/httpd/sat/00001000000401555105.key.pem | openssl enc -base64 -A
m7LfGrBtnEUKtAd/HVe2fe9GhRHLTkB/uB2sb5ODxZFpYW+AzwYru1fBxrF4lJjbg3kG0fy4YgjNdtjnsYRCT0D/SixDAzBBkQCOfmmDzx/gUIgjzs15r05/WadrIv83G+lYvd7Pp/wPvi/ZQf4ShjHPHjEuctLcVYp9TkCiVV1xG+z0NhUPxfvei41ZAe9v80QoYfHuGOjaDzeU7Jbwz2+gUF1z7x4hJA/UWpyKn45t4INipkZtKUAUqOPXp1T73jsznPZvrdBChjH2HIe5WSDALfpUnd70xILQcRGJ7h4+J9p1teC6Hed/O0K6alWZFTVmeej0Dcvu+1ERnfR8Ww==
Si son observadores veran que el sello recien calculado es el mismo que esta almacenado en el atributo "Sello" del XML. El cual fue calculado con la funcion satxmlsv33 de PHP.
Verificacion del sello
Ahora voy a simular lo que hay que hacer para validar que el sello es correcto, es decir, es el sello correspondiente a la factura firmada por el certificado correspondiente.
Esta es una pequen˜a hoja de conversion para extraer el campo del sello.
Para aplicar las reglas usamos el comando xsltproc dando como primer argumento el archivo con las reglas de transofrmacion XSL y como segundo el nombre del archivo con la factura XML.
$ xsltproc sello.xslt fact.xml
m7LfGrBtnEUKtAd/HVe2fe9GhRHLTkB/uB2sb5ODxZFpYW+AzwYru1fBxrF4lJjbg3kG0fy4YgjNdtjnsYRCT0D/SixDAzBBkQCOfmmDzx/gUIgjzs15r05/WadrIv83G+lYvd7Pp/wPvi/ZQf4ShjHPHjEuctLcVYp9TkCiVV1xG+z0NhUPxfvei41ZAe9v80QoYfHuGOjaDzeU7Jbwz2+gUF1z7x4hJA/UWpyKn45t4INipkZtKUAUqOPXp1T73jsznPZvrdBChjH2HIe5WSDALfpUnd70xILQcRGJ7h4+J9p1teC6Hed/O0K6alWZFTVmeej0Dcvu+1ERnfR8Ww==
Ahora este campo del sello obtenido del archivo XML lo de-codificamos del codigo base64 y lo dejamos nuevamente como el sello en binario y lo dejamos en un archivo temporal.
$ xsltproc sello.xslt fact.xml | openssl enc -base64 -d -A -out sello
Ahora si ya validamos con la llave publica que el sello corresponda con la cadena original y con la llave privada.
$ xsltproc cadenaoriginal_3_3.xslt fact.xml | openssl dgst -sha256 -verify /home/httpd/sat/00001000000401555105.cer.pem -signature sello
Verified OK
  1. Con esto sabemos que el XML no ha sido modificado desde que se sello. (Integridad).
  2. El sello fue calculado con el poseedor de la llave privada. (Autenticidad)
  3. Al ser el emisor el unico con la llave privada no puede negar que el CFDI fue emitido por el (No repudio).
Generacion de archivo para impresion
Con el siguiente arhivo de transformacion genero un archivo HTML para consultar en un formato 'agradable al usuario' el contenido de la factura XML.
Invocamos la regla de transformacion para generar el archivo HTML de salida y ya lo podemos consultar o mandar a imprimir.
xsltproc impresion.xslt fact.xml > fact.html

Si desea ver como se ve archivo de consulta de la factura electronica, dele click aqui
Para uso en la empresa yo genero la representacion impresa con funciones fpdf en PHP, este ejemplo es solo como prueba de concepto.