1

In my situation when I run programm on emulator - its work correktly. But when I install apk to phone - have error Not trusted server certificate. What is the problem?

there is a code of my AsyncTask for sending response to the server:

public abstract class BaseAsyncWorker extends AsyncTask<String, Void, String>{
public static final String AS = "BaseAsyncWorker";
private  String URL;
private String result;
final Context context;

public BaseAsyncWorker(String url,Context context){
    this.URL = url; 
    this.context = context;
}
//before
@Override
protected abstract void onPreExecute();

//background
@Override
protected  String doInBackground(String... objects) {
    for (String obj : objects) {
        Log.d(AS,obj.toString() );
        Log.d(AS,"beginning background" );
        Logger.appendLog("Start response...");
        try{


            HostnameVerifier hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

            DefaultHttpClient client = new DefaultHttpClient();

            SchemeRegistry registry = new SchemeRegistry();
            SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
            socketFactory.setHostnameVerifier((X509HostnameVerifier)hostnameVerifier);
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            registry.register(new Scheme("https", socketFactory,443));
            SingleClientConnManager mngr = new SingleClientConnManager(client.getParams(),
                                                                        registry);
            //trustEveryone();
            DefaultHttpClient httpClient = new DefaultHttpClient(mngr,client.getParams());

            //MMGHttpClient httpClient = new MMGHttpClient(context);
            //httpClient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "MyMobiGift Ltd. Android");
            //HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

            HttpPost httpPost = new HttpPost(URL); 

            StringEntity se = new StringEntity(obj);
            httpPost.setEntity(se);
            httpPost.setHeader("Accept", "application/json");
            httpPost.setHeader("Content-type", "application/json");



            HttpResponse response = (HttpResponse)httpClient.execute(httpPost);
            StatusLine status = response.getStatusLine();
            if((status.getStatusCode())==200){
                HttpEntity entity = response.getEntity();
                if(entity!=null){
                    InputStream instream = entity.getContent();
                    result= convertStreamToString(instream);
                    instream.close();
                    Logger.appendLog("End response with result: "+result);
                }else{
                    result=null;
                    Logger.appendLog("End response without result");
                }
            }
        }catch (ClientProtocolException e) {Logger.appendLog("ClientProtocolException at"+e.getMessage());}
        catch (IOException e) {Logger.appendLog("IOException at" + e.getMessage());}

    }   
    return result;  
}
Pavel Shysh
  • 196
  • 2
  • 13

2 Answers2

3

This is what helped me to build a proper working http communication over ssl.

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

If you want client (android device) really (not blindly) trusts host, public certificate needs to be loaded to device's KeyStore, otherwise device won't talk to the server

You will use .crt file but to use with Android KeyStore you need it to be converted to "bks". I do following:

// read .crt file from memory
InputStream inStream = ctx.openFileInput("cetificate.crt");

//InputStream inStream = ctx.getAssets().open("wm_loaner.cer");
if(inStream != null)
{
    KeyStore cert = CertUtils.ConvertCerToBKS(inStream, "MyAlias", "password".toCharArray());
    inStream.close();
}

public static KeyStore ConvertCerToBKS(InputStream cerStream, String alias, char [] password)
{
    KeyStore keyStore = null;
    try
    {
        keyStore = KeyStore.getInstance("BKS", "BC");
        CertificateFactory factory = CertificateFactory.getInstance("X.509", "BC");
        Certificate certificate = factory.generateCertificate(cerStream);
        keyStore.load(null, password);
        keyStore.setCertificateEntry(alias, certificate);
    }
    catch ....
    {
    }
    return keyStore;                                    
}

After certificate was converted and loaded to the KeyStore you can establish a connection

Maxim
  • 4,088
  • 8
  • 48
  • 76
  • 1
    Android 2.3 onwards does not seem to suffer from this to the same extent. The solution here seems to be more security conscience and adding a certificate via Bouncy Castle is indeed better than trusting all (here be gremlins) – Graham Smith Feb 03 '12 at 20:56
  • But I steel have one question remains: I have two files - file.crt and file.pem . Which one to use me to create a repository(KEYSTORE)? – Pavel Shysh Feb 04 '12 at 19:19
1

You can override certificate of webserver by using addSLLCertificateToHttpRequest() method. Call addSLLCertificateToHttpRequest() method before communicating with your server. This will avoid certificate invalidation and always return true. I am writing this method. This is working for me

/**
 * The server has a SSL certificate. This method add SSL certificate to HTTP
 * Request
 */
public static void addSLLCertificateToHttpRequest() {
    // Code to use verifier which return true.
    try {
        SSLContext sslctx = null;
        try {
            sslctx = SSLContext.getInstance("TLS");
            sslctx.init(null, new TrustManager[] { new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] chain, String authType)
                {
                }

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

                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[] {};
                }
            } }, null);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        HttpsURLConnection.setDefaultSSLSocketFactory(sslctx.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }

}
Muhammad Nabeel Arif
  • 18,872
  • 8
  • 49
  • 70
  • im trying now. my code on emulator worked too. But on device - not. – Pavel Shysh Feb 03 '12 at 19:00
  • Muhhamad, this is correctly work on the emulator, the device does not currently have ... I had previously used the code below, and I think they are doing identical work, or I oshiayus? anyway, thank you very much for having responded to that. whether there are such cases that can not do without a table? – Pavel Shysh Feb 03 '12 at 19:26
  • But I steel have one question remains: I have two files - file.crt and file.pem . Which one to use me to create a repository(KEYSTORE)? – Pavel Shysh Feb 04 '12 at 19:25
  • Hi, I tried these steps and I still cannot get it to work. @Nabeel, do you know how should I proceed on? Do you want me to start a new question? – Melvin Lai Mar 06 '12 at 07:56