How to solve javax.net.ssl.SSLHandshakeException Error?

630,247

Solution 1

First, you need to obtain the public certificate from the server you're trying to connect to. That can be done in a variety of ways, such as contacting the server admin and asking for it, using OpenSSL to download it, or, since this appears to be an HTTP server, connecting to it with any browser, viewing the page's security info, and saving a copy of the certificate. (Google should be able to tell you exactly what to do for your specific browser.)

Now that you have the certificate saved in a file, you need to add it to your JVM's trust store. At $JAVA_HOME/jre/lib/security/ for JREs or $JAVA_HOME/lib/security for JDKs, there's a file named cacerts, which comes with Java and contains the public certificates of the well-known Certifying Authorities. To import the new cert, run keytool as a user who has permission to write to cacerts:

keytool -import -file <the cert file> -alias <some meaningful name> -keystore <path to cacerts file>

It will most likely ask you for a password. The default password as shipped with Java is changeit. Almost nobody changes it. After you complete these relatively simple steps, you'll be communicating securely and with the assurance that you're talking to the right server and only the right server (as long as they don't lose their private key).

Solution 2

Now I solved this issue in this way,

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.OutputStream; 

// Create a trust manager that does not validate certificate chains like the default 

TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager() {

            public java.security.cert.X509Certificate[] getAcceptedIssuers()
            {
                return null;
            }
            public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
            {
                //No need to implement.
            }
            public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
            {
                //No need to implement.
            }
        }
};

// 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) 
{
    System.out.println(e);
}

Of course this solution should only be used in scenarios, where it is not possible to install the required certifcates using keytool e.g. local testing with temporary certifcates.

Solution 3

Whenever we are trying to connect to URL,

if server at the other site is running on https protocol and is mandating that we should communicate via information provided in certificate then we have following option:

1) ask for the certificate(download the certificate), import this certificate in trustore. Default trustore java uses can be found in \Java\jdk1.6.0_29\jre\lib\security\cacerts, then if we retry to connect to the URL connection would be accepted.

2) In normal business cases, we might be connecting to internal URLS in organizations and we know that they are correct. In such cases, you trust that it is the correct URL, In such cases above, code can be used which will not mandate to store the certificate to connect to particular URL.

for the point no 2 we have to follow below steps :

1) write below method which sets HostnameVerifier for HttpsURLConnection which returns true for all cases meaning we are trusting the trustStore.

  // trusting all certificate 
 public void doTrustToCertificates() throws Exception {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }
                }
        };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
                }
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

2) write below method, which calls doTrustToCertificates before trying to connect to URL

    // connecting to URL
    public void connectToUrl(){
     doTrustToCertificates();//  
     URL url = new URL("https://www.example.com");
     HttpURLConnection conn = (HttpURLConnection)url.openConnection(); 
     System.out.println("ResponseCode ="+conn.getResponseCode());
   }

This call will return response code = 200 means connection is successful.

For more detail and sample example you can refer to URL.

Share:
630,247

Related videos on Youtube

selladurai
Author by

selladurai

Mobile application developer (WEB 3.0, LAMP/MEAN and J2ME)

Updated on July 08, 2022

Comments

  • selladurai
    selladurai almost 2 years

    I connected with VPN to setup the inventory API to get product list and it works fine. Once I get the result from the web-service and i bind to UI. And also I integrated PayPal with my application for make Express checkout when I make a call for payment I'm facing this error. I use servlet for back-end process. Can any one say how to fix this issue?

    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
    
    • ante.sabo
      ante.sabo about 12 years
      what I would like to know, which exact target was in thath case... You get an exception, but you get no information about target, which might be different of what you expect.. I have such case, I am sure my link has certificate, and I am still getting this exception
  • Osama Javed
    Osama Javed almost 13 years
    P.S I found this java code online to extract and store the public keys of my server so keep googling or wait till sundayish
  • Ryan Stewart
    Ryan Stewart almost 13 years
    Wow, I would hesitate to call that a "fix". You've basically just turned off security. Yes, the data will still be encrypted, but you have no guarantee that you're talking to who you expect to be talking to. The correct solution is to obtain the public key of your target server and import it to the trust store of the JVM making the connection.
  • Ryan Stewart
    Ryan Stewart almost 13 years
    see my answer for an appropriate solution
  • Ryan Stewart
    Ryan Stewart almost 13 years
    Example of what? My answer should have all the steps you need.
  • Ryan Stewart
    Ryan Stewart almost 13 years
    I'll need a little more detail than "not working". Try updating your question with what you've tried and some error output. Unfortunately, it's way past my bedtime, so maybe someone else will be able to answer your questions. This also is a very common situation. You can find lots of information on it online, including the keytool docs.
  • selladurai
    selladurai almost 13 years
    Basically i need to include PayPal cert. I did your steps and cert also added in the appropriate location. then i run the app it say same error?
  • selladurai
    selladurai almost 13 years
    Actually it works well no problem browser and I connected VPN to get inventory list at that time i make payment with PayPal, it say's SSL error but i use offline data or hot coded data means it works.
  • Ryan Stewart
    Ryan Stewart almost 13 years
    @selladurai: You shouldn't need to import a cert for paypal. Unless your cacerts file has been corrupted or modified, it should contain all the trusted root certificates, and paypal's cert should be able to be traced back to one of those. You might try getting a copy of cacerts that you know is good and trying that one instead. If the problem persists, then you may not actually be connecting to paypal.
  • Brune
    Brune almost 11 years
  • Ced
    Ced almost 9 years
    @RyanStewart do I need to import it to glassfish somehow ? Because I did add the .cer file to my cacert in my java home directory but glassfish doesn't seem to use it so I'm still getting the error.
  • vedi0boy
    vedi0boy almost 8 years
    How does this work for distributing the application. Wouldn't it be really non-user friendly to have to go through all these steps? Or would you package a jdk with it already all setup?
  • user207421
    user207421 almost 8 years
    'No need to implement' is completely and utterly incorrect. You have just made your SSL connection insecure. Don't do this.
  • Aditya Vyas-Lakhan
    Aditya Vyas-Lakhan almost 8 years
    @RyanStewart any idea abt stackoverflow.com/questions/38910575/…
  • Jason D
    Jason D almost 8 years
    The code shown here looks helpful if you're writing a very simple test against a dev server, I would not rely on it for Production though.
  • Oliver Dixon
    Oliver Dixon over 7 years
    Google Play store will reject this. They will see that you are ignoring X509Certificate during the APK scan.
  • hb5fa
    hb5fa about 7 years
    It works! This is exactly what I need to do in order to enable my Java webservices to call a remote SSL endpoint. I was concentrating on adding the certificate to Tomcat; when in fact, the certificate should be added to JDK/JRE security instead. Now I understand.
  • abyin007
    abyin007 about 5 years
    @RyanStewart Is there any ways to enable the SSL check after we invoke this method, to bypass the security check?
  • Radu Linu
    Radu Linu over 4 years
    This solution worked to me: stackoverflow.com/a/59087392/4507034
  • Amin Heydari Alashti
    Amin Heydari Alashti about 3 years
    @user207421 you're right. but it depends on the use case is code is implementing. Consider a web crawler that should fetch all the pages as much as possible. Failing due to SSL problem is not a case in that situation. So, the trust all policy is a good policy at those cases.
  • Some Guy
    Some Guy over 2 years
    This was the only answer that worked for me; if I'm accessing sites of billion dollar corporations, turning off my security won't be too harmful, right?