"无效的提供者类型指定" CryptographicException当尝试加载证书的私钥 [英] "Invalid provider type specified" CryptographicException when trying to load private key of certificate

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

问题描述

我要看书已经由第三方服务供应商与我分享证书的私钥,这样我就可以使用它通过线路发送到之前加密一些XML。我这样做C#编程,但我认为这是一个权限或配置的问题,所以我将重点放在这似乎是最相关的事实:




  • 我不认为这个问题是与代码相关的;我的代码工作在其他计算机上,这个问题从微软影响的示例代码。

  • 的证书是作为一个PFX文件提供,仅用于测试目的,所以它也包括一个虚拟的权威认证

  • 使用MMC.EXE,我可以将证书导入个人存储在本地计算机上的私钥权限授予所有相关账户,拖放权威认证之前到受信任的根证书颁发机构。

  • 使用C#,我可以加载的证书(由它的指纹识别),并验证它使用私钥 X509Certificate2.HasPrivateKey 。然而,试图读取密钥导致错误。在.NET中的 CryptographicException 被抛出的消息后,试图访问属性 X509Certificate2.PrivateKey 。在Win32中,调用方法 CryptAcquireCertificatePrivateKey 返回相等的HRESULT, NTE_BAD_PROV_TYPE

  • 这是使用两个微软自己的代码示例时,读取该证书的私钥也发生了同样的异常。

  • 安装在等效店相同的证书为当前用户,而不是本地计算机的,允许成功加载私钥。

  • 我在Windows 8.1中使用本地管理员权限,而且我已经试过在正常和高架上运行我的代码模式。在Windows 7和Windows 8的同事们已经能够加载从本地计算机存储的密钥相同的证书。

  • 我可以成功读取自签名的IIS测试证书的私钥,这是在同一个存储位置。

  • 我已经针对.NET 4.5(这个错误已经报道了一些旧版本的框架)。

  • 我不认为这是证书模板的一个问题,因为我预料到同时影响本地计算机和当前用户的商店一样?



与我的同事,我已经由多个以前曾试图卸载并以各种方式重新安装证书,包括通过IIS管理器,还包括来自同一发行人的旧证书。我看不出在MMC旧的或重复的证书任何痕迹。不过,我确实有它的基础上,最后写入时间相同大小的许多私人密钥文件,一定是我的各种尝试安装后遗留下来的。这些在以下位置,为本地计算机和当前用户分别专卖店:



C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys



C:的\Users\\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21- [休息用户ID]



所以,任何人都可以请告知是否:




  • 这是一个好主意,使用MMC卸载证书,删除所有那些看起来孤立的私钥文件,然后重新安装证书,然后再试一次?

  • 有任何其他的文件,我应该尝试?手动删除

  • 还有什么我应该尝试



更新 - 增加了一个码显示尝试读取私钥示例:

 静态无效的主要()
{
//试图读取从这里装载证书后私钥时出现例外情况:
的X509Store店=新的X509Store(MY,StoreLocation.LocalMachine);如果证书被安装,并从那里,这里装不会发生
//异常:
//的X509Store商店=新的X509Store(MY,StoreLocation.CurrentUser);

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

X509Certificate2Collection集合=(X509Certificate2Collection)store.Certificates;
X509Certificate2Collection fcollection =(X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid,DateTime.Now,FALSE);
X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(fcollection,测试证书选择,从以下列表中的证书来获得上证信息,X509SelectionFlag.MultiSelection);
Console.WriteLine(证书号:{0} {1},scollection.Count,Environment.NewLine);

的foreach(X509Certificate2 X509在scollection)
{

{
Console.WriteLine(密码:{0},x509.HasPrivateKey ?x509.PrivateKey.ToXmlString(假):[N / A]);
x509.Reset();
}
赶上(CryptographicException前)
{
Console.WriteLine(ex.Message);
}
}
store.Close();

到Console.ReadLine();
}


解决方案

该链接的亚历杭德罗的博客是关键。



我相信这是因为该证书存储在您的机器与CNG(加密下一代)API上。旧的.NET API与其不兼容,所以这是行不通的。



您可以使用Security.Cryptography包装该API(的available Codeplex上)。这增加了扩展方法 X509证书/ X509Certificate2 ,所以你的代码看起来是这样的:

 使用Security.Cryptography.X509Certificates; //获取扩展方法

x509证书证书; //填充从别的地方...
如果(cert.HasCngKey())
{
VAR privateKey = cert.GetCngPrivateKey();
}
,否则
{
VAR privateKey = cert.PrivateKey;
}



不幸的是,CNG私钥的对象模型是有点不同。我不知道,如果你可以在你的原始代码示例中导出到XML一样......在我来说,我只需要签署与私钥的一些数据。


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:

  • 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?

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:\ProgramData\Microsoft\Crypto\RSA\MachineKeys

c:\Users\\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-[rest of user ID]

So, can anyone please advise whether:

  • It's a good idea to uninstall the certificate using MMC, delete all those files which look like orphaned private keys, and then re-install the certificate and try again?
  • There any other files which I should try to manually delete?
  • There's anything else I should try?

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

解决方案

The link to Alejandro's blog is key.

I believe this is because the certificate is stored on your machine with the CNG ("Crypto Next-Generation") API. The old .NET API is not compatible with it, so it doesn't work.

You can use the Security.Cryptography wrapper for this API (available on Codeplex). This adds extension methods to X509Certificate/X509Certificate2, so your code will look something like:

using Security.Cryptography.X509Certificates; // Get extension methods

X509Certificate cert; // Populate from somewhere else...
if (cert.HasCngKey())
{
    var privateKey = cert.GetCngPrivateKey();
}
else
{
    var privateKey = cert.PrivateKey;
}

Unfortunately the object model for CNG private keys is quite a bit different. I'm not sure if you can export them to XML like in your original code sample...in my case I just needed to sign some data with the private key.

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

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆