Firma digital de XML con token criptográfico y JAVA

En este tutorial, se verá la implementación de firma digital desde una aplicación escrita en JAVA, haciendo uso de un dispositivo criptográfico con el certificado contenido en el token.

Para la firma y acceso al Token criptográfico se utilizará la librería del firmador estatal disponible en: firmador-libreria ya que encapsula la lógica del token. El estándar utilizado para la firma digital del XML es DSIG que además coincide con la firma utilizada en los sistemas de facturación electrónica.

Se requiere tener instalado git, java y maven. En debian se puede utilizar la siguiente instrucción desde la consola.

  1. sudo apt install git openjdk-8-jdk maven

Una vez instalado, ejecutar las siguientes instrucciones para descargar e instalar la librería del firmador estatal:

  1. git clone https://gitlab.softwarelibre.gob.bo/adsib/firmador_estatal/firmador-libreria.git
  2. cd firmador-libreria
  3. mvn install
  4. cd ..

Hecho esto creamos nuestro proyecto con maven.

  1. mkdir firmar-xml
  2. cd firmar-xml
  3. mvn archetype:generate -DgroupId=bo.gob.adsib.ejemplos -DartifactId=firmaxml -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
  4. cd firmaxml
  5. nano pom.xml

Con los pasos anteriores en la consola de comandos, se abrirá un editor de texto donde se puede copiar el siguiente código de configuración dentro del tag "project":

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <artifactId>maven-assembly-plugin</artifactId>
  5. <configuration>
  6. <finalName>firmaxml</finalName>
  7. <appendAssemblyId>false</appendAssemblyId>
  8. <archive>
  9. <manifest>
  10. <addClasspath>true</addClasspath>
  11. <mainClass>bo.gob.adsib.ejemplos.App</mainClass>
  12. </manifest>
  13. </archive>
  14. <descriptorRefs>
  15. <descriptorRef>jar-with-dependencies</descriptorRef>
  16. </descriptorRefs>
  17. </configuration>
  18. <executions>
  19. <execution>
  20. <id>make-assembly</id>
  21. <phase>package</phase>
  22. <goals>
  23. <goal>single</goal>
  24. </goals>
  25. </execution>
  26. </executions>
  27. </plugin>
  28. </plugins>
  29. </build>

Con el código anterior, se le indica a maven que debe utilizar como clase principal App. Dentro del mismo archivo en el tag "dependencies" se debe agregar la dependencia de la librería del firmador estatal:

  1. <dependency>
  2. <groupId>bo.gob.softwarelibre.firmadorestatal</groupId>
  3. <artifactId>firmadorlibreria</artifactId>
  4. <version>1.0-SNAPSHOT</version>
  5. </dependency>

Con el código anterior, se le indica a maven que debe utilizar como dependencia firmadorlibreria. A continuación guardar el archivo y editar App.java con:

  1. nano src/main/java/bo/gob/adsib/ejemplos/App.java

Dentro del archivo es necesario importar la librería del firmador estatal y otras como se lista a continuación.

  1. import bo.gob.softwarelibre.firmadorestatal.firma.Banderas;
  2. import bo.gob.softwarelibre.firmadorestatal.firma.Firmador;
  3. import bo.gob.softwarelibre.firmadorestatal.token.GestorSlot;
  4. import bo.gob.softwarelibre.firmadorestatal.token.Slot;
  5. import bo.gob.softwarelibre.firmadorestatal.token.Token;
  6. import java.io.File;
  7. import java.nio.file.Files;
  8. import java.security.PrivateKey;
  9. import java.security.cert.X509Certificate;

En el método main iría el siguiente código:

  1. try {
  2. //obtengo el slot de mi token (por defecto el primero "0")
  3. GestorSlot gestorSlot = GestorSlot.getInstance();
  4. gestorSlot.adicionarProveedor("/usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so");
  5. Slot slot = gestorSlot.obtenerSlot(0);
  6. //se inicia el token con el pin de seguridad
  7. Token token = slot.getToken();
  8. token.iniciar("12345678");
  9. //se recupera las claves y certificados del token
  10. PrivateKey priv = token.obtenerClavePrivada("Certificado");
  11. X509Certificate cert = token.obtenerCertificado("Certificado");
  12. //crea instancia del firmador
  13. Firmador firmar = Firmador.getInstance();
  14. //abre el archivo y lo firma
  15. File file = new File("./prueba.xml");
  16. byte[] archivo = Files.readAllBytes(file.toPath());
  17. archivo = firmar.firmar(archivo, priv, Banderas.TIPO_DSIG, token.nombreProveedor(), cert);
  18. //guarda el archivo firmado
  19. File fileSigned = new File("./prueba_firmado.xml");
  20. Files.write(fileSigned.toPath(), archivo);
  21. } catch (Exception ex) {
  22. ex.printStackTrace();
  23. }

El estándar XMLDSIG permite firmar documentos XML de diferentes formas, sin embargo para este tutorial se utilizará específicamente la siguiente:

  • Canonicalization.- http://www.w3.org/TR/2001/REC-xml-c14n-20010315
  • Transformation Algorithm.- http://www.w3.org/2000/09/xmldsig#enveloped-signature
  • Hashing Algorithm.- http://www.w3.org/2001/04/xmlenc#sha256
  • Signature Algorithm.- http://www.w3.org/2001/04/xmldsig-more#rsa-sha256

Y como se puede observar en los comentarios, se lista los tokens para encontrar los conectados, se selecciona el primer token en el índice 0 y se inicia sessión con el pin de seguridad. A continuación se enlaza la llave privada y el certificado x509.

Para firmar el documento XML se crea una instancia de la case Firmador y se envía al método firmar el archivo que contiene el documento XML, el enlace a la llave privada, el tipo de firma en este cado DSIG, el proveedor y el certificado.

Si desea descargar un ejemplo de archivo XML para ser firmado puede hacerlo a través del siguiente link: Archivo XML de ejemplo

Para compilar el proyecto puede utilizar la siguiente instrucción de maven.

  1. mvn package
  2. java -jar target/firmaxml.jar

Si desea descargar un ejemplo de archivo firmado puede hacerlo a través del siguiente link: Archivo firmado de ejemplo

Si desea descargar el código de ejemplo del programa anterior, puede hacerlo a través del siguiente link: Código de ejemplo

© ADSIB 2019 Bolivia