0
votes

I am developing an application on Android that uses REST web service. The web service is in HTTPS. I can't provide the web service details, as it is confidential. I followed the steps mentioned in the link below:

http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/

The application was working fine so far and was able to download the web service content. Suddenly last one week it failed to connect and throws "javax.net.ssl.SSLException: Not trusted server certificate". I followed the steps mentioned below to setup this:

Step 1: I used root certificate provided by GeoTrust in my application to enable secure communication. So collected root certificate "GeoTrust_Global_CA.cer" from Geo trust site: http://www.geotrust.com/resources/root-certificates/index.html

It is a Base64 encoded X.509 format.

Step 2: Downloaded BouncyCastle provider and by using this created key store. I ran following commands using java 6 keytool from command line to generate key store:

keytool -importcert -v -trustcacerts -file "G:\workspace\TestHttps\GeoTrustglobal.cer" -alias IntermediateCA -keystore "G:\workspace\TestHttps\res\raw\mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "G:\workspace\TestHttps\SigningProcess\bcprov-jdk16-146.jar" -storetype BKS -storepass mysecret

After it is successful, it creates myKeyStore.bks and I copied it to /res/raw folder of my application.

Then verified this key store by running the following command:

keytool -importcert -v -trustcacerts -file "G:\workspace\TestHttps\GeoTrustglobal.cer" -alias IntermediateCA -keystore "G:\workspace\TestHttps\res\raw\mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "G:\workspace\TestHttps\SigningProcess\bcprov-jdk16-146.jar" -storetype BKS -storepass mysecret

It returned 1 result with intermediate certificate as follows:

IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43

Step 3:

Now I wrote the following code that is extended from DefaultHttpClient

public class MyHttpClient extends DefaultHttpClient {

    final Context context;

    public MyHttpClient(Context context) {
        this.context = context;
    }

     @Override
    protected ClientConnectionManager createClientConnectionManager() {
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        // Register for port 443 our SSLSocketFactory with our keystore
        // to the ConnectionManager
        registry.register(new Scheme("https", newSslSocketFactory(), 443));
        return new SingleClientConnManager(getParams(), registry);
    }

    private SSLSocketFactory newSslSocketFactory() {
        try {
            // Get an instance of the Bouncy Castle KeyStore format
            KeyStore trusted = KeyStore.getInstance("BKS");
            // Get the raw resource, which contains the keystore with
            // your trusted certificates (root and any intermediate certs)
            InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
            try {
                // Initialize the keystore with the provided trusted certificates
                // Also provide the password of the keystore
                trusted.load(in, "mysecret".toCharArray());
            } finally {
                in.close();
            }
            // Pass the keystore to the SSLSocketFactory. The factory is responsible
            // for the verification of the server certificate.
            SSLSocketFactory sf = new SSLSocketFactory(trusted);
            // Hostname verification from certificate
            // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
            sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
            return sf;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

Then I called DefaultHttpClient using following code:

package com.test.https;

import java.io.IOException;
import java.net.UnknownHostException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.os.Bundle;

public class TestHttps extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        try {
            startConnect();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void startConnect() throws UnknownHostException{
        DefaultHttpClient client = new MyHttpClient(getApplicationContext());
        HttpGet get = new HttpGet("https://ssltest15.bbtest.net/");
        // Execute the GET call and obtain the response
        HttpResponse getResponse = null;


        try {
            getResponse = client.execute(get);
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch(UnknownHostException uhe){
            uhe.printStackTrace();
            throw new UnknownHostException();           
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        String response = null;
        if(getResponse != null){
            HttpEntity responseEntity = getResponse.getEntity();
            try {
                response = EntityUtils.toString(responseEntity);
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
        }
    }
}

When I executed this code, it throws following exception:

java.security.cert.CertPathValidatorException: TrustAnchor for CertPath not found.

javax.net.ssl.SSLException: Not trusted server certificate


So I tried the same application to connect to various other web services including one that is provided by geotrust (https://ssltest15.bbtest.net/) . All throw same exception. My guess on this issue is that,

  1. Web server that is providing the REST web service, might had some changes on their side, that is causing this issue

  2. The Geo Trust cerificate that I use is expired

  3. Steps I followed have some issues

The same application with the above code was working fine before 1 week, suddenly failing now means, there is some change happened in the server side cause this issue. I am unclear about the exact issue.

If anybody can help me understand the issue is greatly appreciated. Thanks in advance.

1
hi. did u get any solution? I am also facing the same problemFoyzul Karim
Looks like there is some issue on the server side. We are working on that.Vignesh

1 Answers

0
votes

It seems like you do not have your trust store properly populated. I know you cannot discuss details of your web service, but what CA is your service's certificate signed off of? You need to put that chain in your trust keystore for your client application.

For example, if your web service is signed off of an intermediate GeoTrust CA, you should put the intermediate GeoTrust CA's cert as well as the root GeoTrust CA's cert into your store. If you still get errors, also put your web service's certificate into your client trust store as well.

Looking at the keytool -list output, you only have a single entry in your trust store.