加密异常“Keyset does not exist”,但只通过WCF。

186

我有一些代码,用于调用一个使用X.509认证进行保护的第三方网络服务。

如果我直接调用该代码(使用单元测试),则可以正常工作,没有任何问题。

当部署后,将通过WCF服务调用此代码。我添加了第二个单元测试来调用WCF服务,但是当我调用第三方网络服务的方法时,它会出现CryptographicException,错误信息为"Keyset does not exist"

我想这是因为我的WCF服务将尝试使用不同的用户来调用第三方网络服务。

有人可以在这个问题上提供更多的指示吗?

24个回答

314

这很可能是因为IIS用户没有访问您证书的私钥。您可以按照以下步骤进行设置...

  1. 开始 → 运行 → MMC
  2. 文件 → 添加/删除控件
  3. 添加证书控件
  4. 选择计算机账户,然后点击下一步
  5. 选择本地电脑(默认),然后点击完成
  6. 在控制台根目录的左侧面板上,导航到证书(本地计算机) → 个人 → 证书
  7. 您的证书很可能在此处。
  8. 右键单击您的证书 → 所有任务 → 管理私钥
  9. 在此处设置您的私钥设置。

1
值得注意的是,在Server 2003上这不是一个选项,除非我的环境配置有问题。但在Windows 7上我可以做到这一点。 - Shawn Hubbard
11
谢谢,我想指出如果您使用iis7.5并且应用程序池运行为applicationpoolidentity,则必须将IIS AppPool\DefaultAppPool用户授予文件权限。这对我解决了问题。 - Ronen Festinger
30
为了使它对我起作用,我必须授予IIS_IUSRS权限。 - TrueEddie
4
如果您在运行IIS Express时遇到此问题,您需要提供自己的登录权限。 - Jez
我之前使用了ApplicationPoolIdentity,但在Windows 10上,我需要授予权限给IIS_IUSRS并执行“iisreset”,然后它才能工作! - kamranicus
显示剩余5条评论

181

这可能是证书权限问题。

在运行单元测试时,您将在自己的用户上下文中执行这些操作,这取决于客户端证书存储在哪个存储区中,该用户将可以访问该证书的私钥。

但是,如果您的WCF服务在IIS下托管或作为Windows服务运行,则很可能会在服务帐户(Network Service、Local Service或其他受限帐户)下运行。

您需要设置适当的权限以允许该服务帐户访问私钥。 MSDN有详细信息


运行计算对我解决了一个完全不同的问题,谢谢。 - John
4
我以管理员身份运行我的应用程序后,问题消失了。 - derek
1
+1 针对 MSDN 文档 的推荐,其中列出的步骤即使针对 Web 应用程序也适用。 - Naren
将“NETWORK SERVICE”添加到证书安全权限中,这对我解决了问题,谢谢! - OpMt

40

昨晚我遇到了相同的问题。私钥权限设置正确,一切似乎都很好,除了"密钥集不存在"的错误。最后发现证书是首先导入到当前用户存储中,然后移动到本地计算机存储中。然而,这没有移动私钥,私钥仍然在

C:\Documents and settngs\Administrator...

而不是

C:\Documents and settngs\All users...

虽然密钥的权限设置正确,但ASPNET无法访问它。当我们重新导入证书,以便将私钥放置在All users分支中时,问题消失了。


1
同样的问题。微软需要停止让安全专家掌管这个疯人院。 - Paul Stovell
2
经过三个小时的努力,这个解决了我的问题 - 谢谢。我使用了FindPrivateKey示例,并且感到困惑的是,即使它出现在MMC插件中的LocalMachine中,它似乎也在我的用户密钥库中。 - Rob Potter
每次我遇到权限问题时,都会浪费很多时间。就像其他答案告诉我的那样,我愿意为你买一杯啤酒。 - Scott Scowden
谢谢!非常感谢!由于这个可怕的问题,我浪费了大约2.5小时的时间,如果没有看到这个,我肯定会浪费2.5天的时间。 - Frank Tzanabetis
我遇到了相反的问题。首先在本地计算机上安装,然后在当前用户上安装。从两个存储中删除所有证书,然后在当前用户下重新安装解决了这个问题。 - Bart Verkoeijen

34
为解决从IIS浏览时出现“密钥集不存在”的问题: 可能是由于私有权限引起的。 查看和授权: 1. 运行>mmc>是 2. 点击文件 3. 点击添加/删除快照… 4. 双击证书 5. 计算机帐户 6. 下一步 7. 完成 8. 好的 9. 点击证书(本地计算机) 10. 点击个人 11. 点击证书 授权: 1. 右键单击证书名称 2. 所有任务>管理私钥… 3. 添加并授予权限(将IIS_IUSRS添加并授予权限对我有效)

3
如果您正在运行一个应用程序池,请添加此用户"IIS AppPool\DefaultAppPool"。 - Sameer Alibhai
这也帮助了我。一旦我给了IIS_IUSRS权限,它就开始工作了。 - Andrej Mohar

22

当我试图从Visual Studio运行WCF应用程序时,遇到了相同的问题。通过以管理员身份运行Visual Studio来解决它。


12

我遇到了这个问题,我的证书有私钥,但是我却遇到了这个错误("密钥集不存在")

原因:你的网站正在使用“网络服务”帐户运行或者权限不足。

解决方案:将应用程序池标识更改为“本地系统”,重新设置IIS并再次检查。 如果开始工作了,则是权限/较低权限问题,你也可以使用其他帐户进行模拟。


10

非常沮丧,我遇到同样的问题并尝试了大部分以上方法。导出证书时正确地具有读取 C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys 文件的权限,但事实证明它没有文件夹权限。添加权限后问题得以解决。


我尝试了很多方法来解决这个问题,但是这一个起了作用! - Gyum Fox
哇 - 没想到那样做居然成功了。我添加了 IISAPPPool\www.mywebsite.com,这是我的应用程序池的Windows用户名,结果它奏效了 :-) - Simon_Weaver
有人知道为什么这个有效吗?是因为某些东西损坏了,因为这很难理解。 - Simon_Weaver
不要这样做!当文件夹..RSA\MachineKeys的基本权限被更改时,服务器会进入“坏状态”,其中证书正在被导入并显示为“Microsoft Software KSP”提供程序类型。更多细节请参见https://www.reddit.com/r/sysadmin/comments/339ogk/this_certificate_issue_invalid_provider_type_has/. - Dhanuka777

4

我遇到了一个错误: 当我运行MVC应用程序时,出现了CryptographicException 'Keyset does not exist'。

解决方案是:为应用程序池正在运行的帐户授予个人证书访问权限。在我的情况下,添加IIS_IUSRS并选择正确的位置解决了这个问题。

RC on the Certificate - > All tasks -> Manage Private Keys -> Add->  
For the From this location : Click on Locations and make sure to select the Server name. 
In the Enter the object names to select : IIS_IUSRS and click ok. 

3

我也遇到了完全相同的问题。 我使用了以下命令:

findprivatekey root localmachine -n "CN="CertName" 

结果显示私钥在 c:\ProgramData 文件夹而不是 C:\Documents and settngs\All users..

当我从 c:\ProgramData 文件夹中删除密钥后,再次运行 findPrivatekey 命令失败。也就是说,它找不到密钥。

但如果我搜索先前命令返回的相同密钥,则仍然可以在 C:\Documents and settngs\All users.. 中找到该密钥。

因此,我认为 IIS 或托管的 WCF 无法从 C:\Documents and settngs\All users.. 中找到私钥。


2
嗨,这个链接将告诉你如何解决这个问题,并找到findprivatekey工具:https://blogs.msdn.microsoft.com/dsnotes/2015/08/13/service-failure-with-cryptographicexception-keyset-does-not-exist/ - Trevor

2
Steve Sheldon的答案解决了我的问题,但是由于我正在编写没有图形界面的证书权限脚本,所以我需要一个可编写脚本的解决方案。我努力寻找我的私钥存储的位置。私钥并不在-C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys中,最终我发现它实际上位于C:\ProgramData\Microsoft\Crypto\Keys中。以下是我是如何找到它的: 我尝试使用FindPrivateKey,但它无法找到私钥,而使用PowerShell时$cert.privatekey.cspkeycontainerinfo.uniquekeycontainername为空/空白。 幸运的是,certutil -store my列出了证书并给我提供了编写解决方案所需的详细信息。 然后,我扫描了C:\ProgramData\Microsoft\Crypto\文件夹,并在C:\ProgramData\Microsoft\Crypto\Keys中找到了文件8787033f8ccb5836115b87acb_ca96c65a-4b42-a145-eee62128a。 为我的服务帐户分配读取访问权限可以解决我的问题。

1
使用“certutil -store my”是解决我的问题的关键。我使用“唯一容器名称”来定位文件,并使用Sysinternals Process Monitor来排除证书文件上的“访问被拒绝”错误。在我的情况下,我必须为NT Authority\IUSR用户提供对证书文件的读取访问权限。 - hsop

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