I am writing an application that needs to read from a REST api that is only available over https. I am running into the issue where the request fails in Mono.Security, with the message: "The authentication or decryption has failed."
I did my research and found that Mono by default doesn't have any trusted certificates. All the sources I found said that I could use
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });
within the Main() and OnCreate() methods in the iOS and Droid projects respectively to override that check and allow any ssl cert. Even with that workaround, I'm still getting the same error. I have stepped through the code and confirmed that the above line is executed when running on iOS and Android.
My code works perfectly when accessing non-https APIs. This is a PCL, not shared, project.
I referred to these questions/resources before asking:
- Ignore SSL certificate errors in Xamarin.Forms (PCL)
- stackoverflow.com/questions/2675133/c-sharp-ignore-certificate-errors/2675183#2675183
- bugzilla.xamarin.com/show_bug.cgi?id=6501
- stackoverflow.com/questions/12287528/webclient-ssl-exception-with-android-4-and-mono-for-android
- www.mono-project.com/docs/faq/security/
Here is the code so far:
public class PawPrintsDataConnection
{
private string response = "";
private Task<string> StartWebRequest(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "GET";
Task<WebResponse> task = Task.Factory.FromAsync (request.BeginGetResponse, asyncResult => request.EndGetResponse (asyncResult), (object)null);
return task.ContinueWith (t => ReadStreamFromResponse (t.Result));
}
private string ReadStreamFromResponse(WebResponse response)
{
using (Stream responseStream = response.GetResponseStream ())
using (StreamReader sr = new StreamReader (responseStream)) {
string strContent = sr.ReadToEnd ();
return strContent;
}
}
public string getRawResponse(){
var task = StartWebRequest(string.Format (@"https://pawprints.rit.edu/v1/petitions?key={0}&limit={1}", "apikey", 50));
this.response = task.Result;
return response;
}
}
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
protected override void OnCreate (Bundle bundle)
{
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });
base.OnCreate (bundle);
global::Xamarin.Forms.Forms.Init (this, bundle);
LoadApplication (new App ());
}
}
static void Main (string[] args)
{
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main (args, null, "AppDelegate");
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
}
In my research, I discovered a bug on the Xamarin bugzilla that may be relevant, but I'm not sure that it applies to the version I'm using. I'm very new to Xamarin dev, so I'm not familiar with things like which version of Mono.security is included. https://bugzilla.xamarin.com/show_bug.cgi?id=26658
If it's helpful, here is the relevant portion of the exception:
System.AggregateException: One or more errors occurred ---> System.Exception: One or more errors occurred ---> System.Exception: Error: SendFailure (Error writing headers) ---> System.Exception: Error writing headers ---> System.Exception: The authentication or decryption has failed. ---> System.Exception: The authentication or decryption has failed.
at Mono.Security.Protocol.Tls.RecordProtocol.ProcessAlert (AlertLevel alertLevel, AlertDescription alertDesc) [0x00013] in ///Library/Frameworks/Xamarin.iOS.framework/Versions/8.6.1.26/src/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:654
at Mono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback (IAsyncResult asyncResult) [0x000dc] in ///Library/Frameworks/Xamarin.iOS.framework/Versions/8.6.1.26/src/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:377