Pues resulta que mi última labor ha consistido en acceder al keystore de Firefox para recuperar certificados y firmar con ellos.
La labor ha sido ardua, ya que he encontrado mil referencias en páginas, foros y blogs, pero como casi siempre, he tenido que ir tomando ideas de aquí y de allí e ir construyendo la solución a partir de todas ellas.
El primer camino consistió en tratar de utilizar la librería
JSS de
Mozilla, pero no hubo manera de que funcionase. Para empezar era necesario colocar una librería en el directorio de instalación de Firefox. Después, necesitabamos firmar (CMS signature) y para ello usabamos las clases de Bouncy Castle, pero no conseguimos firmar con BC con el certificado que obteníamos mediante JSS... ¡¡uff!!.
Hay que decir que realmente sí conseguíamos firmar, pero sólo obteníamos el hash, cuando lo que buscábamos era el formato "detached" (el resultado de firmar es una cadena codificada en base 64 que incluye aparte del hash, información del propio certificado).
Inicialmente, sólo conseguimos firmar solicitando al cliente que indicase el archivo que contenía el certificado. No era lo que queríamos, pero no teníamos otra solución.
Comoquiera que esta solución no satisfacía a nadie, continué investigando, y descubrí la clase
sun.security.pkcs11.SunPKCS11, la cual actúa como wrapper sobre las librerías nativas PKCS11 y permite su uso para acceder a los dispositivos que almacenan certificados.
Para usar la clase es necesario pasarle path completo a un archivo de configuración, cuya contenido consiste en una seríe de parámetros que dependen del módulo PKCS11 nativo que vayamos a cargar.
Por último, quedaba saber qué librerías eran necesarias (incluyendo el módulo PKCS11) para poder acceder al keystore de Firefox. Las librerías son también de Mozilla:
NSS (Network Security Services) y NSPR.
Podemos obtener las librerías NSS de aquí:
Windows:
http://ftp.mozilla.org/pub/mozilla.org/security/nss/releases/NSS_3_11_4_RTM/msvc6.0/WINNT5.0_OPT.OBJ/nss-3.11.4.zipLinux:
http://ftp.mozilla.org/pub/mozilla.org/security/nss/releases/NSS_3_11_4_RTM/Linux2.6_x86_glibc_PTH_OPT.OBJ/nss-3.11.4.tar.gzCuando descomprimimos estos archivos, contienen un directorio lib en el cual aparecen una serie de librerías (.dll para Windows, .so para Linux) de las cuales necesitaremos exáctamente los siguiente archivos:
Windows:
- freebl3.dll
- libnspr4.dll
- libplc4.dll
- libplds4.dll
- softokn3.dll (módulo PKCS11)
Linux:
- libnspr4.so
- libplc4.so
- libplds4.so
- libsoftokn3.so (módulo PKCS11)
Si colocamos estas librerías en el java.library.path, parte de lo que explicaré a continuación no será necesario, pero en mi caso no podía realizar una instalación previa en el cliente, por lo cual mi solución consiste en incluir estos archivos como recursos en el jar que genero y en tiempo de ejecución crear un directorio en "user.home" en el cual escribo los archivos correspondientes al sistema (por supuesto, chequeando previamente si existe el directorio y los archivos están en el mismo).
Antes de poder acceder al keystore, necesitamos algo más. El constructor de la clase SunPKCS11 recibe como parámetro el path a un archivo de configuración que contiene cierta información que depende en parte del la librería nativa PKCS11 que vayamos a usar. En nuestro caso el archivo (test.cfg) debe contener algo parecido a esto:
name = NSS
slot = 2
library = C:/test/softokn3.dll
nssArgs = "configdir='C:/Documents and Settings/usuario/Datos de programa/Mozilla/Firefox/Profiles/zehrgci3.default' certPrefix='' keyPrefix='' secmod='secmod.db' flags=readOnly"
Nota (1): Es muy importante que el caracter separador de archivos sea "/", de lo contrario, obtendremos una excepción en el constructor de la clase SunPKCS11.
Nota (2): Es labor de cada uno averiguar en tiempo de ejecución en qué directorio está almacenado el keystore de Firefox. Lo que es seguro es que está en el "user.dir" o en un directorio dentro del "user.dir". Lo que es seguro es que en el directorio que buscamos deben estar los archivos "cert8.db", "key3.db" y "secmod.db". El directorio exácto en el que se encuentra depende del sistema operativo que usemos.
Lo que debemos hacer es algo parecido a esto:
//Crear el directorio "C:/test/"
//Escribir las librerías correspondientes
//Escribir el archivo de configuración
...
...
// Carga de las librerías en Windows
System.load("C:/test/libnspr4.dll");
System.load("C:/test/libplc4.dll");
System.load("C:/test/libplds4.dll");
System.load("C:/test/softokn3.dll");
//Creamos el Provider con la clase SunPKCS11
Provider nss = new sun.security.pkcs11.SunPKCS11("C:/test/test.cfg");
Security.insertProviderAt(nss, 1);
KeyStore ks = KeyStore.getInstance("PKCS11", nss);
ks.load(null,"".toCharArray());
Enumeration aliases = ks.aliases();
String alias = null;
while (aliases.hasMoreElements()) {
alias = (String) aliases.nextElement();
System.out.println(alias);
}
Security.removeProvider(nss.getName());
En mi siguiente post, enviaré un ejemplo de un código completo y funcional y además explicaré cómo acceder con Java a los certificados almacenados en el DNI electrónico de España.
Si alguien necesita el código inmediatamente, que me envié una respuesta al post.
Saludos,
pedrop.