可以像自签名根 CA 一样信任中间 CA 吗?

信息安全 tls 证书 公钥基础设施 证书颁发机构 x.509
2021-08-11 12:39:51

是否可以在 X.509 规范的限制范围内将中间 CA 标记为受信任用于特定目的,例如验证 VPN、HTTPS 等服务器密钥,就像它与根 CA 一起工作一样?

我的 VPN 客户端都有办法明确提供受信任的 CA 证书,用于验证 VPN 服务器的真实性。只要我提供根 CA 证书,就可以按预期工作 - 证书是受信任的。(中间证书作为 TLS 握手的一部分提供。)

但是,我使用的是中间 CA,并且非常希望提供该证书,而不是根 CA。在我对 X.509 的理解中,这应该有效:

VPN 服务器的密钥由中间 CA 签名,据我了解 X.509,这就是建立可信链所需的全部内容。

但实际上,它不起作用:我的 VPN 客户端无法连接。

除了 VPN,我还尝试了 802.1X/EAPOL 身份验证和多个客户端 - 结果相同:向客户端提供根 CA 证书是可行的;提供我的中间 CA 证书不会。

这是设计使然,还是只是大多数实现的工作方式?

(我使用基于 TLS 的 VPN,但我也尝试过使用 802.1X 和 TTLS,它似乎与 TLS 或 X.509 有关,而不是与我特定的 VPN 客户端/服务器架构有关。)

更新: 我喜欢OpenSSL 提交,它实现了将非自签名 CA 证书添加为信任锚。不幸的是,这还没有包含在任何发布版本中,因此评论中提出的所有解决方法仍然适用。

更新 2: OpenSSL 现在在发布版本中包含此选项,从 1.0.2 开始。命令行客户端的相应标志是partial_chain,而编程标志似乎是X509_V_FLAG_PARTIAL_CHAIN

此外,我最近不得不用 Java 验证服务器证书:至少在 Sun JSSE 提供者的 SSL 实现的 JDK 1.8 版本中,在TrustManager没有任何特殊配置的情况下将叶证书添加到默认工作,并且验证成功,就好像根 CA 已经假如。

4个回答

根 CA实际上是一种错觉X.509中,有信任锚信任锚主要是名称和公钥,您先验地知道并信任它们。将该名称和该公钥表示为“证书文件”(传统上是自签名)只是将信任锚保持为一堆字节的便捷方式。

根据 X.509,CA 只有在您不先验地信任它时才是“中间”;它不是 CA 的固有属性。您需要做的是说服您的软件将 CA 视为信任锚。一种可能的技巧是将相关数据(CA 名称和公钥)重新编码为(据称)自签名证书。请注意,自签名只是一个传统;它之所以存在,主要是因为证书的文件格式具有签名的必填字段。对于“根”CA,这个签名没有意义(验证它没有什么意义,因为它不会给你带来任何安全方面的东西)。因此,使用根 CA 证书的应用程序很少验证签名是“自我”的。

因此,您可以构建一个自定义的“自签名”证书,并将您的“中间 CA”的名称作为SubjectDNIssuerDN. 对于签名,只需放置大约正确大小的随机垃圾字节(256 字节用于 2048 位签名)。然后,尝试将此伪自签名证书设置为根:它可能会与您的 VPN 一起使用。或者,创建您自己的根 CA,并为中间 CA 发出一个额外的证书(您不需要中间 CA 的合作,您只需要它的名称和公钥,并且您在中间 CA 证书中拥有这些)。

根据关于证书验证的 RFC - RFC 3280 - 第 6.2 节:

选择一个或多个受信任的 CA 是本地决定。系统可以提供其任何一个受信任的 CA 作为特定路径的信任锚。对于每条路径,路径验证算法的输入可能不同。用于处理路径的输入可以反映特定于应用程序的要求或对授予特定信任锚的信任的限制。例如,受信任的 CA 可能仅对特定的证书策略受信任。这个限制可以通过路径验证过程的输入来表达。

然而,您最终可能会遇到一些严重的痛苦 - 例如,如果 CA 证书中的策略扩展表明它必须由 CRL 或 OSCP 验证 - 那么您的应用程序可能会合法挂起,而它不能找到根 CA 以验证此过程的某些部分——例如,CRL 可能由根 CA 签名,因此如果信任存储中没有根 CA,则应用程序可能无法处理这种情况。

看起来,根据 RFC,您应该能够设置可以充当信任锚的中间 CA 证书,并且您应该能够创建一组有效的策略设置。但是,我可以根据经验说,您已经进入了“也许”的可疑领域。您在这里提出了一个非典型的非标准配置。大多数情况下,这里使用根 CA,因为它是最高级别的东西,从长远来看,配置信任锚通常很麻烦,人们很乐意使用最高的受信任权力并避免任何需要添加新的随着时间的推移,应用程序的 CA。正确设置策略扩展并让应用程序运行的领域是 Advanced PKI Vodoo - 错误消息通常是荒谬的,

听起来可能是一个实施缺陷,而不是一个深思熟虑的设计决定。

从概念上讲,如果您将中间 CA 证书添加到您的信任锚集(您信任的 CA,因此将接受由他们签名的内容),那么客户端应该愿意接受由该 CA 签名的其他证书,即使该 CA 是不是链中的根。对于客户的行为而言,这将是一种非常合理的方式。但是,这可能是一个不太常见的用例,并且应用程序开发人员没有考虑到,因此他们的代码可能碰巧不支持它。这就是生活。

该系统正在按预期工作。根据定义,中间证书由客户端和根 CA 的证书之间的信任颁发并依赖于信任关系。根 CA 是自签名并受客户端信任,中间 CA 由根 CA 签名。

简单来说,中间 CA 说“嘿,我是 CA,你可以信任我,因为我是由你已经信任的根 CA 签名的”。客户端然后查看他们是否确实信任根 CA,如果已建立信任关系,则验证证书层次结构(证书链)并且可以使用证书。

通过使用某些字段和方法(证书模板、OID、增强密钥使用字段等),您可以指定给定证书的用途,但整个方案依赖于信任证书链根的客户端。