.NET应用程序无法发送客户端证书 - Win 7 vs Win XP?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (28)

我正在开发一个ASP.NET Web应用程序,该应用程序使用HttpWebRequest向另一个服务器发送请求。它通过HTTPS发送请求,并且远程服务器需要客户端证书。该请求在.NET应用程序中失败,显然无法发送正确的客户端证书。我能够成功连接并发送客户端证书,如果我只需访问URL以网页浏览器(Chrome明确)。

下面的代码是一个简单的复制,只有一个基本的GET请求。

var r = WebRequest.Create(url) as HttpWebRequest;
r.ClientCertificates = new X509CertificateCollection { myX509Cert };
using (var resp = r.GetResponse() as HttpWebResponse) {
    ...
}

我收到了我们最喜欢的例外,“无法创建SSL / TLS安全通道”。通常,这些类型的问题指出了您的证书私钥的权限问题。我尝试了所有我能想到的方法来确保所有配置都正确,但也许我错过了一些东西。长话短说,远程服务器正在发送一个CertificateRequest带有列表的TLS ,该列表似乎能够正确识别我的客户端证书,但是我的应用无法响应任何客户端证书。

这是我的设置:

  • Windows 7专业版64位
  • 能够在运行于Visual Studio开发服务器,在本地IIS中运行的ASP.NET WebForms / .NET 3.5应用程序以及在.NET控制台应用程序/ .NET 4中运行的ASP.NET MVC 3 / .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跟踪并看到了这一点:

SecureChannel#26717201 - 我们有用户提供的证书。服务器已经指定了6个发行者。寻找符合任何发行人的证书。 SecureChannel#26717201 - 留下0个客户端证书可供选择。 ... InitializeSecurityContext(In-Buffers count = 2,Out-Buffer length = 0,返回代码= CertUnknown)。

我启用了完整的SCHANNEL日志记录,并看到此警告:

远程服务器已请求SSL客户端身份验证,但未找到合适的客户端证书。将尝试匿名连接。此SSL连接请求可能成功或失败,具体取决于服务器的策略设置。

我运行了Wireshark,并看到远程服务器发送了一个CertificateRequest,并且它似乎有一个Distinguished Name条目,其中指定了我的客户端证书的CN \ OU \ O值。之后,我的应用程序发送一个证书响应,没有证书。

似乎我错过了设置此证书以便在Windows 7中与.NET应用程序一起正常工作的情况。我最好的猜测是,与XP计算机相比,我的新Windows 7计算机上有一些不同的东西导致了这种情况现在失败。我目前无法访问Windows XP环境来确认这一点; 我会在几天内,但真的想尽快解决这个问题。

如上所述,当在Chrome中连接到URL时,浏览器要求我提供客户端证书,并且我可以提供正确的证书并成功连接。但是,我无法在Internet Explorer(9)中成功完成此操作。我只是得到“Internet Explorer无法显示网页”,没有其他提示或解释。我被告知这可能WebRequest.Create与IE有类似的行为有关。我正在研究这可能意味着什么,但会重视对此的任何想法。

另外,我应该注意到远程服务器使用自签名的SSL证书。我原本以为这可能是问题所在,因此我将该证书添加为MMC中的受信任根,以便证书在我的计算机上显示为有效。这并没有解决问题。

提问于
用户回答回答于

原来这是一个相当简单的问题,但很难发现。我的应用程序在其密钥库中有我的客户端证书的远程服务器,但不是我客户端证书的信任链中的任何根证书。

我能够使用我的代码成功发送请求到需要客户端证书的不同服务器。在发送这个成功的请求时,我在Wireshark中捕获了一个捕获,并在发送失败请求到另一个服务器时进行了捕获。在Wireshark捕获中,我找到了“Server Hello”并比较了从远程服务器发送的消息。“良好”的远程服务器正在发送我的客户端证书,并且还在其消息的“证书请求”部分发送其根证书。“不好”的远程服务器只发送我的客户端证书。

这提醒我System.Net诊断跟踪读取“服务器已指定6个发行者...留下0个客户端证书可供选择”。所以事实证明,“发行人”是这里的关键词。最初很容易忽略,因为在我对TLS握手的初步分析中,服务器在证书请求中发送了我的客户端证书。事后看来,服务器应该发送根证书而不是客户端证书本身是有道理的。

用户回答回答于

我想为这个问题增加另一个“解决方案”。

如果该列表太长,服务器可能无法发送正确的发布者列表。这似乎是微软的限制。http://support.microsoft.com/kb/933430

资料来源:http : //netsekure.org/2011/04/tls-client-authentication-and-trusted-issuers-list/

解决办法是要求服务器不要发送列表。(通过编辑注册表值)

HKEY_LOCAL_MACHINE \系统\ CurrentControlSet \控制\ SecurityProviders \ SCHANNEL

值名称:SendTrustedIssuerList值类型:REG_DWORD值数据:0(False)

扫码关注云+社区