Xamarin Android:具有自定义证书颁发机构证书验证的本机TLS,ClientWebSocket失败

时间:2018-08-22 12:43:29

标签: xamarin xamarin.android tls1.2 client-certificates x509certificate2

客户端环境是Xamarin Android本机TLS 1.2 SSL / TLS实现(boringssl,又名btls),使用System.Net.WebSockets.ClientWebSocket。这是在Android 7.0设备上运行。 Visual Studio 2017 15.8.1,Xamarin.Android 9.0.0.18。

服务器环境是运行Fleck(WebSocket服务器)的Windows .NET 4.7,其使用由自制的证书颁发机构(CA)颁发的证书(配置为TLS 1.2)配置为TLS 1.2。

假设已通过“设置”->“安全性”->“从SD卡安装”在Android设备上安装了自制CA Cert(.pem或.cer格式),则ClientWebSocket可以使用TLS 1.2正常连接,就像人们期望的那样。由于这是针对本地(我的应用程序的一部分)问题的全局解决方案,更不用说为更大的设备生态系统打开安全漏洞了,我不希望此设置。

然后,我尝试了几种方法来将CA的信任仅限于我的应用程序,但是没有成功。无论采用哪种方法,ClientWebSocket.ConnectAsync()始终会抛出相同的异常:A call to SSPI failedSsl error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED at /Users/builder/jenkins/workspace/xamarin-android-d15-8/xamarin-android/external/mono/external/boringssl/ssl/handshake_client.c:1132

我创建了一个sample windows server and console app and Xamarin.Forms Android app,用于说明此问题以及下面介绍的解决方法。包括自定义CA证书。服务器代码会动态发布带有绑定到您的IP /主机名的SAN的客户端证书,以便于复制。

尝试1:

Apply the android:networkSecurityConfig="@xml/network_security_config" attribute to the application element in the AndroidManifest.xml file,包括资源Resources\raw\sample_ca.pem Resources\xml\network_security_config.xml

<?xml version="1.0" encoding="utf-8" ?>
<network-security-config>
  <base-config>
    <trust-anchors>
      <certificates src="@raw/sample_ca"/>
      <certificates src="system"/>
      <certificates src="user"/>
    </trust-anchors>
  </base-config>
</network-security-config>

这没有明显的效果,我在调试输出中看不到任何表明运行时甚至正在加载它的内容。我看到referencesmessages像这样:

D/NetworkSecurityConfig: No Network Security Config specified, using platform default

但是,无论有没有此设置,我都从未见过类似或类似的消息。我真的不知道它是否被应用,或者btls实现甚至使用/尊重它。

有趣的是,由于Android minSdk设置为24,目标sdk为27,我希望缺少此声明会导致TLS 1.2无法正常工作,如果我只是将CA添加到android设备中用户证书存储。我怀疑周围有一些Xamarin错误。

尝试2:

将CA添加到X509存储,希望btls将其用作证书的来源。这种方法在Windows / .NET 4上有效(确实会弹出一个对话框,以接受证书的添加)。

        X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
        store.Open(OpenFlags.ReadWrite);
        var certs = store.Certificates.Find(X509FindType.FindByThumbprint, cert.Thumbprint, false);
        if (certs.Count == 0)
            store.Add(cert);
        store.Close();

尝试3:

处理ServerCertificateValidationCallback。在Xamarin Android中永远不会调用此方法,但是这种方法在Windows / .NET 4中有效。

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, errors) =>
{
    if (errors == SslPolicyErrors.None)
        return true;    
    //BUGBUG: Obviously there should be a much more extensive check here.
    if (certificate.Issuer == caCert.Issuer)
        return true;    
    return false;
};

围绕btls存在some Mono个问题,还有一个pull request使这种方法在不久的将来成为可能。

尝试4:

将CA证书(和/或从CA发行的证书)添加到ClientWebSocket.Options ClientCertificates集合中。从技术上讲,这不适用于CA Certs,而应该是用于自签名证书的方法。我在此仅出于完整性目的提供它。如预期的那样,它也不起作用。

完整复制代码

易于使用的代码来证明上述问题以及上述所有尝试的变通方法是available on GitHub

1 个答案:

答案 0 :(得分:-2)

我不知道问题出在什么地方,但是我也遇到了一些问题,因为我是从第一个https Web服务开始的。 原因是,我从一个自签名证书开始,没有丑陋的解决方法是行不通的... 因此..仅使用公共供应商的已签名(受信任)证书,您应该没有任何问题... 要在http和https之间切换,您只需更改网址(从http更改为https)-无需对应用程序ae进行进一步更改。 通常,我通常先使用http(从.ini文件加载的url ist)对Web服务进行(本地)测试,然后将Web服务复制到“真实的” Web服务器(带有证书和https url)。 我从来没有遇到任何问题(使用受信任的证书时)...