【问题标题】:Xamarin AndroidClientHandler sending client certificateXamarin AndroidClientHandler 发送客户端证书
【发布时间】:2018-11-29 20:28:13
【问题描述】:

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

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

有很多答案提供了代码,但没有告诉我为什么代码有效或何时应该调用它。我已经花了一个多星期的时间。

谁能提供一个简单的代码示例并简单解释一下为什么要这样做。

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

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

我查看了很多文章和解决方案,但我没有看到客户端证书在哪里通过。

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

【问题讨论】:

  • 也许可以试试这个博客中的内容:dotnetdevaddict.co.za/2015/07/31/…。通常建议不要使用自签名证书,因为 CA 颁发的官方证书很便宜或免费。自签名证书使事情变得复杂。
  • 看这个它提到了一个自签名证书。他们是在谈论 Web 应用程序上的 SSL 证书,还是在谈论客户端证书?同样在文章中并不清楚为什么我需要这样做,我想了解这些原则,而不仅仅是将代码复制到我的应用程序中。不幸的是,目前我只有自签名证书,所以我陷入了困境。
  • 我得出的结论是,您不能使用 Xamarin HttpClient 和 AndroidClientHandler 在 HTTPS 请求中发送客户端证书。谁能确认一下?
  • 我可以确认,如果您使用 AndroidClientHandler,则永远不会调用 System.Net.ServicePointManager.ServerCertificateValidationCallback。如果您需要设置和使用该回调,则必须使用托管的 HttpClient 处理程序。
  • 嗨@jgoldberger 不太清楚你的意思。这与使用 Xamarin HttpClient 和 AndroidClientHandler 在 HTTPS 请求中发送客户端证书有何关系

标签: android ssl xamarin httpclient client-certificates


【解决方案1】:

我见过的 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;
    }
}

【讨论】:

  • 这对我很有用。我还能够从用户凭据密钥库添加客户端证书。
猜你喜欢
  • 2013-06-06
  • 1970-01-01
  • 2018-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-07
  • 2012-03-28
  • 2018-09-05
相关资源
最近更新 更多