系统相关
首页 > 系统相关> > C#-UWP Windows Store应用程序上的TLS客户端证书认证

C#-UWP Windows Store应用程序上的TLS客户端证书认证

作者:互联网

我正在尝试连接到使用TLS和客户端证书身份验证的服务器.下面是一个代码片段:

async Task TestClientCertAuth()
{
    int iWinInetError = 0;
    Uri theUri = new Uri("http://xxx-xxx");
    try
    {
        using (HttpBaseProtocolFilter baseProtocolFilter = new HttpBaseProtocolFilter())
        {
            // Task<Certificate> 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<Certificate> 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<Certificate> GetClientCertificate()
{
    IReadOnlyList<Certificate> 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异常-我认为这意味着ERROR_INTERNET_SECURITY_CHANNEL_ERROR.服务器证书信任没有问题.客户端证书已安装在应用程序本地存储中,我很想使用CertificateStores.FindAllAsync来检索它.查看SSL跟踪,可以看到未发送客户端证书.

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

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

解决方法:

Microsoft Blog Entry提供了有关AllowUI为false时为什么会发生此错误的信息,并提供了一种解决方法.在任何情况下都不能绕过证书同意UI,这是欧盟必须经历的事情.看起来Windows Phone上的行为也有所不同.尝试了此解决方案,它似乎可以在桌面和桌面上运行.通常的想法是通过尝试访问私钥来“初始化”证书,以供当前应用会话中的较低级别的API使用.在这种情况下,我们只是尝试对一些虚拟数据进行签名.欧盟授予对证书的访问权限后,TLS会话建立就会成功进行.需要检查如何
这在Windows Phone上仍然有效.

    private async Task<bool> 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;
    }

可以在基本协议过滤器上设置客户端证书之前调用RequestClientCertificateAccess.

@Tomas Karban,感谢您的回复.我尚未使用sharedUserCertificates,因此,如果我理解正确,我可以枚举的任何证书都必须位于应用程序的证书存储中.如果您尚未看到我分享的链接,可能会对您的情况有所帮助.

标签:winrt-httpclient,ssl,windows-runtime,c
来源: https://codeday.me/bug/20191118/2030225.html