Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allowing Java to use an untrusted certificate for SSL/HTTPS connection

I've been working on a program to extract information from a dynamic web application, and the program worked fine until I set my tomcat server to use SSL using a self-signed(thus, untrusted) certificate. The stack trace of the error is:

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) 

In a web browser, the user is prompted a warning when accessing a HTTPS site with an untrusted certificate, and asked to make an exception if he likes to proceed; I would like to implement a similar functionality for my command-line application... I admit that I am new to socket programming and networking in general; any advice solving this problem will be great!

like image 782
Midnight Blue Avatar asked Jul 29 '09 15:07

Midnight Blue


People also ask

How set SSL certificate in Java?

The steps to install a new certificate into the Java default truststore are: extract cert from server: openssl s_client -connect server:443. import certificate into truststore using keytool: keytool -import -alias alias.server.com -keystore $JAVA_HOME/jre/lib/security/cacerts.


2 Answers

Here is some relevant code:

// 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) { } 

This will completely disable SSL checking—just don't learn exception handling from such code!

To do what you want, you would have to implement a check in your TrustManager that prompts the user.

like image 176
Yishai Avatar answered Oct 05 '22 17:10

Yishai


Following code from here is a useful solution. No keystores etc. Just call method SSLUtilities.trustAllHttpsCertificates() before initializing the service and port (in 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 
like image 23
Krzysztof Szewczyk Avatar answered Oct 05 '22 16:10

Krzysztof Szewczyk