Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTPS using SSLv3 #174

Closed
luisgabriel opened this issue Jun 16, 2014 · 11 comments
Closed

HTTPS using SSLv3 #174

luisgabriel opened this issue Jun 16, 2014 · 11 comments

Comments

@luisgabriel
Copy link
Contributor

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.

@koush
Copy link
Owner

koush commented Jun 16, 2014

Hm, let me look

@koush
Copy link
Owner

koush commented Jun 16, 2014

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();
            }
        }
    }

@luisgabriel
Copy link
Contributor Author

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

@koush
Copy link
Owner

koush commented Jun 16, 2014

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.

@koush
Copy link
Owner

koush commented Jun 16, 2014

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.

@luisgabriel
Copy link
Contributor Author

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.

@koush
Copy link
Owner

koush commented Jun 17, 2014

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.

@fy2462
Copy link

fy2462 commented Dec 2, 2014

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 ?

@blazecake
Copy link

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.

@YaYaGo
Copy link

YaYaGo commented Oct 16, 2015

how to pause the executing task

@MikeRzDev
Copy link

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.

sacaratoqv added a commit to sacaratoqv/AndroidAsync that referenced this issue Aug 5, 2024
For some reason when the server uses SSLv3 the lib is not able to decode
the messages properly. To workaround this issue it's needed to set the
enabled protocols to SSLv3 (only).

This patch enables to explicitly set the enabled protocols.

For more info: koush/AndroidAsync#174
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants