【发布时间】:2012-04-09 03:20:10
【问题描述】:
我正在开发一个使用 HttpWebRequest 向另一台服务器发送请求的 ASP.NET Web 应用程序。它通过 HTTPS 发送请求,远程服务器需要客户端证书。 .NET 应用程序中的请求失败,显然无法发送正确的客户端证书。如果我只需使用网络浏览器(特别是 Chrome)访问 URL,我我能够成功连接并发送客户端证书。
下面的代码是一个简单的复制,只有一个基本的 GET 请求。
var r = WebRequest.Create(url) as HttpWebRequest;
r.ClientCertificates = new X509CertificateCollection { myX509Cert };
using (var resp = r.GetResponse() as HttpWebResponse) {
...
}
我得到了我们最喜欢的异常,“无法创建 SSL/TLS 安全通道”。通常,这些类型的问题指向证书私钥的权限问题。我尝试了我能想到的一切来确保这一切都正确配置,但也许我错过了一些东西。长话短说,远程服务器正在发送一个 TLS CertificateRequest,其中包含一个似乎可以正确识别我的客户端证书的列表,但我的应用程序无法响应任何客户端证书。
这是我的设置:
- Windows 7 专业版 64 位
- 能够在 Visual Studio 开发服务器中运行的 ASP.NET MVC 3 / .NET 4 应用程序、在本地 IIS 中运行的 ASP.NET WebForms / .NET 3.5 应用程序以及 .NET 控制台应用程序 / .NET 4
- 最近安装了 Microsoft .NET Framework 4.5。尚未检查这是否是个问题
这是我尝试过的所有内容,以及我所知道的:
- 此代码在 Windows XP 机器上运行时似乎运行良好
- 我确保将我的客户端证书导入到本地计算机的个人证书存储中,并为我自己和所有相关 IIS 用户正确配置了私钥权限
- 我尝试在我的机器上重新安装证书几次
- 我已确认.NET 应用程序可以访问X509 证书和
HasPrivateKey= true - 确保我的客户端证书有效。它实际上是运行此应用程序的 Web 服务器的 SSL 证书
- 我在请求对象中设置了
PreAuthenticate = true。没有影响 - 我试过设置
ServicePointManager.Expect100Continue = false,没有效果 - 我尝试设置
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3,但显然远程服务器需要 TLS,所以没有帮助 - 我将
ServicePointManager.ServerCertificateValidationCallback委托设置为始终返回true。但是请求在 TLS 握手的早期就失败了,甚至在调用这个委托之前就失败了 - 当我在 Chrome 中访问 URL 时,它要求我提供客户端证书,并提供正确的客户端证书作为选项,我选择了该证书并得到有效响应。当我在 Fiddler 中构建请求时也可以正常工作。因此,这绝对是我的 .NET 代码的具体问题,而不是证书本身或远程服务器等。
- 与我合作的供应商在不同的远程服务器上设置了相同的服务,并且该服务需要不同的客户端证书。所以我用不同的 URL 和客户端证书尝试了同样的事情并得到了同样的失败
我添加了System.Net trace 并看到了这个:
SecureChannel#26717201 - 我们有用户提供的证书。服务器已指定 6 个颁发者。寻找与任何颁发者匹配的证书。
SecureChannel#26717201 - 剩下 0 个客户端证书可供选择。
...
InitializeSecurityContext(In-Buffers 计数=2,Out-Buffer 长度=0,返回代码=CertUnknown)。
我启用了完整的SCHANNEL logging,并看到了这个警告:
远程服务器已请求 SSL 客户端身份验证,但找不到合适的客户端证书。将尝试匿名连接。此 SSL 连接请求可能成功或失败,具体取决于服务器的策略设置。
我运行了 Wireshark,看到远程服务器发送了一个 CertificateRequest,并且它似乎有一个 Distinguished Name 条目,其中我的客户端证书的 CN\OU\O 值被准确指定。之后,我的应用程序发送一个没有证书的证书响应。
似乎我在设置此证书以在 Windows 7 中与 .NET 应用程序正常工作时缺少一些东西。我最好的猜测是,与 XP 机器相比,我的新 Windows 7 机器上有一些不同之处,即导致现在失败。我目前无法访问 Windows XP 环境来确认这一点;我会在几天后解决这个问题。
任何想法将不胜感激。谢谢!
EDIT 如上所述,在 Chrome 中连接 URL 时,浏览器要求我提供客户端证书,我可以提供正确的证书并成功连接。但是,我无法在 Internet Explorer (9) 中成功执行此操作。我只是得到“Internet Explorer 无法显示网页”,没有其他提示或解释。有人告诉我这可能是相关的,因为WebRequest.Create 具有与 IE 相似的行为。我正在研究这可能意味着什么,但会重视对此的任何想法。
编辑 另外,我应该注意远程服务器使用自签名 SSL 证书。我最初认为这可能是问题所在,因此我将证书添加为 MMC 中的受信任根,以便证书在我的机器上显示为有效。这并没有解决问题。
【问题讨论】:
-
证书是否包含“客户端身份验证 (1.3.6.1.5.5.7.3.2)”增强密钥使用扩展?如果没有,可能是 Chrome 不小心允许它被选中。
-
原来客户端证书没有这个Enhanced Key Usage扩展。我很确定该代码过去在指向不同的远程 URL 和不同的客户端证书时可以正常工作,即使该客户端证书没有客户端身份验证增强密钥使用。不过,这给了我一个调查的途径,谢谢。
-
实际上 Damien,我错了 - 所有这些证书都包含客户端身份验证增强密钥使用扩展。
-
完全没有必要在wiki上做这个。你们都很好。
标签: .net client certificate ssl