2009-07-29 13 views
47

J'ai travaillé sur un programme pour extraire des informations d'une application web dynamique, et le programme a fonctionné correctement jusqu'à ce que je mette mon serveur tomcat à utiliser SSL en utilisant certificat signé (donc, non approuvé). La trace de la pile de l'erreur est:Autoriser Java à utiliser un certificat non approuvé pour une connexion SSL/HTTPS

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
Error: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
     at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:150) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1584) 
     at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:174) 
     at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:168) 
     at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:848) 
     at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:106) 
     at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:495) 
     at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:433) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:877) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1089) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1116) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1100) 
     at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:402) 
     at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:170) 
     at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:857) 
     at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230) 
     at com.certicom.gls.glscs.nongui.URLReader$PostURL.setupURL(URLReader.java:34) 
     at com.certicom.gls.glscs.nongui.URLReader.getLogin(URLReader.java:227) 
     at com.certicom.gls.glscs.nongui.URLReader.testLogin(URLReader.java:436) 
     at com.certicom.gls.glscs.nongui.Controller.loginMenu(Controller.java:384) 
     at com.certicom.gls.glscs.nongui.Controller.menu(Controller.java:324) 
     at com.certicom.gls.glscs.nongui.Controller.<init>(Controller.java:49) 
     at com.certicom.gls.glscs.nongui.Controller.main(Controller.java:61) 

Dans un navigateur web, l'utilisateur est invité un avertissement lorsque l'accès à un site HTTPS avec un certificat non approuvé, et a demandé de faire une exception s'il aime procéder; Je voudrais implémenter une fonctionnalité similaire pour mon application en ligne de commande ... J'avoue que je suis nouveau dans la programmation socket et le réseau en général; tout conseil pour résoudre ce problème sera génial!

+0

Vous pouvez utiliser [cette implémentation] (http://abhinavasblog.blogspot.com/2011/07 /allow-untrusted-certificate-for-https.html) ... il a deux parties 1. un fichier de classe avec la méthode statique à appeler avant l'appel 'Https' – Abhinava

Répondre

73

Here est un code pertinent:

// Create a trust manager that does not validate certificate chains 
TrustManager[] trustAllCerts = new TrustManager[]{ 
    new X509TrustManager() { 
     public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
      return null; 
     } 
     public void checkClientTrusted(
      java.security.cert.X509Certificate[] certs, String authType) { 
     } 
     public void checkServerTrusted(
      java.security.cert.X509Certificate[] certs, String authType) { 
     } 
    } 
}; 

// Install the all-trusting trust manager 
try { 
    SSLContext sc = SSLContext.getInstance("SSL"); 
    sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 
} catch (Exception e) { 
} 

// Now you can access an https URL without having the certificate in the truststore 
try { 
    URL url = new URL("https://hostname/index.html"); 
} catch (MalformedURLException e) { 
} 

Cela apprendra désactiver complètement le contrôle juste-SSL ne la gestion des exceptions de ce code! Pour faire ce que vous voulez, vous devez implémenter une vérification dans votre TrustManager qui invite l'utilisateur.

+6

C'est la façon de le faire; Cependant, vous devez faire très attention à ce que ce code ne soit pas en production - et si vous utilisez des certificats non approuvés dans une application de production, c'est une mauvaise chose. Si vous disposez d'un environnement d'injection de dépendances tel que Spring dans votre application, envisagez d'isoler ce code et d'avoir une version sécurisée pour l'environnement de production. –

+3

Le paramètre 'new java.security.SecureRandom()' peut également être remplacé par 'null'. –

+0

Depuis Java 7, 'X509ExtendedTrustManager'rather peut contourner d'autres problèmes tels que les contraintes d'algorithme. Bien sûr, je dois réitérer le commentaire de @ TimHowland .. – amcc

5

Le code suivant de here est une solution utile. Pas de keystore etc. Appelez simplement la méthode SSLUtilities.trustAllHttpsCertificates() avant d'initialiser le service et le port (dans SOAP).

import java.security.GeneralSecurityException; 
import java.security.SecureRandom; 
import java.security.cert.X509Certificate; 
import javax.net.ssl.HostnameVerifier; 
import javax.net.ssl.HttpsURLConnection; 
import javax.net.ssl.SSLContext; 
import javax.net.ssl.TrustManager; 
import javax.net.ssl.X509TrustManager; 

/** 
* This class provide various static methods that relax X509 certificate and 
* hostname verification while using the SSL over the HTTP protocol. 
* 
* @author Jiramot.info 
*/ 
public final class SSLUtilities { 

    /** 
    * Hostname verifier for the Sun's deprecated API. 
    * 
    * @deprecated see {@link #_hostnameVerifier}. 
    */ 
    private static com.sun.net.ssl.HostnameVerifier __hostnameVerifier; 
    /** 
    * Thrust managers for the Sun's deprecated API. 
    * 
    * @deprecated see {@link #_trustManagers}. 
    */ 
    private static com.sun.net.ssl.TrustManager[] __trustManagers; 
    /** 
    * Hostname verifier. 
    */ 
    private static HostnameVerifier _hostnameVerifier; 
    /** 
    * Thrust managers. 
    */ 
    private static TrustManager[] _trustManagers; 

    /** 
    * Set the default Hostname Verifier to an instance of a fake class that 
    * trust all hostnames. This method uses the old deprecated API from the 
    * com.sun.ssl package. 
    * 
    * @deprecated see {@link #_trustAllHostnames()}. 
    */ 
    private static void __trustAllHostnames() { 
    // Create a trust manager that does not validate certificate chains 
    if (__hostnameVerifier == null) { 
     __hostnameVerifier = new SSLUtilities._FakeHostnameVerifier(); 
    } // if 
    // Install the all-trusting host name verifier 
    com.sun.net.ssl.HttpsURLConnection 
      .setDefaultHostnameVerifier(__hostnameVerifier); 
    } // __trustAllHttpsCertificates 

    /** 
    * Set the default X509 Trust Manager to an instance of a fake class that 
    * trust all certificates, even the self-signed ones. This method uses the 
    * old deprecated API from the com.sun.ssl package. 
    * 
    * @deprecated see {@link #_trustAllHttpsCertificates()}. 
    */ 
    private static void __trustAllHttpsCertificates() { 
    com.sun.net.ssl.SSLContext context; 

    // Create a trust manager that does not validate certificate chains 
    if (__trustManagers == null) { 
     __trustManagers = new com.sun.net.ssl.TrustManager[]{new SSLUtilities._FakeX509TrustManager()}; 
    } // if 
    // Install the all-trusting trust manager 
    try { 
     context = com.sun.net.ssl.SSLContext.getInstance("SSL"); 
     context.init(null, __trustManagers, new SecureRandom()); 
    } catch (GeneralSecurityException gse) { 
     throw new IllegalStateException(gse.getMessage()); 
    } // catch 
    com.sun.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(context 
      .getSocketFactory()); 
    } // __trustAllHttpsCertificates 

    /** 
    * Return true if the protocol handler property java. protocol.handler.pkgs 
    * is set to the Sun's com.sun.net.ssl. internal.www.protocol deprecated 
    * one, false otherwise. 
    * 
    * @return true if the protocol handler property is set to the Sun's 
    * deprecated one, false otherwise. 
    */ 
    private static boolean isDeprecatedSSLProtocol() { 
    return ("com.sun.net.ssl.internal.www.protocol".equals(System 
      .getProperty("java.protocol.handler.pkgs"))); 
    } // isDeprecatedSSLProtocol 

    /** 
    * Set the default Hostname Verifier to an instance of a fake class that 
    * trust all hostnames. 
    */ 
    private static void _trustAllHostnames() { 
     // Create a trust manager that does not validate certificate chains 
     if (_hostnameVerifier == null) { 
      _hostnameVerifier = new SSLUtilities.FakeHostnameVerifier(); 
     } // if 
     // Install the all-trusting host name verifier: 
     HttpsURLConnection.setDefaultHostnameVerifier(_hostnameVerifier); 
    } // _trustAllHttpsCertificates 

    /** 
    * Set the default X509 Trust Manager to an instance of a fake class that 
    * trust all certificates, even the self-signed ones. 
    */ 
    private static void _trustAllHttpsCertificates() { 
    SSLContext context; 

     // Create a trust manager that does not validate certificate chains 
     if (_trustManagers == null) { 
      _trustManagers = new TrustManager[]{new SSLUtilities.FakeX509TrustManager()}; 
     } // if 
     // Install the all-trusting trust manager: 
     try { 
      context = SSLContext.getInstance("SSL"); 
      context.init(null, _trustManagers, new SecureRandom()); 
     } catch (GeneralSecurityException gse) { 
      throw new IllegalStateException(gse.getMessage()); 
     } // catch 
     HttpsURLConnection.setDefaultSSLSocketFactory(context 
      .getSocketFactory()); 
    } // _trustAllHttpsCertificates 

    /** 
    * Set the default Hostname Verifier to an instance of a fake class that 
    * trust all hostnames. 
    */ 
    public static void trustAllHostnames() { 
     // Is the deprecated protocol setted? 
     if (isDeprecatedSSLProtocol()) { 
      __trustAllHostnames(); 
     } else { 
      _trustAllHostnames(); 
     } // else 
    } // trustAllHostnames 

    /** 
    * Set the default X509 Trust Manager to an instance of a fake class that 
    * trust all certificates, even the self-signed ones. 
    */ 
    public static void trustAllHttpsCertificates() { 
    // Is the deprecated protocol setted? 
    if (isDeprecatedSSLProtocol()) { 
     __trustAllHttpsCertificates(); 
    } else { 
     _trustAllHttpsCertificates(); 
    } // else 
    } // trustAllHttpsCertificates 

    /** 
    * This class implements a fake hostname verificator, trusting any host 
    * name. This class uses the old deprecated API from the com.sun. ssl 
    * package. 
    * 
    * @author Jiramot.info 
    * 
    * @deprecated see {@link SSLUtilities.FakeHostnameVerifier}. 
    */ 
    public static class _FakeHostnameVerifier implements 
     com.sun.net.ssl.HostnameVerifier { 

    /** 
    * Always return true, indicating that the host name is an acceptable 
    * match with the server's authentication scheme. 
    * 
    * @param hostname the host name. 
    * @param session the SSL session used on the connection to host. 
    * @return the true boolean value indicating the host name is trusted. 
    */ 
    public boolean verify(String hostname, String session) { 
     return (true); 
    } // verify 
    } // _FakeHostnameVerifier 

    /** 
    * This class allow any X509 certificates to be used to authenticate the 
    * remote side of a secure socket, including self-signed certificates. This 
    * class uses the old deprecated API from the com.sun.ssl package. 
    * 
    * @author Jiramot.info 
    * 
    * @deprecated see {@link SSLUtilities.FakeX509TrustManager}. 
    */ 
    public static class _FakeX509TrustManager implements 
     com.sun.net.ssl.X509TrustManager { 

    /** 
    * Empty array of certificate authority certificates. 
    */ 
    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{}; 

    /** 
    * Always return true, trusting for client SSL chain peer certificate 
    * chain. 
    * 
    * @param chain the peer certificate chain. 
    * @return the true boolean value indicating the chain is trusted. 
    */ 
    public boolean isClientTrusted(X509Certificate[] chain) { 
     return (true); 
    } // checkClientTrusted 

    /** 
    * Always return true, trusting for server SSL chain peer certificate 
    * chain. 
    * 
    * @param chain the peer certificate chain. 
    * @return the true boolean value indicating the chain is trusted. 
    */ 
    public boolean isServerTrusted(X509Certificate[] chain) { 
     return (true); 
    } // checkServerTrusted 

    /** 
    * Return an empty array of certificate authority certificates which are 
    * trusted for authenticating peers. 
    * 
    * @return a empty array of issuer certificates. 
    */ 
    public X509Certificate[] getAcceptedIssuers() { 
     return (_AcceptedIssuers); 
    } // getAcceptedIssuers 
    } // _FakeX509TrustManager 

    /** 
    * This class implements a fake hostname verificator, trusting any host 
    * name. 
    * 
    * @author Jiramot.info 
    */ 
    public static class FakeHostnameVerifier implements HostnameVerifier { 

    /** 
    * Always return true, indicating that the host name is an acceptable 
    * match with the server's authentication scheme. 
    * 
    * @param hostname the host name. 
    * @param session the SSL session used on the connection to host. 
    * @return the true boolean value indicating the host name is trusted. 
    */ 
    public boolean verify(String hostname, javax.net.ssl.SSLSession session) { 
     return (true); 
    } // verify 
    } // FakeHostnameVerifier 

    /** 
    * This class allow any X509 certificates to be used to authenticate the 
    * remote side of a secure socket, including self-signed certificates. 
    * 
    * @author Jiramot.info 
    */ 
    public static class FakeX509TrustManager implements X509TrustManager { 

    /** 
    * Empty array of certificate authority certificates. 
    */ 
    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{}; 

    /** 
    * Always trust for client SSL chain peer certificate chain with any 
    * authType authentication types. 
    * 
    * @param chain the peer certificate chain. 
    * @param authType the authentication type based on the client 
    * certificate. 
    */ 
    public void checkClientTrusted(X509Certificate[] chain, String authType) { 
    } // checkClientTrusted 

    /** 
    * Always trust for server SSL chain peer certificate chain with any 
    * authType exchange algorithm types. 
    * 
    * @param chain the peer certificate chain. 
    * @param authType the key exchange algorithm used. 
    */ 
    public void checkServerTrusted(X509Certificate[] chain, String authType) { 
    } // checkServerTrusted 

    /** 
    * Return an empty array of certificate authority certificates which are 
    * trusted for authenticating peers. 
    * 
    * @return a empty array of issuer certificates. 
    */ 
    public X509Certificate[] getAcceptedIssuers() { 
     return (_AcceptedIssuers); 
    } // getAcceptedIssuers 
    } // FakeX509TrustManager 
} // SSLUtilities 
2

Une autre option est d'obtenir un « .pem » (clé publique) fichier pour ce serveur, et l'installer sur place dans le coeur du dossier « cacerts » de votre JRE, il sera en mesure de télécharger à partir ce serveur sans se plaindre, sans compromettre la structure SSL complète de votre JVM en cours d'exécution et permettre le téléchargement à partir d'autres serveurs cert inconnus ...

Questions connexes