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

5

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

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 服务器上时,应用程序会抛出 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文件中的私钥引起的。因此,当我将其导入到机器证书存储并通过在客户端证书上右键单击“所有任务->管理私钥...”添加时,一切都正常工作,但我想避免这种情况。
有没有一种方法可以在Windows Server上使用从文件加载的客户端证书,而不必将客户端证书PFX文件导入到证书存储中?

你的客户端在哪里运行?客户端是什么类型的应用程序?客户端是否在IIS工作进程中运行?错误是在客户端还是服务器端抛出的? - Rohith
这是一个 .NET Web 应用程序,使用客户端相互认证进行 HTTP 调用远程服务器。它正在 IIS 工作进程中运行。错误出现在客户端。 - klappvisor
你在导入到用户证书存储时是否正常工作,还是使用了机器证书存储? - bartonjs
我将它导入到机器存储中,因为应该由不同的用户访问,是的,当我导入它并将IIS_IUSRS添加到所有任务->管理私钥...时,它可以工作。我会编辑问题... - klappvisor
1
我在加载PFX文件到IIS时遇到了相同的问题。结果发现我需要编辑应用程序池,然后按照这里的详细说明启用"加载用户配置文件"功能:https://dev59.com/bHE85IYBdhLWcg3wyGt_#47506891 - Chris Stubbs
3个回答

2
由于示例中涉及使用机器存储,因此您可以尝试切换到 MachineKeySet 加载。

替换为

var certificate = new X509Certificate2(clientCertPath);

使用

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

这对于客户端身份验证证书来说不应该是必要的,但如果在加载和使用之间发生了用户模拟,可能会导致用户密钥集问题。

1

首先,尝试使用X509KeyStorageFlags.PersistKeySet。接下来,据我所知,您可以将密钥导入密钥存储并直接使用它。如此处所述,您应该首先将密钥导入存储(无论是否持久),然后再使用密钥。


我尝试过,但不幸的是它没有起作用。我确实想避免将密钥导入存储并使用 pfx 文件,因为它在桌面 Windows 上可以工作。 - klappvisor
IIS应用程序池标识怎么样?您尝试将默认的ApplicationPoolIdentity更改为具有更高特权的用户吗? - Oleg M

0

试试这个吧,只需将这个代码添加到启动代码中即可

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接