I am trying to connect to a server and sending a HTTPS based request to it using the following code:

// create the URL with the target URL specified
URL url = new URL(vTargetURL);

// create a HTTP connection to the URL specified
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();

// set the timeout for the request
urlConnection.setReadTimeout(30000);

//add request header
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Length", String.valueOf(vRequestXML.length()));
for (HashMap.Entry<String, String> entry : vHttpHeaders.entrySet()) {           
    urlConnection.setRequestProperty(entry.getKey(), entry.getValue());
}


// send the request
DataOutputStream dataOutputStream = new DataOutputStream(urlConnection.getOutputStream());
dataOutputStream.writeBytes(vRequestXML);
dataOutputStream.flush();
dataOutputStream.close();

// read the response
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String inputLine;

StringBuffer response = new StringBuffer();         
while ((inputLine = bufferedReader.readLine()) != null) {
    response.append(inputLine);
}                   
bufferedReader.close();

The problem I am facing is that my code is failing at the statement

DataOutputStream dataOutputStream = new DataOutputStream(urlConnection.getOutputStream());

with the Exception

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

I only understand there is some issue related to the certificate of the server. I am able to bypass this issue by using the following code:

final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
};  

urlConnection.setHostnameVerifier(DO_NOT_VERIFY);

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {

    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[] {};
    }

    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

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

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

Also, when I checked the server address on this website, I got the following error

enter image description here

I know that trusting all host is not a way to solve this problem, but I am not able conclude how should I process about solving these issues. Specifically I want to understand:

  1. What are the possible reasons for such an Exception.
  2. How can I resolve the issues.

Any leads are appreciated.

Thanks.

1

There are 1 best solutions below

0
On

When you make a HTTPS connection, the server you connect to sends his certificate to prove you got the right server. This certificate is normally signed by another certificate, either by that of a CA (certificate authority), or by just another certificate, which in turn is signed. However long that chain is, on the bottom you find the certificate of a CA.

How do you know that this CA certificate is ok? Java solves this problem by storing the certificates of all trusted CAs in a keystore (cacerts).

The error you are facing is most likely the result of a certificate signed by a CA that is not in the keystore. It is either a self-signed certificate (the certificate itself acting as its own CA), a certificate signed by an in-house CA of some company, or by a small unknown CA.

Yo have to decide whether you want to trust all certificates signed by this CA. In that case take the CA certificate, and put it in your cacerts file.

I have no idea on how to do that on android, though. The standard java tool to do this is keytool.