Forum Xamarin.Forms
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

How to do SSL certificate pinning in Xamarin forms?

VIVEKNEGIVIVEKNEGI USMember ✭✭✭

Hi all, I want to implement SSL certificate pinning with server using xamarin forms. Could any one please share me the code

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai
  • Viplav04Viplav04 Member ✭✭

    Hi

    Refering to https://thomasbandt.com/certificate-and-public-key-pinning-with-xamarin

    and using AndroidHttpsClientHandler in Plan B, how to call the new handler in the pcl project??

  • HaiNguyen.6340HaiNguyen.6340 USMember ✭✭
    edited October 7

    @Viplav04 said:
    Hi

    Refering to https://thomasbandt.com/certificate-and-public-key-pinning-with-xamarin

    and using AndroidHttpsClientHandler in Plan B, how to call the new handler in the pcl project??

    Hi guy !
    Is this still working currently? I tried but no luck, a side that ModernHttpClient is not kept up today, last version is 2015. I have been stuck with this same issue on Xamarin Forms/Android last few days. I have been able to resolve this issue. It is so frustrating. Very appreciate your help.

  • Viplav04Viplav04 Member ✭✭

    @HaiNguyen.6340

    Hi, this problem went away from me. I simply use the normal HttpClient.

    if DEBUG

      client = new HttpClient(DependencyService.Get<IHttpClientHandlerService>().GetInsecureHandler());
    

    else

      client = new HttpClient();
    

    endif

    You can create an insecure handler in the Android and IOS project for debugging.

    In Release mode, you only need a SSL certificate at the server.

  • HaiNguyen.6340HaiNguyen.6340 USMember ✭✭
    edited October 8

    @Viplav04 - Thanks for your response.
    1) So am I correct to say....unless I deploy using DEBUG build, RELEASE works just fine by using just this?

    var client = new HttpClient();

    In my case, I never work with either DEBUG or RELEASE. Would you mind sharing your HttpClientHandlerService & IHttpClientHandlerService classes?

    2) Do you see this implementation being an issue with API server runs on TLS1.2 (TLS 1.0 disabled)

    3) Below is my implementation using Thomas Bandt Plan B, What am I missing?

    in portable project I added IHttpClientHandlerService.cs

     using System.Net.Http; 
    namespace Apps.Models
    { 
        public interface IHttpClientHandlerService
        {
            HttpClientHandler GetInsecureHandler();
        } 
    }
    
    

    in android project I added this HttpClientHandlerService.cs, notice I replaced my certificate file name

    using System.IO;
    using System.Net.Http;
    using Java.Security;
    using Java.Security.Cert;
    using Javax.Net.Ssl;
    using Xamarin.Android.Net;
    using Xamarin.Forms;
    using Apps.Droid;
    using Apps.Models;
    
    [assembly: Dependency(typeof(HttpClientHandlerService))]
    namespace ETC.CrudeTransport.Apps.OrderUp.Droid
    {
    
        //Hai Nguyen added
        public class HttpClientHandlerService : IHttpClientHandlerService
        {
            public HttpClientHandler GetInsecureHandler()
            {
                return new DroidTlsClientHandler();
            }
        }
    
        //exact code from Thomas Bandt @https://thomasbandt.com/certificate-and-public-key-pinning-with-xamarin
        internal class DroidTlsClientHandler : AndroidClientHandler
        {
            private TrustManagerFactory _trustManagerFactory;
            private KeyManagerFactory _keyManagerFactory;
            private KeyStore _keyStore;
    
            protected override TrustManagerFactory ConfigureTrustManagerFactory(KeyStore keyStore)
            {
                if (_trustManagerFactory != null)
                {
                    return _trustManagerFactory;
                }
    
                _trustManagerFactory = TrustManagerFactory
                    .GetInstance(TrustManagerFactory.DefaultAlgorithm);
    
                _trustManagerFactory.Init(keyStore);
    
                return _trustManagerFactory;
            }
    
            protected override KeyManagerFactory ConfigureKeyManagerFactory(KeyStore keyStore)
            {
                if (_keyManagerFactory != null)
                {
                    return _keyManagerFactory;
                }
    
                _keyManagerFactory = KeyManagerFactory
                    .GetInstance(KeyManagerFactory.DefaultAlgorithm);
    
                _keyManagerFactory.Init(keyStore, null);
    
                return _keyManagerFactory;
            }
    
            protected override KeyStore ConfigureKeyStore(KeyStore keyStore)
            {
                if (_keyStore != null)
                {
                    return _keyStore;
                }
    
                _keyStore = KeyStore.GetInstance(KeyStore.DefaultType);
                _keyStore.Load(null, null);
    
                CertificateFactory cff = CertificateFactory.GetInstance("X.509");
                Certificate cert;
    
                // Add your Certificate to the Assets folder and address it here by its name
                using (Stream certStream = Android.App.Application.Context.Assets.Open("HaiNguyenCert.crt"))
                {
                    cert = cff.GenerateCertificate(certStream);
                }
    
                _keyStore.SetCertificateEntry("TrustedCert", cert);
    
                return _keyStore;
            }
        } 
    }
    

    in portable project App.cs I added call API as follow

    switch (Device.RuntimePlatform)
                    {
                        case Device.Android:
                            client = new HttpClient(DependencyService.Get<IHttpClientHandlerService>().GetInsecureHandler());
                            break;
                        default:
                            System.Net.ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
                            client = new HttpClient(new HttpClientHandler());
                            break;
                    }
                    var response = await client.PostAsync(uri, new StringContent(payload, Encoding.UTF8, \"application/json\"));
                    if (response.IsSuccessStatusCode)
                    {
                        var data = await response.Content.ReadAsStringAsync();
                        if (App.IsValidJson(data)) 
                            token = JsonConvert.DeserializeObject<TokenData>(data);  
                    }
    

    Then I added HaiNguyenCert.crt to Assets directory. Right-click on that file->properties and set Build Action=AndroidAsset (It took me sometimes to realize this)

    Thank you for all the helps!

  • Viplav04Viplav04 Member ✭✭

    @HaiNguyen.6340

    The Question is why do you want to test for one single certificate? You will have to always update your app and server together when there is a change in certificate.

    In debug mode I use this :

    public class HttpClientHandlerService : IHttpClientHandlerService
      {
        public HttpClientHandler GetInsecureHandler()
        {
          HttpClientHandler handler = new HttpClientHandler();
          handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
          {
           // if (cert.Issuer.Equals("CN=localhost"))
              return true;
           // return errors == System.Net.Security.SslPolicyErrors.None;
          };
          return handler;
        }
      }
    

    In release :
    new HttpClient(); works for me. I already released an app with this. Your server should have a certificate.

  • HaiNguyen.6340HaiNguyen.6340 USMember ✭✭

    @Viplav04
    Good question! I don't know exactly why I need this. I chased down this rabit hole because my Android app failed to make call to my https API server same app works fine on iOS devices, so I am trying everything I can get my hand on. ;-(

  • HaiNguyen.6340HaiNguyen.6340 USMember ✭✭

    Goodness. Issue has been identified. it has nothing to do with any this. It was the dame my company's wifi access point. I lost so many days and energy on this. I really want to FOL

Sign In or Register to comment.