Entorno
El entorno de la prueba es el siguiente:- Apache: 2.2
- JBoss EAP 6.4
- Android: 4.4.4
Además, los componentes involucrados son:
Componente | Versión | URL |
---|---|---|
Página de firma | N/A | http://192.168.43.239/sdxc/test/storageRetrieve |
Autofirma | Cliente movil firma 1.5 | N/A |
Server trifase | 1.5 | http://192.168.43.239/afirma-server-triphase-signer/SignatureService |
Signature Storage | 1.5 | http://192.168.43.239/afirma-signature-storage/StorageService |
Signature Retrieve | 1.5 | http://192.168.43.239/afirma-signature-retriever/RetrieveService |
Directorio entrada server trifase | N/A | D:\tmp\afirma\entrada |
Directorio salida server trifase | N/A | D:\tmp\afirma\salida |
Directorio temporal servlets | N/A | D:\tmp\afirma\TriStorageRetrieve |
Visión general
En esta prueba se lanzará una firma de tipo PAdES, sobre el fichero "prueba1.pdf", empleando el servidor trifase y los servlets de almacenamiento Sotrage y Retrieve.
El servidor trifase sirve para que la gestión del fichero que se va a firmar se haga en servidor y, por tanto, nunca se envíe completo al dispositivo del usuario. Este modo de funcionamiento se basa en tres etapas:
El servidor trifase sirve para que la gestión del fichero que se va a firmar se haga en servidor y, por tanto, nunca se envíe completo al dispositivo del usuario. Este modo de funcionamiento se basa en tres etapas:
- Autofirma llama al servidor trifase para indicarle que prepare la firma. Es decir, que coja el fichero y prepare el hash que hay que firmar.
- Autofirma recibe el hash y lo firma con la clave privada del certificado de usuario.
- Autofirma llama al servidor trifase para indicarle que complete la firma. Es decir, que coja el hash firmado y lo "incruste" en el fichero a firmar.
Los servlets de almacenamiento sirven para permitir una comunicación bidireccional entre el navegador de usuario y Autofirma cuando ésta no puede hacerse de forma directa. Si el navegador o el dispositivo de usuario no permiten el uso de sockets (tanto por restricciones tecnológicas como de seguridad), se emplean estos servlets a modo de repositorio intermedio. Autofirma escribe datos y el navegador de usuario los lee. Según he visto, el contenido que se guarda en estos ficheros intermedios va cifrado con una clave generada por el navegador al comienzo del proceso.
El uso de server trifase y de los servlets de almacenamiento es independiente entre sí. Es decir, se puede usar server trifase sin servlets, y se pueden usar servlets sin server trifase. También se puede realizar la firma sin ninguno de los dos.
- Si sólo se emplea server trifase, el navegador obligatoriamente debe soportar sockets. La comunicación entre navegador y autofirma se hace de forma directa. La ventaja es que el fichero a firmar no sale del backend.
- Si sólo se emplean los servlets, el navegador envía a Autofirma el fichero a firmar (se envía como cadena Base 64 durante la invocación). Al terminar la firma, Autofirma deja el fichero firmado (completo) en el repositorio intermedio para que lo lea el navegador. La ventaja es que el navegador no necesita soportar sockets.
- Si no se emplea ninguno de los dos mecanismos anteriores, el navegador debe soportar sockets. El fichero a firmar se envía durante la invocación y, una vez firmado, se recupera a través de un socket. La ventaja es que es el método más simple.
Combinando server trifase y servlets de almacenamiento se consigue que el navegador no tenga que soportar sockets, que el fichero no salga del backend, y que los mensajes intercambiados con los servlets de almacenamiento no contengan la firma en sí, sino información acerca de su finalización.
Mensajería
A continuación un ejemplo de firma correcta. Las trazas que incorporo provienen de dos fuentes:
- Trazas del frontal Apache, empleando el módulo mod_dumpio
- Trazas de JBoss, para el server trifase y los servlets de almacenamiento
1 - Navegador - Autofirma
Dese el navegador se hace una invocación por protocolo a autofirma pasándole los siguientes parámetros:
intent://sign?ver=1&op=sign&id=8wp29aKd7L4486I60UrR&key=11095593&stservlet=http://192.168.43.239/afirma-signature-storage/StorageService&format=PAdEStri&algorithm=SHA512withRSA&properties=c2VydmVyVXJsPWh0dHA6Ly8xOTIuMTY4LjQzLjIzOS9hZmlybWEtc2VydmVyLXRyaXBoYXNlLXNpZ25lci9TaWduYXR1cmVTZXJ2aWNl&dat=cHJ1ZWJhMS5wZGY=#Intent;scheme=afirma;package=es.gob.afirma;end
Aquí, los parámetros relevantes son:
- op. Operación de firma
- id. Es un identificador que se empleará para nombrar los ficheros de "intercambio" que gestionará el Signature Storage y Retrieve.
- key. Algún tipo de clave generada para cifrar ciertos mensajes.
- Dirección de estos servlets
- formato y algortimo de firma
- properties. Contiene los parámetros adicionales, en este caso la dirección del server trifase.
- dat. Identificador del fichero que se va a firmar (cHJ1ZWJhMS5wZGY=)
2 - Autofirma - Server trifase (Prefirma)
Después de que el usuario selecciona el certificado de firma, Autofirma lanza un petición contra server trifase indicándole los datos del fichero que se quiere firmar y el certificado del firmate (sólo clave pública e identificación):
POST /afirma-server-triphase-signer/SignatureService op=pre&cop=sign&format=pades&algo=SHA512withRSA&cert=MIII(...)A4=&doc=cHJ1ZWJhMS5wZGY=¶ms=IwojRnJpIEZlYiAxNiAxMjowMTo0OCBDRVQgMjAxOApzZXJ2ZXJVcmw9aHR0cFw6Ly8xOTIuMTY4LjQzLjIzOS9hZmlybWEtc2VydmVyLXRyaXBoYXNlLXNpZ25lci9TaWduYXR1cmVTZXJ2aWNlCg==Parseando los parámetros tenemos:
- op=pre. Operación de prefirma
- cop=sign. Código de operación de firma
- format=pades. Firma PAdES
- algo=SHA512withRSA. Algoritmo de firma
- cert=MIII(...). Certificado del firmante (parte pública)
- doc=cHJ1ZWJhMS5wZGY=. Nombre del documento que se va a firmar. En este caso "prueba1.pdf"
- params=Iwoj(...). Parámetros adicionales. En este caso contiene la dirección completa del servidor trifase, es decir, se referencia a sí mismo
12:01:48,611 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) == INICIO FIRMA TRIFASICA == 12:01:48,614 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Recuperamos el documento mediante el DocumentManager 12:01:48,614 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Recuperamos el documento con identificador: cHJ1ZWJhMS5wZGY= 12:01:48,615 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Buscamos el fichero: D:\tmp\afirma\entrada\prueba1.pdf 12:01:48,617 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Recuperado documento de 175247 octetos 12:01:48,617 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Formato de firma seleccionado: pades 12:01:48,617 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) == PREFIRMA en servidor 12:01:48,618 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Prefirma PAdES - Firma - INICIO 12:01:48,618 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Se invocan las funciones internas de prefirma PAdES 12:01:48,641 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Se ha seleccionado la generacion de CAdES para inclusion en PAdES 12:01:48,644 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Se prepara la respuesta de la prefirma PAdES 12:01:48,644 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Prefirma PAdES - Firma - FIN 12:01:48,644 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Se ha calculado el resultado de la prefirma y se devuelve 12:01:48,645 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) == FIN PREFIRMA
Básicamente lee el fichero que se solicita y prepara el hash que tendrá que deberá firmar Autofirma. Con esto se evita devolver todo el fichero.
El resultado es un XML, en base 64, con la siguiente estructura:
<xml> <firmas> <firma Id="73d6e601-7442-4737-aee2-6aa699cdc393"> <param n="NEED_PRE">true</param> <param n="TIME">1518778908618</param> <param n="PRE">(....)</param> <param n="PID">WzxkYzQ5NmI1Y2ZjZDAxZDJmNTYwNGQzZWQwNTlhM2RkNz48NGM0YTA2ODc0OTM2MDg1OTNlOTU2MjYxODViYTIyNTI+XQ==</param> </firma> </firmas> </xml>
De aquí, lo más salientable es que en el tag "PRE" da la impresión de que se devuelve la el hash a firmar, junto con información del propio certificado.
2 - Autofirma - Server trifase (Postfirma)
Autofirma realiza la firma en local empleando la clave privada del certificado de usuario, que nunca sale del dispositivo.
Al terminar vuelve llamar al server trifase para que "incruste" esta firma en el PDF.
Los parámetros de la petición son:POST /afirma-server-triphase-signer/SignatureService op=post&cop=sign&format=pades&algo=SHA512withRSA&cert=MIII(...)&doc=cHJ1ZWJhMS5wZGY=&session=PHhtb(...)¶ms=IwojRnJpIEZlYiAxNiAxMjowMTo0OCBDRVQgMjAxOApzZXJ2ZXJVcmw9aHR0cFw6Ly8xOTIuMTY4LjQzLjIzOS9hZmlybWEtc2VydmVyLXRyaXBoYXNlLXNpZ25lci9TaWduYXR1cmVTZXJ2aWNlCg==
Los parámetros son casi los mismos que en el mensaje de prefirma, cambiando la operación. Pero, además, en esta ocasión llega un parámetro session que contiene un XML con el resultado de la firma.
El contenido de session se pinta en los logs del server trifase;
Dentro del tag "PRE" se manda lo mismo que se recibió en la petición anterior. A mayores en el campo "PK1" irá la firma en sí.
Como resultado se devuelve un mensaje de OK referenciando el fichero que se acaba de firmar.
El contenido de session se pinta en los logs del server trifase;
12:01:48,757 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) == INICIO FIRMA TRIFASICA == 12:01:48,764 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Recibidos los siguientes datos de sesion para 'post': <xml> <firmas> <firma Id="73d6e601-7442-4737-aee2-6aa699cdc393"> <param n="PRE">MYI(...)</param> <param n="PK1">s/5oZ(...)</param> <param n="PID">WzxkYzQ5NmI1Y2ZjZDAxZDJmNTYwNGQzZWQwNTlhM2RkNz48NGM0YTA2ODc0OTM2MDg1OTNlOTU2MjYxODViYTIyNTI+XQ==</param> <param n="TIME">1518778908618</param> <param n="NEED_PRE">true</param> </firma> </firmas> </xml> 12:01:48,765 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Recuperamos el documento mediante el DocumentManager 12:01:48,766 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Recuperamos el documento con identificador: cHJ1ZWJhMS5wZGY= 12:01:48,766 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Buscamos el fichero: D:\tmp\afirma\entrada\prueba1.pdf 12:01:48,767 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Recuperado documento de 175247 octetos 12:01:48,767 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Formato de firma seleccionado: pades 12:01:48,768 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) == POSTFIRMA en servidor 12:01:48,804 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Postfirma PAdES - Firma - INICIO 12:01:48,804 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Se invocan las funciones internas de postfirma PAdES 12:01:48,820 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Postfirma PAdES - Firma - FIN 12:01:48,820 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Se ha calculado el resultado de la postfirma y se devuelve. Numero de bytes: 227838 12:01:48,820 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Almacenamos la firma mediante el DocumentManager 12:01:48,826 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Escribiendo el fichero: D:\tmp\afirma\salida\prueba1.pdf 12:01:48,826 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Documento almacenado 12:01:48,827 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) == FIN POSTFIRMA
Dentro del tag "PRE" se manda lo mismo que se recibió en la petición anterior. A mayores en el campo "PK1" irá la firma en sí.
Como resultado se devuelve un mensaje de OK referenciando el fichero que se acaba de firmar.
OK NEWID=cHJ1ZWJhMS5wZGY=
3 - Autofirma - Signature Storage
Cuando la firma ya se completó, Autofirma llama al Signatura Storage para decirle que cree el fichero de intercambio y que dentro guarde cierta información.
POST /afirma-signature-storage/StorageService op=put&v=1_0&id=8wp29aKd7L4486I60UrR&dat=5.G0z2jkmD9erRoyvk0bCobg==
Se le indica que cree el fichero 8wp29aKd7L4486I60UrR y que escriba en él el texto indicado en la variable dat. Aparentemente es algún tipo de texto cifrado empleando un algoritmo de clave simétrica...
En el servidor, el Signature Storage genera los siguientes mensajes de log:
12:01:48,865 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) == INICIO GUARDADO == 12:01:48,866 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Se solicita guardar un fichero con el identificador: 8wp29aKd7L4486I60UrR 12:01:48,914 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Se guardo correctamente el fichero: D:\tmp\afirma\TriStorageRetrieve\8wp29aKd7L4486I60UrR 12:01:48,915 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) == FIN DEL GUARDADO ==
4 - Navegador - Signature Retrieve
La forma que tiene el navegador de saber si la firma se ha completado o, en su caso, si se ha producido algún error, es invocando al Signature Retrieve. Se le pide el fichero cuyo nombre se preacordó al comienzo, y que contiene un texto cifrado indicativo de que la firma ha ido bien.
En el servidor, el Signature Retrieve genera los siguientes mensajes de log:
12:01:49,019 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) == INICIO DE LA RECUPERACION == 12:01:49,020 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Se solicita el fichero con el identificador: 8wp29aKd7L4486I60UrR 12:01:49,021 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Se recupera el fichero: 8wp29aKd7L4486I60UrR 12:01:49,022 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) == FIN DE LA RECUPERACION == 12:01:49,022 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Limpiamos el directorio temporal 12:01:49,023 INFO [es.gob.afirma] (ajp-/0.0.0.0:8009-1) Fin de la limpieza
Al recuperar el resultado de la firma (el navegador no obtiene la firma en sí, porque esta todavía está en el directorio de salida del server trifase) el navegador sabrá si el proceso ha ido bien y, según proceda, llamar a los callbacks de éxito o error.
No hay comentarios:
Publicar un comentario