TLS 的哪一部分指定了如何验证证书链

信息安全 tls 证书 证书颁发机构
2021-08-13 20:31:24

我有时会遇到这样一种情况,即我看到一个根 CA 证书设置为比中间 CA 证书更早过期。

我的问题是 - 如果您有兴趣保持中间 CA 处于活动状态,并且需要更新它以引用新创建的根证书,那么中间 CA 需要更改吗?我相信这是颁发者字段,但这是否能够像某些 SAN 一样动态更新,或者您是否还需要更新中间 CA 证书?

我想这也可以概括为——证书在哪里指向你的签名人以及它是什么样的?

回答在握手过程中证书链在哪里呈现给客户端的奖励点,以及什么是必要的(我假设它完全是客户端导向的,因为某些客户端不需要服务器提供证书链来验证服务器证书的合法性)?

3个回答

在 SSL/TLS 中,服务器系统地将其证书链发送给客户端(好吧,除非客户端想要协商一个根本不使用证书的密码套件,但这在实践中非常罕见)。请参阅TLS 标准,特别是此图,它说明了一切:

  Client                                               Server

  ClientHello                  -------->
                                                  ServerHello
                                                 Certificate*
                                           ServerKeyExchange*
                                          CertificateRequest*
                               <--------      ServerHelloDone
  Certificate*
  ClientKeyExchange
  CertificateVerify*
  [ChangeCipherSpec]
  Finished                     -------->
                                           [ChangeCipherSpec]
                               <--------             Finished
  Application Data             <------->     Application Data

         Figure 1.  Message flow for a full handshake

有关 SSL/TLS 如何工作的(更多)更完整的解释,请阅读此答案


但请注意,虽然 SSL/TLS 正式依赖于 X.509 证书,但该协议并非与 X.509 不可挽回地结合在一起。在握手动态中,想法是服务器将其公钥发送到证书链中的客户端,然后客户端以某种方式使用服务器的公钥。客户端如何获取服务器的公钥有点超出范围;通常,客户端通过解码和验证服务器发送的证书链来做到这一点,但客户端可以通过它认为合适的任何其他方式自由地“知道”服务器的公钥。在某些专用应用程序(尤其是嵌入式系统)中,客户端可能包含服务器公钥的硬编码副本,并且只使用它,完全无视服务器发送的任何内容为“

此外,从 SSL/TLS 的角度来看,“证书链”是一系列不透明的 blob,因此总长度不超过 16 兆字节。虽然这些 blob 通常是编码的 X.509 证书,但它们可能是其他东西,只要客户端同意(并且忽略服务器证书链的客户端将根据定义同意任何内容)。甚至还有一个正式定义的RFC,用于在 SSL/TLS 中使用 OpenPGP 密钥而不是 X.509 证书。

如果证书链遵循通常的规则(X.509 证书,客户端验证),则X.509 规则适用。完整的 X.509 路径验证算法是魔鬼混淆和腐蚀好人的作品但是,作为一个简单的总结,颁发的证书(您的“中间 CA 证书”)通过以下两个属性与其颁发者(在您的情况下为根)匹配,这些属性都必须满足:

  • 颁发者(根)中的字段subjectDN必须issuerDN与颁发者(中间 CA)中的字段相同。由于大量可能的编码和用于大小写匹配的拜占庭 Unicode 规则,名称的实际“相等”是一个潜在的复杂概念。

  • 已签署证书颁发证书上的签名必须可以根据颁发者的公钥进行验证。

因此,如果您想保持中间 CA 证书不变,那么至少,新根需要使用与旧根完全相同的名称,以及完全相同的密钥对。如果您更改其中一个(或两个),则需要为中间 CA 重新颁发新证书。

相同的原则适用于整个链:如果您更改中间 CA 证书,那么您可能仍然保持终端实体证书不变(中间 CA 先前颁发的证书),如果(且仅当)新的中间 CA 证书仍然包含相同的中间 CA 名称和中间 CA 公钥。

实际上,TLS 规范本身几乎没有关于证书验证的内容。TLS 规范足够灵活,可以允许 X.509 证书以外的身份验证类型,例如OpenPGP 证书Kerberos

对X.509相关的概念有一些期待和参考,比如certificate_authoritiesclient-cert认证的列表,Server Certificatecertificate_list消息中的定义,以及一些alert消息的含义。

也就是说,就 TLS 规范而言,证书链相当不透明。要点之一在附录 D中:

D.2. Certificates and Authentication

   Implementations are responsible for verifying the integrity of
   certificates and should generally support certificate revocation
   messages.  Certificates should always be verified to ensure proper
   signing by a trusted Certificate Authority (CA).  The selection and
   addition of trusted CAs should be done very carefully.  Users should
   be able to view information about the certificate and root CA.

验证过程往往依赖于其他规范:RFC 5280(或仍为 RFC 3280)用于 PKI 方面,即链的验证,以及RFC 6125用于名称验证(或仍为 RFC 2818 和其他协议特定的规范) )。

作为一般规则,证书的颁发者专有名称应该是颁发它的 CA 证书的主题专有名称。至于替代名称,规范说

4.2.1.7. Issuer Alternative Name

   As with Section 4.2.1.6, this extension is used to associate Internet
   style identities with the certificate issuer.  Issuer alternative
   name MUST be encoded as in 4.2.1.6.  Issuer alternative names are not
   processed as part of the certification path validation algorithm in
   Section 6.  (That is, issuer alternative names are not used in name
   chaining and name constraints are not enforced.)

(如果您仍希望 CA 证书中的公钥验证证书的签名,您还需要重新使用相同的密钥材料。)

您想要的摘要答案:

  • Issuer字段是一个 DN,它标识谁签署了证书。
  • DN(专有名称)是那些古怪的“C=US,O=HAL,OU=Discovery One,CN=Dave Bowman”字符串之一
  • 但是,只有当您在本地受信任的根中时,拥有正确的名称才重要!

但是对于您的主要问题-中级证书无需更改即可引用新更新的根证书。可以为根颁发新证书,而不会使旧证书无效或断开与中间证书的链接。“颁发者”是一个字符串,而不是序列号,因此正确放置在受信任存储区中的根证书的同名重新颁发可以延长原始证书的到期时间。

上个月我遇到了一个这样的案例;我有一个由 Entrust L1C 中间证书签名的证书,该证书又由 CN=Entrust.net 证书颁发机构 (2048) 签名。直到最近,该根证书的副本如下:

Certificate:
Data:
    Version: 3 (0x2)
    Serial Number: 946059622 (0x3863b966)
Signature Algorithm: sha1WithRSAEncryption
    Issuer: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048)
    Validity
        Not Before: Dec 24 17:50:51 1999 GMT
        Not After : Dec 24 18:20:51 2019 GMT
    Subject: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048)

在 1 月下旬的操作系统升级期间,根证书悄悄地被更新的版本取代。请注意,序列号和有效日期会发生变化,但 Issuer 字符串不会:

Certificate:
Data:
    Version: 3 (0x2)
    Serial Number: 946069240 (0x3863def8)
Signature Algorithm: sha1WithRSAEncryption
    Issuer: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048)
    Validity
        Not Before: Dec 24 17:50:51 1999 GMT
        Not After : Jul 24 14:15:12 2029 GMT
    Subject: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048)

给定这两个不同的根文件,openssl 使用其中一个正确验证了证书链:

$ md5sum entrust.*.pem
da9ff9cd8e8e2256e9efcf5c4ef3891f  entrust.L1C.pem
244f3bbf6b112e7d399342c097db22a5  entrust.new.root.pem
0315b2915a0f74cc3498cfdd54933452  entrust.old.root.pem
$ openssl verify -CAfile entrust.old.root.pem entrust.L1C.pem
entrust.L1C.pem: OK
$ openssl verify -CAfile entrust.new.root.pem entrust.L1C.pem
entrust.L1C.pem: OK
$

对于奖励积分:

TLS 握手通常是这样开始的:

C -> S客户端你好

S -> C服务器你好

S -> C服务器证书

并且证书是从最具体的-> 中间-> 根以流的形式发送的。实际上,您可以从 Wireshark 之类的嗅探器中获取字节并将它们保存到文件中,并将它们视为 .der(二进制编码证书)。为了方便起见,我使用上面的证书做到了这一点,并使用 openssl 将它们从 .der 转换为 .pem。