8

I'm trying to access my RESTful API to retrieve data from a MySQL database. Everything is set up and works perfectly on my C# WPF project. But when using the exact same code in Xamarin Forms (built for Android) I cannot get a successful SSL handshake with my server.

Server details

  • Let's Encrypt SSL certificate (definitely valid)
  • Apache BasicAuth (.htaccess)
  • HTTPS only (Rewrite HTTP on), so port 443
  • REST API: php-crud-api (by mevdschee) to access MariaDB 10.3

I'm using Flurl.Http (uses HttpClient) to establish the connection, but get an exception on jsonReader.Wait():

var jsonReader = "https://example.com/my_api/api.php/records/my_table?order=id,desc&size=10"
            .WithHeader("Accept", "application/json")
            .WithBasicAuth("username", "password")
            .GetJsonAsync<JsonRootObject>();
            // Wait for completion.
            jsonReader.Wait();


This is my AggregateException:

System.AggregateException: One or more errors occurred. (Call failed. An error occurred while sending the request
GET https://example.com/my_api/api.php/records/my_table?order=id,desc&size=10) ---> Flurl.Http.FlurlHttpException: Call failed. An error occurred while sending the request
GET https://example.com/my_api/api.php/records/my_table?order=id,desc&size=10 ---> System.Net.Http.HttpRequestException: An error occurred while sending the request
---> System.Net.WebException: Error: TrustFailure (Authentication failed, see inner exception.) ---> System.Security.Authentication.AuthenticationException:
Authentication failed, see inner exception. ---> Mono.Btls.MonoBtlsException: Ssl error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED
at /Users/builder/jenkins/workspace/xamarin-android-d16-1/xamarin-android/external/mono/external/boringssl/ssl/handshake_client.c:1132
at Mono.Btls.MonoBtlsContext.ProcessHandshake () [0x00038] in <74989b9daab94528ac2c4b7da235b9c5>:0 
at Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake (Mono.Net.Security.AsyncOperationStatus status, System.Boolean renegotiate) [0x000a1] in <74989b9daab94528ac2c4b7da235b9c5>:0 
at (wrapper remoting-invoke-with-check) Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake(Mono.Net.Security.AsyncOperationStatus,bool)
at Mono.Net.Security.AsyncHandshakeRequest.Run (Mono.Net.Security.AsyncOperationStatus status) [0x00006] in <74989b9daab94528ac2c4b7da235b9c5>:0
at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation (System.Threading.CancellationToken cancellationToken) [0x000ff] in <74989b9daab94528ac2c4b7da235b9c5>:0
at Mono.Net.Security.AsyncProtocolRequest.StartOperation (System.Threading.CancellationToken cancellationToken) [0x0008b] in <74989b9daab94528ac2c4b7da235b9c5>:0 


What I've tried / what I know

  • Code works perfectly in WPF
  • Exact same code (copy-paste) does not work in Xamarin Forms (tested on Android Pie)
  • does not work in emulator nor dedicated device
  • accessing the REST API via browser works and delivers results as expected (tested on my PC, the emulator in Chrome and my dedicated Android)
  • changing the HttpClient implementation or SSL/TLS implementation under Project properties -> Android Options -> Advanced does not help

Why is my SSL handshake failing? What is Xamarin doing differently than WPF?

MadWalnut
  • 111
  • 1
  • 7
  • Seems you are using a self-signed certificate, try one signed by an authority. – Kate Orlova Jun 17 '19 at 22:21
  • @KateOrlova No, I am using a Let's Encrypt certificate. The certificate is trusted by all my browsers (also on Android), as well as when running the code in WPF. – MadWalnut Jun 17 '19 at 22:30
  • I'm not familiar with Flurl.Http but I will offer a suggestion for you: set the TLS level explicitly to 1.2 or 1.3. I have seen odd behavior when left to the framework and OS to decide, that odd behavior can disappear when you explicitly define the TLS level. – slugster Jun 17 '19 at 23:56
  • @slugster No luck unfortunately, same error. – MadWalnut Jun 18 '19 at 17:50
  • Had same problem due to miss configured nginx until just used certbot and all went fine – Nick Kovalsky Mar 01 '20 at 13:30
  • Might help: https://stackoverflow.com/a/70583868/7149454 – Nick Kovalsky Jan 10 '22 at 07:29

2 Answers2

3

It turned out to be an Apache configuration error. I checked my domain and noticed an error. This was fixed by adding the certificate's chain-file in my Apache Directives:

SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

The last line was the missing one. Weird that browsers and WPF trusted the certificate even without the chain-file. Anyway, now it also works on Android.

In the meantime I've been using this piece of code to disable the SSL validation in my app:

// This disables the SSL certificate validity check.
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

That code is unsafe and should only be used for testing.

MadWalnut
  • 111
  • 1
  • 7
0

your Flurl.Http can fail due to the usage of 2 different project types (.net standard vs class library - I had exactly the same problem with http client I wrote)

try a different http client for .net standard.

in any case, you can write your own http client and debug - that is my recommendation.
if you still stuck - write back I'll help.

Ami Vaknin
  • 194
  • 6
  • I tried using a WebClient to download the JSON. But this also throws "System.Net.WebException: Error: TrustFailure". Of course only in Xamarin - in my WPF project (not in same solution) it works. There must be something Xamarin or Android specific I'm missing. How would you write an own HTTP Client for testing purposes? – MadWalnut Jun 18 '19 at 17:54
  • In my case, I had to write HttpClient wrapper to avoid the problems I encountered. – Ami Vaknin Aug 07 '19 at 07:59