Using https connection for source image in Xamarin forms - xamarin

I'm developing an app using Xamarin Forms (4.5.0.356).
I have to show an image which come from an HTTPS links using the default bind:
<Image Source="{Binding PhotoURL}" />
At runtime I have the error:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:219)
at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:192)
at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:149)
at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:112)
at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:184)
at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:461)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127)
at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:89)
at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(Unknown Source:0)
I know the error is caused by a self signed certificate, and I usually manage this type of error with a HttpClientHandler like the following:
var handler = new HttpClientHandler()
{
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
{
//bypass
return true;
},
};
_httpClient = new HttpClient(handler) { BaseAddress = new Uri(Constants.HTTP_BASE_ADDRESS) };
But how can I do the Xamarin.Android.Net.AndroidClientHandler manages self-signed certificates when the bind mechanism assigns an https source to an image control?
Thanks

Related

connect to a server with a self-signed certificate

Ive been doing some research about how to consume a web api executed on my localhost throught a xamarin app. The web api works perfect, I can adding and getting the data to/from my sql server using a web browser but if I try to connect xamarin to it Ive always received authentication error (Mono.Btls.MonoBtlsException: Ssl error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED). Im basically doind this. I followed this post:
http://xamarininterviewquestion.blogspot.com/2019/06/ssl-certificate-and-public-key-pinning.html
So as it definitly didnt work, Id like to try another way;
Set TLSConfig DangerousAcceptAnyServerCertificateValidator to true. Because for know Im happy if Im able to test it.
Thats cool but as Im not a pro I have no idea about implement this;
var httpHandler = new HttpClientHandler();
// Return `true` to allow certificates that are untrusted/invalid
httpHandler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
Ive got "DangerousAcceptAnyServerCertificateValidator" doesnt have a definition.
Thank you all in advance and sorry if Ive not been clear.
DangerousAcceptAnyServerCertificateValidator isn't applicable to Xamarin platforms, according to its documentation.
But literally you can write the same code like,
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
HttpClient client = new HttpClient(handler);
https://stackoverflow.com/a/64741829/11182
if you are using Refit then you can do this
public HttpClient PreparedClient()
{
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => { return true; };
HttpClient client = new HttpClient(handler) { BaseAddress = new Uri(EndpointConstants.BaseUrl) };
return client;
}
private T RefitApi<T>() => RestService.For<T>(PreparedClient());
and if you need to specify settings you can do this
private T RefitApiWithToken<T>() => RestService.For<T>(PreparedClient(), refitSettings);
When using Refit for Xamarin forms
public HttpClient PreparedClient()
{
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => { return true; };
HttpClient client = new HttpClient(handler) { BaseAddress = new Uri(EndpointConstants.BaseUrl) };
return client;
}
var apiResponse = RestService.For<T>(PreparedClient());

Security token validation between Identity Server 4 and 3

I am trying to use a IdS4 server on .Net Core 2.0 with an IdS3 webforms client on .Net45.
As I login via the client I get this exception on the client browser.
[SecurityTokenSignatureKeyNotFoundException: IDX10500: Signature validation failed. Unable to resolve SecurityKeyIdentifier: 'SecurityKeyIdentifier
(
IsReadOnly = False,
Count = 2,
Clause[0] = X509ThumbprintKeyIdentifierClause(Hash = 0x6B7ACC520305BFDB4F7252DAEB2177CC091FAAE1),
Clause[1] = System.IdentityModel.Tokens.NamedKeySecurityKeyIdentifierClause
)
',
token: '{"alg":"RS256","kid":"6B7ACC520305BFDB4F7252DAEB2177CC091FAAE1","typ":"JWT",
"x5t":"a3rMUgMFv9tPclLa6yF3zAkfquE"}.{"nbf":1517303703,"exp":1517304003,
"iss":"http://localhost:5000","aud":"webforms","nonce":"636529004845229500.Mjg4YmMxMGEtZjk2MC00YWY5LWJiNTQtYmU0Njg0MDIwYTFhNzczN2Q1ZGMtN2YxYy00NGJmLWJhNzItNTM1ZDc0OTMyNzBj",
"iat":1517303703,"c_hash":"6Sty4gdTWGo4nEo0V_VSVQ","sid":"17936a127b0267d2588646052c4447c6",
"sub":"6498d093-8dc3-4d69-988e-3914d564f4d0","auth_time":1517303700,
"idp":"local","amr":["pwd"]}'.]
I first got this exception without Clause[0] and thought it was because the two samples I was using have different certificates embedded within them.
My attempt to fix this involved creating a new certificate following this guide.
In IdS4 Startup I have
services.AddIdentityServer()
.AddSigningCredential(GetSigningCredential())
and
private X509Certificate2 GetSigningCredential()
{
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var certs = store.Certificates.Find(X509FindType.FindBySerialNumber, "3506fe4f69dc22b340e9c2af500d4659", false);
store.Close();
return certs[0];
}
With the clients secret set to the X509 thumbprint.
This seems to be working. On the IdS3 client I cannot find a way to validate the security token, I assume this would be done by validating the certificate?
If anybody could help me understand my issue better that would be great, I cannot find any useful documentation or examples relating to my case so pretty much anything would be helpful.
Thanks in advance.
Turns out I was trying to validate in the wrong places. All i had to do was point to the certificate in the clients Startup.cs.
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Configuration = new OpenIdConnectConfiguration()
{
// Other Stuff...
SigningTokens = { new X509SecurityToken(GetX509Certificate2()) },
// More Stuff...
Where GetX509Certificate2() is:
private X509Certificate2 GetX509Certificate2()
{
var store = new X509Store(StoreName.TrustedPeople, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
return cert = store.Certificates.Find(X509FindType.FindByThumbprint, "**thumbprint**", false)[0];
}

Xamarin .Net Core HttpClientHandler Method Not Implemented(VS for Mac)

I am writing a .net core(Standard 1.6) library that connects to my WebAPI. The WebApi requires a client certificate.
The .net core library is something being called from a Xamarin iOS app.
I cannot for the life of me send an HTTP request with a Client Certificate header.
I can use the library and post to the API with a client certificate from Visual Studio 2017 on a windows machine.
When I move the same project into my Xamarin iOS app using VS for Mac I get:
"Method Not Implemented" when setting the SslProtocol or adding the client certificate:
var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.SslProtocols = SslProtocols.Tls12;
handler.ClientCertificates.Add(new X509Certificate2(certificate));
Relevant libraries:
using System.Net;
using System.Net.Http;
using System.Security;
using System.Security.Cryptography.X509Certificates;
Any help would be greatly appreciated.
Alright, this took me quite a while but i was able to send a client certificate in a web request to use for client auth on our server.
First, as awesome as Xamarin and .netCore are, they are missing alot of the methods .net developers are used to. I was not able to build a crossplatform request that would work on both Android and ios such as the HttpWebRequest.
For ios, i created a custom class that inherits from:NSUrlConnectionDataDelegate
I then override the:
public override void WillSendRequestForAuthenticationChallenge(NSUrlConnection
connection, NSUrlAuthenticationChallenge challenge)
{
byte[] cert = System.IO.File.ReadAllBytes("clientCertificate.pfx");
NSUrlCredential credential = iSecurity.ImportPK12File(cert, "certPassword");
challenge.Sender.UseCredential(credential, challenge);
}
I then created a class that returns the credential:
//cert is a byte array of a .pfx file included in the resource file
//iSecurity Custom class
NSUrlCredential credential = iSecurity.ImportPK12File(cert, "certpassword");
public static NSUrlCredential ImportPK12File(byte[] fileBytes, string passPhrase)
{
var cert = new X509Certificate2(fileBytes, passPhrase);
var options = NSDictionary.FromObjectAndKey(NSObject.FromObject(passPhrase), SecImportExport.Passphrase);
NSDictionary[] importStatus;
SecStatusCode statusCode = SecImportExport.ImportPkcs12(fileBytes, options, out importStatus);
if(statusCode != SecStatusCode.Success){
throw new Exception("Error importing certificate. ");
}
NSObject obj = importStatus[0]["trust"];
IntPtr secTrustRef = obj.Handle;
var identityHandle = importStatus[0][SecImportExport.Identity];
var identity = new SecIdentity(identityHandle.Handle);
var certificate = new SecCertificate(cert.GetRawCertData());
SecCertificate[] certificates = { certificate };
return NSUrlCredential.FromIdentityCertificatesPersistance(identity, certificates, NSUrlCredentialPersistence.ForSession);
}
You may also be able to override this method and send the creds:
public override void ReceivedAuthenticationChallenge(NSUrlConnection connection, NSUrlAuthenticationChallenge challenge)
{
base.ReceivedAuthenticationChallenge(connection, challenge);
}
And i may move it to there but in order to fire this off you create the delegate of your class that inherits from :NSUrlConnectionDataDelegate
and add this to your connection. Any request fired through this connection will override the method and pass the certificate.

Xamarin PCL self signed certificat for Android and IOS

I'm trying to pass my full Rest service from http to https.
I created a self-signed certificate, I had it to IIS Express. I validate it on google Chrome and it work perfectly fine with postman. My rest service work in http and https.
I use a PCL project (IOS and Android) everything is working fine with http request but I have exception with https request. the exception message is null.
I tried to create a test certificate directly from Visual Studio 2015 but the button is disabled in properties ->Signing.
I also tried to install my self-signed certificate as a Trusted Root but no success for the communication between my simulator and my rest Service.
my code
public partial class MainPage : ContentPage
{
private string url = string.Empty;
private HttpClient _client;
public MainPage()
{
InitializeComponent();
switch (Device.RuntimePlatform)
{
case Device.iOS:
_client = new HttpClient(new NSUrlSessionHandler());
break;
case Device.Android:
_client = new HttpClient();
break;
}
_client = new HttpClient();
test();
}
private async void test()
{
//url = "http://192.168.1.106:9630/PrototypeB.svc/Test";
url = "https://192.168.1.106:44301/PrototypeB.svc/Test";
try
{
var _content = await _client.GetStringAsync(url);
List<Test> _posts = JsonConvert.DeserializeObject<List<Test>>(_content);
}
catch (HttpRequestException e)
{
string test = e.Message;
}
catch (Exception e)
{
string test = e.Message;
}
}
}
How can I communicate with my Android and IOS Simulator with https and self-signed certificate?
You can use ServicePointManager to ignore the certificate validation check.
Execute the code in your iOS and Android platforms like this:
System.Net.ServicePointManager.ServerCertificateValidationCallback += (se, cert, chain, sslerror) => {
return true;
};
References:
Untrusted HTTPS
certificate
HTTPS ignore
certificate
Ignore SSL certificate errors in Xamarin.Forms (PCL)
SSL Validation in
PCL
Also, ModernHttpClient Pro provide this feature, but it is not free.

How to setup selfhosted https WCF service with embedded certificates on client and server?

Im creating a simple WCF service for receiving crash reports.
The service will run self-hosted as a console program and must run without any installation of certificates.
Security-wise i need to ensure that the data send by the client is only send to our server and that the data is not intercepted. From the server point of view i would also like to ensure that the connecting client is using a specific certificate (embedded in the client assembly) to discourage abuse of the service.
I have created a single self-signed certificate and plan to embed the .cer (containing the public part of the certificate) in the client assembly and embed the PFX containing the certificate with the private key into the service host program assembly. (I was led to believe by this that i could use a single certificate).
My problem is that no matter how is setup this up i get the following error:
"An error occurred while making the HTTP request to https://localhost:8080/errorservice. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server."
There shouldnt be a mismatch between the bindings, as they are created using the same code:
public static BasicHttpBinding CreateStreamingBinding() {
BasicHttpBinding streamBinding = new BasicHttpBinding();
streamBinding.TransferMode = TransferMode.StreamedRequest;
streamBinding.MaxReceivedMessageSize = long.MaxValue;
streamBinding.Security = new BasicHttpSecurity
{
Transport = new HttpTransportSecurity
{
ClientCredentialType = HttpClientCredentialType.None,
ProxyCredentialType =HttpProxyCredentialType.None
},
Mode = BasicHttpSecurityMode.Transport,
};
streamBinding.MaxBufferSize = int.MaxValue;
streamBinding.MessageEncoding = WSMessageEncoding.Mtom;
streamBinding.SendTimeout = new TimeSpan( 1, 0, 0, 0, 0 );
streamBinding.ReceiveTimeout = new TimeSpan( 1, 0, 0, 0, 0 );
return streamBinding;
}
On the client the code to create service is setup like this (the certificate location is just for testing):
protected ErrorReportingServiceClient CreateClient() {
X509Certificate2 cert = new X509Certificate2( #"C:\certs\reporting.cer" );
EndpointAddress endpointAddress = new EndpointAddress( new Uri( ReportingServiceUri ));
ErrorReportingServiceClient client = new ErrorReportingServiceClient( CreateStreamingBinding(), endpointAddress );
client.ClientCredentials.ServiceCertificate.DefaultCertificate = cert;
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
client.ClientCredentials.ClientCertificate.Certificate = cert;
return client;
}
On the service side the setup is as follows:
X509Certificate2 cert = new X509Certificate2( #"C:\certs\reporting.pfx", <password>);
BasicHttpBinding basicHttpBinding = CreateStreamingBinding();
host.Credentials.ClientCertificate.Certificate = cert;
host.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
host.Credentials.ServiceCertificate.Certificate = cert;
host.AddServiceEndpoint( contractType, basicHttpBinding, baseAddress );
Any help on how to setup this correctly would be greatly appreciated.
The question was answered on the MSDN forums:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/14f44296-5e3d-4df5-8cc4-a185415852b7

Resources