所有不同的 X509KeyStorageFlags 的基本原理是啥?

Posted

技术标签:

【中文标题】所有不同的 X509KeyStorageFlags 的基本原理是啥?【英文标题】:What is the rationale for all the different X509KeyStorageFlags?所有不同的 X509KeyStorageFlags 的基本原理是什么? 【发布时间】:2019-03-15 22:50:24 【问题描述】:

今天,一位同事遇到了另一个与这些相关的错误!过去我发现这些标志非常令人沮丧,因为如果您在实例化 X509Certificate2 对象、导出它们或将它们保存在 X509Store 中时稍微弄错了它们,您可能会遇到各种奇怪的错误,例如:

出乎意料地无法告诉 NETSH.exe 或 ASP.net [通过其指纹] 使用某个 SSL 证书,即使您的机器存储中有该证书 出乎意料的是,您可以导出证书数据,但使用 .Export() 在没有私钥的情况下导出它 出乎意料的是,您的单元测试在较新的 Windows 版本上开始失败,显然是因为您没有使用正确的标志

是的,它们都被记录在案了(而且有些文档似乎很有意义),但为什么要这么复杂呢?

【问题讨论】:

安全,安全,安全。不同的证书有不同的用途,所有标志都旨在帮助各种用途。您碰巧只使用 IIS/ASP.NET 的服务器证书,因此您会发现一些标志/行为“出乎意料”。然而,其他人可以很容易地发现它们有用和关键。所以不会有合适的答案。 @Lex Li 嗯,是的,我想它应该有助于安全......我只是不太明白如何。这可能就是为什么我倾向于猜错标志的原因。哦,这是否意味着我使用错误的标志编写了安全漏洞? 不幸的是,是的。如果您使用错误的标志,则可能存在安全问题。例如,某些证书必须使用不可导出的私钥安装(与您的情况不同),如果您使用可导出的私钥安装它们,则可能会在您眼皮子底下发生损坏。迭代确切的场景并不容易,但如果您碰巧认识具有安全背景的人,您可能会咨询并了解更多信息。 SO 太宽泛了。 【参考方案1】:

主要是,今天必须这么复杂,因为昨天这么复杂,没有人想出更简单的方法。

我无法在这里提出线性叙述,所以请忍受需要的来回编织。

什么是 PFX/PKCS#12 文件?

虽然我不能完全说明 PFX 的起源是什么,但在 Windows 函数的名称中有一个线索可以读取和写入它们:PFXImportCertStore 和 PFXExportCertStore。它们包含许多可以使用属性标识符相互关联的独立实体(证书、私钥和其他东西)。它们似乎被设计为整个证书存储的导出/导入机制,就像所有 CurrentUser\My.但由于一种存储是“内存存储”(任意集合),.NET 导入/导出是有意义的,但会出现一些复杂情况(来自 .NET 之前)。

Windows 私钥

Windows 支持许多不同位置的私钥,但对于旧式加密 API,它们归结为 4 部分寻址方案:

加密提供者的名称 密钥容器的名称 这是机器相关密钥还是用户相关密钥的标识符 这是“签名”密钥还是“交换”密钥的标识符。

这已简化为 CNG 的 3 部分方案:

存储引擎的名称 密钥的名称 这是机器相关密钥还是用户相关密钥的标识符。

为什么需要机器或非机器标识符?

CAPI 和 CNG 都支持直接与命名键交互。因此,您创建了一个名为“EmailDecryption”的密钥。系统上的另一个用户创建了一个同名的密钥。那应该工作吗?我们可能会。所以,huzzah,确实如此!单独的键,因为它们保存在与创建它们的用户相关的上下文中。

但是现在您需要一个可供多个用户使用的密钥。这不是您通常想要的东西,所以它不是默认设置。这是一个选择。 CRYPT_MACHINE_KEYSET 标志诞生了。

我会继续说,我听说现在不鼓励直接使用命名键; CAPI/CNG 团队更喜欢以 GUID 命名的密钥,并且您可以通过证书存储与它们进行交互。但这是进化的一部分。

导入 PFX 有什么作用?

PFXImportCertStore 将所有证书从 PFX 复制到提供的存储中。它还导入(CryptImportKey 或 BCryptImportKey,取决于它认为需要什么)。然后,对于它导入的每个密钥,它(通过 PFX 中的属性值)找到匹配的证书,并在证书存储表示上设置一个属性为“这是我的 4 部分标识符”(CNG 密钥只是设置了第 4 个部分为 0);这就是证书所知道的关于其私钥的全部内容。

(PFX 是一种非常复杂的文件格式,如果没有使用任何“奇怪的部分”,则此描述是正确的)

密钥寿命

Windows 私钥永远存在,或者直到有人删除它们。

因此,当 PFX 导入它们时,它们将永远存在。如果您要导入 CurrentUser\My,这是有道理的。如果你做的事情是暂时的,那就没有意义了。

.NET 颠倒关系 / 让它“太容易”

Windows 设计(主要)是您与证书存储区交互,并从证书存储区获取证书。 .NET 较晚出现,并且(根据了解应用程序实际在做什么来推测)将证书作为***对象,并存储某种次要的东西。

因为 Windows 证书(实际上是“存储证书元素”)“知道”它们的私钥是什么,所以 .NET 证书“知道”它们的私钥是什么。

哦,但是 MMC 证书管理器说它可以使用其私钥导出证书(到 PFX 中),为什么证书构造函数不能接受除了“只是一个证书”格式之外的那些字节?好的,现在可以了。

协调生命周期

您打开一些字节作为 X509Certificate/X509Certificate2。这是一个“无密码”的 PFX(通过任何可能是真的方式)。您发现它是错误的,然后您将证书交给了垃圾收集器。该私钥永远存在,因此您的硬盘驱动器会慢慢填满,并且密钥存储访问变得越来越慢。然后你生气了,重新格式化你的电脑。

这看起来很糟糕,所以 .NET 所做的就是当证书(的一个字段)被垃圾收集(实际上,最终确定)它告诉 CAPI(或 CNG)删除密钥。现在事情按预期工作,对吧?好吧,只要程序没有异常终止。

哦,您已将其添加到持久存储中?但是在新的证书存储实体“知道”如何找到私钥之后,我将删除私钥。这似乎很糟糕。

输入X509KeyStorageFlags.PersistKeySet

PersistKeySet 说“不要这样做删除”。当您打算将证书添加到 X509Store 时。

如果您想在不指定标志的情况下获得相同的行为,请在导入后致电Environment.FailFast,或拔下计算机。

关于机器或用户位

在 .NET 中,您可以轻松地在一个集合中获取一包证书并在其上调用 Export。如果有些人有机器密钥,而另一些人有用户密钥怎么办? PFXExportCertStore 进行救援。导出机器密钥时,它会记下一个表明它是机器密钥的标识符,因此 import 会将其放回同一位置。

嗯,通常。也许您从一台机器上导出了机器密钥,而您只想在另一台机器上以非管理员身份检查它。好的,你可以指定CRYPT_USER_KEYSET aka X509KeyStorageFlags.UserKeySet

哦,您作为用户在一台机器上创建了它,但希望它作为另一台机器上的机器密钥?美好的。 CRYPT_MACHINE_KEYSET / X509KeyStorageFlags.MachineKeySet.

我真的需要“临时”文件吗?

如果您只是检查 PFX 文件,或者想临时使用它们,为什么还要费心将密钥写入磁盘呢?好的,Windows Vista 说,我们可以直接将私钥加载到加密密钥对象中,然后我们会告诉你指针。

PKCS12_NO_PERSIST_KEY/X509KeyStorageFlags.EphemeralKeySet

我想如果 Windows 在 NT4 中具有此功能,那么这将是 .NET 的默认设置。它现在不能成为默认值,因为太多的事情取决于“正常”导入如何检测私钥是否可用的内部机制。

最后两个呢?

PFXImportCertStore 的默认模式是私钥不能重新导出。要告诉它错误,您可以指定CRYPT_EXPORTABLE / X509KeyStorageFlags.Exportable

CAPI 和 CNG 都支持一种机制,其中软件密钥在使用私钥之前可能需要同意或密码(如智能卡的 PIN 提示),但您必须在首次创建(或导入)时声明) 钥匙。因此 PFXImportCertStore 允许您指定 CRYPT_USER_PROTECTED(而 .NET 将其公开为 X509KeyStorageFlags.UserProtected)。

最后两个确实只对“一个私钥”PFX 有意义,因为它们适用于所有密钥。它们也不包含原始密钥可能具有的全部选项...... CNG 和 CAPI 都支持“可归档”密钥,这意味着“可导出一次”。机器密钥上的自定义 ACL 在 PFX 中也得不到任何支持。

总结

对于证书(或证书集合),一切都很简单。一旦涉及到私钥,事情就会变得一团糟,Windows 证书(存储)的抽象会变得有点薄,您需要了解持久性模型和存储模型。

【讨论】:

哇,这是一个非常丰富和详细的答案。我希望我可以对它进行超过+1的投票。非常感谢您与大家分享这个! 哦,是的.. 赏金! 在使用 X509Certificate2.Install() 安装带有 X509KeyStorageFlags.PersistKeySet 和 X509KeyStorageFlags.MachineKeySet 标志的 pfx 文件时,您知道什么会导致稍后在某些机器上删除证书私钥吗?稍后是 2 个月或 1 天(可能在重新启动后,不确定)。

以上是关于所有不同的 X509KeyStorageFlags 的基本原理是啥?的主要内容,如果未能解决你的问题,请参考以下文章

我应该处理 X509Certificate2 吗?

X509证书未在服务器上加载私钥文件

Java X509 证书解析和验证

如何验证 x509 证书的签名?

x509的简介

是否可以创建没有签名字段的 x509 证书? [复制]