En el último post expliqué cómo usar un Provider
propio para autenticarse con certificado de cliente en una conexión HTTPS. El siguiente paso era inevitable: queríamos usar la misma infraestructura para firmar ficheros jar (requisito indispensable si queremos desplegar un applet con ciertos privilegios, por ejemplo).
Como sabéis, el JDK nos ofrece una herramienta de línea de comandos llamada jarsigner
. Es la única opción que tenemos para firmar un jar, ya que no se ofrece un API para poder hacerlo de forma programática. La herramienta está pensada sobre todo para utilizar un keystore
Java o un fichero PKCS#12, donde estaría la clave privada. Pero ¿qué hacemos si la única forma de acceder a la misma es mediante un Provider
propio.
Nuevamente la solución pasa por estudiar primero cómo se haría con un PKCS#11. La documentación oficial de Oracle es un poco parca al respecto, pero suficiente para hacernos una idea. Al igual que ocurría en el post anterior, si nuestra implementación no está basada en un fichero en el disco donde se encuentran las entradas, como opción -keystore
se debe pasar el literal "NONE". La opción -storetype
deberá tener el nombre que le hayamos dado a nuestro propio tipo de KeyStore
. Y aquí viene lo importante: deberemos usar la opción -providerClass
con el nombre completo de nuestra implementación de Provider
, incluyendo el paquete. Un ejemplo sencillo podría ser el siguiente:
jarsigner -keystore NONE -storetype MyType -storepass password -providerClass my.package.MyProvider /path/to/app.jar alias
Pero para que nos funcione, antes debemos hacer algo muy importante. ¿Cómo sabe la herramienta jarsigner
dónde está el jar con nuestra implementación de Provider
? Pues en realidad, no lo sabe. Ni tampoco se lo podemos decir. La herramienta jarsigner
no tiene una opción -classpath
o similar con que pasarle las rutas con los jars que debe usar. Así que nuestra única posibilidad es añadir nuestra implementación a la instalación del JDK, en la carpeta destinada a extender el JRE: $JAVA_HOME/jre/lib/ext/
. No hay que perder de vista que tal vez necesitemos permisos de administrador para ello.
Además, hay tener en cuenta las implicaciones de esta acción: cualquier aplicación Java que se ejecute con esa instalación, podrá usar nuestra implementación de Provider
. Eso no quiere decir que nuestra implementación pueda usarse por accidente si no queremos. Añadir nuestros jars a la carpeta de extensión, sólo quiere decir que sus clases estarán disponibles, como si se trataran de las del propio JRE. Pero si una aplicación quiere hacer uso de nuestro Provider
, necesitará instalarlo con la conocida llamada a java.security.Security.addProvider(java.security.Provider provider). Si queremos que nuestro Provider
esté siempre disponible como el resto de los que trae el JDK, sin necesidad de añadirlo dinámicamente en nuestra aplicación, debemos configurarlo en el fichero $JAVA_HOME/jre/lib/security/java.security
(y hay que estar muy seguros de que realmente es eso lo que queremos).
Posiblemente, nuestra implementación necesite algún parámetro. En mi caso concreto, era la URL del servicio remoto. En el caso de la implementación PKCS#11 de Sun, es un fichero de configuración. Si a jarsigner
le pasamos la opción -providerArg
, el JDK buscará un constructor con un String
como único argumento, y lo invocará usando el valor de la opción en cuestión.
Otro detalle muy importante, que nos puede dar sorpresas si no lo tenemos en cuenta. La herramienta usa una serie de algoritmos de firma por defecto, dependiendo del tipo de nuestra clave privada. Por ejemplo, para una clave RSA, el algoritmo por defecto es SHA256withRSA
a partir de Java 7. Si nuestro Provider
no implementa el algoritmo que jarsigner
elija, se utilizará otro Provider
, con resultados no deseados. Así que, o bien nos aseguramos de que nuestro Provider
implemente los algoritmos por defecto, o bien utilizamos la opción -sigalg
, indicando el algoritmo que queremos usar.
Así que nuestra llamada a jarsigner
nos podría quedar algo parecido a esto (por claridad, he troceado el comando en varias líneas):
$HAVA_HOME/bin/jarsigner \
-keystore NONE \
-storetype MyKeyStoreType \
-storepass mypassword \
-providerClass my.own.package.MyProvider \
-providerArg "some string with some configuration" \
-sigalg SHA1withRSA \
/path/to/file/to/be/signed/app.jar \
alias-to-use
No hay comentarios:
Publicar un comentario