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

Error when connecting from Android to a server that does not support TLS 1.0 #173

Open
decraw opened this issue Jul 16, 2015 · 14 comments
Open

Comments

@decraw
Copy link

decraw commented Jul 16, 2015

I am attempting to use ModernHttpClient to get around the mono limitation of not supporting HTTPS/TLS 1.1. For PCI reasons this is necessary in my app.

ModernHttpClient works great to resolve the issue on iPhone, but on android, I get the following when attempting an HTTP GET to a server that only support TLS 1.1 and above.

07-16 22:04:25.797 I/mono-stdout(12467): Javax.Net.Ssl.SSLException: Exception of type 'Javax.Net.Ssl.SSLException' was thrown.
07-16 22:04:25.797 I/mono-stdout(12467):   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.T07-16 22:04:25.797 I/mono-stdout(12467):   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in <filename unknown>:0 
07-16 22:04:25.797 I/mono-stdout(12467):   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0004e] in <filename unknown>:0 
07-16 22:04:25.797 I/mono-stdout(12467):   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in <filename unknown>:0 
07-16 22:04:25.797 I/mono-stdout(12467):   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in <filename unknown>:0 
07-16 22:04:25.797 I/mono-stdout(12467):   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[OkHttp.Response].GetResult () [0x00000] in <filename unknown>:0 
07-16 22:04:25.797 I/mono-stdout(12467):   at ModernHttpClient.NativeMessageHandler+<SendAsync>d__8.MoveNext () [0x0000e] in d:\Downloads\ModernHttpClient-2.4.2\ModernHttpClient-2.4.2\src\ModernHttpClient\Android\OkHttpNetworkHandler.cs:191 
07-16 22:04:25.797 I/mono-stdout(12467): --- End of stack trace from previous location where exception was thrown ---
07-16 22:04:25.797 I/mono-stdout(12467):   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in <filename unknown>:0 
07-16 22:04:25.797 I/mono-stdout(12467):   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0004e] in <filename unknown>:0 
07-16 22:04:25.801 I/mono-stdout(12467):   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in <filename unknown>:0 
07-16 22:04:25.801 I/mono-stdout(12467):   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in <filename unknown>:0 
07-16 22:04:25.801 I/mono-stdout(12467):   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[System.Net.Http.HttpResponseMessage].GetResult () [0x00000] in <filename unknown>:0 
07-16 22:04:25.801 I/mono-stdout(12467):   at System.Net.Http.HttpClient+<SendAsyncWorker>c__async0.MoveNext () [0x000f3] in <filename unknown>:0 
07-16 22:04:25.801 I/mono-stdout(12467): --- End of stack trace from previous location where exception was thrown ---
07-16 22:04:25.801 I/mono-stdout(12467):   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in <filename unknown>:0 
07-16 22:04:25.801 I/mono-stdout(12467):   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0004e] in <filename unknown>:0 
07-16 22:04:25.801 I/mono-stdout(12467):   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in <filename unknown>:0 
07-16 22:04:25.801 I/mono-stdout(12467):   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in <filename unknown>:0 
07-16 22:04:25.801 I/mono-stdout(12467):   at System.Runtime.CompilerServices.TaskAwaiter`1[System.Net.Http.HttpResponseMessage].GetResult () [0x00000] in <filename unknown>:0 
07-16 22:04:25.801 I/mono-stdout(12467):   at Playground.Android.MainActivity+<>c__DisplayClassa+<<OnCreate>b__7>d__d.MoveNext () [0x00181] in d:\Downloads\ModernHttpClient-2.4.2\ModernHttpClient-2.4.2\src\Playground.Android\MainActivity.cs:108 
07-16 22:04:25.801 I/mono-stdout(12467):   --- End of managed exception stack trace ---
07-16 22:04:25.801 I/mono-stdout(12467): javax.net.ssl.SSLException: SSL handshake aborted: ssl=0xb9c0c8f0: I/O error during system call, Connection reset by peer
07-16 22:04:25.801 I/mono-stdout(12467):    at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
07-16 22:04:25.801 I/mono-stdout(12467):    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)
07-16 22:04:25.801 I/mono-stdout(12467):    at com.squareup.okhttp.Connection.upgradeToTls(Connection.java:242)
07-16 22:04:25.801 I/mono-stdout(12467):    at com.squareup.okhttp.Connection.connect(Connection.java:159)
07-16 22:04:25.801 I/mono-stdout(12467):    at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:175)
07-16 22:04:25.801 I/mono-stdout(12467):    at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:120)
07-16 22:04:25.801 I/mono-stdout(12467):    at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:330)
07-16 22:04:25.801 I/mono-stdout(12467):    at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:319)
07-16 22:04:25.801 I/mono-stdout(12467):    at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:241)
07-16 22:04:25.801 I/mono-stdout(12467):    at com.squareup.okhttp.Call.getResponse(Call.java:271)
07-16 22:04:25.801 I/mono-stdout(12467):    at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:228)
07-16 22:04:25.805 I/mono-stdout(12467):    at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:199)
07-16 22:04:25.805 I/mono-stdout(12467):    at com.squareup.okhttp.Call.access$100(Call.java:34)
07-16 22:04:25.805 I/mono-stdout(12467):    at com.squareup.okhttp.Call$AsyncCall.execute(Call.java:162)
07-16 22:04:25.805 I/mono-stdout(12467):    at com.squareup.okhttp.internal.NamedRunnable.run(NamedRunnable.java:33)
07-16 22:04:25.805 I/mono-stdout(12467):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
07-16 22:04:25.805 I/mono-stdout(12467):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
07-16 22:04:25.805 I/mono-stdout(12467):    at java.lang.Thread.run(Thread.java:841)
Thread finished:  #3
The thread 'Unknown' (0x3) has exited with code 0 (0x0).
@mazloumi
Copy link

Hi, I also have issues with connecting to websites using TLS. The following code works when I call the google website but not my own website that is using a CA signed certificate.

        var handler = new NativeMessageHandler();
        handler.ClientCertificateOptions = ClientCertificateOption.Automatic;

        var client = new HttpClient(handler);
        var stuff = await client.GetStringAsync("https://www.google.com");

        System.Diagnostics.Debug.WriteLine (stuff);

It may be that it works with google because it is using SSLv3 instead of TLS 1.2

Google:

Supported versions: SSLv3 TLSv1.0 TLSv1.1 TLSv1.2
Deflate compression: no
Supported cipher suites (ORDER IS NOT SIGNIFICANT):
SSLv3
RSA_WITH_RC4_128_MD5
RSA_WITH_RC4_128_SHA
RSA_WITH_3DES_EDE_CBC_SHA
RSA_WITH_AES_128_CBC_SHA
RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_RC4_128_SHA
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
(TLSv1.0: idem)
(TLSv1.1: idem)
TLSv1.2
RSA_WITH_RC4_128_MD5
RSA_WITH_RC4_128_SHA
RSA_WITH_3DES_EDE_CBC_SHA
RSA_WITH_AES_128_CBC_SHA
RSA_WITH_AES_256_CBC_SHA
RSA_WITH_AES_128_CBC_SHA256
RSA_WITH_AES_256_CBC_SHA256
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_RC4_128_SHA
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

Server certificate(s):
5d1b140376f38d49f93f3f83385f890ea60bd5c6: CN=www.google.com, O=Google Inc, L=Mountain View, ST=California, C=US

Minimal encryption strength: strong encryption (96-bit or more)
Achievable encryption strength: strong encryption (96-bit or more)
BEAST status: protected
CRIME status: protected

Our website only supports TLS 1.2:

Supported versions: TLSv1.2
Deflate compression: no
Supported cipher suites (ORDER IS NOT SIGNIFICANT):
TLSv1.2
RSA_WITH_AES_128_CBC_SHA
RSA_WITH_AES_256_CBC_SHA

Server certificate(s):
3c66369603213fd186ede4d2b320a21e0d577f7a: CN=www.foo.bar, OU=Domain Control Validated

Minimal encryption strength: strong encryption (96-bit or more)
Achievable encryption strength: strong encryption (96-bit or more)
BEAST status: protected
CRIME status: protected

The exception we get is this:

[MonoDroid] UNHANDLED EXCEPTION:
[MonoDroid] Javax.Net.Ssl.SSLHandshakeException: Exception of type 'Javax.Net.Ssl.SSLHandshakeException' was thrown.
[MonoDroid] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <IL 0x00011, 0x0004b>
[MonoDroid] at System.Runtime.CompilerServices.AsyncMethodBuilderCore.m__0 (object) <IL 0x00006, 0x0003b>
[MonoDroid] at Android.App.SyncContext/c__AnonStorey0.<>m__0 () [0x00000] in /Users/builder/data/lanes/1879/5f55a9ef/source/monodroid/src/Mono.Android/src/Android.App/SyncContext.cs:18
[MonoDroid] at Java.Lang.Thread/RunnableImplementor.Run () [0x0000b] in /Users/builder/data/lanes/1879/5f55a9ef/source/monodroid/src/Mono.Android/src/Java.Lang/Thread.cs:36
[MonoDroid] at Java.Lang.IRunnableInvoker.n_Run (intptr,intptr) [0x00009] in /Users/builder/data/lanes/1879/5f55a9ef/source/monodroid/src/Mono.Android/platforms/android-21/src/generated/Java.Lang.IRunnable.cs:71
[MonoDroid] at (wrapper dynamic-method) object.db6b7d7d-be63-41ee-8f1c-1c176a7678e5 (intptr,intptr) <IL 0x00011, 0x0001f>
[MonoDroid] --- End of managed exception stack trace ---
[MonoDroid] javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb9430130: Failure in SSL library, usually a protocol error
[MonoDroid] error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:741 0x97235990:0x00000000)
[MonoDroid] at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:448)
[MonoDroid] at com.squareup.okhttp.Connection.upgradeToTls(Connection.java:242)
[MonoDroid] at com.squareup.okhttp.Connection.connect(Connection.java:159)
[MonoDroid] at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:175)
[MonoDroid] at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:120)
[MonoDroid] at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:330)
[MonoDroid] at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:319)
[MonoDroid] at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:241)
[MonoDroid] at com.squareup.okhttp.Call.getResponse(Call.java:271)
[MonoDroid] at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:228)
[MonoDroid] at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:199)
[MonoDroid] at com.squareup.okhttp.Call.access$100(Call.java:34)
[MonoDroid] at com.squareup.okhttp.Call$AsyncCall.execute(Call.java:162)
[MonoDroid] at com.squareup.okhttp.internal.NamedRunnable.run(NamedRunnable.java:33)
[MonoDroid] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
[MonoDroid] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
[MonoDroid] at java.lang.Thread.run(Thread.java:841)
[MonoDroid] Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb9430130: Failure in SSL library, usually a protocol error
[MonoDroid] error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:741 0x97235990:0x00000000)
[MonoDroid] at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
[MonoDroid] at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)
[MonoDroid] ... 16 more

@adammeaney
Copy link

I know that in my own project, I encountered this same issue. What I discovered was that before Android Jelly Bean, they did not support TLS 1.1 and 1.2. This caused devices running before then not to be able to connect to my server that did not accept anything less.

In JB and KitKat, devices supported this, but it was not enabled by default. This leads to them not being able to connect either.

Lollipop changed to have support enabled by default, therefore those devices worked for me.

The fix employed by myself was to make a custom SSLSocketFactory that is used to supply the OkHttp client.

It then does

SSLSocket socket = (SSLSocket) _factory.CreateSocket(address, port, localAddress, localPort);
socket.SetEnabledProtocols(socket.GetSupportedProtocols());

For each CreateSocket method in there.

And in the NativeMessageHandler constructor, I added:

var factory = new ImprovedSSLSocketFactory();
client.SetSslSocketFactory(factory);

This allowed me to communicate with TLS 1.1 and 1.2.

I can post the code better if desired, but my git skills are not great for a pull request.

Source

@decraw
Copy link
Author

decraw commented Jul 29, 2015

Thanks adammeaney , I will try that and see if it works. I can probably put together a pull request for this code.

@PrintsCharming
Copy link

Adammeaney...can you provide a sample of that? Banging my newbie Android developer head against the wall over here.

I'm targeting API 19

@adammeaney
Copy link

This is a pretty lazy feeling implementation, but it works for me.

using Javax.Net.Ssl;

namespace ModernHttpClient
{
    internal class ImprovedSSLSocketFactory : SSLSocketFactory
    {
        SSLSocketFactory _factory = (SSLSocketFactory)Default;

        public override string[] GetDefaultCipherSuites()
        {
            return _factory.GetDefaultCipherSuites();
        }

        public override string[] GetSupportedCipherSuites()
        {
            return _factory.GetSupportedCipherSuites();
        }

        public override Java.Net.Socket CreateSocket(Java.Net.InetAddress address, int port, Java.Net.InetAddress localAddress, int localPort)
        {
            SSLSocket socket = (SSLSocket)_factory.CreateSocket(address, port, localAddress, localPort);
            socket.SetEnabledProtocols(socket.GetSupportedProtocols());

            return socket;
        }

        public override Java.Net.Socket CreateSocket(Java.Net.InetAddress host, int port)
        {
            SSLSocket socket = (SSLSocket)_factory.CreateSocket(host, port);
            socket.SetEnabledProtocols(socket.GetSupportedProtocols());

            return socket;
        }

        public override Java.Net.Socket CreateSocket(string host, int port, Java.Net.InetAddress localHost, int localPort)
        {
            SSLSocket socket = (SSLSocket)_factory.CreateSocket(host, port, localHost, localPort);
            socket.SetEnabledProtocols(socket.GetSupportedProtocols());

            return socket;
        }

        public override Java.Net.Socket CreateSocket(string host, int port)
        {
            SSLSocket socket = (SSLSocket)_factory.CreateSocket(host, port);
            socket.SetEnabledProtocols(socket.GetSupportedProtocols());

            return socket;
        }

        public override Java.Net.Socket CreateSocket(Java.Net.Socket s, string host, int port, bool autoClose)
        {
            SSLSocket socket = (SSLSocket)_factory.CreateSocket(s, host, port, autoClose);
            socket.SetEnabledProtocols(socket.GetSupportedProtocols());

            return socket;
        }

        protected override void Dispose(bool disposing)
        {
            _factory.Dispose();
            base.Dispose(disposing);
        }

        public override Java.Net.Socket CreateSocket()
        {
            SSLSocket socket = (SSLSocket)_factory.CreateSocket();
            socket.SetEnabledProtocols(socket.GetSupportedProtocols());

            return socket;
        }
    }
}

@PrintsCharming
Copy link

Thanks adammeaney I'll give it a spin

@jorgenstorlie
Copy link

Is it possible to do this without changing the NativeMessageHandler code?

@adammeaney
Copy link

Not that I was able to discover.

The problem was that the sockets normally created did not know they supported TLS 1.1 or 1.2 further back.

There may be another way to tell the device they should be supported. I have seen code using something called ServicePointManager when I was looking for this, but none of that code seemed to resolve my issues. This was the first things I discovered.

If we get lucky, @paulcbetts will patch something similar into ModernHttpClient eventually, so we can go back to just using his released package.

@jorgenstorlie
Copy link

I tried to use your code, but it does not work for me

here is the url that does not work:

"https://appgateway.contendo.no/tngwebinfo?params=%7B%22session_id%22%3A%220913184FBDEB4ECBA6D9E0DF3BCF6A8E%22%2C%22version%22%3A%222%22%7D"

Have you a change to check if it works for you?

@adammeaney
Copy link

I wrote this code before the changes were made to use the official OkHttp client in this repo.

With the official client, I do not seem to get the same results as before. I have not yet bothered to determine why, as I have it working for now and don't have the time to deal with http clients not working quite right.

@jorgenstorlie
Copy link

Is it someone that have a solution on this?

@jamespettigrew
Copy link

An official fix would be nice, but Adam's code appears to work for me with a fork of the repo as it stands today.

kunni80 pushed a commit to kunni80/ModernHttpClient that referenced this issue Apr 5, 2016
… Lollipop

Error when connecting from Android to a server that does not support
TLS 1.0
@adamfisher
Copy link

Can the commit to kunni80's forked repo please be reintegrated?

@walalm
Copy link

walalm commented Jul 27, 2016

I'm hoping this get merged soon.

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

8 participants