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.
- 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:
- git clone https://gitlab.softwarelibre.gob.bo/adsib/firmador_estatal/firmador-libreria.git
- cd firmador-libreria
- mvn install
- cd ..
Hecho esto creamos nuestro proyecto con maven.
- mkdir firmar-xml
- cd firmar-xml
- mvn archetype:generate -DgroupId=bo.gob.adsib.ejemplos -DartifactId=firmaxml -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
- cd firmaxml
- 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":
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <configuration>
- <finalName>firmaxml</finalName>
- <appendAssemblyId>false</appendAssemblyId>
- <archive>
- <manifest>
- <addClasspath>true</addClasspath>
- <mainClass>bo.gob.adsib.ejemplos.App</mainClass>
- </manifest>
- </archive>
- <descriptorRefs>
- <descriptorRef>jar-with-dependencies</descriptorRef>
- </descriptorRefs>
- </configuration>
- <executions>
- <execution>
- <id>make-assembly</id>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </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:
- <dependency>
- <groupId>bo.gob.softwarelibre.firmadorestatal</groupId>
- <artifactId>firmadorlibreria</artifactId>
- <version>1.0-SNAPSHOT</version>
- </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:
- 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.
- import bo.gob.softwarelibre.firmadorestatal.firma.Banderas;
- import bo.gob.softwarelibre.firmadorestatal.firma.Firmador;
- import bo.gob.softwarelibre.firmadorestatal.token.GestorSlot;
- import bo.gob.softwarelibre.firmadorestatal.token.Slot;
- import bo.gob.softwarelibre.firmadorestatal.token.Token;
- import java.io.File;
- import java.nio.file.Files;
- import java.security.PrivateKey;
- import java.security.cert.X509Certificate;
En el método main iría el siguiente código:
- try {
- //obtengo el slot de mi token (por defecto el primero "0")
- GestorSlot gestorSlot = GestorSlot.getInstance();
- gestorSlot.adicionarProveedor("/usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so");
- Slot slot = gestorSlot.obtenerSlot(0);
- //se inicia el token con el pin de seguridad
- Token token = slot.getToken();
- token.iniciar("12345678");
- //se recupera las claves y certificados del token
- PrivateKey priv = token.obtenerClavePrivada("Certificado");
- X509Certificate cert = token.obtenerCertificado("Certificado");
- //crea instancia del firmador
- Firmador firmar = Firmador.getInstance();
- //abre el archivo y lo firma
- File file = new File("./prueba.xml");
- byte[] archivo = Files.readAllBytes(file.toPath());
- archivo = firmar.firmar(archivo, priv, Banderas.TIPO_DSIG, token.nombreProveedor(), cert);
- //guarda el archivo firmado
- File fileSigned = new File("./prueba_firmado.xml");
- Files.write(fileSigned.toPath(), archivo);
- } catch (Exception ex) {
- ex.printStackTrace();
- }
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.
- mvn package
- 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