在C#中导入证书时,`PersistKeySet`存储标志的影响是什么?

19
在我的应用程序中,使用以下代码以编程方式将客户端认证证书添加到MY-存储中:

在我的应用程序中,使用以下代码以编程方式向MY存储添加客户端认证证书:

//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存储区(指纹和认证链也正确)。

但是在某些计算机上(具有本地用户帐户的Windows 7 Professional SP1和Widnows Server 2008 R2),证书后来无法用于客户端身份验证(“无法建立 SSL/TLS 安全通道的信任关系”)。 在一个具有域用户帐户的 Windows 8.1 Enterprise 计算机上,有时会进行身份验证,但并非总是如此。

我拼命尝试了几件事情,最终发现添加X509KeyStorageFlags.PersistKeySet到存储标志中可以解决问题。 因此,第一行现在为:

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

有了这些标志,证书可以在所有设备上使用。 虽然我很高兴我的应用程序现在可以按预期工作,但我想知道为什么? PersistKeySet标志到底是做什么的?它为什么会影响证书能够何时以及由谁使用?

在这种情况下,MSDN并没有提供太多帮助。


1
可能与密钥安装在临时容器而不是永久容器中有关。请参阅此处的详细信息:https://support.microsoft.com/en-gb/kb/950090 - momar
2个回答

27

导入PFX时,公钥证书元素被加载到内存中,私钥材料被存储到键存储提供程序中。.NET的默认行为是在X509Certificate2对象被Dispose(或其资源通过垃圾回收被终止)时删除私钥材料。 PersistKeySet标志可防止发生此清理。

如果您要添加到持久化证书存储中,则始终要设置PersistKeySet。如果不添加到持久存储中,则很可能不需要设置。

如果您的导入过程长时间存在,则会看到在导入之后的任意时间,新访问私钥将开始失败。如果它的存在时间较短,则可能始终无法正常工作。


1
非常有帮助,谢谢!你有可靠的资源可以给我吗? - Florian-Rh
4
https://support.microsoft.com/en-us/kb/950090 描述了未能使用 PersistKeySet 的故障情况;https://github.com/dotnet/corefx/issues/8186 描述了当前两种导入模式的对比,以及一个提出的第三种模式;.NET Core 实现可以在 https://github.com/dotnet/corefx 上找到(.NET Framework 版本在虚拟机内处理,因此不在 ReferenceSource 上)。 - bartonjs

3
在我的理解中,如果指定了 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

您知道证书中哪个属性指示了它被导出的位置吗? - AlphaKilo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接