How to use self-signed SSL in android network library (ION)?
Asked Answered
C

4

10

Using this network library:

https://github.com/koush/ion

As the current status is development, I would like to use self-signed SSL cert

The library forum has some discussion:

https://github.com/koush/ion/issues/3

 Ion ion = Ion.getDefault(c);
    ion.configure().createSSLContext("TLS");
    ion.getHttpClient().getSSLSocketMiddleware().setSSLContext(sslContext);
    ion.getHttpClient().getSSLSocketMiddleware().setTrustManagers(trustManagers);

After some studies , I have grab the crt and getting sslContext and trustmanager, the problem is , it still return exception

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

Here is my attempt :

    try {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream caInput = getResources().openRawResource(R.raw.load);
        Certificate ca;
        try {
            ca = cf.generateCertificate(caInput);
            //System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
        } finally {
            caInput.close();
        }

        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        ssl_context = SSLContext.getInstance("TLS");
        ssl_context.init(null, tmf.getTrustManagers(), null);
    } catch (Exception e) {
        Log.d("test1", "A: " + e);
    }

    Ion.getDefault(this).getHttpClient().getSSLSocketMiddleware().setTrustManagers(tmf.getTrustManagers());
    Ion.getDefault(this).getHttpClient().getSSLSocketMiddleware().setSSLContext(ssl_context);

    //test SSL
    Ion.getDefault(this).with(this)
            .load("https://na2b.no-ip.com/dragonair/can_app/api/media_list.php")
            .asJsonObject()
            .setCallback(new FutureCallback<JsonObject>() {
                @Override
                public void onCompleted(Exception e, JsonObject result) {
                    if (e != null) {
                        Log.d("test1", "B: " + e);
                    } else {
                        Log.d("test1", "result" + result);
                    }
                }
            });

notice that the exception is at the B: part so that means trustmanager and SSLcontext should build correctly, how to fix that?

Thanks for helping.

Clench answered 31/12, 2015 at 3:23 Comment(6)
i have done that will okhttp by looking @ developer.android.com/training/articles/security-ssl.html. see if it helps looking at the docs.Walther
To use with self-signed cert, please read my answer at #32154615 or #32970452Hang
@Hang , thanks for advice, it seems can not override the network library settingsClench
Pls read my answer, pay attention to wrappedTrustManagersHang
Thanks will try tonightClench
Yes, and don't forget to setHostnameVerifier if you get the exception "Hostname '<address>' was not verified"Hang
H
10

For your issue, IMO, you can refer to my following sample code. I have tested with my web service (Asp.Net WebAPI). Hope it helps!

public class MainActivity extends AppCompatActivity {

    private Context mContext = this;

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

        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            // cert file stored in \app\src\main\res\raw
            InputStream caInput = getResources().openRawResource(R.raw.your_cert);

            Certificate ca = cf.generateCertificate(caInput);
            caInput.close();

            KeyStore keyStore = KeyStore.getInstance("BKS");
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);

            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);

            TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());

            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, wrappedTrustManagers, null);

            AsyncSSLSocketMiddleware sslMiddleWare = Ion.getDefault(mContext).getHttpClient().getSSLSocketMiddleware();
            sslMiddleWare.setTrustManagers(wrappedTrustManagers);
            sslMiddleWare.setHostnameVerifier(getHostnameVerifier());
            sslMiddleWare.setSSLContext(sslContext);

            // Post application/x-www-form-urlencoded and read a String
            Ion.with(mContext)
                    .load("https://yourserver/token")
                    .setBodyParameter("grant_type", "password")
                    .setBodyParameter("username", "bnk")
                    .setBodyParameter("password", "bnk123456789")
                    .asString()
                    .setCallback(new FutureCallback<String>() {
                        @Override
                        public void onCompleted(Exception e, String result) {
                            if (result != null) {
                                Log.i("ionSample", result);
                            } else if (e != null) {
                                e.printStackTrace();
                            }
                        }
                    });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private HostnameVerifier getHostnameVerifier() {
        return new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
                // or the following:
                // HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
                // return hv.verify("www.yourserver.com", session);
            }
        };
    }

    private TrustManager[] getWrappedTrustManagers(TrustManager[] trustManagers) {
        final X509TrustManager originalTrustManager = (X509TrustManager) trustManagers[0];
        return new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return originalTrustManager.getAcceptedIssuers();
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
                        try {
                            if (certs != null && certs.length > 0){
                                certs[0].checkValidity();
                            } else {
                                originalTrustManager.checkClientTrusted(certs, authType);
                            }
                        } catch (CertificateException e) {
                            Log.w("checkClientTrusted", e.toString());
                        }
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
                        try {
                            if (certs != null && certs.length > 0){
                                certs[0].checkValidity();
                            } else {
                                originalTrustManager.checkServerTrusted(certs, authType);
                            }
                        } catch (CertificateException e) {
                            Log.w("checkServerTrusted", e.toString());
                        }
                    }
                }
        };
    }   
}

Logcat output:

I/ionSample: {"access_token":"oS1SHxck8TzidTL...P-_6VFjRlDsjF9_A0JONu59rzYOVQV...ka78pHSvRPB5YrrBlHsF562Ay__Jd0MDfpOB0SRML2N8O3XPZK8woV4vjASzfGEzi7KJMmY8pkM_-P9ohHhWPD3PtgRahiqTUSapdpg6n197uJxdQWyU","token_type":"bearer","expires_in":2591999,"userName":"bnk",".issued":"Wed, 06 Jan 2016 06:26:45 GMT",".expires":"Fri, 05 Feb 2016 06:26:45 GMT"}
Hang answered 6/1, 2016 at 6:31 Comment(3)
Thanks for great answer. one last question, if there is an image library e.g. Picasso , that grab the https image , is it using the SSL as well? is the above code for network usage in ION only?Clench
Nice comment! I have not tried with Picasso yet, however, I think it can be used as the following OkHttpClient okHttpClient = new OkHttpClient(); okHttpClient.setSslSocketFactory(sslContext.getSocketFactory()); Picasso.Builder builder = new Picasso.Builder(this); OkHttpDownloader okHttpDownloader = new OkHttpDownloader(okHttpClient); builder.downloader(okHttpDownloader); Picasso picasso = builder.build(); picasso.load("https://...");Hang
And okHttpClient.setHostnameVerifier(getHostnameVerifier());Hang
D
3

As the current status is development, I would like to ignore the SSL checking , but instead of replace https with http

Use Delete, Backspace, or equivalent operations to remove the s from the https scheme in your URL. Done.

This assumes that your server supports plain HTTP. If it does not, talk to whoever is maintaining the server.

Any experience in bypass the SSL checking (with using self sign cert) before?

Self-signed SSL certificates are not used to "bypass the SSL checking". If you are connecting to an HTTPS server that is using a self-signed certificate, then you configure Ion (or other HTTP clients) to recognize that certificate.

You "bypass the SSL checking" by not requesting an https:// URL, and having a server that supports a plain http:// URL.

And the problem is how to construct the sslContext obj / trust managers ?

If you actually have a server that is using a self-signed SSL certificate, you can use my CWAC-Security library to create the TrustManager[]. Or, follow the Java snippets in Nikolay Elenkov's old blog post, adapting them for use with Ion.

Default answered 5/1, 2016 at 11:46 Comment(1)
The library looks like just what I need, thanks a lotClench
D
2
1. Generate the self signed certificate by openssl libarary.
https://mcmap.net/q/35871/-how-to-generate-a-self-signed-ssl-certificate-using-openssl-closed
2. Import the same certificate or its root certificate to your server(ISS or apache.
3. Use following code in client 
// 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 = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
    ca = cf.generateCertificate(caInput);
    System.out.println("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();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);

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

// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection =
    (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);

http://developer.android.com/training/articles/security-ssl.html
Displume answered 6/1, 2016 at 3:54 Comment(1)
thanks , the problem is copyInputStreamToOutputStream is unresolved? And how to apply to ION library?Clench
E
0
try {
            TrustManager[] wrappedTrustManagers = new TrustManager[]{
                    new X509TrustManager() {
                        public void checkClientTrusted(X509Certificate[] chain, String authType) {
                        }

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

                        public X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[]{};
                        }
                    }
            };

            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, wrappedTrustManagers, null);

            AsyncSSLSocketMiddleware sslMiddleWare = Ion.getDefault(this).getHttpClient().getSSLSocketMiddleware();
            sslMiddleWare.setTrustManagers(wrappedTrustManagers);
            sslMiddleWare.setHostnameVerifier(new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            sslMiddleWare.setSSLContext(sslContext);

            Ion.with(this)
                    .load("https://yoururl")
                    .setBodyParameter("key1", "value1")
                    .setBodyParameter("key2", "value2")
                    .asString()
                    .setCallback(new FutureCallback<String>() {
                        @Override
                        public void onCompleted(Exception e, String result) {
                            if (result != null)
                                Log.d("responsearrived", result);

                            if (e != null) Log.d("responserror", e.toString());
                        }
                    });
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

This is more dangerous, and should be used for testing purposes only... But this works, without adding certificates to the filesystem... You mentioned that your project is in development phase, so this should help you, for now...

Elohist answered 9/7, 2016 at 21:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.