Solución:
https://mms.nw.ru utiliza un certificado autofirmado que no está en el conjunto de administrador de confianza predeterminado. Para resolver el problema, realice una de las siguientes acciones:
- Configurar
SSLContext
con unTrustManager
que acepta cualquier certificado (ver más abajo). - Configurar
SSLContext
con un almacén de confianza adecuado que incluya su certificado. - Agregue el certificado para ese sitio al almacén de confianza de Java predeterminado.
Aquí hay un programa que crea un contexto SSL (en su mayoría sin valor) que acepta cualquier certificado:
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SSLTest {
public static void main(String [] args) throws Exception {
// configure the SSLContext with a TrustManager
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
SSLContext.setDefault(ctx);
URL url = new URL("https://mms.nw.ru");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
System.out.println(conn.getResponseCode());
conn.disconnect();
}
private static class DefaultTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
}
https://mms.nw.ru probablemente use un certificado no emitido por una autoridad de certificación. En consecuencia, debe agregar el certificado a su almacén de claves Java de confianza como se explica en No se puede encontrar una ruta de certificación válida para el destino solicitado:
Al trabajar en un cliente que funciona con un servidor habilitado para SSL que se ejecuta en el protocolo https, puede obtener el error “No se puede encontrar una ruta de certificación válida para el destino solicitado” si el certificado del servidor no es emitido por la autoridad de certificación, sino autofirmado o emitido por un CMS privado.
Que no cunda el pánico. Todo lo que necesita hacer es agregar el certificado del servidor a su almacén de claves Java de confianza si su cliente está escrito en Java. Es posible que se pregunte cómo es posible que no pueda acceder a la máquina donde está instalado el servidor. Hay un programa simple que puede ayudarlo. Descargue el programa Java y ejecútelo
% java InstallCert _web_site_hostname_
Este programa abrió una conexión al host especificado e inició un protocolo de enlace SSL. Imprimió el seguimiento de la pila de excepciones del error que ocurrió y le muestra los certificados utilizados por el servidor. Ahora le solicita que agregue el certificado a su KeyStore de confianza.
Si ha cambiado de opinión, ingrese ‘q’. Si realmente desea agregar el certificado, ingrese ‘1’ u otros números para agregar otros certificados, incluso un certificado de CA, pero generalmente no desea hacerlo. Una vez que haya hecho su elección, el programa mostrará el certificado completo y luego lo agregará a un almacén de claves de Java llamado ‘jssecacerts’ en el directorio actual.
Para usarlo en su programa, configure JSSE para usarlo como su almacén de confianza o cópielo en su directorio $ JAVA_HOME / jre / lib / security. Si desea que todas las aplicaciones Java reconozcan el certificado como confiable y no solo JSSE, también puede sobrescribir el archivo cacerts en ese directorio.
Después de todo eso, JSSE podrá completar un protocolo de enlace con el host, que puede verificar ejecutando el programa nuevamente.
Para obtener más detalles, puede consultar el blog de Leeland No más ‘no se puede encontrar una ruta de certificación válida para el objetivo solicitado’
Además de la respuesta correcta de Pascal Thivent, otra forma es guardar el certificado de Firefox (Ver certificado -> Detalles -> exportar) o openssl s_client
e importarlo a la tienda de confianza.
Solo debe hacer esto si tiene una forma de verificar ese certificado. De lo contrario, hágalo la primera vez que se conecte, al menos le dará un error si el certificado cambia inesperadamente en conexiones posteriores.
Para importarlo en una tienda de confianza, use:
keytool -importcert -keystore truststore.jks -file servercert.pem
De forma predeterminada, el almacén de confianza predeterminado debe ser $JAVA_HOME/jre/lib/security/cacerts
y su contraseña debe ser changeit
, consulte la guía de referencia JSSE para obtener más detalles.
Si no desea permitir ese certificado globalmente, sino solo para estas conexiones, es posible crear una SSLContext
para ello:
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream("/.../truststore.jks");
ks.load(fis, null);
// or ks.load(fis, "thepassword".toCharArray());
fis.close();
tmf.init(ks);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
Luego, debe configurarlo para Apache HTTP Client 3.x implementando uno si su SecureProtocolSocketFactory
para usar esto SSLContext
. (Hay ejemplos aquí).
Apache HTTP Client 4.x (aparte de la versión más antigua) tiene soporte directo para pasar un SSLContext
.