java - recomienda - ¿Cómo puede mi biblioteca con certificado ssl incorporado también permitir el uso con certificados predeterminados?
keytool windows (2)
Estoy distribuyendo un contenedor de biblioteca para clientes internos, y la biblioteca incluye un certificado que utiliza para llamar a un servicio que también es interno a nuestra red.
El administrador de confianza se configura de la siguiente manera
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore keystore = KeyStore.getInstance("JKS");
InputStream keystoreStream =
clazz.getClassLoader().getResourceAsStream("certs.keystore"); // (on classpath)
keystore.load(keystoreStream, "pa55w0rd".toCharArray());
trustManagerFactory.init(keystore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, trustManagers, null);
SSLSocketFactory socketFact = context.getSocketFactory();
connection.setSSLSocketFactory(socketFact);
Todo esto funciona bien, excepto en los casos en que los usuarios necesitan otros certificados o el certificado predeterminado.
Intenté esto Registrando múltiples almacenes de claves en JVM sin suerte (estoy teniendo problemas para generalizarlo para mi caso)
¿Cómo puedo usar mi certificado y seguir permitiendo que las bibliotecas de usuarios también usen sus propios certificados?
Está configurando una conexión con un almacén de claves personalizado que actúa como un almacén de confianza (un certificado de su servidor en el que confía). No está anulando el comportamiento de JVM predeterminado, por lo que el resto de la conexión que pueden hacer otras aplicaciones que incluyen su biblioteca no se verán afectadas.
Por lo tanto, no necesita un administrador de múltiples almacenes de claves, de hecho, su código funciona perfectamente.
He adjuntado un ejemplo completo a continuación con un almacén de claves google.jks
que incluye la CA raíz de Google y una conexión con el almacén de confianza de JVM predeterminado. Esta es la salida
request("https://www.google.com/", "test/google.jks", "pa55w0rd"); //OK
request("https://www.aragon.es/", "test/google.jks", "pa55w0rd"); // FAIL sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
request("https://www.aragon.es/", null, null); //OK
El problema no está en el código que ha adjuntado, así que verifique lo siguiente en su código:
El almacén de confianza
certs.keystore
se encuentra realmente en su classpathLa configuración del almacén de confianza no se establece a nivel de JVM usando
-Djavax.net.ssl.trustStore
Los errores encontrados (inclúyalos en su pregunta) están realmente relacionados con la conexión SSL
package test;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
public class HTTPSCustomTruststore {
public final static void main (String argv[]) throws Exception{
request("https://www.google.com/", "test/google.jks", "pa55w0rd"); //Expected OK
request("https://www.aragon.es/","test/google.jks","pa55w0rd"); // Expected FAIL
request("https://www.aragon.es/",null,null); //using default truststore. OK
}
public static void configureCustom(HttpsURLConnection connection, String truststore, String pwd)throws Exception{
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore keystore = KeyStore.getInstance("JKS");
InputStream keystoreStream = HTTPSCustomTruststore.class.getClassLoader().getResourceAsStream(truststore);
keystore.load(keystoreStream, pwd.toCharArray());
trustManagerFactory.init(keystore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, trustManagers, new java.security.SecureRandom());
SSLSocketFactory socketFact = context.getSocketFactory();
connection.setSSLSocketFactory(socketFact);
}
public static void request(String urlS, String truststore, String pwd) {
try {
URL url = new URL(urlS);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
if (truststore != null) {
configureCustom((HttpsURLConnection) conn, truststore, pwd);
}
conn.connect();
int statusCode = conn.getResponseCode();
if (statusCode != 200) {
System.out.println(urlS + " FAIL");
} else {
System.out.println(urlS + " OK");
}
} catch (Exception e) {
System.out.println(urlS + " FAIL " + e.getMessage());
}
}
}
Puede importar los certificados predeterminados en su almacén personalizado para tener un almacén personalizado combinado y usarlo.