Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android HTTPS SNI support using SSLCertificateSocketFactory

I am trying to add SNI support using SSLCertificateSocketFactory.setHostname, With wireshark i see the communication between client and SNI enabled server, The CLIENT HELLO goes to the server(with the correct hostname set), Server responds with Server Hello and sends certificate to client but after that client is not sending Certificate and communication/Handshake stops, via openssl command openssl s_client -connect theclient -servername thehostname -cert thecertificate everything goes smooth, Handshake occurs successfully ..

I am using sockets and on socket.startHandshake i get exception : IOException :javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

           final SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0);

            socket = (SSLSocket) sslSocketFactory.createSocket(InetAddress.getByName("theserver"), 443);


            socket.setEnabledProtocols(socket.getSupportedProtocols());

            String[] cipherArray = socket.getEnabledCipherSuites();
            for(int i = 0; i<cipherArray.length; i++) {
                Log.e("","Available Cipher:"+cipherArray[i]);
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                sslSocketFactory.setHostname(socket, "thehostname");
            } else {
                try {
                    java.lang.reflect.Method setHostnameMethod = socket.getClass().getMethod("setHostname", String.class);
                    setHostnameMethod.invoke(socket, "thehostname");
                } catch (Exception e) {
                    Log.w("", "SNI not useable", e);
                }
            }
            socket.setSoTimeout(20000);
            socket.setUseClientMode(true);
            Log.i(getClass().toString(), "Connected.");
            socket.startHandshake();
            SSLSession session = socket.getSession();
            boolean secured = session.isValid();

The solution of this IOexception SSLHANDSHAKEEXCEPTION on android developers is https://developer.android.com/training/articles/security-ssl.html#CommonProblems :

"Take a specific CA from an InputStream, uses it to create a KeyStore, which is then used to create and initialize a TrustManager. A TrustManager is what the system uses to validate certificates from the server and—by creating one from a KeyStore with one or more CAs—those will be the only CAs trusted by that TrustManager.

Given the new TrustManager, the example initializes a new SSLContext which provides an SSLSocketFactory you can use to override the default SSLSocketFactory from HttpsURLConnection. This way the connection will use your CAs for certificate validation."

Now the sslcontext returns SSLSOCKETFACTORY, i want to use SSLCertificateSocketFactory (for sethostname method) What to do .. I hope the question is clear, if not let me know or feel free to make to more clear

like image 344
baboo Avatar asked Jun 24 '14 22:06

baboo


1 Answers

You can use the NetCipher library to get a modern TLS config when using Android's HttpsURLConnection including SNI support. NetCipher configures the HttpsURLConnection instance to use the best supported TLS version, as well as the best suite of ciphers for that TLS version. First, add it to your build.gradle:

compile 'info.guardianproject.netcipher:netcipher:2.0.0-alpha1'

Or you can download the netcipher.jar and include it directly in your app. Then instead of calling:

HttpURLConnection connection = (HttpURLConnection) sourceUrl.openConnection();

Call this:

HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl);

If you want to see how its done in the code, look at TlsOnlySocketFactory

like image 179
Hans-Christoph Steiner Avatar answered Nov 18 '22 11:11

Hans-Christoph Steiner