Las aplicaciones Java generan el error javax.net.ssl.SSLHandshakeException: PKIX path building failed cuando la cadena de certificados del servidor está incompleta o cuando el truststore del JDK en el cliente no incluye el certificado raíz obligatorio. Identifique cuál es la causa y aplique la solución correspondiente.
Síntomas
Una aplicación Java que se conecta a un endpoint HTTPS falla con el siguiente mensaje:
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
La misma dirección HTTPS funciona correctamente en Chrome o Firefox, donde se muestra el ícono de candado de seguridad. Sin embargo, los clientes que no son navegadores (aplicaciones Java, curl, wget) reportan un fallo en el handshake TLS o un error de verificación de certificado.
Por qué los navegadores funcionan y Java falla: Los navegadores modernos implementan Authority Information Access (AIA) chasing. Cuando un servidor envía una cadena de certificados incompleta, estos descargan automáticamente los certificados intermedios faltantes para completarla. Los clientes Java no hacen esto; requieren que el servidor envíe la cadena completa durante el handshake TLS.
Causas
Causa 1: Cadena de certificados del servidor incompleta. El servidor envía únicamente su propio certificado (el certificado del nombre de dominio) y omite los certificados intermedios que lo vinculan con una raíz de confianza. Los clientes Java no pueden construir la cadena de confianza y rechazan la conexión.
Causa 2: Truststore del JDK desactualizado. El servidor envía una cadena completa, pero el truststore del JDK en el cliente (
$JAVA_HOME/jre/lib/security/cacerts) no incluye el certificado raíz o el certificado raíz de firma cruzada que utiliza dicha cadena. Esto suele ocurrir con versiones antiguas del JDK. Por ejemplo, después de que DigiCert cambió de la raíz G1 a la G2, las versiones anteriores del JDK dejaron de confiar en la raíz G2. Para más detalles, consulte Anuncio sobre el reemplazo del certificado raíz de DigiCert.
Diagnóstico del servidor
Antes de aplicar una solución, compruebe si el servidor envía una cadena de certificados completa. Tiene dos opciones disponibles:
Opción A: Comando de OpenSSL (requiere OpenSSL)
Ejecute el siguiente comando y reemplace your.domain.com:443 por el endpoint real de su servidor.
# Connect to the server and display the certificate chain it provides
openssl s_client -connect your.domain.com:443 -showcerts
Opción B: SSL Labs Server Test (no requiere CLI)
Vaya a https://www.ssllabs.com/ssltest/, introduzca su dominio y revise el campo Chain issues en el reporte. El valor Ninguna significa que la cadena está completa. Si aparece Incomplete o Extra download, al servidor le faltan certificados intermedios.
Interpretación de la salida de OpenSSL
Cadena incompleta (Causa 1)
La sección Certificate chain muestra una sola entrada (depth=0). El código de retorno de verificación es distinto de cero:
Certificate chain
0 s:/CN=your.domain.com
i:/C=US/O=DigiCert Inc/CN=DigiCert TLS RSA SHA256 2020 CA1
---
Server certificate
-----BEGIN CERTIFICATE-----
(Server certificate content)
-----END CERTIFICATE-----
...
Verify return code: 20 (unable to get local issuer certificate)
Cadena completa (estado correcto)
La salida contiene varios certificados que forman una cadena ordenada desde depth=0 (certificado del servidor) hasta depth=1 (certificado intermedio). El código de retorno de verificación es 0 (ok):
Certificate chain
0 s:/CN=your.domain.com
i:/C=US/O=DigiCert Inc/CN=DigiCert TLS RSA SHA256 2020 CA1
1 s:/C=US/O=DigiCert Inc/CN=DigiCert TLS RSA SHA256 2020 CA1
i:/C=US/O=DigiCert Inc/CN=DigiCert Global Root CA
---
...
Verify return code: 0 (ok)
Si la cadena está completa pero el cliente Java sigue fallando, continúe con Corregir un truststore del JDK desactualizado.
Corregir una cadena de certificados del servidor incompleta
Configure nuevamente el servidor para que envíe la cadena completa. Esto aplica tanto para servidores web como NGINX, Apache y Tomcat, como para load balancers como Server Load Balancer (SLB).
Obtenga el paquete completo de la cadena de certificados de su autoridad certificadora (CA). Este archivo suele contener primero el certificado del servidor y después todos los certificados intermedios. Generalmente se llama
fullchain.pemochain.pem.-
Compruebe el orden de los certificados en el archivo: el certificado del servidor debe ir primero, seguido de cada certificado intermedio.
Nota: Si los certificados están en un orden incorrecto, el servidor web podría fallar al iniciar.
-----BEGIN CERTIFICATE----- (Your server certificate content) -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- (Intermediate certificate 1 content) -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- (Intermediate certificate 2 content, if it exists) -----END CERTIFICATE----- Actualice la configuración SSL de su servidor web o gateway para que apunte a este archivo de certificado completo. Después, reinicie el servicio.
Vuelva a ejecutar el comando de OpenSSL o la prueba de SSL Labs. Compruebe que aparezca
Verify return code: 0 (ok)y que no existan problemas en la cadena.
Corregir un truststore del JDK desactualizado
Si la cadena del servidor está completa pero el cliente Java sigue fallando, al truststore del JDK le falta el certificado raíz obligatorio.
Actualizar el JDK (recomendado)
Actualice a la versión de parche Long-Term Support (LTS) más reciente de su JDK. Por ejemplo, utilice la última actualización de JDK 8, JDK 11 o JDK 17. Las versiones de parche más nuevas incluyen una biblioteca de certificados raíz actualizada que resuelve los problemas de reemplazo de raíces de CA. Además, incorporan correcciones de seguridad importantes.
Importar manualmente el certificado raíz (solución temporal)
Si no es posible actualizar el JDK de inmediato, importe el certificado raíz faltante en el truststore cacerts del JDK.
Descargue el archivo del certificado raíz faltante. Consulte Descargar certificados raíz.
-
Ejecute el siguiente comando de
keytool. Reemplace los marcadores de posición por los valores reales. La contraseña predeterminada del truststore eschangeit.Marcador de posición
Descripción
<give-a-unique-alias>Un nombre único para esta entrada de certificado en el truststore
<path-to-root-ca.crt>La ruta local del archivo de certificado raíz descargado
$JAVA_HOMESu directorio de instalación de Java
# Replace <path-to-root-ca.crt> with the path to the root certificate file # Replace $JAVA_HOME with your Java installation directory keytool -import -alias <give-a-unique-alias> -keystore $JAVA_HOME/jre/lib/security/cacerts -file <path-to-root-ca.crt> -storepass changeit Reinicie la aplicación Java y compruebe que ahora se conecte correctamente al endpoint HTTPS.
Mejores prácticas
Despliegue la cadena completa en cada actualización de certificado. Cada vez que renueve o reemplace un certificado, despliegue
fullchain.pem(o su equivalente), no solo el certificado del nombre de dominio. Un proceso que funciona con el certificado anterior puede fallar sin mostrar errores si cambia algún certificado intermedio.Monitoree proactivamente el estado de los certificados. Configure el monitoreo de nombres de dominio públicos para recibir alertas antes de que los problemas de certificados provoquen interrupciones en el servicio.