我正在尝试读取第三方服务提供商与我共享的证书的私钥,因此我可以使用它来加密一些 XML,然后再通过网络将其发送给他们。我在 C# 中以编程方式这样做,但我认为这是一个权限或配置错误的问题,所以我将专注于似乎最相关的事实:
- 我认为这个问题与代码无关;我的代码可以在其他计算机上运行,并且该问题会影响 Microsoft 的示例代码。
- 该证书以 PFX 文件的形式提供,仅用于测试目的,因此它还包括一个虚拟证书颁发机构。
- 使用 MMC.exe,我可以将证书导入本地计算机的个人存储中,然后将私钥的权限授予所有相关帐户,并将证书颁发机构拖放到受信任的根证书颁发机构中。
- 使用 C#,我可以加载证书(由其指纹识别)并使用
X509Certificate2.HasPrivateKey
. 但是,尝试读取密钥会导致错误。在 .NETCryptographicException
中,在尝试访问属性时会抛出消息“指定的提供程序类型无效”X509Certificate2.PrivateKey
。在 Win32 中,调用该方法CryptAcquireCertificatePrivateKey
会返回等效的 HRESULTNTE_BAD_PROV_TYPE
,. - 这与使用 Microsoft 自己的两个代码示例读取证书的私钥时也会发生的异常相同。
- 在当前用户的等效存储中(而不是本地计算机)安装相同的证书,可以成功加载私钥。
- 我在具有本地管理员权限的 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 卸载证书,删除所有看起来像孤立私钥的文件,然后重新安装证书并重试?
- 还有其他我应该尝试手动删除的文件吗?
- 还有什么我应该尝试的吗?
更新 - 添加了显示尝试读取私钥的代码示例:
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();
}