xamarin.android adding client certificate

前端 未结 2 818
醉梦人生
醉梦人生 2021-01-07 10:12

I\'m trying to send a request to a web api in Xamarin.Android. The api requires a client certificate. I followed the advice in this question: xamarin.ios httpclient clientce

相关标签:
2条回答
  • 2021-01-07 10:38

    In the post you mentioned probably the managed handler is used. Since this handler currently doesn't support TLS 1.2 you shouldn't use it, but instead really use the AndroidClientHandler (see also Xamarin and TLS 1.2). Unfortunately ClientCertificates is indeed not implemented in AndroidClientHandler.

    If you want to use client certificate with android you can extend the AndroidClientHandler:

    using Java.Security;
    using Java.Security.Cert;
    using Javax.Net.Ssl;
    using Xamarin.Android.Net; 
    using Xamarin.Forms;
    
    public class AndroidHttpsClientHandler : AndroidClientHandler
    {
        private SSLContext sslContext;
    
        public AndroidHttpsClientHandler(byte[] customCA, byte[] keystoreRaw) : base()
        {
            IKeyManager[] keyManagers = null;
            ITrustManager[] trustManagers = null;
    
            // client certificate
            if (keystoreRaw != null)
            {
                using (MemoryStream memoryStream = new MemoryStream(keystoreRaw))
                {
                    KeyStore keyStore = KeyStore.GetInstance("pkcs12");
                    keyStore.Load(memoryStream, clientCertPassword.ToCharArray());
                    KeyManagerFactory kmf = KeyManagerFactory.GetInstance("x509");
                    kmf.Init(keyStore, clientCertPassword.ToCharArray());
                    keyManagers = kmf.GetKeyManagers();
                }
            }
    
            // custom truststore if you have your own ca
            if (customCA != null)
            {
                CertificateFactory certFactory = CertificateFactory.GetInstance("X.509");
    
                using (MemoryStream memoryStream = new MemoryStream(customCA))
                {
                    KeyStore keyStore = KeyStore.GetInstance("pkcs12");
                    keyStore.Load(null, null);
                    keyStore.SetCertificateEntry("MyCA", certFactory.GenerateCertificate(memoryStream));
                    TrustManagerFactory tmf = TrustManagerFactory.GetInstance("x509");
                    tmf.Init(keyStore);
                    trustManagers = tmf.GetTrustManagers();
                }
            }
            sslContext = SSLContext.GetInstance("TLS");
            sslContext.Init(keyManagers, trustManagers, null);
        }
    
        protected override SSLSocketFactory ConfigureCustomSSLSocketFactory(HttpsURLConnection connection)
        {
            SSLSocketFactory socketFactory = sslContext.SocketFactory;
            if (connection != null)
            {
                connection.SSLSocketFactory = socketFactory;
            }
            return socketFactory;
        }
    }
    
    0 讨论(0)
  • 2021-01-07 10:47

    If you refer to AndroidClientHandler Source Code, you can find following statement:

    AndroidClientHandler also supports requests to servers with "invalid" (e.g. self-signed) SSL certificates. Since this process is a bit convoluted using the Java APIs, AndroidClientHandler defines two ways to handle the situation. First, easier, is to store the necessary certificates (either CA or server certificates) in the collection or, after deriving a custom class from AndroidClientHandler, by overriding one or more methods provided for this purpose(, and ). The former method should be sufficient for most use cases...

    So, for usage of AndroidClientHandler you should use clientHandler.TrustedCerts together with Java.Security.Cert.X509Certificate:

    Java.Security.Cert.X509Certificate cert = null;
    try
    {
        CertificateFactory factory = CertificateFactory.GetInstance("X.509");
        using (var stream = Application.Context.Assets.Open("MyCert.pfx"))
        {
             cert = (Java.Security.Cert.X509Certificate)factory.GenerateCertificate(stream);
        }
        } catch (Exception e)
        {
             System.Console.WriteLine(e.Message);
        }
        if (clientHandler.TrustedCerts != null)
        {
             clientHandler.TrustedCerts.Add(cert);
        }
        else
        {
             clientHandler.TrustedCerts = new List<Certificate>();
             clientHandler.TrustedCerts.Add(cert);
        }
    

    Notes: don't use Application.Context.Assets.Open("ca.pfx").CopyTo(mmstream); otherwise you will get inputstream is empty exception.

    0 讨论(0)
提交回复
热议问题