尝试加载证书的私钥时出现

尝试加载证书的私钥时出现

本文介绍了“指定的提供程序类型无效"尝试加载证书的私钥时出现 CryptographicException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试读取第三方服务提供商与我共享的证书的私钥,因此我可以使用它来加密一些 XML,然后再通过网络将其发送给他们.我在 C# 中以编程方式执行此操作,但我认为这是权限或配置错误的问题,因此我将重点关注似乎最相关的事实:

I'm trying to read the private key of a certificate which has been shared with me by a third-party service provider, so I can use it to encrypt some XML before sending it to them over the wire. I'm doing so programmatically in C#, but I think this is a permissions or misconfiguration issue, so I'll focus on the facts which seem to be most relevant:

  • 我认为这个问题与代码无关;我的代码可以在其他计算机上运行,​​并且该问题会影响 Microsoft 的示例代码.
  • 证书以 PFX 文件的形式提供,仅用于测试目的,因此它还包含一个虚拟证书颁发机构.
  • 使用 MMC.exe,我可以将证书导入本地计算机的个人存储中,然后将私钥的权限授予所有相关帐户,并将证书颁发机构拖放到受信任的根证书颁发机构中.
  • 使用 C#,我可以加载证书(由其指纹识别)并使用 X509Certificate2.HasPrivateKey 验证它是否具有私钥.但是,尝试读取密钥会导致错误.在 .NET 中,当尝试访问属性 X509Certificate2.PrivateKey 时,会引发 CryptographicException 并显示消息指定的提供程序类型无效".在 Win32 中,调用方法 CryptAcquireCertificatePrivateKey 返回等效的 HRESULT,NTE_BAD_PROV_TYPE.
  • 使用 Microsoft 自己的两个代码示例读取证书的私钥时也会出现同样的异常.
  • 在当前用户的等效存储中(而不是本地计算机)安装相同的证书,可以成功加载私钥.
  • 我使用的是具有本地管理员权限的 Windows 8.1,并且我尝试在正常模式和提升模式下运行我的代码.使用 Windows 7 和 Windows 8 的同事已经能够从本地机器存储中加载相同证书的密钥.
  • 我可以成功读取自签名 IIS 测试证书的私钥,该证书位于同一存储位置.
  • 我已经针对 .NET 4.5(一些旧版本的框架报告了此错误).
  • 我不认为这是证书模板的问题,因为我希望这会同样影响本地计算机和当前用户存储?
  • I don't think this issue is code-related; my code works on other computers, and the issue affects sample code from Microsoft.
  • The certificate was provided as a PFX file and is just for test purposes, so it also includes a dummy certification authority.
  • Using MMC.exe, I can import the certificate into the personal store for the local machine, before granting permissions on the private key to all relevant accounts, and dragging and dropping the certification authority into the Trusted Root Certification Authorities.
  • Using C#, I can load the certificate (identified by its thumbprint) and verify that it has a private key using X509Certificate2.HasPrivateKey. However, trying to read the key causes an error. In .NET a CryptographicException is thrown with the message "Invalid provider type specified" upon trying to access the property X509Certificate2.PrivateKey. In Win32, calling the method CryptAcquireCertificatePrivateKey returns the equivalent HRESULT, NTE_BAD_PROV_TYPE.
  • This is the same exception which also occurs when using two of Microsoft's own code samples to read the private key of the certificate.
  • Installing the same certificate in the equivalent store for the current user, instead of the local machine, allows the private key to be successfully loaded.
  • I'm on Windows 8.1 with local administrator rights, and I've tried running my code in both normal and elevated modes. Colleagues on Windows 7 and Windows 8 have been able to load the key from the local machine store for the same certificate.
  • I can successfully read the private key of the self-signed IIS test certificate, which is in the same store location.
  • I am already targeting .NET 4.5 (this error has been reported with some older versions of the framework).
  • I don't think this is a problem with certificate templates, because I would expect that to affect both the local machine and current-user stores equally?

与我的同事不同,我之前曾多次尝试以各种方式卸载和重新安装证书,包括通过 IIS 管理器以及来自同一颁发者的旧证书.我在 MMC 中看不到任何旧证书或重复证书的痕迹.但是,我确实有许多大小相同的私钥文件,根据最后一次写入时间,在我进行各种安装尝试后,这些文件肯定被遗忘了.这些位于以下位置,分别用于本地计算机和当前用户存储:

Unlike my colleagues, I have made multiple previous attempts to uninstall and re-install the certificate in various ways, including via IIS Manager and also including an older certificate from the same issuer. I can't see any traces of old or duplicate certificates in MMC. However, I do have many private key files of identical size which, based on the last-write time, must have been left behind after my various installation attempts. These are found at the following locations, for the local machine and current user stores respectively:

c:ProgramDataMicrosoftCryptoRSAMachineKeys

c:ProgramDataMicrosoftCryptoRSAMachineKeys

c:Users\AppDataRoamingMicrosoftCryptoRSAS-1-5-21-[其余用户 ID]

c:Users\AppDataRoamingMicrosoftCryptoRSAS-1-5-21-[rest of user ID]

那么,谁能告诉我是否:

So, can anyone please advise whether:

  • 最好使用 MMC 卸载证书,删除所有看起来像孤立私钥的文件,然后重新安装证书并重试?
  • 还有其他我应该尝试手动删除的文件吗?
  • 还有什么我应该尝试的吗?

更新 - 添加了显示尝试读取私钥的代码示例:

UPDATE - Added a code sample showing an attempt to read a private key:

static void Main()
{
    // Exception occurs when trying to read the private key after loading certificate from here:
    X509Store store = new X509Store("MY", StoreLocation.LocalMachine);
    // Exception does not occur if certificate was installed to, and loaded from, here:
    //X509Store store = new X509Store("MY", StoreLocation.CurrentUser);

    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

    X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
    X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
    X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(fcollection, "Test Certificate Select", "Select a certificate from the following list to get information on that certificate", X509SelectionFlag.MultiSelection);
    Console.WriteLine("Number of certificates: {0}{1}", scollection.Count, Environment.NewLine);

    foreach (X509Certificate2 x509 in scollection)
    {
        try
        {
            Console.WriteLine("Private Key: {0}", x509.HasPrivateKey ? x509.PrivateKey.ToXmlString(false) : "[N/A]");
            x509.Reset();
        }
        catch (CryptographicException ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
    store.Close();

    Console.ReadLine();
}

推荐答案

我最近收到了两个新证书,在 Windows 8 和 Server 2012/2012 R2 上遇到了同样的问题.在 Windows 10 上,问题不再发生(但这对我没有帮助,因为在服务器上使用了操作证书的代码).虽然 Joe Strommen 的解决方案原则上可行,但不同的私钥模型将需要对使用证书的代码进行大量更改.我发现更好的解决方案是将私钥从 CNG 转换为 RSA,正如 Remy Blok 这里.

I had the same problem on Windows 8 and Server 2012/2012 R2 with two new certificates I recently received. On Windows 10, the problem no longer occurs (but that does not help me, as the code manipulating the certificate is used on a server). While the solution of Joe Strommen in principle works, the different private key model would require massive change to the code using the certificates. I find that a better solution is to convert the private key from CNG to RSA, as explained by Remy Blok here.

Remy 使用 OpenSSL 和两个较旧的工具来完成私钥转换,我们希望将其自动化并开发了一个仅限 OpenSSL 的解决方案.给定 MYCERT.pfx 和 CNG 格式的私钥密码 MYPWD,这些是在 RSA 中使用私钥获取新 CONVERTED.pfx 的步骤格式和密码:

Remy uses OpenSSL and two older tools to accomplish the private key conversion, we wanted to automate it and developed an OpenSSL-only solution. Given MYCERT.pfx with private key password MYPWD in CNG format, these are the steps to get a new CONVERTED.pfx with private key in RSA format and same password:

  1. 提取公钥,完整的证书链:
OpenSSL pkcs12 -in "MYCERT.pfx" -nokeys -out "MYCERT.cer" -passin "pass:MYPWD"
  1. 提取私钥:
OpenSSL pkcs12 -in "MYCERT.pfx" -nocerts -out "MYCERT.pem" -passin "pass:MYPWD" -passout "pass:MYPWD"
  1. 将私钥转换为 RSA 格式:
OpenSSL rsa -inform PEM -in "MYCERT.pem" -out "MYCERT.rsa" -passin "pass:MYPWD" -passout "pass:MYPWD"
  1. 将公钥与 RSA 私钥合并到新的 PFX:
OpenSSL pkcs12 -export -in "MYCERT.cer" -inkey "MYCERT.rsa" -out "CONVERTED.pfx" -passin "pass:MYPWD" -passout "pass:MYPWD"

如果您加载转换后的 pfx 或将其导入 Windows 证书存储区,而不是 CNG 格式的 pfx,则问题消失,C# 代码无需更改.

If you load the converted pfx or import it in the Windows certificate store instead of the CNG format pfx, the problem goes away and the C# code does not need to change.

我在自动执行此操作时遇到的另一个问题:我们使用生成的长密码作为私钥,并且密码可能包含 ".对于 OpenSSL 命令行,密码中的 " 字符必须转义为 "".

One additional gotcha that I encountered when automating this: we use long generated passwords for the private key and the password may contain ". For the OpenSSL command line, " characters inside the password must be escaped as "".

这篇关于“指定的提供程序类型无效"尝试加载证书的私钥时出现 CryptographicException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 16:23