为什么X509Certificate2有时无法从Blob创建?

10

我有一个ASP.NET Web服务,它接收一个字节数组,该数组代表包含X.509证书的.pfx文件的内容。 服务器端代码使用System.Security.Cryptography.X509Certificate2构造函数从字节数组中加载证书:

X509Certificate2 native_cert = new X509Certificate2(
                pkcs12_buf /*byte array*/,
                password,
                X509KeyStorageFlags.PersistKeySet |
                X509KeyStorageFlags.Exportable
            );

根据我的服务进程运行的身份不同,这个调用要么成功,要么失败并出现“内部错误”异常。异常堆栈中的最后一个调用是X509Utils._LoadCertFromBlob,它是在mscore.dll中的非托管代码。

当在使用服务帐户凭据的交互式登录下的控制台应用程序中运行此代码时,它会成功。但在使用服务帐户凭据的应用程序池下的w3wp.exe中运行时,则会失败。将应用程序池标识更改为管理员可解决该问题,因此这必须是特权问题,但我不知道需要哪些特权。该代码未触及文件系统或Windows证书存储区。

[更新:更多信息]
此错误出现在Windows事件日志中:

*Cryptographic Parameters:*   
**Provider Name:**  Microsoft Software Key Storage Provider  
**Algorithm Name:** Not Available.  
**Key Name:**   {E182E13B-166D-472A-A24A-CBEF0808E9ED}  
    **Key Type:**   User key.

*Cryptographic Operation:*  
**Operation:**  Open Key.  
    **Return Code:**    0x2  

有什么想法吗?

2个回答

9
我刚刚自己找到了这个问题的解决方案:
X509KeyStorageFlags flags = X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet;

X509Certificate2 cert = new X509Certificate2(pkcs12_buf, password, flags);

这里的技巧是使用本地密钥存储 MachineKeySet 标志,而不是用户配置文件密钥存储,如果您没有指定替代位置,则默认为用户配置文件密钥存储。由于 ASP.NET 进程标识不加载用户配置文件存储,因此在以编程方式导入证书时无法访问存储,但您可以访问机器存储。
我认为 PersistKeySet 只是保持私钥已加载,但我不确定它确切的作用-如果您需要访问私钥,则需要它。

为什么ASP.Net用户上下文在运行时无法访问自己的存储?(这确实解决了我的问题-这是一个经典的“但它在我的开发机器上工作!”只是好奇其中的原因。) - DFTR

2

尝试授予ASP.NET账户对以下文件夹的权限:C:\Documents And Settings\All Users\Microsoft\Crypto\RSA\MachineKeys\(根据您的环境可能会有所不同)


我认为你走在了正确的道路上,但它似乎并没有尝试访问文件系统。成功访问的帐户在用户个人配置文件下访问Microsoft\Crypto\RSA(而不是AllUsers)。失败的那个甚至根据procmon也没有尝试访问文件系统。 - jlew
这个权限更改在Win2k8上对我有用。节省了大量调试时间。谢谢! - CodingWithSpike

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