在 C# 中导入证书时,`PersistKeySet`-StorageFlag 的影响是什么

What is the impact of the `PersistKeySet`-StorageFlag when importing a Certificate in C#

在我的应用程序中,使用以下代码以编程方式将客户端身份验证证书添加到 MY-Store:

//certData is a byte[]
//password is a SecureString
X509Certificate2 certificate = new X509Certificate2(certData, password, X509KeyStorageFlags.Exportable);
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
try
{
    store.Open(OpenFlags.ReadWrite);
    store.Add(certificate);
}
finally
{
    store.Close();
}

使用此代码,证书已正确导入我测试的所有机器上的 MY-Store(指纹和证书链也正确)。

但在某些机器上(Windows 7 Professional SP1 和 Widnows Server 2008 R2 具有本地用户帐户)证书之后无法用于客户端身份验证("Could not establish trust relationship for the SSL/TLS secure channel" )。 在具有域用户帐户的 Windows 8.1 企业计算机上,身份验证有时有效,但并非总是有效。

我拼命尝试了几件事,最后找到了将 X509KeyStorageFlags.PersistKeySet 添加到存储标志的解决方案。 所以第一行现在是:

X509Certificate2 certificate = new X509Certificate2(certData, password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);

有了这些标志,证书就可以在所有设备上使用。 尽管我很高兴我的应用程序现在可以按预期方式运行,但我想了解 为什么 ? PersistKeySet-Flag 到底做了什么,为什么它会影响证书的使用时间和使用人?

MSDN 在这种情况下不是很有帮助。

导入 PFX 时,public 证书元素被加载到内存中,私钥 material 被保存到密钥存储提供程序中。 .NET 中的默认行为是在处置 X509Certificate2 对象(或其资源正在通过垃圾收集完成)时删除私钥 material。 PersistKeySet 标志阻止此清理发生。

如果要添加到持久化证书存储区,则始终要设置 PersistKeySet。当不添加到持久存储时,您很可能不希望设置它。

如果您的导入过程是长期存在的,那么您会看到的行为是在导入后的任意时间对私钥的新访问开始失败。如果它是短暂的,那么它可能总是无法工作。

据我所知,如果指定 PersistKeySet 标志,它会将导入的 PFX 的私钥保存在磁盘上,与导出的 PFX 的来源证书(userkeyset 或 machinekeyset)的位置相同).如果 PFX 是由工具生成的(例如 pvk2pfx.exe),则没有源并且使用默认值(userkeyset)。

在这种情况下,如果作为导出PFX源的证书的私钥存储在machinekeyset,那么私钥将在machinekeyset导入,这里:\ProgramData\Microsoft\Crypto\RSA\MachineKeys.

否则,它将存储在userkeyset,这里: \Users\user\AppData\Roaming\Microsoft\Crypto\RSA\S-1-....

如果您希望您的证书在整个计算机上可用,而不考虑 PFX 的原始位置,您可能需要考虑改用 MachineKeySet