Autoridades de Certificación personalizadas en Java: la pesadilla detrás de una VPN

Y aquí estamos, rascandonos la cabeza y preguntándonos por qué no hemos podido conectarnos a esa API por la que llevamos tiempo intentando hacer funcionar.

Yo, a la 1 am y después de 6 horas mirando documentacion de Spring

Una de las cuestiones a tener en cuenta, cuando trabajamos detras de una VPN corporativa, es que es probable que muchos recursos estén bloqueados, y que otros simplemente han sido “alterados” o sobrepasados por la configuracion de la VPN.

Este caso puede que no sea visible, ya que los grandes proveedores de VPN usan Autoridades de Certificacion (CA) que están incluidas en los navegadores más comunes como Chrome, Firefox, Safari o Edge.

Sin embargo este no siempre es el caso cuando hablamos de la Máquina Virtual de Java (JVM) y sus certificados CA incluidos.

Como identificar que el error procede de una CA no configurada en tu JVM?, no tenemos una lista extensiva de errores, pero si podemos dar un indicio con el siguiente mensaje de error:

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Y aunque el error nos dice algo relacionado con una “ruta de certificacion”, si es la primera vez que ves un error de estos puede que no sepas como solucionarlo.

Lo primero que debemos saber, es donde se almacenan los certificados de CA que usa nuestra JVM/JDK, que comúnmente se ubican en esta ruta:

$JAVA_HOME/lib/security/cacerts

Donde $JAVA_HOME es la ruta de instalacion de nuestra JVM/JDK, la ubicacion puede variar dependiendo del Sistema Operativo (SO), pero es una buena práctica que la variable de entorno siempre este definida. En el caso de Linux y MacOs, es posible ejecutar el siguiente comando para saber si la tenemos instalada y que nos diga donde se encuentra:

$ /usr/libexec/java_home
/Users/razor/Library/Java/JavaVirtualMachines/openjdk-21.0.2/Contents/Home

En caso que nuestra variable no este correctamente configurada, podriamos ejecutar esta linea para asignarla de manera efectiva:

$ export JAVA_HOME=$(/usr/libexec/java_home)

Ahora que tenemos configurado nuestro entorno de JVM, debemos obtener una copia del certificado que usa la API que deseamos configurar. Para efectos académicos, usaremos la API de libros de Google.

Para obtener una copia del certificado, usaremos OpenSSL con el siguiente comando:

$ openssl s_client -connect books.googleapis.com:443 < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > public.crt

Explicando lo que hace el anterior comando, va a procesar el certificado SSL que será provisto al navegar a https//books.googleapis.com (como es conexion al puerto 443, se infiere que es HTTPS), y lo guardará en el archivo public.crt, después de extraer la informacion real del certificado.

Ahora que tenemos el certificado, solo resta agregarlo a la cadena de certificacion de nuestra JVM, lo que haremos con el comando keytool que se incluye en nuestra JVM:

$ $JAVA_HOME/bin/keytool -import -alias books.googleapis.com -cacerts -file public.crt -noprompt

Nuevamente explicando el comando, ejecutamos la utilidad keytool desde nuestra ubicacion de instalacion de JVM, importando (-import) el certificado ubicado en el archivo public.crt (-file) en nuestra lista de CAs de confianza (-cacerts), usando el alias books.googleapis.com.

El parámetro -alias nos permite administrar posteriormente dicho certificado, ya sea que toque actualizarlo, o cuando no necesitemos mas porque estemos fuera de la VPN. El parámetro -noprompt es para no tener que confirmar la acción, algo util si quisieras incluir estas instrucciones en un solo archivo y ejecutarlas periódicamente.

Para probar que nuestro problema ha sido resuelto, podriamos ejecutar simplemente nuestra aplicación de nuevo, no obstante pueda que nuestra aplicación sea demasiado grande y nuestro tiempo muy valioso.

Una sugerencia sería usar SSLPoke, una utilidad de Atlassian, que nos ayuda a verificar si los certificados instalados son correctos para conectarnos a un sitio:

$ $JAVA_HOME/bin/java SSLPoke books.googleapis.com 443
Successfully connected

Ya con estos pasos descritos anteriormente, el error causado por los certificados CA detras de una VPN debería estar resuelto.

También te podría gustar...

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *