C# 如何从PKCS“12字节数组”构造X509Certificate2引发CryptographicException(“系统找不到指定的文件”)?
我试图从字节数组中的PKCS#12 blob构造一个C# 如何从PKCS“12字节数组”构造X509Certificate2引发CryptographicException(“系统找不到指定的文件”)?,c#,.net,cryptography,x509certificate2,pkcs#12,C#,.net,Cryptography,X509certificate2,Pkcs#12,我试图从字节数组中的PKCS#12 blob构造一个X509Certificate2,得到一个相当令人费解的错误。此代码在Windows XP上具有管理员权限的桌面应用程序中运行 堆栈跟踪如下所示,但我在尝试排除故障时迷失了方向,因为\u LoadCertFromBlob标记为[MethodImpl(MethodImplOptions.InternalCall)] 编辑:blob是一个真正的PKCS#12,通过包含RSA私钥和证书(自签名或最近使用CA注册)生成--我试图通过从一个库导出并导入到
X509Certificate2
,得到一个相当令人费解的错误。此代码在Windows XP上具有管理员权限的桌面应用程序中运行
堆栈跟踪如下所示,但我在尝试排除故障时迷失了方向,因为\u LoadCertFromBlob
标记为[MethodImpl(MethodImplOptions.InternalCall)]
编辑:blob是一个真正的PKCS#12,通过包含RSA私钥和证书(自签名或最近使用CA注册)生成--我试图通过从一个库导出并导入到另一个库,将私钥和证书从BouncyCastle库转换到System.Security.Cryptography库。这段代码适用于绝大多数已经试用过的系统;我只是从来没有见过那个构造函数抛出的特定错误。这可能是一个盒子上的某种环境怪异
编辑2:该错误发生在不同城市的不同环境中,我无法在本地复制它,因此我可能不得不将其归因于XP安装故障
但是,既然你问了,这里是有问题的片段。代码采用BouncyCastle表示形式的私钥和证书,从个人密钥存储中删除相同可分辨名称的所有以前的证书,并通过中间PKCS#12 blob将新私钥和证书导入个人密钥存储
//打开个人密钥库
var msMyStore=new X509Store(StoreName.My);
msMyStore.Open(OpenFlags.MaxAllowed);
//删除以前为同一DN颁发的任何证书
旧证书=
msMyStore.Certificates.Cast()文件
.其中(c=>X509Name
.GetInstance(Asn1Object.FromByteArray(c.SubjectName.RawData))
.同等(当前证书.主题DN))
.ToArray();
如果(oldCerts.Length>0)MSMSystore.RemoveRange(新X509Certificate2Collection(oldCerts));
//从私钥和证书构建PKCS#12 blob
var pkcs12store=new Pkcs12StoreBuilder().Build();
pkcs12store.SetKeyEntry(_Pkcs12KeyName,
新的不对称密钥输入(KeyPair.Private),
新[]{new X509CertificateEntry(CurrentCertificate)};
var pkcs12data=new MemoryStream();
pkcs12store.Save(pkcs12data,_Pkcs12Password.tocharray(),Random);
//然后导入它。这个构造函数调用失败了
_MyCertificate2=新的X509Certificate2(pkcs12data.ToArray(),
_PKCS12密码,
X509keystrageFlags.可出口);
msMyStore.Add(_MyCertificate2);
msMyStore.Close();
您有PKCS#12还是只有PFX文件?在微软的世界里,情况是一样的,但其他人却有不同的想法(参见)
你可以试着跟着我
X509Certificate2 cert = X509Certificate2(byte[] rawData, "password");
X509Certificate2 cert2 = X509Certificate2(byte[] rawData, "password",
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable);
()或
(如果需要使用某些标志,请参阅Microsoft文档上的和)
已更新:如果插入代码片段而不仅仅是异常堆栈跟踪,这将非常有用
您使用哪个
x509keystrageflags
?您可以使用查找哪个文件找不到X509Certificate2
构造函数。例如,Windows XP上的当前用户没有出现问题的默认密钥容器。您可以创建它,然后重试导入。我遇到了完全相同的问题。当在特定用户下运行时,相同的代码和数据/证书在Windows 2003 x86上运行良好,但在另一个帐户下失败(该帐户也用于运行IIS应用程序池)
显然,其他一些事情耗尽了Windows上的资源,因此失败的用户无法真正加载用户的配置文件(他的桌面看起来很奇怪),尽管事件查看器中没有相关事件
重新启动暂时解决了问题。虽然这不是问题的永久解决方案,但它表明还有其他东西(例如COM+组件、本机代码服务等)需要调查。它还显示了Windows平台的不稳定性…我遇到了同样的问题 根据这一点,问题是构造函数试图将证书加载到当前用户的配置文件中,但是.Net代码我正在模拟用户,因此它没有加载用户配置文件。构造函数需要加载的用户配置文件才能正常工作 从文章中: X509Certificate2类构造函数尝试将证书导入应用程序运行所在的用户帐户的用户配置文件中。很多时候,ASP.NET和COM+应用程序模拟客户端。这样做时,出于性能原因,它们不会加载模拟用户的用户配置文件。因此,他们无法访问模拟用户的“用户”证书存储
加载用户配置文件修复了错误。在Windows 2012上的web应用程序中运行此操作时,将应用程序池选项
加载用户配置文件
设置为true使其正常工作
要执行此操作,请运行
inetmgr.exe
,转到右侧应用程序池的Advanced Settings
,将Process Model
下的Load User Profile
更改为true。我也遇到了同样的问题
这种特殊的不稳定性似乎与严重依赖进程间通信的桌面软件和面对资源耗尽时的鲁棒性差有关。我在GNOME上看到过完全相同的问题,尤其是Evolu
// open the personal keystore
var msMyStore = new X509Store(StoreName.My);
msMyStore.Open(OpenFlags.MaxAllowed);
// remove any certs previously issued for the same DN
var oldCerts =
msMyStore.Certificates.Cast<X509Certificate2>()
.Where(c => X509Name
.GetInstance(Asn1Object.FromByteArray(c.SubjectName.RawData))
.Equivalent(CurrentCertificate.SubjectDN))
.ToArray();
if (oldCerts.Length > 0) msMyStore.RemoveRange(new X509Certificate2Collection(oldCerts));
// build a PKCS#12 blob from the private key and certificate
var pkcs12store = new Pkcs12StoreBuilder().Build();
pkcs12store.SetKeyEntry(_Pkcs12KeyName,
new AsymmetricKeyEntry(KeyPair.Private),
new[] {new X509CertificateEntry(CurrentCertificate)});
var pkcs12data = new MemoryStream();
pkcs12store.Save(pkcs12data, _Pkcs12Password.ToCharArray(), Random);
// and import it. this constructor call blows up
_MyCertificate2 = new X509Certificate2(pkcs12data.ToArray(),
_Pkcs12Password,
X509KeyStorageFlags.Exportable);
msMyStore.Add(_MyCertificate2);
msMyStore.Close();
X509Certificate2 cert = X509Certificate2(byte[] rawData, "password");
X509Certificate2 cert2 = X509Certificate2(byte[] rawData, "password",
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable);
X509Certificate2 cert = X509Certificate2("C:\Path\my.pfx", "password");