java - cacerts - keytool import trusted certificate
Java: sun.security.provider.certpath.SunCertPathBuilderException: no se puede encontrar una ruta de certificación válida para el objetivo solicitado (17)
Tengo una clase que descargará un archivo de un servidor https . Cuando lo ejecuto, devuelve una gran cantidad de errores. Parece que tengo un problema con mi certificado. ¿Es posible ignorar la autenticación cliente-servidor? ¿Si es así, cómo?
package com.da;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.concurrent.Future;
import org.apache.http.HttpResponse;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.impl.nio.client.DefaultHttpAsyncClient;
import org.apache.http.nio.IOControl;
import org.apache.http.nio.client.HttpAsyncClient;
import org.apache.http.nio.client.methods.AsyncCharConsumer;
import org.apache.http.nio.client.methods.HttpAsyncGet;
import org.apache.http.nio.client.methods.HttpAsyncPost;
public class RSDDownloadFile {
static FileOutputStream fos;
public void DownloadFile(String URI, String Request) throws Exception
{
java.net.URI uri = URIUtils.createURI("https", "176.66.3.69:6443", -1, "download.aspx",
"Lang=EN&AuthToken=package", null);
System.out.println("URI Query: " + uri.toString());
HttpAsyncClient httpclient = new DefaultHttpAsyncClient();
httpclient.start();
try {
Future<Boolean> future = httpclient.execute(
new HttpAsyncGet(uri),
new ResponseCallback(), null);
Boolean result = future.get();
if (result != null && result.booleanValue()) {
System.out.println("/nRequest successfully executed");
} else {
System.out.println("Request failed");
}
}
catch(Exception e){
System.out.println("[DownloadFile] Exception: " + e.getMessage());
}
finally {
System.out.println("Shutting down");
httpclient.shutdown();
}
System.out.println("Done");
}
static class ResponseCallback extends AsyncCharConsumer<Boolean> {
@Override
protected void onResponseReceived(final HttpResponse response) {
System.out.println("Response: " + response.getStatusLine());
System.out.println("Header: " + response.toString());
try {
//if(response.getStatusLine().getStatusCode()==200)
fos = new FileOutputStream( "Response.html" );
}catch(Exception e){
System.out.println("[onResponseReceived] Exception: " + e.getMessage());
}
}
@Override
protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException {
try
{
while (buf.hasRemaining())
{
//System.out.print(buf.get());
fos.write(buf.get());
}
}catch(Exception e)
{
System.out.println("[onCharReceived] Exception: " + e.getMessage());
}
}
@Override
protected void onCleanup() {
try
{
if(fos!=null)
fos.close();
}catch(Exception e){
System.out.println("[onCleanup] Exception: " + e.getMessage());
}
System.out.println("onCleanup()");
}
@Override
protected Boolean buildResult() {
return Boolean.TRUE;
}
}
}
Errores:
URI Query: https://176.66.3.69:6443/download.aspx?Lang=EN&AuthToken=package
Aug 2, 2011 3:47:57 PM org.apache.http.impl.nio.client.NHttpClientProtocolHandler exception
SEVERE: I/O error: General SSLEngine problem
javax.net.ssl.SSLHandshakeException: General SSLEngine problem
at com.sun.net.ssl.internal.ssl.Handshaker.checkThrown(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.checkTaskThrown(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.writeAppRecord(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.wrap(Unknown Source)
at javax.net.ssl.SSLEngine.wrap(Unknown Source)
at org.apache.http.impl.nio.reactor.SSLIOSession.doHandshake(SSLIOSession.java:154)
at org.apache.http.impl.nio.reactor.SSLIOSession.isAppInputReady(SSLIOSession.java:276)
at org.apache.http.impl.nio.client.InternalClientEventDispatch.inputReady(InternalClientEventDispatch.java:79)
at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:161)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:335)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:275)
at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:542)
at java.lang.Thread.run(Unknown Source)
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
at com.sun.net.ssl.internal.ssl.Handshaker$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.net.ssl.internal.ssl.Handshaker$DelegatedTask.run(Unknown Source)
at org.apache.http.impl.nio.reactor.SSLIOSession.doHandshake(SSLIOSession.java:180)
... 9 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
at sun.security.validator.Validator.validate(Unknown Source)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(Unknown Source)
... 16 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
at java.security.cert.CertPathBuilder.build(Unknown Source)
... 21 more
onCleanup()
[DownloadFile] Exception: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
Shutting down
Done
- Exporte el certificado SSL usando Firefox. Puede exportarlo presionando la URL en el navegador y luego seleccione la opción para exportar el certificado. Supongamos que el nombre del archivo cert es your.ssl.server.name.crt
- Vaya a su
JRE_HOME/bin
oJDK/JRE/bin
- Escriba el comando
-
keytool -keystore ../lib/security/cacerts -import -alias your.ssl.server.name -file ./relative-path-to-cert-file/your.ssl.server.name.crt
- Reinicia tu proceso de Java
AVG versión 18.1.3044 (con Windows 10) interfiere con mi aplicación Spring local.
Solución: ingrese en la sección de AVG llamada "Web y correo electrónico" y desactive la "protección de correo electrónico". AVG bloquea el certificado si el sitio no es seguro.
Citando de No más ''no se puede encontrar una ruta de certificación válida para el objetivo solicitado''
cuando intenta abrir una conexión SSL a un host usando JSSE. Lo que esto generalmente significa es que el servidor está utilizando un certificado de prueba (posiblemente generado mediante keytool) en lugar de un certificado de una autoridad de certificación comercial bien conocida como Verisign o GoDaddy. Los navegadores web muestran cuadros de diálogo de advertencia en este caso, pero como JSSE no puede suponer que un usuario interactivo está presente, arroja una excepción por defecto.
La validación de certificados es una parte muy importante de la seguridad de SSL, pero no estoy escribiendo esta entrada para explicar los detalles. Si está interesado, puede comenzar leyendo la propaganda de Wikipedia. Estoy escribiendo esta entrada para mostrar una forma simple de hablar con ese host con el certificado de prueba, si realmente lo desea.
Básicamente, desea agregar el certificado del servidor a KeyStore con sus certificados de confianza
Pruebe el código provisto allí. Podría ayudar.
Compruebe si la ruta de acceso de java está disponible en $PATH
.
Si no, ve a la cabeza y actualiza PATH
usando PATH=$PATH:/xxx/xxx/jre/bin
El origen de este error en mi instancia de Apache 2.4 (utilizando un certificado comodín de Comodo) era una ruta incompleta al certificado raíz firmado SHA-1. Había múltiples cadenas en el certificado emitido, y la cadena que conducía a un certificado raíz SHA-1 carecía de un certificado intermedio . Los navegadores modernos saben cómo manejar esto, pero Java 7 no lo maneja por defecto (aunque hay algunas formas intrincadas de lograr esto en el código). El resultado son mensajes de error idénticos al caso de los certificados autofirmados:
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
... 22 more
En este caso, se está produciendo el mensaje "no se puede encontrar una ruta de certificación válida para el objetivo solicitado" debido al certificado intermedio faltante. Puede verificar qué certificado falta utilizando la prueba SSL Labs contra el servidor. Una vez que encuentre el certificado apropiado, descárguelo y (si el servidor está bajo su control) agréguelo al paquete de certificados. Alternativamente, puede importar el certificado faltante localmente. Acomodar este problema en el servidor es una solución más general al problema.
El problema aparece cuando su servidor tiene un certificado autofirmado. Para solucionarlo, puede agregar este certificado a la lista de certificados de confianza de su JVM.
En este artículo, el autor describe cómo recuperar el certificado de su navegador y agregarlo al archivo cacerts de su JVM. Puede editar el archivo JAVA_HOME/jre/lib/security/cacerts
o ejecutar su aplicación con el parámetro -Djavax.net.ssl.trustStore
. Verifique qué JDK / JRE está utilizando también, ya que a menudo es una fuente de confusión.
Consulte también: ¿Cómo se resuelven los nombres de los servidores de certificados SSL? ¿Puedo agregar nombres alternativos con la herramienta de claves? Si se encuentra con java.security.cert.CertificateException: No name matching localhost found
excepción java.security.cert.CertificateException: No name matching localhost found
.
Esto es lo que funciona de manera confiable para mí en macOS. Asegúrate de reemplazar example.com y 443 con el nombre de host real y el puerto al que intentas conectarte, y dale un alias personalizado. El primer comando descarga el certificado proporcionado del servidor remoto y lo guarda localmente en formato x509. El segundo comando carga el certificado guardado en el almacén de confianza SSL de Java.
openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2>/dev/null) -out ~/example.crt
sudo keytool -importcert -file ~/example.crt -alias example -keystore $(/usr/libexec/java_home)/jre/lib/security/cacerts -storepass changeit
Esto también puede deberse al uso de certificados GoDaddy con Java 7 que se firman con SHA2.
Chrome y todos los demás navegadores están comenzando a desaprobar los certificados SSL que se firman usando SHA1, ya que no es tan seguro.
Puede encontrar más información sobre el problema aquí , y cómo resolverlo en su servidor si lo necesita ahora.
La respuesta de @Gabe Martin-Dempesy me fue útil. Y escribí un pequeño guión relacionado con él. El uso es muy simple.
Instale un certificado desde el host:
> sudo ./java-cert-importer.sh example.com
Elimine el certificado que ya se instaló.
> sudo ./java-cert-importer.sh example.com --delete
java-cert-importer.sh
#!/usr/bin/env bash
# Exit on error
set -e
# Ensure script is running as root
if [ "$EUID" -ne 0 ]
then echo "WARN: Please run as root (sudo)"
exit 1
fi
# Check required commands
command -v openssl >/dev/null 2>&1 || { echo "Required command ''openssl'' not installed. Aborting." >&2; exit 1; }
command -v keytool >/dev/null 2>&1 || { echo "Required command ''keytool'' not installed. Aborting." >&2; exit 1; }
# Get command line args
host=$1; port=${2:-443}; deleteCmd=${3:-${2}}
# Check host argument
if [ ! ${host} ]; then
cat << EOF
Please enter required parameter(s)
usage: ./java-cert-importer.sh <host> [ <port> | default=443 ] [ -d | --delete ]
EOF
exit 1
fi;
if [ "$JAVA_HOME" ]; then
javahome=${JAVA_HOME}
elif [[ "$OSTYPE" == "linux-gnu" ]]; then # Linux
javahome=$(readlink -f $(which java) | sed "s:bin/java::")
elif [[ "$OSTYPE" == "darwin"* ]]; then # Mac OS X
javahome="$(/usr/libexec/java_home)/jre"
fi
if [ ! "$javahome" ]; then
echo "WARN: Java home cannot be found."
exit 1
elif [ ! -d "$javahome" ]; then
echo "WARN: Detected Java home does not exists: $javahome"
exit 1
fi
echo "Detected Java Home: $javahome"
# Set cacerts file path
cacertspath=${javahome}/lib/security/cacerts
cacertsbackup="${cacertspath}.$$.backup"
if ( [ "$deleteCmd" == "-d" ] || [ "$deleteCmd" == "--delete" ] ); then
sudo keytool -delete -alias ${host} -keystore ${cacertspath} -storepass changeit
echo "Certificate is deleted for ${host}"
exit 0
fi
# Get host info from user
#read -p "Enter server host (E.g. example.com) : " host
#read -p "Enter server port (Default 443) : " port
# create temp file
tmpfile="/tmp/${host}.$$.crt"
# Create java cacerts backup file
cp ${cacertspath} ${cacertsbackup}
echo "Java CaCerts Backup: ${cacertsbackup}"
# Get certificate from speficied host
openssl x509 -in <(openssl s_client -connect ${host}:${port} -prexit 2>/dev/null) -out ${tmpfile}
# Import certificate into java cacerts file
sudo keytool -importcert -file ${tmpfile} -alias ${host} -keystore ${cacertspath} -storepass changeit
# Remove temp certificate file
rm ${tmpfile}
# Check certificate alias name (same with host) that imported successfully
result=$(keytool -list -v -keystore ${cacertspath} -storepass changeit | grep "Alias name: ${host}")
# Show results to user
if [ "$result" ]; then
echo "Success: Certificate is imported to java cacerts for ${host}";
else
echo "Error: Something went wrong";
fi;
Para aquellos a los que les gusta Debian y Java preempaquetado:
sudo mkdir /usr/share/ca-certificates/test/ # don''t mess with other certs
sudo cp ~/tmp/test.loc.crt /usr/share/ca-certificates/test/
sudo dpkg-reconfigure --force ca-certificates # check your cert in curses GUI!
sudo update-ca-certificates --fresh --verbose
No olvide verificar /etc/default/cacerts
para:
# enable/disable updates of the keystore /etc/ssl/certs/java/cacerts
cacerts_updates=yes
Para eliminar cert:
sudo rm /usr/share/ca-certificates/test/test.loc.crt
sudo rm /etc/ssl/certs/java/cacerts
sudo update-ca-certificates --fresh --verbose
Pude hacerlo funcionar solo con código, es decir, sin necesidad de utilizar la herramienta de claves:
import com.netflix.config.DynamicBooleanProperty;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.conn.NoopIOSessionStrategy;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class Test
{
private static final DynamicIntProperty MAX_TOTAL_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40);
private static final DynamicIntProperty ROUTE_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40);
private static final DynamicIntProperty CONNECT_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connect.timeout", 60000);
private static final DynamicIntProperty SOCKET_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.socket.timeout", -1);
private static final DynamicIntProperty CONNECTION_REQUEST_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connectionrequest.timeout", 60000);
private static final DynamicBooleanProperty STALE_CONNECTION_CHECK = DynamicPropertyFactory.getInstance().getBooleanProperty("X.checkconnection", true);
public static void main(String[] args) throws Exception
{
SSLContext sslcontext = SSLContexts.custom()
.useTLS()
.loadTrustMaterial(null, new TrustStrategy()
{
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
{
return true;
}
})
.build();
SSLIOSessionStrategy sslSessionStrategy = new SSLIOSessionStrategy(sslcontext, new AllowAll());
Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create()
.register("http", NoopIOSessionStrategy.INSTANCE)
.register("https", sslSessionStrategy)
.build();
DefaultConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(IOReactorConfig.DEFAULT);
PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager(ioReactor, sessionStrategyRegistry);
connectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS.get());
connectionManager.setDefaultMaxPerRoute(ROUTE_CONNECTIONS.get());
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(SOCKET_TIMEOUT.get())
.setConnectTimeout(CONNECT_TIMEOUT.get())
.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT.get())
.setStaleConnectionCheckEnabled(STALE_CONNECTION_CHECK.get())
.build();
CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom()
.setSSLStrategy(sslSessionStrategy)
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig)
.build();
httpClient.start();
// use httpClient...
}
private static class AllowAll implements X509HostnameVerifier
{
@Override
public void verify(String s, SSLSocket sslSocket) throws IOException
{}
@Override
public void verify(String s, X509Certificate x509Certificate) throws SSLException {}
@Override
public void verify(String s, String[] strings, String[] strings2) throws SSLException
{}
@Override
public boolean verify(String s, SSLSession sslSession)
{
return true;
}
}
}
Si está utilizando el certificado Let''s Encrypt en el servidor de destino y JRE / JDK <8u101 , siga esta respuesta para solucionarlo.
Solo para Windows, siga estos pasos:
- En Chrome ve a la configuración.
- En Configuración, haga clic en Mostrar configuración avanzada.
- En HTTPS / SSL, haga clic en Administrar certificados.
- Exportar su certificado.
- En las búsquedas de Windows (presionando la tecla de Windows en el teclado), escriba java.
- Seleccione la opción (Configurar Java) que abrirá el Panel de control de Java
- Seleccione la pestaña Seguridad en el Panel de control de Java
- Seleccione Administrar certificados
- Haga clic en importar
- En la pestaña (Usuario) seleccionada y tipo de certificado como (Certificados de confianza)
- Haga clic en el botón importar y busque el certificado descargado e impórtelo.
Tiene dos opciones, importe el certificado autofirmado en el almacén de claves de java para cada JVM en el que se ejecutará el software o pruebe la fábrica SSL no validación:
jdbc:postgresql://myserver.com:5432/mydatabasename?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory
Tuve el mismo problema con el error de certificados y fue debido a SNI, y el cliente http que utilicé no implementó SNI. Entonces, una actualización de la versión hizo el trabajo
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
Tuve el mismo problema con un certificado de comodín firmado válido de Symantec.
Primero intente ejecutar su aplicación java con -Djavax.net.debug = SSL para ver qué está pasando realmente.
Terminé importando el certificado intermedio que causaba la ruptura de la cadena de certificación .
Descargué el certificado intermedio que falta de symantec (puede ver el enlace de descarga del certificado faltante en el registro de inicio de sesión de ssl: http://svrintl-g3-aia.verisign.com/SVRIntlG3.cer en mi caso).
E importé el certificado en el almacén de claves de Java. Después de importar el certificado intermedio, mi comodín ssl cert finalmente comenzó a funcionar:
keytool -import -keystore ../jre/lib/security/cacerts -trustcacerts -alias "VeriSign Class 3 International Server CA - G3" -file /pathto/SVRIntlG3.cer
ACTUALIZACIÓN: Que un reinicio ayudó fue una coincidencia (así lo esperaba, ¡hurra!). La verdadera causa del problema era esta: cuando a Gradle se le ordena utilizar un almacén de claves específico, ese almacén de claves también debe contener todos los certificados raíz oficiales. De lo contrario, no puede acceder a las bibliotecas desde los repositorios regulares. Lo que tuve que hacer fue esto:
Importar el certificado autofirmado:
keytool -import -trustcacerts -alias myselfsignedcert -file /Users/me/Desktop/selfsignedcert.crt -keystore ./privateKeystore.jks
Agregue los certificados raíz oficiales:
keytool -importkeystore -srckeystore <java-home>/lib/security/cacerts -destkeystore ./privateKeystore.jks
Quizás el daemon Gradle también se interpuso en el camino. ./gradlew --status
pena matar a todos los daemons que se encuentran con ./gradlew --status
si las cosas empiezan a parecer sombrías.
PUBLICACIÓN ORIGINAL:
Nadie lo creerá, lo sé. Aún así, si todo lo demás falla, pruébelo: después de reiniciar mi Mac, el problema desapareció. Grrr.
Antecedentes: ./gradlew jar me mantuvo "incapaz de encontrar una ruta de certificación válida para el objetivo solicitado"
Estoy atrapado con un certificado autofirmado, guardado desde el navegador, importado en privateKeystore.jks. Luego se le indicó a Gradle que trabaje con privateKeystore.jks:
org.gradle.jvmargs=-Djavax.net.debug=SSL -Djavax.net.ssl.trustStore="/Users/me/IntelliJ/myproject/privateKeystore.jks" -Djavax.net.ssl.trustStorePassword=changeit
Como se mencionó, esto solo funcionó después de un reinicio.