Cómo firmar documentos PDF con firma digital de Costa Rica con software libre

Actualización: he publicado un nuevo artículo con una herramienta propia que simplifica la firma de PDF en el siguiente enlace: Firmador digital de documentos para Costa Rica.

La información de este artículo ha quedado obsoleta.

La Política de Formatos Oficiales de los Documentos Electrónicos Firmados Digitalmente de Costa Rica especifica el tipo de documentos y su formato de firma digital. En el caso de PDF se utiliza un estándar especificado en Europa para firma digital avanzada (AdES) y en el caso de los PDF se llama PAdES. En el documento oficial enlazado previamente se muestra que tiene que soportar PAdES-LTV (permite la validación de forma longeva) y sugiere que se use el perfil Baseline. El asunto es que no hay mucho software libre en el mercado que permita la firma digital avanzada en PDF, sin embargo la propia Comisión Europea tiene un proyecto para ello (Digital Signature Services), que es un conjunto de librerías y herramientas en Java que permiten trabajar con firma digital con los estándares europeos, incluyendo soporte para PDF.

Hasta no hace mucho tiempo, una de las pocas implementaciones libres para trabajar con firma digital avanzada en PDF era iText, sin embargo este proyecto cambió de licencia y las condiciones de uso contradecían la propia licencia, además de presuntas incompatibilidades en contribuciones del código por parte de terceros que la hacían incompatible con la nueva licencia. Afortunadamente, el proyecto DSS (usando Apache PDFBox como alternativa a iText) permite firmar documentos PDF cumpliendo con la política de formatos oficiales nacional.

Instalación en GNU/Linux

Existe un firmador en formato independiente que funciona en el escritorio. Se puede descargar DSS standalone app package 5.1 (este es el más reciente en el momento de escribir esta entrada de blog).

Una vez descargado, descomprimir el archivo, contendrá dss-app.jar y un par de scripts para lanzar el jar de forma sencilla. El firmador que hay dentro del jar utiliza por defecto un servidor TSA europeo, para cambiarlo habrá que modificar un fichero que hay dentro del jar en la ruta spring/applicationContext.xml y buscar el texto: http://tsa.belgium.be/connect para reemplazarlo por el siguiente: http://tsa.sinpe.fi.cr/tsahttp/ y guardarlo modificado con este cambio dentro del archivo jar (un archivo jar es un archivo zip realmente).

Para poder ejecutar este jar en GNU/Linux se necesita el JRE de OpenJDK 8 y además OpenJFX 8 (JavaFX). En Fedora se instala java-1.8.0-openjdk-openjfx y en Ubuntu se instala openjfx.

Una vez instaladas las dependencias de Java, se puede ejecutar desde la terminal en la carpeta donde se haya descomprimido con sh dss-run.sh o bien con java -jar dss-app.jar.

Firmado de un documento PDF

En fichero a firmar (File to sign) se selecciona el documento PDF que se desea firmar digitalmente.

En formato de firma (Signature format) se debe elegir PAdES porque se trata de un PDF.

En PAdES solamente existe el formato envuelto (Enveloped), por lo que este campo lo selecciona automáticamente.

En el nivel (Level) se elige el nivel de perfil de PAdES. PAdES-BASELINE-LTA es el equivalente a PAdES-LTV.

En algoritmo de resumen hash encriptado (Digest algorithm) se recomienda que sea como mínimo de tipo SHA-2, en la imagen de ejemplo se ha seleccionado SHA-512.

En Signature token API se tiene que seleccionar PKCS #11, entonces se desplegará PKCS #11 library donde hay que especificar dónde está la librería del módulo de Firma Digital (libASEP11.so).

En contraseña (Password) se ingresa el PIN de la tarjeta de Firma Digital.

Cuando se presione sobre Sign se iniciará el proceso de firmado y tras unos segundos aparecerá una ventana para guardar el PDF generado en la ubicación que se desee.

Eso es todo. El documento PDF ya tiene una firma válida en el país.

Existen formas de validar la firma del documento PDF con software libre (para no tener que usar Acrobat Reader DC como en este ejemplo), pero se explicará en próximas entradas de blog.

Aunque este firmador no tiene campo de estampa visible (“firma visible”), la política de documento oficial no indica que el documento requiera disponer este detalle visual en los PDF.

8 comentarios en “Cómo firmar documentos PDF con firma digital de Costa Rica con software libre

  1. Jonathan Vargas:

    Es bueno saber que el proyecto usa JavaFX, nosotros vamos en esa misma línea para olvidarnos de SWT, vos recordarás bien el difícil mantenimiento que implicaba para diversos sistemas, además de los problemas con los componentes de visualización disponibles.

  2. Ima:

    hola, cuando intento ejecutar los jar o sh me sale esto:

    ima@imarubuntu:/media/ima/Respaldo/descargan firefox ubuntu/firmador de pdf linux/dss stadalone firmar pdfs$ sh dss-run.sh
    dss-run.sh: 2: dss-run.sh: /bin/java: not found
    ima@imarubuntu:/media/ima/Respaldo/descargan firefox ubuntu/firmador de pdf linux/dss stadalone firmar pdfs$ java -jar dss-app.jar
    Exception in thread “main” java.lang.UnsupportedClassVersionError: eu/europa/esig/dss/standalone/DSSApplication : Unsupported major.minor version 52.0
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:803)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482)
    ima@imarubuntu:/media/ima/Respaldo/descargan firefox ubuntu/firmador de pdf linux/dss stadalone firmar pdfs$

    y no abre…

    me podría ayudar, gracias de antemano

    1. Francisco de la Peña:

      Hola, es posible que la versión de Java que tenga instalada por defecto sea Java 7 o que faltara algún paquete específico más. Este firmador requiere Java 8. Se pueden tener instaladas varias versiones de Java. Primero hay que asegurarse de tener Java 8 instalado (el JRE), ya sea el de Oracle o el de OpenJDK (funciona con ambos). En Ubuntu 16.04 y posteriores es sencillo mediante el comando:
      sudo apt-get install default-jre
      Y luego se puede cambiar la versión por defecto de Java en su Ubuntu con el comando:
      sudo update-alternatives --config java
      y seleccionando el número correspondiente a la versión 8.
      Si tiene una versión más antigua de Ubuntu (por ejemplo, 14.04) recomendaría actualizar a una versión más reciente, ya que instalar Java 8 en versiones anteriores a la 16.04 es más complicado porque no viene en el repositorio de paquetes de serie.
      Saludos.

  3. luis brenes:

    Buenas, sigo todos los pasos y cuando firmo el documento, solamente me sale un mensaje que dice oops, an error ocured y exit. No me dice más nada.

    Tal vez pueda ayudarme.

    1. Francisco de la Peña:

      Hola, gracias Luis por el aviso. El enlace estaba apuntando a la versión 5.2, que tiene ese problema. Acabo de actualizar el enlace a la versión 5.1 que funciona como se espera.

      En cualquier caso en los próximos días voy a publicar un firmador propio que soluciona este problema y agrega otras mejoras, como incrustar la cadena de certificados. El código fuente en desarrollo está en https://gitlab.com/firmador/firmador

  4. Alejandro:

    Debido a un proyecto al que le debo hacer un “enhancement” para que firme electronicame archivos PDF. He visto como funciona receta digital, y el documento (que asumo que debe ser un XLM) se firma en el servidor solicitando un PIN por medio de un applet en JAVA. Quisiera hacer esto mismo con este firmador ya que vos lo tenés funcional. Mi consulta es, bajo los estándares de firma electronicamente esto entraría como una “mala practica”? Agradezco cual info que me pueda pasar

    1. Francisco de la Peña:

      Hola Alejandro:
      No conozco los detalles técnicos sobre la especificación, quizás sea XAdES (o al menos así debería ser así en caso de firmar XML para cumplir con la política de formatos oficiales emitida por el MICITT). Lo habitual para firmar digitalmente desde sitios web es una aplicación con acceso al dispositivo de firma. Suele ser habitual usar Java Web Start para lanzarlos, o una aplicación nativa de escritorio previamente descargada. También existen mecanismos intermedios como ficheros de extensión exclusiva asociados a un firmador para que se abra con él, con datos internos para saber cómo subirlo de vuelta. También existe la posibilidad de asociar protocolos personalizados (cosa://, por ejemplo), aunque el soporte en navegadores no es tan bueno.
      Lo que se firma es un hash criptográfico, no siendo necesario descargar el documento entero, entonces se puede devolver el hash firmado y el servidor puede ensamblarlo al documento. Si es pequeño el documento, como en el caso de la mayoría de XML, puede ser más simple obtener el documento entero para que el componente de escritorio se encargue de eso, aunque esto puede incrementar el tamaño de la aplicación descargable al requerir analizadores sintácticos, validadores y demás.
      Sobre si se trata de una mala práctica o no, en realidad no hay una forma alternativa sencilla de acceder al hardware del token desde un sitio web.
      La otra opción es hacerlo de forma no automatizada pero esto hace un poco más tedioso el tener que descargarlo manualmente, abrirlo en el firmador manualmente, guardar el documento firmado manualmente y subirlo manualmente. Algo que mucha gente quizás ya hace con Adobe Reader y similares.
      Con respecto a si el programa Firmador lo soporta o no, estoy trabajando precisamente estos días para que permita la comunicación entre el navegador (mediante JavaScript y XMLHttpRequest) y un servicio local que está en escucha en un puerto determinado en localhost mientras está la aplicación en ejecución. Esto permite recibir datos desde el sitio web y devolverlos. Así funcionan los componentes de firma de RACSA del SICOP, o el firmador SignumOne de Flecha Roja en Hacienda, entre otros. Aunque este par tienen algunas prácticas obsoletas e inseguras en su operación que han sido reportadas, es posible hacerlo bien hoy en día en la mayoría de navegadores, con la excepción notable de Safari, pero Apple ya está trabajando en una solución.
      Tengo otro artículo en el blog titulado “Soluciones modernas para usar firma digital desde la web” que escribí hace 4 años con más información, con respecto al punto anterior, en los comentarios.
      Cualquier otro detalle me avisa, saludos.

Deja un comentario

Tu dirección de correo electrónico no será publicada.