UWP Windowsapp store应用上的TLS客户端证书身份validation

我正在尝试连接到使用TLS和客户端证书身份validation的服务器。 以下是代码段:

async Task TestClientCertAuth() { int iWinInetError = 0; Uri theUri = new Uri("http://xxx-xxx"); try { using (HttpBaseProtocolFilter baseProtocolFilter = new HttpBaseProtocolFilter()) { // Task GetClientCertificate() displays a UI with all available // certificates with and returns the user selecter certificate. An // oversimplified implementation is included for completeness. baseProtocolFilter.ClientCertificate = await GetClientCertificate(); baseProtocolFilter.AllowAutoRedirect = false; baseProtocolFilter.AllowUI = false; using (HttpClient httpClient = new HttpClient(baseProtocolFilter)) using (HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Get, theUri)) using (HttpResponseMessage httpResponse = await httpClient.SendRequestAsync(httpRequest)) { httpResponse.EnsureSuccessStatusCode(); // Further HTTP calls using httpClient based on app logic. } } } catch (Exception ex) { iWinInetError = ex.HResult & 0xFFFF; LogMessage(ex.ToString() + " Error code: " + iWinInetError); throw; } } // Task GetClientCertificate() displays a UI with all available // certificates with and returns the user selecter certificate. An // oversimplified implementation is included for completeness. private async Task GetClientCertificate() { IReadOnlyList certList = await CertificateStores.FindAllAsync(); Certificate clientCert = null; // Always choose first enumerated certificate. Works so long as there is only one cert // installed and it's the right one. if ((null != certList) && (certList.Count > 0)) { clientCert = certList.First(); } return clientCert; } 

SendRequestAsync调用引发HRESULT 0x80072F7D的exception – 我相信这意味着ERROR_INTERNET_SECURITY_CHANNEL_ERROR。 服务器证书信任没有问题。 客户端证书安装在应用程序本地存储中,我可以使用CertificateStores.FindAllAsync检索它。 查看SSL跟踪,我可以看到没有发送客户端证书。

如果HttpBaseProtocolFilter.AllowUI设置为true,则不会发生上述问题。 在这种情况下,SendRequestAsync调用会导致显示UI,要求同意使用客户端证书。 在此对话框中选择“允许”后,我可以看到在跟踪中发送的客户端证书和证书validation消息,并且连接已成功建立。

问题:应用程序代码已经处理了用户的证书选择。 我想知道是否有任何方法可以指定以编程方式使用客户端证书的同意。 因为启用AllowUI会导致其他副作用 – 例如,如果服务器使用WWW-Authenticate:Basic标头重新构建401 HTTP代码,则基本protoctolfilter会弹出它自己的UI以接受用户凭据,而不会给调用者带来机会处理它。 想要避免上述两个UI,因为我已经选择了客户端证书并从具有自己UI的用户获取凭据。 谢谢

此Microsoft博客条目提供有关在AllowUI为false时发生此错误的原因的信息并提供解决方法。 在任何情况下都不能绕过证书同意UI,因此这是欧盟必须经历的事情。 似乎Windows Phone上的行为也不同。 试过这个解决方案,它似乎适用于桌面和表面。 一般的想法是通过尝试访问私钥来“激活”当前应用程序会话中的低级API使用的证书。 在这种情况下,我们只是尝试签署一些虚拟数据。 一旦欧盟授予对证书的访问权限,TLS会话建立就会成功完成。 需要检查它在Windows Phone上的行为方式。

  private async Task RequestCertificateAccess(Certificate cert) { bool signOK = false; try { IBuffer data = CryptographicBuffer.ConvertStringToBinary("ABCDEFGHIJKLMNOPQRSTUVWXYZ012345656789", BinaryStringEncoding.Utf8); CryptographicKey key = await PersistedKeyProvider.OpenKeyPairFromCertificateAsync(cert, HashAlgorithmNames.Sha1, CryptographicPadding.RsaPkcs1V15); IBuffer sign = await CryptographicEngine.SignAsync(key, data); signOK = CryptographicEngine.VerifySignature(key, data, sign); } catch (Exception ex) { LogMessage(ex.ToString(), "Certificate access denied or sign/verify failure."); signOK = false; } return signOK; } 

可以在基本协议filter上设置客户端证书之前调用RequestClientCertificateAccess。

@Tomas Karban,感谢您的回复。 我没有使用sharedUserCertificates,因此如果我理解正确,我可以枚举的任何证书都必须在应用程序的证书库中。 如果您还没有看到,我分享的链接可能对您的案例有所帮助。

我认为你没有将证书存储在应用程序自己的证书库中。 如果设置HttpBaseProtocolFilter.AllowUI = true并确认对话框,则应用程序将获得使用用户存储中的私钥的权限。 如果没有UI确认,应用程序只能使用自己的证书存储中的私钥。

Windows 10 Mobile的情况更糟 – 据我所知,无法将HttpBaseProtocolFilter.AllowUI设置为true(请参阅我的问题在Windows 10 Mobile上无法将HttpBaseProtocolFilter.AllowUI设置为true )。 这留下了使用应用程序自己的证书库的唯一选择。