2
votes

I was attempting to connect to my remote server with HTTPS. I'm using a certificate from "Let's Encrypt". The php file I'm calling just echos a "Success" I used the following code from developer.android.com for trusting the CA:

public class VerifyKey extends AsyncTask<Void, Void, Void> {

    public static final String CERTIFICATE_TYPE_X_509 = "X.509";
    public static final String CERTIFICATE_ALIAS = "domain_name";
    public static final String SERVER_URL = "https://domain_name";

    Context mContext;

    public VerifyKey(Context c)
    {
        mContext=c;
    }

    @Override
    protected Void doInBackground(Void... params) {
        try
        {
            // Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
            InputStream caInput = mContext.getResources().openRawResource(R.raw.ca);
            Certificate ca;
            try {
                ca = cf.generateCertificate(caInput);
                Log.d("CONN_TEST_SSL","ca=" + ((X509Certificate) ca).getSubjectDN());

            } finally {
                caInput.close();
            }

// Create a KeyStore containing our trusted CAs
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);

// Create a TrustManager that trusts the CAs in our KeyStore
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            MainActivity.tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            MainActivity.tmf.init(keyStore);

// Create an SSLContext that uses our TrustManager
            MainActivity.ssl_context = SSLContext.getInstance("TLS");
            MainActivity.ssl_context.init(null, MainActivity.tmf.getTrustManagers(), null);

// Tell the URLConnection to use a SocketFactory from our SSLContext
            URL url = new URL("https://domain_name/register.php");
            HttpsURLConnection urlConnection =
                    (HttpsURLConnection)url.openConnection();
            urlConnection.setSSLSocketFactory(MainActivity.ssl_context.getSocketFactory());
            InputStream in = urlConnection.getInputStream();

            BufferedReader br=new BufferedReader(new InputStreamReader(in));

            Log.d("CONN_TEST_SSL",br.readLine());
        }
        catch(Exception ex)
        {
            Log.d("CONN_TEST_SSL", "Problem", ex);
        }

        return null;
    }
}

For the first log( getSubjectDN() ) I got:

ca=CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US

For the test url, I got "Success"

As you can see, I declared static variables for TrustManagerFactory and SSLContext at MainActivity

Now things went upside down when I implemented another class:

public class AuthServerInterface extends AsyncTask<String, Void, String> {


    String resp;
    private Context cont;
    private int myflag;

    public AsyncResponse del;

    public AuthServerInterface(Context context,AsyncResponse mydel,int flag) {
        this.cont = context;
        this.del=mydel;
        resp=new String("");
        this.myflag=flag;
    }


    protected void onPreExecute(){
    }

    @Override
    protected String doInBackground(String... arg0) {

        String msg="";

        if(myflag==0)
        {
            try {
                String fname = (String)arg0[0];
                String lname = (String)arg0[1];
                String mail_id = (String)arg0[2];
                String phone_no = (String)arg0[3];

                String link = MainActivity.BASE_DOMAIN + "register.php";

                String data = URLEncoder.encode("fname", "UTF-8") + "=" +
                        URLEncoder.encode(fname, "UTF-8");

                data+="&"+URLEncoder.encode("lname", "UTF-8") + "=" +
                        URLEncoder.encode(lname, "UTF-8");

                data+="&"+URLEncoder.encode("mail_id", "UTF-8") + "=" +
                        URLEncoder.encode(mail_id, "UTF-8");

                data+="&"+URLEncoder.encode("phone_no", "UTF-8") + "=" +
                        URLEncoder.encode(phone_no, "UTF-8");

                Log.d(data,"CONN_TEST");

                URL url = new URL(link);

                /////////////

                HttpsURLConnection conn =
                        (HttpsURLConnection)url.openConnection();
                conn.setSSLSocketFactory(MainActivity.ssl_context.getSocketFactory());
                /////////////

                conn.setDoOutput(true);
                OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());

                wr.write(data);
                wr.flush();

                BufferedReader reader = new BufferedReader(new
                        InputStreamReader(conn.getInputStream()));

                StringBuilder sb = new StringBuilder();
                String line = null;

                // Read Server Response
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                    break;
                }
                msg=sb.toString();
            } catch (Exception e) {

                msg= new String("Exception: " + e.getMessage());
            }
        }

        return msg;

    }

    @Override
    protected void onPostExecute(String result){
        del.processFinish(result);
    }

... and called them as follows:

VerifyKey vk=new VerifyKey(getBaseContext());
                vk.execute();

                AuthServerInterface SI=new AuthServerInterface(getBaseContext(), new AsyncResponse() {
                    @Override
                    public void processFinish(String output) {

                        Log.d(output," CONN_TEST_REAL");

                    }
                },0);

                SI.execute(first_name,last_name,mail_id,phone_no);

The part for verification worked fine. But for the second part...

[ 06-11 16:48:44.093  2725: 2725 D/Exception: Hostname domain_name not verified:
                                                                                                                   certificate: sha1/xItPZS3lzfY8syDdUhT CONN_TEST_REAL

I am kind of new to SSL on Android. What could have gone wrong?

1

1 Answers

1
votes

Well, I figured it out myself.

The BASE_DOMAIN string I supplied in MainActivity had "www"!

Smallest things can cause the biggest problems