By design when we open an SSL connection in Java (e.g. through java.net.URL.openConnection(“https://….”)) the JSSE implementation of the SSL protocol performs few validations to ensure the requested host is not fake. This involves validation of the server’s X.509 certificate with the PKIX algorithm and checking the host name agains the certificate subject. If the SSL certificate is not validates as trusted or does not match the target host, an HTTPS and other SSL encrypted connection cannot be established and all attempts will result in SSLHandshakeException or IOException.

Example of HTTPS Connection in Java that will Fail Due to Certificate Validation Failure

Consider we are trying to download a resource from HTTPS server:
 
HashMap data = new HashMap();
data.put("page", "2");
data.put("page_size", "5");
String url = "https://www.nakov.com:2083/";
postData(url, data);

public void postData(String url, HashMap data) {
        RequestQueue requstQueue = Volley.newRequestQueue(MainActivity.this);

        JsonObjectRequest jsonobj = new JsonObjectRequest(Request.Method.POST, url, new JSONObject(data),
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        Log.d("test_disable_sess", response.toString());
                        Toast.makeText(MainActivity.this, "This is my " + response.toString(),
                                Toast.LENGTH_LONG).show();

//                        if(mResultCallback != null){
//                            mResultCallback.notifySuccess(response);
//                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.d("test_disable_err", error.toString());
                        Toast.makeText(MainActivity.this, "This is my " + error.toString(),
                                Toast.LENGTH_LONG).show();

//                        if(mResultCallback != null){
//                            mResultCallback.notifyError(error);
//                        }
                    }
                }
        ) {
            //here I want to post data to sever
        };
        int socketTimeout = 30000; // 30 seconds. You can change it
        RetryPolicy policy = new DefaultRetryPolicy(socketTimeout,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
        jsonobj.setRetryPolicy(policy);
        requstQueue.add(jsonobj);

    }
If the server uses self-signed X.509 certificate, we will get SSLHandshakeException the following exception during the SSL handshaking:
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
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    ...
This exception can be avoided if we import the server’s self-signed certificate in the JVM trusted store, a file called “cacerts”. For more information see this post: http://www.java-samples.com/showtutorial.php?tutorialid=210. We could have also another issue. If the server uses trusted certificate (issued from trusted CA like VeriSign), but for different host, we will get another exception (IOException) during the host verification step of the SSL handshaking:
Exception in thread "main" <strong>java.io.IOException: HTTPS hostname wrong: should be <www.nakov.com></strong>
    at sun.net.www.protocol.https.HttpsClient.checkURLSpoofing(Unknown Source)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)

How to Turn Off Certificate Validation in Java HTTPS Connections?

Avoiding these exceptions is possible by switching off the certificate validation and host verification for SSL for the current Java virtual machine. This can be done by replacing the default SSL trust manager and the default SSL hostname verifier:
 
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.RetryPolicy;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;

import org.json.JSONObject;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.HashMap;

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;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//=============================================================

Disable_Certificate_Validation_Java_SSL_Connections();
//============================================================
        HashMap data = new HashMap();
        data.put("page", "2");
        data.put("page_size", "5");
        String url = "https://www.nakov.com:2083/";
        postData(url, data);
    }

    public void Disable_Certificate_Validation_Java_SSL_Connections() {

// 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(X509Certificate[] certs, String authType) {
            }

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

        // Install the all-trusting trust manager
        SSLContext sc = null;
        try {
            sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            Log.d("test_disable", "OK========");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }

        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);
    }

    public void postData(String url, HashMap data) {
        RequestQueue requstQueue = Volley.newRequestQueue(MainActivity.this);

        JsonObjectRequest jsonobj = new JsonObjectRequest(Request.Method.POST, url, new JSONObject(data),
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        Log.d("test_disable_sess", response.toString());
                        Toast.makeText(MainActivity.this, "This is my " + response.toString(),
                                Toast.LENGTH_LONG).show();

//                        if(mResultCallback != null){
//                            mResultCallback.notifySuccess(response);
//                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.d("test_disable_err", error.toString());
                        Toast.makeText(MainActivity.this, "This is my " + error.toString(),
                                Toast.LENGTH_LONG).show();

//                        if(mResultCallback != null){
//                            mResultCallback.notifyError(error);
//                        }
                    }
                }
        ) {
            //here I want to post data to sever
        };
        int socketTimeout = 30000; // 30 seconds. You can change it
        RetryPolicy policy = new DefaultRetryPolicy(socketTimeout,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
        jsonobj.setRetryPolicy(policy);
        requstQueue.add(jsonobj);

    }
}
Be careful when using this hack! Skipping certificate validation is dangerous and should be done in testing environments only.
Total Views 110, Views Today 1

Leave a Reply

Your email address will not be published. Required fields are marked *