Fix certificate problem in HTTPSTag(s): Networking


HTTPS protocol is supported since JDK1.4 (AFAIK), you have nothing special to do.
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;

public class ConnectHttps {
  public static void main(String[] args) throws Exception {
    URL url = new URL("https://www.rgagnon.com/howto.html");
    URLConnection con = url.openConnection();
    Reader reader = new InputStreamReader(con.getInputStream());
    while (true) {
      int ch = reader.read();
      if (ch==-1) {
        break;
      }
      System.out.print((char)ch);
    }
  }
}
However, you can have a problem if the server certificate is self-signed by a testing certification authority (CA) which is not in trusted CAs of Java on the client side. An exception like
Exception in thread "main" 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
is thrown. This is a common situation with a development server.

The fix is to add the self signed certificate to trusted CAs on the client side. You do that by updating the CACERT file in the your JRE_HOME/lib directory.

Check this tutorial : http://www.java-samples.com/showtutorial.php?tutorialid=210 or follow this procedure :

  • Export the certificate from your web browser.
    • In Google Chrome, open the endpoint url, then press F12, then go to security tab in Developer window.
    • Click "View Certificate", go to Details tab, and export to a .cer file (click "Copy to file", and just follow the wizard using default settings at each step).
  • Now that you have your .cer file, you need to update the cacerts in your JRE installation. The keytool utility (included in your Java installation) is used to do that.
    • Open a cmd with admin rights, then navigate to the bin directory of your java installation, and run the following command :
      keytool -import -alias myNewCertificate -file "/path/to/mycert.cer" -keystore "<JRE_HOME>\lib\security\cacerts" -storepass changeit
      where /path/to/mycert.cer is the absolute path to your .cer file created in the first step and
      replace "JRE_HOME" with the path to your java installation (can be something like c:\Program Files\Java\jre1.8.0_131).

Or you can override the check and accept an untrusted certificate (with the risk coming with it! It's a HACK and should not be used in code in production).

import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;

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

public class ConnectHttps {
  public static void main(String[] args) throws Exception {
    /*
     *  fix for
     *    Exception in thread "main" 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
     */
    TrustManager[] trustAllCerts = new TrustManager[] {
       new X509TrustManager() {
          public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
          }

          public void checkClientTrusted(X509Certificate[] certs, String authType) {  }

          public void checkServerTrusted(X509Certificate[] certs, String authType) {  }

       }
    };

    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

    // Create all-trusting host name verifier
    HostnameVerifier allHostsValid = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
          return true;
        }
    };
    // Install the all-trusting host verifier
    HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
    /*
     * end of the fix
     */

    URL url = new URL("https://securewebsitewithuntrustedcertificate.com");
    URLConnection con = url.openConnection();
    Reader reader = new InputStreamReader(con.getInputStream());
    while (true) {
      int ch = reader.read();
      if (ch==-1) {
        break;
      }
      System.out.print((char)ch);
    }
  }
}