koush / AndroidAsync

Asynchronous socket, http(s) (client+server) and websocket library for android. Based on nio, not threads.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

HTTPS using SSLv3

luisgabriel opened this issue · comments

I'm getting the following error when I try to request something to a server over HTTPS and the server uses SSLv3:

javax.net.ssl.SSLProtocolException: Unexpected message type has been received: 22
at org.apache.harmony.xnet.provider.jsse.SSLRecordProtocol.unwrap(SSLRecordProtocol.java:360)
at org.apache.harmony.xnet.provider.jsse.SSLEngineImpl.unwrap(SSLEngineImpl.java:464)
at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:383)
at com.koushikdutta.async.AsyncSSLSocketWrapper$2.onDataAvailable(AsyncSSLSocketWrapper.java:101)
at com.koushikdutta.async.BufferedDataEmitter.onDataAvailable(BufferedDataEmitter.java:33)
at com.koushikdutta.async.BufferedDataEmitter.onDataAvailable(BufferedDataEmitter.java:61)
at com.koushikdutta.async.Util.emitAllData(Util.java:20)
at com.koushikdutta.async.AsyncNetworkSocket.onReadable(AsyncNetworkSocket.java:175)
at com.koushikdutta.async.AsyncServer.runLoop(AsyncServer.java:758)
at com.koushikdutta.async.AsyncServer.run(AsyncServer.java:603)
at com.koushikdutta.async.AsyncServer.access$700(AsyncServer.java:37)
at com.koushikdutta.async.AsyncServer$13.run(AsyncServer.java:552)
com.koushikdutta.async.http.ConnectionClosedException: connection closed before response completed.
at com.koushikdutta.async.http.AsyncHttpResponseImpl$3.onCompleted(AsyncHttpResponseImpl.java:95)
at com.koushikdutta.async.AsyncSSLSocketWrapper.report(AsyncSSLSocketWrapper.java:396)
at com.koushikdutta.async.AsyncSSLSocketWrapper.access$100(AsyncSSLSocketWrapper.java:29)
at com.koushikdutta.async.AsyncSSLSocketWrapper$2.onDataAvailable(AsyncSSLSocketWrapper.java:130)
at com.koushikdutta.async.BufferedDataEmitter.onDataAvailable(BufferedDataEmitter.java:33)
at com.koushikdutta.async.BufferedDataEmitter.onDataAvailable(BufferedDataEmitter.java:61)
at com.koushikdutta.async.Util.emitAllData(Util.java:20)
at com.koushikdutta.async.AsyncNetworkSocket.onReadable(AsyncNetworkSocket.java:175)
at com.koushikdutta.async.AsyncServer.runLoop(AsyncServer.java:758)
at com.koushikdutta.async.AsyncServer.run(AsyncServer.java:603)
at com.koushikdutta.async.AsyncServer.access$700(AsyncServer.java:37)
at com.koushikdutta.async.AsyncServer$13.run(AsyncServer.java:552)

I'm testing using the following code:

AsyncHttpClient.getDefaultInstance().executeString(new AsyncHttpGet("https://node.photobeamer.com"), new AsyncHttpClient.StringCallback() {
    @Override
    public void onCompleted(Exception e, AsyncHttpResponse response, String result) {
    if (e != null) {
        e.printStackTrace();
        return;
    }
    android.util.Log.v(TAG, "-> Ok! Result: \n" + result);
    }
});

I could workaround this problem applying the following patch:

diff --git a/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java b/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java
index ff45a61..da2ae8f 100644
--- a/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java
+++ b/AndroidAsync/src/com/koushikdutta/async/AsyncSSLSocketWrapper.java
@@ -9,6 +9,7 @@ import com.koushikdutta.async.wrapper.AsyncSocketWrapper;

 import org.apache.http.conn.ssl.StrictHostnameVerifier;

+import java.lang.String;
 import java.nio.ByteBuffer;
 import java.security.GeneralSecurityException;
 import java.security.KeyStore;
@@ -61,6 +62,9 @@ public class AsyncSSLSocketWrapper implements AsyncSocketWrapper, AsyncSSLSocket
         else {
             engine = sslContext.createSSLEngine();
         }
+
+        engine.setEnabledProtocols(new String[] { "SSLv3" });
+
         mHost = host;
         mPort = port;
         engine.setUseClientMode(clientMode);

The strange part is that the default enabled protocols (returned by engine.getEnabledProtocols()) is ["TLSv1", "SSLv3"] and it does not work. When I set it to be only SSLv3 it works.

Hm, let me look

Looking around line 157, can you let me know what SSLEngine gets instantiated? Default or TLS?

    static {
        // following is the "trust the system" certs setup
        try {
            // critical extension 2.5.29.15 is implemented improperly prior to 4.0.3.
            // https://code.google.com/p/android/issues/detail?id=9307
            // https://groups.google.com/forum/?fromgroups=#!topic/netty/UCfqPPk5O4s
            // certs that use this extension will throw in Cipher.java.
            // fallback is to use a custom SSLContext, and hack around the x509 extension.
            if (Build.VERSION.SDK_INT <= 15)
                throw new Exception();
            sslContext = SSLContext.getInstance("Default");
        }
        catch (Exception ex) {
            try {
                sslContext = SSLContext.getInstance("TLS");
                TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }

                    public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
                    }

                    public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
                        for (X509Certificate cert : certs) {
                            if (cert != null && cert.getCriticalExtensionOIDs() != null)
                                cert.getCriticalExtensionOIDs().remove("2.5.29.15");
                        }
                    }
                } };
                sslContext.init(null, trustAllCerts, null);
            }
            catch (Exception ex2) {
                ex.printStackTrace();
                ex2.printStackTrace();
            }
        }
    }

The first one ( sslContext = SSLContext.getInstance("Default") ) gets instantiated.

What device is this? Custom ROM or no?

It's actually kind of worrisome that you need to force SSLv3. That's been deprecated in favor of TLS.

Server issue maybe? Can you screenshot me the cert as shown in the browser? I want to see how a browser connects to it. Protocols etc.

I have tested on a Nexus 4 (with Android 4.4.3) and on a Galaxy S3 (with Android 4.3), both using official ROMs.

The cert info:
ssl-node
ssl-node2

I'm not sure if it's a sever issue (I don't have access to the server), but I was suspecting that it's an issue on the Android platform. For some reason when there is other protocols besides SSLv3 enabled the SSL engine is not able to decode the messages.

Yikes, even the browser is using SSLv3. TLS should be backwards compatible, but it is not, for some unknown reason. May be an Android bug:

http://stackoverflow.com/a/11194217/704837

Same issue w/ the normal HttpClient.

Ideally, the fix is that the server uses TLS and not SSLv3. If the server is not in your control, your workaround seems to be what others use. I'll merge your patch.

Hi, koush,
I want to develop on the android platform with your androidasync. But when I send message by invoking the socket.io API, server received a message with http head. why it is ? that only 0.9.x version can do socket.io? where is the 0.9.x download link or the git commit version ?

commented

SocketIOClient.connect(AsyncHttpClient.getDefaultInstance(), "http://192.168.1.2:3000", new ConnectCallback() {
@OverRide
public void onConnectCompleted(Exception ex, SocketIOClient client) {
if (ex != null) {
ex.printStackTrace();
return;
}
client.setStringCallback(new StringCallback() {
@OverRide
public void onString(String string) {
System.out.println(string);
}
});
client.on("someEvent", new EventCallback() {
@OverRide
public void onEvent(JSONArray argument, Acknowledge acknowledge) {
System.out.println("args: " + arguments.toString());
}
});
client.setJSONCallback(new JSONCallback() {
@OverRide
public void onJSON(JSONObject json) {
System.out.println("json: " + json.toString());
}
});
}
});

Hi, koush,
I use this "connect" method to receive msg, The method "client.on("someEvent", new EventCallback())" is perform on Android 4.1, But don't perform on Android 5.0.1, It's very weird.

how to pause the executing task

is not very clear how to fix this, because im using the latest version (2.1.8) and it doesnt work on android 4.4 and 4.3 :S.