X509证书 - 密钥集不存在

46

我有一个使用WinForms编写的应用程序,它使用 WCF 服务,并将证书作为参数传递给函数:

mySvcClient.SendDocument(cert.Export(X509ContentType.SerializedCert, "password"));
...
在WCF服务中,我使用字节数组重新创建了证书:
public void SendDocument (byte[] binaryCert)
{   
     X509Certificate2 cert = new X509Certificate2(binaryCert, "password");
...

但是当我使用证书对XML进行签名时,遇到了“密钥集不存在”的错误:

if (cert.HasPrivateKey) // WORKS!!!
{   
    signedXml.SigningKey = cert.PrivateKey; // THROW "keyset does not exist" EXCEPTION
...

在我的电脑上,这个应用程序能够百分之百正常工作!但是在 Web 服务器上,我遇到了这个错误!

问题是:即使从字节数组重新创建 X509Certificate2,我需要一些特殊的权限才能访问私钥吗?

谢谢!


1
这个链接可能会对你有所帮助... https://dev59.com/GXRB5IYBdhLWcg3wgXdV#39223239 - Md. Ilyas Hasan Mamun
我曾经遇到过同样的问题,这是唯一对我有效的解决方案。https://dev59.com/GXRB5IYBdhLWcg3wgXdV#57667772 - CharithJ
11个回答

48
如果您正在使用Windows Server 2008或Windows 7,则需要获得读取私钥的权限。
  1. 使用FindPrivateKey工具查找路径。 例如:

FindPrivateKey My LocalMachine -n "CN=MyCert" –a

它会返回路径:C:\ ProgramData \ Microsoft \ Crypto \ RSA \ MachineKeys [文件名]

  1. 转到该路径并打开文件属性

  2. 转到安全选项卡

  3. 单击“编辑”,然后单击“添加”

  4. 在打开的对话框中写入:IIS AppPool \ [您的应用程序池名称],然后单击“确定”

现在您的应用程序池有权限读取此私钥。


7
设置证书权限的另一种方法是通过证书管理控制台,详见:https://dev59.com/GXRB5IYBdhLWcg3wgXdV#3176253。 - victorvartan
这里的问题是私钥权限,而不是证书权限。如果我能够通过证书管理解决它,我就不会读到这篇帖子了。 - undefined

41

我曾遇到这个问题,我的证书含有私钥但是我收到了"密钥集不存在"的错误提示。

原因:你的网站正在"Network services"账户下运行,或者权限不足。

解决方法:将应用程序池标识更改为"本地系统",重置IIS并再次检查。如果它开始工作,则是权限/权限不足问题,您也可以使用其他帐户进行模拟。


1
似乎存在这样一种情况,即使您的应用程序池标识是具有正确权限的帐户,如果您尝试在应用程序的Application_Start中访问私钥,则仍需要授予IIS_IUSRS组读取访问权限才能完成操作。 - RMD
在我的情况下,我不得不将应用程序池身份更改为“本地系统”,并提供私钥访问权限给“IIS_IUSRS”。证书需要安装在本地计算机商店。 - Amit
这是一种更简单的开发环境和部署方法。 - Dhanuka777
1
在生产环境中,不要使用本地系统权限,因为这样会赋予应用程序池超级管理员权限,这是不推荐的做法。这很危险。 - Dhanuka777

22
我遇到了同样的问题,而我不知道为什么(感到惭愧),但它起作用了:

我遇到了同样的问题,而我不知道如何解决(很惭愧),但是它奏效了:

var certificate = new X509Certificate2(filePath, password,
    X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);

certificate.PrivateKey; // before: error "KeySet does not exist"!

using (certificate.GetRSAPrivateKey()) { } // pure black magic

certificate.PrivateKey; // after: just works! lol

我希望有人能够解开这个谜团。


7
请注意,根据MSDN页面上的说明,此解决方案仅适用于.NET 4.6或更高版本。 - Richard Barker
1
这解决了我的问题。更让人困惑的是,PrivateKey 在我的本地机器上可以工作,但在部署的代码上却不行。 - riv_rec
1
不起作用。仍然会随机抛出“Keyset不存在”的错误。 - sports
这也解决了我的问题,我和@riv_rec有同样的问题,在本地工作正常但在部署版本上不起作用。 - Jacob Finamore
2
这个解决方案也适用于基于.NET 6的WPF应用程序。在我的情况下,我不必做黑魔法部分。只需将X509KeyStorageFlags.PersistKeySet添加到密钥存储标志中即可。X509Certificate2?certificate = new X509Certificate2(certificateFilePath,password,X509KeyStorageFlags.PersistKeySet);。感谢Nisarg Shah和@Kim Tranjan对此的帮助。 - Tangere Apps

5
Vano Maisuradze的回答是正确的。如果你正在寻找FindPrivateKey工具,它包含在.NET Framework 4的Windows Communication Foundation(WCF)和Windows Workflow Foundation(WF)示例中,可以在此处找到:http://www.microsoft.com/en-us/download/confirmation.aspx?id=21459
下载并解压后,在Visual Studio中打开WF_WCF_Samples\WCF\Setup\FindPrivateKey\CS项目进行编译。然后打开命令提示符并导航到:WF_WCF_Samples\WCF\Setup\FindPrivateKey\CS\bin。
接着按照Vano Maisuradze的回答继续操作即可。

3

对于本地开发,请确保用户具有访问证书的权限,特别是如果您将其安装在本地计算机存储中。

  1. 打开证书管理器(mmc.exe或certlm)
  2. 转到证书
  3. 右键单击 > 所有任务 > 管理私钥
  4. 为当前用户分配权限
  5. 完成

我在使用Rider进行调试时也遇到了这种情况。


这在我的情况下是正确的答案。VS2022和.NET Framework 4.8.1。 - BHP

2
我认为问题在于您需要将密钥添加到计算机的证书存储中。

0

默认情况下,应用程序池身份帐户无法访问证书存储。

您可以按照 Vaibhav.Inspired 指示更改为 Network Services 帐户,或者授予访问证书的权限。

执行以下命令以允许访问:

WinHttpCertCfg.exe -g -c LOCAL_MACHINE\MY -s "IssuedToName" -a "AccountName"

注:

- The tool may need to be installed first. The setup will place the tool at `C:\Program Files (x86)\Windows Resource Kits\Tools\WinHttpCertCfg.exe`.
- `IssuedName` is the issuer property of the certificate that the application will attempt to access
- The command must be run from command prompt with elevated privileges

参考资料: https://support.microsoft.com/en-us/help/901183/how-to-call-a-web-service-by-using-a-client-certificate-for-authentica 步骤2

同时,在安装证书时,您需要启用“将此密钥标记为可导出”选项。


0
由于私钥是敏感信息,因此它们不会与证书存储在同一位置。 类似于Vano Maisuradze的方法,您可以使用Process Monitor实用程序 捕获系统服务的跟踪并确定文件在文件系统中的位置。然后,授予用户对该文件的读取权限,以解决“密钥集不存在”的错误。您还可以在procman中找到运行线程的用户。

0

我在C#控制台应用程序上遇到了同样的问题,在阅读了这里的答案后,我认为问题在于权限。然后我以管理员身份运行了Visual Studio,它就可以工作了。


0

如果您能够调试应用程序,请尝试以管理员模式运行IDE。您还可以从MMC中添加新用户。


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