Skip to content

HTTPS using SSLv3 #174

Closed
Closed

Description

@luisgabriel

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.

Activity

  1. koush commented on Jun 16, 2014

    @koush
    Owner

    Hm, let me look

  2. koush commented on Jun 16, 2014

    @koush
    Owner

    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();
                }
            }
        }
  3. luisgabriel commented on Jun 16, 2014

    @luisgabriel
    ContributorAuthor

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

  4. koush commented on Jun 16, 2014

    @koush
    Owner

    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.

  5. koush commented on Jun 16, 2014

    @koush
    Owner

    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.

  6. luisgabriel commented on Jun 16, 2014

    @luisgabriel
    ContributorAuthor

    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.

  7. koush commented on Jun 17, 2014

    @koush
    Owner

    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.

  8. fy2462 commented on Dec 2, 2014

    @fy2462

    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 ?

  9. blazecake commented on Mar 10, 2015

    @blazecake

    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.

  10. YaYaGo commented on Oct 16, 2015

    @YaYaGo

    how to pause the executing task

  11. MikeRzDev commented on Jul 7, 2016

    @MikeRzDev

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions