Los certificados se utilizan como firmas digitales , que proporciona una autenticación segura cuando se conectan los clientes a un servidor.
Keytool genera un almacen de claves , que tienen certificados de seguridad.
Los Keystores pueden utilizar el formato P12 o JKS .
P12 archivos son casi universalmente compatibles, pero el formato es extremadamente complejo.
Es posible utilizar keytool para convertir P12 a JKS , un formato más sencillo sólo se puede acceder a través de las aplicaciones Java.
Aqui las Instrucciones :
1.- Haga clic en " Inicio". Escriba " cmd" en el cuadro de búsqueda y luego presionar "Enter " para abrir el símbolo del sistema .
2.-Tipo "cd /" sin las comillas en la aplicación de línea de comandos y presione "Enter " para acceder a la carpeta raíz.
3.- Escriba "cd " seguido por el pleno del ruta de acceso que une al directorio donde se guarda el almacén de claves
4.-Escriba lo siguiente en el símbolo del sistema para convertir P12 a JKS :
keytool- importkeystore - srckeystore keystore.p12 - srcstoretype PKCS12 - deststoretype keystore.jks JKS - destkeystore
Pulse " Enter" después de cada comando para convertir P12 a JKS en Keytool .
Es posible que se le pida para crear una nueva contraseña para el almacén de claves JKS , se recomienda que utilice la misma contraseña del almacén de claves originales
Generar y convertir claves y certificados con OpenSSL
Usando los comandos expuestos en este artículo y con OpenSSL podemos crear una clave pública y privada para usarlo con ssh o para cifrar y descifrar mensajes, un certificado autofirmado que podremos usar en un servidor de aplicaciones para usar un protocolo seguro y también convertir las claves y certificados a uno de los formatos aceptados por la aplicación que usemos.
Para un uso personal como enviar correos o archivos cifrados o firmados digitalmente usar GnuPG es una buena opción. En Internet los servidores también se aprovechan del uso de criptografía para realizar comunicaciones seguras entre el usuario y el servidor.Para hacer uso en un servidor de una comunicación https donde los datos viajan cifrados y sin que otras partes salvo el usuario y el servidor puedan acceder a los datos necesitamos un certificado digital. Un certificado es un archivo que contiene la clave pública sirviéndonos para verificar su autenticidad. Un certificado autofirmado es un certificado firmado con la misma clave privada asociada a la clave pública que contiene el certificado. Un certificado autofirmado es suficiente para un entorno de pruebas pero en un servidor para proporcionar confianza a los usuarios deberemos solicitar que una autoridad de certificados que nos firme con su clave nuestro certificado, si el usuario confía en esa autoridad de certificado puede de esta manera confiar en nuestro certificado y clave pública. Varias entidades de registro de dominios o halojamiento web ofrecen la compra de certificados SSL, en el artículo Certificado SSL, de empresa, «wildcard» y de validación extendida comento con un poco más detalle los varios tipos de certificados y algunas opciones donde obtenerlos o comprarlos.
Dependiendo del tipo de certificado que solicitemos y nos entregue la autoridad de certificado el usuario podrá ver que está simplemente accediendo a un servidor con conexión segura, ver los detalles de nuestro certificado y en algunos casos el usuario podrá ver en la barra de direcciones en verde el nombre de la entidad, que puede darle al usuario más confianza y ver que realmente está accediendo al servidor correcto y no a uno que esté intentando suplantar una identidad. En este último caso la barra de direcciones no tendría en verde el nombre de la entidad, esto es algo que como usuarios debemos comprobar al acceder a determinados sitios de forma segura.
Con la herramienta OpenSSL y los siguientes comandos podemos generar claves y certificados y realizar las conversiones entre formatos que necesitemos.
Convertir un certificado a otros formatos
Dependiendo de la autoridad de certificado el certificado puede estar en diferentes formatos, dependiendo del servidor donde tengamos idea de usarlo podemos necesitar convertirlo a otro formato. También podemos usar OpenSSL para hacer las conversiones.Convertir un certificado en formato DER (.crt .cer .der) a PEM
$ cat localhost.key localhost.crt > localhost.pem |
$ openssl x509 -in localhost.crt -out localhost.pem |
$ openssl x509 -inform der -in localhost.cer -out localhost.pem |
Convertir un certificado en formato PEM a DER
$ openssl x509 -outform der -in localhost.pem -out localhost.der |
Convertir un archivo en formato PKCS#12 (.pfx .p12) que contiene una clave privada y certificado a PEM
$ openssl pkcs12 -in localhost.p12 -out localhost.pem -nodes |
$ keytool -importkeystore -destkeystore localhost.keystore -srckeystore localhost.p12 -srcstoretype pkcs12 |
Aqui unos ejemplos:
openssl genrsa -out localhost.key 8192 |
openssl req -new -key localhost.key -out localhost.csr |
openssl x509 -outform der -in localhost.pem -out localhost.der |
openssl pkcs12 -in localhost.p12 -out localhost.pem -nodes |
keytool -importkeystore -destkeystore localhost.keystore -srckeystore localhost.p12 -srcstoretype pkcs12 |
openssl rsa -in localhost.key -pubout > localhost.pub |
Otra forma enerar y convertir claves y certificados con OpenSSL
En primer lugar, asegúrese de que usted tiene OpenSSL instalado. Muchos sistemas operativos ya lo han instalado como he encontrado con Mac OS X.Los dos comandos siguientes convertir el archivo pfx a un formato que puede ser abierto como un Java PKCS12 almacén de claves:
openssl pkcs12 -in mypfxfile.pfx -out mypemfile.pem
openssl pkcs12 -export -in mypemfile.pem -out mykeystore.p12 -name "MyCert"
Tenga en cuenta que el nombre proporcionado en el segundo comando es el alias de tu clave en el nuevo almacén de claves.
Referencia
Usted puede verificar el contenido del almacén de claves utilizando el programa de utilidad keytool de Java con el siguiente comando:
keytool -v -list -keystore mykeystore.p12 -storetype pkcs12
Por último, si necesita usted puede convertir esto en un
almacén de claves JKS importando el almacén de claves creado
anteriormente en un nuevo almacén de claves:keytool -importkeystore -srckeystore mykeystore.p12 -destkeystore clientcert.jks -srcstoretype pkcs12 -deststoretype JKS
Exportar e Importar con Java Keytool
Informacion de ReferenciaExportar su certificado a un archivo
Si desea respaldar su certificado para utilizar en el mismo u otro servidor web también con Java solo necesita copiar el archivo .keystore a un medio extraible.
Si desea exportar su certificado para importar en otro servidor web sin Java deberá descargar e instalar un programa externo para poder hacerlo ya que la herramienta keytool no cuenta con un comando para extraer la clave privada del .keystore.
Alguno de los programas que le permitirán hacer la exportación de la clave privada son: KeyTool-IUI, Portecle, Keystore Explorer
Importar su certificado desde un archivo
Para utilizar su archivo .pfx o .p12 como keystore para tomcat debe ejecutar el siguiente comando:
keytool -import -alias tomcat -keystore archivo.p12
Su keystore se encuentra ahora listo para ser configurado en tomcat modificando el archivo server.xml de la siguiente forma:
keystoreType="PKCS12"
keystoreFile="archivo.p12"
keystorePass=Contraseña
Convertir su certificado de .pfx o .p12 a .jks
Deberá contar con openssl y alguno de los programas que le permitirán convertir el formato de su certificado como por ejemplo: KeyTool-IUI, Portecle, Keystore ExplorerCualquiera de estos programas tienen la opción de abrir un .pfx o .p12 y guardarlo como .jks o .keystore cambiando el formato de manera sencilla. En nuestra experiencia, todos ellos fallan en importar el archivo en formato .pfx o .p12 si existe la más mínima diferencia en formatos.
Si estos programas fallan en abrir su .pfx o .p12 deberá seguir estos pasos para convertir su certificado en un formato que estos programas puedan abrir.
(Puede descargar openssl para Windows de aqui)
Extraer su clave privada y convertirla
openssl pkcs12 -in archivo.pfx -nocerts -nodes -out clavepriv.pem
openssl rsa -in clavepriv.pem -out convertpriv.pem
Extraer sus certificados
openssl pkcs12 -in archivo.pfx -nokeys -out cert.pem
Generar keystore
Ahora debe crear un nuevo keystore vacío utilizando alguno de los programas mencionados e importar la clave privada y el certificado extraídos, ya sea por separado (KeyTool-IUI) o concatenando los certificados al archivo de la clave (Portecle)
Concatenar archivos
Windows
copy convertpriv.pem+cert.pem completo.pem
Linux
cat convertpriv.pem cert.pem > completo.pem
Como convertir un Keystore JKS al formato PKCS12 (.p12)
NOTA: Este comando es compatible con versiones de JDK/JRE 1.6 o mayores. Keytool es una herramienta de terceros.
keytool -importkeystore -srckeystore [MY_KEYSTORE.jks] -destkeystore [MY_FILE.p12]
-srcstoretype JKS - deststoretype PKCS12 -deststorepass [PASSWORD_PKCS12]
Lista de parametros:
MY_KEYSTORE.jks: ruta del archivo keystore que desea convertir.
MY_FILE.p12: ruta del archivo PKCS12 (.p12 o extension .pfx) que se crear.
PASSWORD_PKCS12: la contraseña del archivo PKCS12.
Para verificar el contenido del archivo PKCS12, ejecute el siguiente comando:
keytool -list -v -keystore MY_FILE.p12 -storetype pkcs12
Java Archivo .JKS Creación de un .PFX
Convertir de Formatos de Certificado de .PFX al .JKS
Tenga en cuenta que el objetivo de estas instrucciones es para mostrar cómo separar los certificados SSL y la llave privada para generar un archivo .PFX y combinarlos en un Keystore "Almacén de Llaves" de Java.Esta operación requirirá las dos programas Keytool y OpenSSL, y una utilidad de Weblogic específicas también.
Convertir PFX al JKS En Weblogic
PFX es un formato de certificados SSL que se utilice en Windows que combina ambos el archivo de todos los certificados SSL de la cadena de confianza que contine el archivo de la llave pública y la llave privada asociada en un solo archivo .PFX.
Con el fin de convertir sus archivos de certificado en un formato que se puede utilizar por un servidor basado en Java, usted tendrá que extraer primero los certificados y la llave privada de su archivo PFX mediante el programa OpenSSL, y luego importar el CERT a su Keystore "Almacén de Llaves" usando el programa Keytool.
- En primer lugar, Cree un Archivo .PFX desde el servidor de Microsoft si no lo ha hecho.
- En segundo lugar, ejecute el siguiente comando de OpenSSL para extraer sus certificados y la llave privada del archivo .PFX:
openssl pkcs12-in-out suDominio.pfx certificado_temporario.crt -nodes
- Ahora debería tener un archivo llamado certificado_temporario.crt. Abra este archivo con un editor de texto (como WordPad) y verá la llave privada aparece en primer lugar, seguido por los archivos de su certificado:
----- BEGIN RSA PRIVATE KEY -----
(Bloque de Texto Cifrado)
----- END RSA PRIVATE KEY -----
- Cortar y pegar todo la llave privada, incluyendo el BEGIN y END etiquetas a un archivo de texto y guardarlo como su_dominio_com.key
- Los certificados que queda en su certificado_temporario.crt será en el siguiente orden, Certificado de Servidor, Certificado Intermedio, Certificado Raíz, dependiendo de su exportación PFX podría haber entre 2 y 4 certificados por separado dentro de este fichero.
- Con tal que haya exportado el certificado correctamente, tendrá toda lo necesario para guardar el certificado. Asegúrese de que la llave privada se quitó del archivo, y luego seguir adelante y guarde este archivo como su_dominio_com.pem.
- Si usted tiene acceso para iniciar sesión en su cuenta DigiCert, seguir adelante e iniciar sesión en, haga clic en el número de pedido y descargue el archivo TrustedRoot.crt.
- Si no, vaya de nuevo en el archivo vaya a abrir el archivo certificado_temporario.crt en un editor de texto y copie el segundo certificado incluso las etiquetas BEGIN CERTIFICATE y END CERTIFICATE en un archivo nuevo y nombre este archivo TrustedRoot.crt.
- Usted puede asegurarse de que haya elegido el archivo correcto, verificando que su TrustedRoot.crt se emitió por la misma organización. Nota: Debido al hecho de que DigiCert frecuentamente emite certificados firmado por unas otras autoridades de certificación para mejorar la compatibilidad en varias tipos de servidores y aplicaciones de cliente y servidor, la información de su certificado raíz puede ser diferente de lo que se muestra en la imagen de abajo.
- Cree una Almacén de Llaves de Autoridad Confiada-
Ejecutar las siguientes dos líneas como un comando (en una linea) en Keytool:
keytool -import -trustcacerts -file TrustedRoot.crt -alias servidor
-Keystore nuevo_almacen_confiado.jks -storepass NUEVACONTRASEÑA
Usted debe ingresar su contraseña después de -storepass en el código de encima.
- A continuación, se creará un Identidad Almacén de Certificados, Ejecute el siguiente comando:
-
java utils.ImportPrivateKey -keystore nuevo_almacen_identidad.jks -storepass
CONTRASEÑA -storetype JKS -keypass NUEVACONTRASEÑA -alias
servidor -certfile certificado_temporario.crt -keyfile su_dominio_com.key
-Keyfilepass PFXCONTRASEÑA
Entre su propia contraseña para el storepass-y-keypass atributos, por encima, y la contraseña de PFX que se habrían creado cuando el archivo PFX fue creado.
Ahora debe tener dos archivos, nuevo_almacen_confiado.jks y
nuevo_almacen_identidad.jks. Estos archivos deben estar listos para
estar habilitado para SSL en su servidor basado en Java.
Autenticación de cliente SSL en web services con Axis2
Normalmente uso Axis2 para crear mis clientes de web services; es
bastante sencillo ya que solamente hay que ejecutar el script wsdl2java
pasando el WSDL del web service y se genera una clase que contiene todo
lo necesario para invocar los métodos publicados en el servicio.
Recientemente, me topé con un web service que en pruebas funcionó muy bien pero resulta que en producción había que activar SSL (o sea https://blabla en el URL en vez de solamente http://blabla) y además tuve que implementar un esquema muy poco usual (aunque sea un estándar): autenticación de cliente con PKI (Public Key Infrastructure - Infraestructura de Llave Pública).
El funcionamiento de SSL por lo general es que solamente el servidor se autentica con el cliente, y luego el cliente se autentica de alguna forma específica a la aplicación. La manera en que funciona la autenticación del servidor en una conexión SSL es via PKI; el servidor utiliza un certificado X509 que contiene su información, una fecha de expiración, una llave pública (RSA por lo general) y algunos datos del emisor de dicho certificado. En PKI se maneja el concepto de cadena de confianza, que consiste en que para poder aceptar el certificado de alguien más como válido, es necesario conocer al emisor o emisores de dicho certificado, hasta llegar al certificado raíz; si todos son considerados válidos y conocidos por el cliente, entonces se puede considerar válido el certificado del servidor.
Con Axis2 o cualquier otra herramienta para web services, todo este mecanismo de autenticar al servidor se maneja ya de forma automática. De hecho quien se encarga es el mismo JRE, porque con el ambiente Java ya vienen incluidos los certificados raíz más populares, por lo que cualquier certificado emitido por ellos será aceptado como válido (siempre y cuando cumpla las otras condiciones, como que esté vigente, etc).
Pero en SSL también el servidor puede autenticar a los clientes de la misma forma, es decir, solicitando al cliente su certificado X509 para validarlo. Esto ya no se maneja de manera tan transparente en Java; una opción para lograr esto es tener el certificado cliente y la correspondiente llave privada, almacenados en el KeyStore del usuario que corre el programa que quiere hacer la conexión que requiere autenticación de cliente. Pero entonces hay que estar configurando el KeyStore de cada cliente, y eso puede ser problemático, o bien puede ser que ni siquiera tengamos permiso de modificar ese KeyStore y por lo tanto hay que usar un KeyStore privado.
Esto último fue mi caso: tengo una aplicación que invoca distintos web services y solamente uno de ellos me pide este esquema, por lo que no quiero modificar todo el KeyStore porque hay que hacerlo en desarrollo y luego en producción y cualquier otra persona que quiera invocar el web service tiene que hacer lo mismo. De modo que preferí hacer un KeyStore privado para este web service. En Axis2, necesitamos primero que nada crear una fábrica de sockets para el HttpClient que usa el cliente del web service. De modo que hay que implementar la interfaz
Ya que tenemos el KeyStore, necesitamos crear una KeyManagerFactory con el mismo:
Finalmente, ya que tenemos el KeyManagerFactory, debemos crear un SSLContext que es con el que vamos a crear los sockets que necesita el web service para enviar y recibir datos:
El objeto SSLContext es el que se debe usar en los métodos para crear
sockets de nuestra implementación de SecureProtocolSocketFactory. La
implementación es bastante directa, simplemente en cada método hay que
devolver un socket creado por el SSLContext con los parámetros
recibidos, por ejemplo:
Con esto apenas tenemos lo necesario para poder crear sockets SSL con
un contexto que permite autenticar al cliente si el servidor lo
requiere. Ahora tenemos que registrar este SecureProtocolSocketFactory
con nuestro web service, para el protocolo https (podríamos ponerle el
nombre que sea al protocolo; siempre y cuando usemos ese protocolo en el
URL, se va a usar nuestra fábrica de sockets). Si el web service lo
generamos usando Axis2 ADB con el programa wsdl2java (yo usé Axis2 1.5)
entonces:
Con lo anterior, si le pasamos al web service un URL que comience con https:// entonces se va a usar nuestra fábrica de sockets, la cual tiene el SSLContext que contiene el certificado y llave privada del archivo PKCS12 para poder autenticarse con el server. Si el servidor tiene un certificado válido emitido por una de las autoridades certificadas reconocidas por nuestra instalación de Java, ya estamos listos para invocar el web service via SSL.
Adicionalmente, si el servidor usa un certificado auto-firmado, al invocar el web service vamos a obtener un error porque Java no reconoce el certificado del servidor; en este caso, hay que hacer algo de trabajo adicional. Necesitamos obtener el certificado del servidor, y guardarlo en un archivo de KeyStore. Por seguridad, no recomiendo usar el KeyStore default del usuario, sino usar uno separado. Para ello necesitamos un archivo con el certificado y luego lo importamos a un nuevo KeyStore con la herramienta keytool (esto no es tan relevante para este post, simplemente hay que ver la documentación del programa keytool; al final tendremos un archivo tipo JKS protegido por un password).
Una vez que tenemos el archivo, debemos crear un TrustManagerFactory, de preferencia en el mismo lugar donde creamos el KeyManagerFactory (dentro de nuestra fábrica de sockets, antes de crear el SSLContext):
Con esto, ya tenemos un SSLContext que crea sockets para conexiones SSL donde se reconoce únicamente el certificado auto-firmado del servidor y que se van a autenticar con el certificado y llave privada del archivo PKCS12.
Estuve peleándome un buen rato con esto porque no hay mucha documentación, espero le sirva a alguien en el futuro. Aplica para Axis2, lo hice con 1.5 pero supongo que funciona con algunas versiones anteriores.
De hecho esto funciona para autenticar a un cliente con cualquier servidor SSL; en el caso de web services hay que encapsular todo esto en la implementación de SecureProtocolSocketFactory pero en caso de usar SSL puro, el código será muy similar aunque vaya encapsulado en algún componente distinto.
Recientemente, me topé con un web service que en pruebas funcionó muy bien pero resulta que en producción había que activar SSL (o sea https://blabla en el URL en vez de solamente http://blabla) y además tuve que implementar un esquema muy poco usual (aunque sea un estándar): autenticación de cliente con PKI (Public Key Infrastructure - Infraestructura de Llave Pública).
El funcionamiento de SSL por lo general es que solamente el servidor se autentica con el cliente, y luego el cliente se autentica de alguna forma específica a la aplicación. La manera en que funciona la autenticación del servidor en una conexión SSL es via PKI; el servidor utiliza un certificado X509 que contiene su información, una fecha de expiración, una llave pública (RSA por lo general) y algunos datos del emisor de dicho certificado. En PKI se maneja el concepto de cadena de confianza, que consiste en que para poder aceptar el certificado de alguien más como válido, es necesario conocer al emisor o emisores de dicho certificado, hasta llegar al certificado raíz; si todos son considerados válidos y conocidos por el cliente, entonces se puede considerar válido el certificado del servidor.
Con Axis2 o cualquier otra herramienta para web services, todo este mecanismo de autenticar al servidor se maneja ya de forma automática. De hecho quien se encarga es el mismo JRE, porque con el ambiente Java ya vienen incluidos los certificados raíz más populares, por lo que cualquier certificado emitido por ellos será aceptado como válido (siempre y cuando cumpla las otras condiciones, como que esté vigente, etc).
Pero en SSL también el servidor puede autenticar a los clientes de la misma forma, es decir, solicitando al cliente su certificado X509 para validarlo. Esto ya no se maneja de manera tan transparente en Java; una opción para lograr esto es tener el certificado cliente y la correspondiente llave privada, almacenados en el KeyStore del usuario que corre el programa que quiere hacer la conexión que requiere autenticación de cliente. Pero entonces hay que estar configurando el KeyStore de cada cliente, y eso puede ser problemático, o bien puede ser que ni siquiera tengamos permiso de modificar ese KeyStore y por lo tanto hay que usar un KeyStore privado.
Esto último fue mi caso: tengo una aplicación que invoca distintos web services y solamente uno de ellos me pide este esquema, por lo que no quiero modificar todo el KeyStore porque hay que hacerlo en desarrollo y luego en producción y cualquier otra persona que quiera invocar el web service tiene que hacer lo mismo. De modo que preferí hacer un KeyStore privado para este web service. En Axis2, necesitamos primero que nada crear una fábrica de sockets para el HttpClient que usa el cliente del web service. De modo que hay que implementar la interfaz
org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory
.
En mi caso, recibí el certificado y la llave privada en un archivo de
tipo PKCS#12, un formato que permite almacenar precisamente una serie de
llaves privadas y sus correspondientes certificados, protegido todo por
un password. Afortunadamente, Java permite leer este tipo de archivos
como un KeyStore. Simplemente hay que hacer lo siguiente:
String password = "el password del archivo PKCS12"
java.security.KeyStore ks = KeyStore.getInstance("PKCS12"); InputStream stream = //obtener de alguna manera un InputStream para el contenido del archivo PKCS12
ks.load(stream, password.toCharArray());
stream.close();
java.security.KeyStore ks = KeyStore.getInstance("PKCS12"); InputStream stream = //obtener de alguna manera un InputStream para el contenido del archivo PKCS12
ks.load(stream, password.toCharArray());
stream.close();
javax.net.ssl.KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, password.toCharArray());
kmf.init(ks, password.toCharArray());
Finalmente, ya que tenemos el KeyManagerFactory, debemos crear un SSLContext que es con el que vamos a crear los sockets que necesita el web service para enviar y recibir datos:
javax.net.ssl.SSLContext ssl = SSLContext.getInstance("SSL"); //Otra opcion es TLS
ssl.init(kmf.getKeyManagers(), null, null); //El segundo parametro es una lista de TrustManagers, si pasamos null se usan los de default de Java //El tercer parametro es un SecureRandom, si pasamos null si usa el default de Java
ssl.init(kmf.getKeyManagers(), null, null); //El segundo parametro es una lista de TrustManagers, si pasamos null se usan los de default de Java //El tercer parametro es un SecureRandom, si pasamos null si usa el default de Java
public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
throws IOException, UnknownHostException {
return ssl.getSocketFactory().createSocket(host, port, localHost, localPort); }
throws IOException, UnknownHostException {
return ssl.getSocketFactory().createSocket(host, port, localHost, localPort); }
NuestraSubclaseDeSecureProtocolSocketFactory fabrica = //esta la debemos tener ya lista
org.apache.commons.httpclient.protocol.Protocol proto = new Protocol("https", fabrica, 443); //El protocolo tiene el nombre, la fabrica de sockets, y el puerto default a donde deben conectarse
miWebServiceStub._getServiceClient().getOptions().setProperty(HTTPConstants.CUSTOM_PROTOCOL_HANDLER, proto);
org.apache.commons.httpclient.protocol.Protocol proto = new Protocol("https", fabrica, 443); //El protocolo tiene el nombre, la fabrica de sockets, y el puerto default a donde deben conectarse
miWebServiceStub._getServiceClient().getOptions().setProperty(HTTPConstants.CUSTOM_PROTOCOL_HANDLER, proto);
Con lo anterior, si le pasamos al web service un URL que comience con https:// entonces se va a usar nuestra fábrica de sockets, la cual tiene el SSLContext que contiene el certificado y llave privada del archivo PKCS12 para poder autenticarse con el server. Si el servidor tiene un certificado válido emitido por una de las autoridades certificadas reconocidas por nuestra instalación de Java, ya estamos listos para invocar el web service via SSL.
Adicionalmente, si el servidor usa un certificado auto-firmado, al invocar el web service vamos a obtener un error porque Java no reconoce el certificado del servidor; en este caso, hay que hacer algo de trabajo adicional. Necesitamos obtener el certificado del servidor, y guardarlo en un archivo de KeyStore. Por seguridad, no recomiendo usar el KeyStore default del usuario, sino usar uno separado. Para ello necesitamos un archivo con el certificado y luego lo importamos a un nuevo KeyStore con la herramienta keytool (esto no es tan relevante para este post, simplemente hay que ver la documentación del programa keytool; al final tendremos un archivo tipo JKS protegido por un password).
Una vez que tenemos el archivo, debemos crear un TrustManagerFactory, de preferencia en el mismo lugar donde creamos el KeyManagerFactory (dentro de nuestra fábrica de sockets, antes de crear el SSLContext):
String pass2 = "el password del keystore que contiene el certificado del servidor";
javax.net.ssl.TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm()); KeyStore ks2 = KeyStore.getInstance("JKS"); InputStream stream2 = //obtener un InputStream al archivo tipo JKS que generamos con keytool y que contiene el certificado auto-firmado del servidor
ks2.load(stream2, pass2.toCharArray());
stream2.close();
tmf.init(ks2); //Modificamos el inicializador de nuestro SSLContext, el segundo parametro ya tiene valor
ssl.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
javax.net.ssl.TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm()); KeyStore ks2 = KeyStore.getInstance("JKS"); InputStream stream2 = //obtener un InputStream al archivo tipo JKS que generamos con keytool y que contiene el certificado auto-firmado del servidor
ks2.load(stream2, pass2.toCharArray());
stream2.close();
tmf.init(ks2); //Modificamos el inicializador de nuestro SSLContext, el segundo parametro ya tiene valor
ssl.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
Con esto, ya tenemos un SSLContext que crea sockets para conexiones SSL donde se reconoce únicamente el certificado auto-firmado del servidor y que se van a autenticar con el certificado y llave privada del archivo PKCS12.
Estuve peleándome un buen rato con esto porque no hay mucha documentación, espero le sirva a alguien en el futuro. Aplica para Axis2, lo hice con 1.5 pero supongo que funciona con algunas versiones anteriores.
De hecho esto funciona para autenticar a un cliente con cualquier servidor SSL; en el caso de web services hay que encapsular todo esto en la implementación de SecureProtocolSocketFactory pero en caso de usar SSL puro, el código será muy similar aunque vaya encapsulado en algún componente distinto.
No hay comentarios:
Publicar un comentario