How to use self-signed SSL in android network libr

2019-03-26 08:15发布

问题:

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.

回答1:

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"}


回答2:

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.



回答3:

1. Generate the self signed certificate by openssl libarary.
http://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-openssl
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


回答4:

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...