Root CA Certificate 可以位于证书路径的中间吗?

Can Root CA Certificate located in the middle of certificate path?

我制作了一个连接到网站 (tls) 并将证书链保存到文件的程序。

有时网站的证书链看起来与我预期的不同。

其中一个证书链是由 Sectigo(ex Comodo)CA 颁发的。

我认为 "AddTrust External CA Root" 应该位于链的最后一个证书中,但位于其链中的第二个证书中。(请查看下面的证书链部分)

$ openssl  s_client -showcerts -connect adblockplus.org:443
CONNECTED(00000003)
depth=3 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root
verify return:1
depth=2 C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
verify return:1
depth=1 C = GB, ST = Greater Manchester, L = Salford, O = Sectigo Limited, CN = Sectigo RSA Extended Validation Secure Server CA
verify return:1
depth=0 serialNumber = HRB 73508, jurisdictionC = DE, businessCategory = Private Organization, C = DE, postalCode = 50825, ST = Nordrhein-Westfalen, L = K\C3\B6ln, street = Lichtstra\C3Fe 25, O = Eyeo GmbH, OU = COMODO EV SSL, CN = www.adblockplus.org
verify return:1

---
Certificate chain
 0 s:/serialNumber=HRB 73508/jurisdictionC=DE/businessCategory=Private Organization/C=DE/postalCode=50825/ST=Nordrhein-Westfalen/L=K\xC3\xB6ln/street=Lichtstra\xC3\x9Fe 25/O=Eyeo GmbH/OU=COMODO EV SSL/CN=www.adblockplus.org
   i:/C=GB/ST=Greater Manchester/L=Salford/O=Sectigo Limited/CN=Sectigo RSA Extended Validation Secure Server CA
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
 1 s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
   i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
 2 s:/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority
   i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
 3 s:/C=GB/ST=Greater Manchester/L=Salford/O=Sectigo Limited/CN=Sectigo RSA Extended Validation Secure Server CA
   i:/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
---
Server certificate
subject=/serialNumber=HRB 73508/jurisdictionC=DE/businessCategory=Private Organization/C=DE/postalCode=50825/ST=Nordrhein-Westfalen/L=K\xC3\xB6ln/street=Lichtstra\xC3\x9Fe 25/O=Eyeo GmbH/OU=COMODO EV SSL/CN=www.adblockplus.org
issuer=/C=GB/ST=Greater Manchester/L=Salford/O=Sectigo Limited/CN=Sectigo RSA Extended Validation Secure Server CA

我的问题是:

  1. 这种情况正常吗?
  2. Web 服务器(这次是 adblockplus)正在制作证书路径吗?
  3. 如何确定有效的证书路径?

欢迎任何评论。谢谢

一个TLS-was-SSL服务器应该在握手中以正确的顺序发送证书链,但有些服务器不会,包括OpenSSL在内的大多数客户端仍然会只要叶子 (end-entity) 证书是 first,通过匹配 issuer=subject 名称来正确处理它。注意验证过程的痕迹:

depth=3 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root
verify return:1
depth=2 C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
verify return:1
depth=1 C = GB, ST = Greater Manchester, L = Salford, O = Sectigo Limited, CN = Sectigo RSA Extended Validation Secure Server CA
verify return:1
depth=0 serialNumber = HRB 73508, jurisdictionC = DE, businessCategory = Private Organization, C = DE, postalCode = 50825, ST = Nordrhein-Westfalen, L = K\C3\B6ln, street = Lichtstra\C3Fe 25, O = Eyeo GmbH, OU = COMODO EV SSL, CN = www.adblockplus.org
verify return:1

您可以看到证书使用的顺序是正确的top-to-bottom,即使它们没有收到正确的 bottom-to-top 顺序。

这种不当行为很常见,TLS 1.3 已更改为正式允许这种行为。比较 RFC 5246 7.4.2 中的 TLS 1.2:

certificate_list ... The sender's certificate MUST come first in the list. Each following certificate MUST directly certify the one preceding it. Because certificate validation requires that root keys be distributed independently, the self-signed certificate that specifies the root certificate authority MAY be omitted from the chain, under the assumption that the remote end must already possess it in order to validate it in any case.

RFC 8446 4.4.2 中的 TLS 1.3,强调:

... The sender's certificate MUST come in the first CertificateEntry in the list. Each following certificate SHOULD directly certify the one immediately preceding it. Because certificate validation requires that trust anchors be distributed independently, a certificate that specifies a trust anchor MAY be omitted from the chain, provided that supported peers are known to possess any omitted certificates.

Note: Prior to TLS 1.3, "certificate_list" ordering required each certificate to certify the one immediately preceding it; however, some implementations allowed some flexibility. Servers sometimes send both a current and deprecated intermediate for transitional purposes, and others are simply configured incorrectly, but these cases can nonetheless be validated properly. For maximum compatibility, all implementations SHOULD be prepared to handle potentially extraneous certificates and arbitrary orderings from any TLS version, with the exception of the end-entity certificate which MUST be first.

(客户端证书的另一个方向也是如此,但很少使用,而服务器证书几乎总是如此。)