从 PKCS#12 字节数组构造 X509Certificate2 如何抛出 CryptographicException(“系统找不到指定的文件。”)?

发布于 2024-09-25 15:17:49 字数 2711 浏览 1 评论 0原文

我试图从字节数组中的 PKCS#12 blob 构造一个 X509Certificate2 并收到一个相当令人费解的错误。此代码在 Windows XP 上具有管理员权限的桌面应用程序中运行。

堆栈跟踪如下,但我在尝试排除故障时迷失了方向,因为 _LoadCertFromBlob 被标记为 [MethodImpl(MethodImplOptions.InternalCall)]

System.Security.Cryptography.CryptographicException: The system cannot find the file specified.
  at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)
  at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)
  at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)
  at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)

编辑: blob 是由 BouncyCastle for C# 生成的真正的 PKCS#12包含 RSA 私钥和证书(自签名或最近在 CA 注册)——我想做的是将私钥和证书从 BouncyCastle 库导出到 System.Security.Cryptography 库一个并导入到另一个。该代码适用于它所尝试过的绝大多数系统;我只是从未见过该构造函数抛出的特定错误。那个盒子上可能有某种环境怪异。

编辑2:该错误发生在不同城市的不同环境中,并且我无法在本地重现它,因此我最终可能不得不将其归因于损坏的XP安装。

不过,既然你问了,这里就是有问题的片段。该代码采用 BouncyCastle 表示形式的私钥和证书,从个人密钥存储中删除相同专有名称的任何先前证书,并通过中间 PKCS#12 blob 将新的私钥和证书导入个人密钥存储中。

// 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();

I'm trying to construct an X509Certificate2 from a PKCS#12 blob in a byte array and getting a rather puzzling error. This code is running in a desktop application with administrator rights on Windows XP.

The stack trace is as follows, but I got lost trying to troubleshoot because _LoadCertFromBlob is marked [MethodImpl(MethodImplOptions.InternalCall)].

System.Security.Cryptography.CryptographicException: The system cannot find the file specified.
  at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)
  at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)
  at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)
  at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)

EDIT: The blob is a true PKCS#12 generated by BouncyCastle for C# containing a RSA private key and certificate (either self-signed or recently enrolled with a CA) -- what I'm trying to do is convert the private key and certificate from the BouncyCastle library to the System.Security.Cryptography library by exporting from one and importing to the other. This code works on the vast majority of systems it's been tried on; I've just never seen that particular error thrown from that constructor. It may be some sort of environmental weirdness on that one box.

EDIT 2: The error is occurring in a different environment in a different city, and I'm unable to reproduce it locally, so I may end up having to chalk it up to a broken XP installation.

Since you asked, though, here is the fragment in question. The code takes a private key and certificate in BouncyCastle representation, deletes any previous certificates for the same Distinguished Name from the personal key store, and imports the new private key and certificate into the personal key store via an intermediate PKCS#12 blob.

// 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();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

宣告ˉ结束 2024-10-02 15:17:49

您有 PKCS#12 还是 PFX 文件?在 Microsoft 世界中,情况是相同的,但其他人则有不同的想法(请参阅 此存档页面)。

您可以尝试以下操作

X509Certificate2 cert = X509Certificate2(byte[] rawData, "password");
X509Certificate2 cert2 = X509Certificate2(byte[] rawData, "password",
              X509KeyStorageFlags.MachineKeySet |
              X509KeyStorageFlags.PersistKeySet |
              X509KeyStorageFlags.Exportable);

(X509Certificate2(Byte[]))或

X509Certificate2 cert = X509Certificate2("C:\Path\my.pfx", "password");

(请参阅X509Certificate2(String, String)导入(字符串、字符串、 ) 在 Microsoft Docs 上,如果您需要使用一些标志)

更新:这将是如果您插入代码片段而不仅仅是异常堆栈跟踪,则会很有帮助。

您使用哪种X509KeyStorageFlags?您可以使用进程监视器来找出哪个文件找不到X509Certificate2 构造函数。例如,出现问题的 Windows XP 上的当前用户可能没有默认密钥容器。您可以创建它并重试导入。

Do you have PKCS#12 or just PFX-file? In the Microsoft world it is the same, but other think another (see this archived page).

You can try just following

X509Certificate2 cert = X509Certificate2(byte[] rawData, "password");
X509Certificate2 cert2 = X509Certificate2(byte[] rawData, "password",
              X509KeyStorageFlags.MachineKeySet |
              X509KeyStorageFlags.PersistKeySet |
              X509KeyStorageFlags.Exportable);

(X509Certificate2(Byte[])) or

X509Certificate2 cert = X509Certificate2("C:\Path\my.pfx", "password");

(see X509Certificate2(String, String) and Import(String, String, X509KeyStorageFlags) on Microsoft Docs if you need use some flags)

UPDATED: It would be helpful if you insert a code fragment and not only the exception stack trace.

Which X509KeyStorageFlags do you use? You can use Process Monitor to find out which file could not find the X509Certificate2 constructor. It can be for example that there are no default key container for the current user on the Windows XP having the problem. You can create it and retry the import.

惯饮孤独 2024-10-02 15:17:49

我遇到了同样的问题。

根据这篇旧知识库文章问题是构造函数尝试将证书加载到当前用户的配置文件中,但是我正在模拟用户的.Net 代码,因此它没有加载用户配置文件。构造函数需要加载的用户配置文件才能正常工作。

来自文章:

X509Certificate2 类构造函数尝试将证书导入到应用程序运行所在的用户帐户的用户配置文件中。很多时候,ASP.NET 和 COM+ 应用程序会模拟客户端。当他们这样做时,出于性能原因,他们不会加载模拟用户的用户配置文件。因此,他们无法访问模拟用户的“用户”证书存储。

加载用户配置文件修复了该错误。

I ran into the same issue.

According to this old KB article the problem was that the constructor tries to load the cert into the current user's profile, but the .Net code I was impersonating the user and so it had not loaded the user profile. The constructor requires the loaded user profile to work properly.

From the article:

The X509Certificate2 class constructors attempt to import the certificate into the user profile of the user account that the application runs in. Many times, ASP.NET and COM+ applications impersonate clients. When they do, they do not load the user profiles for the impersonated user for performance reasons. So, they cannot access the "User" certificate store for the impersonated user.

Loading the user profile fixed the error.

逆流 2024-10-02 15:17:49

我也有同样的问题。

  1. 在托管站点的服务器上打开 IIS。
  2. 找到该站点的应用程序池。
  3. 单击高级设置。
  4. 将“加载用户配置文件”更改为 true。 (可能需要重新启动或重新引导)

这允许 加密子系统 工作。

< img src="https://i.sstatic.net/RVRB9.png" alt="在此处输入图像描述">

I had this same problem.

  1. Open IIS on the server hosting the site.
  2. Find the application pool for the site.
  3. Click Advanced Settings.
  4. Change "Load User Profile" to true. (may require restart or reboot)

This allows the crypto subsystem to work.

enter image description here

我是有多爱你 2024-10-02 15:17:49

在 Windows 2012 上的 Web 应用程序中遇到此问题,将应用程序池选项 Load User Profile 设置为 true 可以使其工作。

为此,请运行 inetmgr.exe,转到正确应用程序池的高级设置,在进程模型下更改加载用户配置文件为真。

Running into this in an web application on Windows 2012, Setting application pool option Load User Profile to true made it work.

To do this, run inetmgr.exe, go to Advanced Settings for the right application pool, change Load User Profile under Process Model to true.

南薇 2024-10-02 15:17:49

我有完全相同的问题。当在特定用户下运行时,相同的代码和数据/证书在 Windows 2003 x86 上运行良好,但在另一个帐户(也用于运行 IIS 应用程序池)下失败。

显然,其他一些事情耗尽了 Windows 上的资源,因此失败的用户无法真正加载用户的配置文件(他的桌面看起来很奇怪),尽管事件查看器中没有相关事件

重新启动暂时解决了问题。虽然这不是问题的永久解决方案,但它表明还有其他东西(例如,COM+ 组件、本机代码服务等)消耗了资源,需要进行调查。这也说明了Windows平台的不稳定...

I had exactly the same problem. The same code and data/certs ran fine on Windows 2003 x86 when running under a specific user, but failed under another account (which was also used for running IIS app pools).

Apparently, some other thing exhausted resources on Windows, so that the failing user could not really load the user's profile (his desktop was weird-looking), although there were no related events in Event Viewer.

A reboot solved the problem temporarily. Although this is no permanent solution to the problem, it shows that there's something else (eg, COM+ components, native code services, etc) consuming resources that needs to be investigated. It also shows the instability of Windows platforms...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文