xamarin.android添加客户端证书

时间:2018-02-23 16:06:58

标签: android xamarin

我试图向Xamarin.Android中的网络API发送请求。 api需要客户端证书。我遵循了这个问题中的建议:xamarin.ios httpclient clientcertificate not working with https,但我得到了一个未实现的方法"例外。有人可以帮忙吗?

这是我的代码:

    string result = await CallApi(new System.Uri("myurl"));

    protected async Task<string> CallApi(Uri url)
    {
        try
        {
            AndroidClientHandler clientHandler = new AndroidClientHandler();
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Ssl3;

            using (var mmstream = new MemoryStream())
            {
                Application.Context.Assets.Open("mycert.pfx").CopyTo(mmstream);
                byte[] b = mmstream.ToArray();

                X509Certificate2 cert = new X509Certificate2(b, "password", X509KeyStorageFlags.DefaultKeySet);
                clientHandler.ClientCertificates.Add(cert);
            }

            ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });

            HttpClient client = new HttpClient(clientHandler);
            HttpResponseMessage response = await client.GetAsync(url);
            response.EnsureSuccessStatusCode();

            string responseBody = await response.Content.ReadAsStringAsync();
            Console.WriteLine(responseBody);
            return responseBody;
        }
        catch (HttpRequestException e)
        {
            Console.WriteLine("\nException Caught!");
            return string.Empty;
        }
    }

1 个答案:

答案 0 :(得分:3)

在您提到的帖子中,可能使用了托管处理程序。由于此处理程序当前不支持TLS 1.2,因此您不应使用它,而应使用AndroidClientHandler(另请参见Xamarin and TLS 1.2)。 不幸的是ClientCertificates确实没有在AndroidClientHandler中实现。

如果您想在Android上使用客户端证书,则可以扩展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;
    }
}