从文件加载客户端证书的HttpClient

时间:2017-05-31 09:26:50

标签: c# iis dotnet-httpclient client-certificates mutual-authentication

我想将相互身份验证添加到在IIS服务器下运行的客户端.NET应用程序(它是一个调用其他Web服务的Web服务)。客户端应用程序从文件加载客户端证书,它在我的开发机器上使用以下代码正常工作(我尝试使用.NET 4.6.2的Windows 7和Windows 10):

var handler = new WebRequestHandler();
var certificate = new X509Certificate2(clientCertPath); -- PFX file with client cert and private key 
handler.ClientCertificates.Add(certificate);
handler.AuthenticationLevel = AuthenticationLevel.MutualAuthRequired;
client = new HttpClient(handler);

但是当此代码部署到生产Windows 2016 Server计算机时,该应用程序将抛出The request was aborted: Could not create SSL/TLS secure channel.

我启用了对System.Net的跟踪,这就是我在日志中看到的

SecureChannel#66407304 - Certificate is of type X509Certificate2 and contains the private key.
AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent  = Outbound, scc     = System.Net.SecureCredential)
AcquireCredentialsHandle() failed with error 0X8009030D.
AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent  = Outbound, scc     = System.Net.SecureCredential)
AcquireCredentialsHandle() failed with error 0X8009030D.
Exception in HttpWebRequest#60537518:: - The request was aborted: Could not create SSL/TLS secure channel..

事实证明,此错误是由于缺少IIS用户在PFX文件中读取私钥的权限而导致的。因此,当我将其导入计算机证书存储区并通过单击客户端证书IIS_IUSRS上的右键添加All Tasks -> Manage Private Keys...时,一切正常,但我想避免这种情况。

有没有办法处理从Windows Server上的文件加载的客户端证书,而不是将客户端证书PFX文件导入证书存储区?

3 个答案:

答案 0 :(得分:1)

首先,尝试X509KeyStorageFlags.PersistKeySet。接下来我理解你可以使用密钥将其导入密钥存储。如上所述here,您应首先将密钥导入到商店中(无论是否持久),然后使用密钥。

答案 1 :(得分:0)

由于工作涉及使用机器商店的示例,您可以尝试更改为MachineKeySet负载。

替换

var certificate = new X509Certificate2(clientCertPath);

var certificate = new X509Certificate2(clientCertPath, null, X509KeyStorageFlags.MachineKeySet);

不应对于客户端身份验证证书,但如果您在加载和使用之间发生用户模拟,则可能导致用户密钥集问题。

答案 2 :(得分:0)

尝试一下,只需将其添加到启动代码中

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

        ServicePointManager.ServerCertificateValidationCallback =
            (a, b, c, d) => true;