Xamarin AndroidClientHandler发送客户端证书

时间:2018-11-29 20:28:13

标签: android ssl xamarin httpclient client-certificates

我想我可能在这里遗漏了一些东西,但是如何将客户端证书发送到需要客户端证书的SSL站点。

我正在使用HttpClient并传递一个AndroidClientHandler

有许多提供代码的答案,但没有告诉我为什么代码可以工作或何时调用。我已经花了一个多星期了。

有人能提供一个简单的代码示例以及为什么要这样做的简单解释。

我正在使用自签名证书。我设法忽略了任何证书验证,并且在配置为不需要客户端证书时可以调用SSL站点。

但是现在我需要知道如何通过客户端证书。

我看过许多文章和解决方案,但看不到客户证书在哪里传递。

任何帮助将不胜感激。谢谢

1 个答案:

答案 0 :(得分:0)

我见过的Xamarin示例忽略了将IPrivateKey添加到用于填充KeyManagerFactory的KeyStore中

/// <summary>
/// Represents a Java X509Certificate with private key
/// </summary>
public class CertificateDetails
{
    public CertificateDetails(IPrivateKey privateKey, X509Certificate[] chain)
    {
        PrivateKey = privateKey;
        Chain = chain;
    }

    /// <summary>
    /// Gets the private key
    /// </summary>
    public IPrivateKey PrivateKey { get; }

    /// <summary>
    /// Gets certificate chain
    /// </summary>
    public IReadOnlyCollection<X509Certificate> Chain { get; }
}


/// <summary>
/// HttpClientHandler based on native Android  <see cref="Java.Net.HttpURLConnection"/> that uses a client certificate
/// </summary>
public class AuthAndroidClientHander : AndroidClientHandler
{
    readonly CertificateDetails _certificateDetails;

    public AuthAndroidClientHander(CertificateDetails certificateDetails)
    {
        if (certificateDetails is null)
        {
            throw new ArgumentNullException(nameof(certificateDetails));
        }
        _certificateDetails = certificateDetails;

        //get root certs
        var trustManagerFactory = TrustManagerFactory.GetInstance(TrustManagerFactory.DefaultAlgorithm);
        trustManagerFactory.Init((KeyStore)null);
        var x509trustManager = trustManagerFactory.GetTrustManagers().OfType<IX509TrustManager>().First();
        var acceptedIssuers = x509trustManager.GetAcceptedIssuers();

        //trust both default issuers and chain of client certifiate
        TrustedCerts = _certificateDetails.Chain.Concat(acceptedIssuers).ToList<Certificate>();
    }

    /// <summary>
    /// Configure keyStore passed into <see cref="AndroidClientHandler.ConfigureKeyManagerFactory"/> and <see cref="AndroidClientHandler.ConfigureTrustManagerFactory"/>
    /// </summary>
    /// <param name="keyStore"></param>
    /// <returns></returns>
    protected override KeyStore ConfigureKeyStore(KeyStore keyStore)
    {
        // replace keyStore generated by base class with a PKCS12 instead of the default KeyStore.DefaultType
        keyStore = KeyStore.GetInstance("PKCS12");

        //replicate base's SetupSSL() behavior of adding all TrustedCerts to keystore in  
        keyStore.Load(null, null);

        if (TrustedCerts?.Any() == true)
        {

            for (var i = 0; i < TrustedCerts.Count; i++)
            {

                Certificate cert = TrustedCerts[i];
                if (cert == null)
                {
                    continue;
                }
                keyStore.SetCertificateEntry($"ca{i}", cert);

            }

        }

        //add private key to keystore
        keyStore.SetKeyEntry("privateKey", _certificateDetails.PrivateKey, null, _certificateDetails.Chain.ToArray());

        return keyStore;
    }

    protected override KeyManagerFactory ConfigureKeyManagerFactory(KeyStore keyStore)
    {
        var kmf = KeyManagerFactory.GetInstance("x509");
        kmf.Init(keyStore, null);
        return kmf;
    }

    protected override TrustManagerFactory ConfigureTrustManagerFactory(KeyStore keyStore)
    {
        var tmf = TrustManagerFactory.GetInstance(TrustManagerFactory.DefaultAlgorithm);
        tmf.Init(keyStore);
        return tmf;
    }
}