6

I am trying to understand the practical mechanisms of cross-signing (intermediate) certificates. As an example, I am looking at the Let's Encrypt Chain of Trust. That page mentions:

IdenTrust has cross-signed our intermediates. This allows our end certificates to be accepted by all major browsers while we propagate our own root.

Additionally, the page contains links to both the intermediate certificate signed with the private key belonging to their own ISRG Root CA as well as the intermediate certificate cross-signed with the private key belong to IdenTrust's CA.

My expectation was to see both of those intermediate certificates coming by on the wire when setting up a TLS connection with www.letsencrypt.org, leaving it up to the client to decide which of the two intermediates to use to build a chain of trust. However, I only see the intermediate signed by IdenTrust.

I have observed this with wireshark, analyzing the TLS traffic as I browsed www.letsencrypt.org with my web browser. To force "the other" chain of trust, I un-trusted the DST Root CA X3 certificate in the Keychain Access app (I am on a Mac) and indeed I was no longer able to browse the site. Then I added the ISRG Root X1 certificate, indicating to always trust it but I could still not browse the site. This supports my observation that the intermediate certificate signed by ISRG is never provided by the server.

I also tried the openssl s_client app, but to no avail.

Suppose that I happen to trust the ISRG Root and not IdenTrust, how do I make the server share with me the intermediate certificate signed by the ISRG Root? Or more generally asked, if multiple chains of trust are available, for example because of cross-signing, how are the certificates of both chains shared with clients? Why do I not receive a bundle that contains both certificates for the intermediate?


Update: the first answer states that the TLS spec does not allow for multiple certificate chains to be exchanged. That explains a lot.

However, my expectations are set by the answers to the question What is the use of cross signing certificates in X.509?. The accepted answer there mentions: "It's about expanding trust" and "increasing the ease of verification of trust, such as situations where you've got clients that trust CA1 or CA2 (but not both). In such a case, you can cross-sign a cert to be trusted by both.".

If only one chain is allowed to be exchanged, then that does not seem like "expanding trust" but more like "modifying trust". Also, for a particular server, if it has to select one particular chain then the "ease of verification" argument no longer holds either -- at least not if your only mechanism available is the TLS handshake. Is that correct?

1 Answers1

2

This question is somewhat related, and you can see from StackzOfZtuff's answer that only one chain can be sent. When connecting with openssl s_client -connect letsencrypt.org:443 it's returning the chain the the IdenTrust root (Digital Signature Trust Co. which IdenTrust bought a long time ago):

Certificate chain
 0 s:/CN=www.letsencrypt.org
   i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
 1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
   i:/O=Digital Signature Trust Co./CN=DST Root CA X3

Since the certificate chain sent has the signature from IdenTrust, it can't be verified with the ISRG root.

As noted here the client is under no obligation to use the chain the server sends, it may attempt to build its own chain to a trusted root. However, this requires that the client already have all of the necessary intermediates that weren't sent by the server.

If I add the intermediate signed by ISRG Root X1 to my trust store, s_client will discover that chain despite being sent the IdenTrust chain (unless told not to by using -no_alt_chains):

$ openssl s_client -connect letsencrypt.org:443
CONNECTED(00000003)
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = www.letsencrypt.org
verify return:1
---
Certificate chain
 0 s:/CN=www.letsencrypt.org
   i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
 1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
   i:/O=Digital Signature Trust Co./CN=DST Root CA X3
AndrolGenhald
  • 15,506
  • 5
  • 45
  • 50
  • Thanks for pointing to the resources that confirm what I am seeing. However, it does make me wonder what the remaining value of cross-signing is, when doing TLS at least. I have updated my question (I did not think it was sufficient to ask a new question, but might decide it is :-) ) – Reinier Torenbeek Aug 10 '18 at 16:44
  • @ReinierTorenbeek I'm doing a bit more research, I'm not entirely sure my answer is correct...for example it seems to contradict [this](https://security.stackexchange.com/a/166086). Could be I'm misinterpreting something. – AndrolGenhald Aug 10 '18 at 16:47
  • Figured out what I was missing, now I'm not sure how I forgot about it...The client is allowed to discover its own chain to a trusted root, it just has to have all the intermediates available. – AndrolGenhald Aug 10 '18 at 17:14
  • I see how this additional preparation makes the certificate verification succeed and this seems to answer my question. But how would the client know that another version of the intermediate certificate is available in the first place? Apparently, some "out-of-band knowledge" is required to leverage the advantages that cross-signing is supposed to provide. – Reinier Torenbeek Aug 10 '18 at 19:49
  • In fact, I was reading up on the news item [Let's Encrypt Root Trusted By All Major Root Programs](https://letsencrypt.org/2018/08/06/trusted-by-all-major-root-programs.html) and it mentions that they expect it will take a least 5 (!) years before the vast majority of systems will be updated to trust the Let's encrypt chain. Until then, the cross-signed intermediate will remain. So far for ease of verification thanks to cross-signing... – Reinier Torenbeek Aug 10 '18 at 20:10
  • Nit: client/relier MAY find/use a different chain than sent if it has the intermediates already OR it can get them on demand, which for letsencrypt and **many CAs today can be done using AuthorityInfoAccess** -- as 64418 says. Browsers often(?) do this, but `s_client` doesn't. – dave_thompson_085 Aug 11 '18 at 06:47
  • @dave_thompson_085 I looked into that yesterday, but running `openssl x509` on the letsencrypt.org cert only gives 1 "CA Issuers" line with URI:http://cert.int-x3.letsencrypt.org/, and `openssl x509 -inform DER -in <(curl http://cert.int-x3.letsencrypt.org/) -text -noout` shows the IdenTrust intermediate. I didn't have time to read the RFC or look into it further, so I wasn't sure if there was some limitation, if I was doing something wrong, or if letsencrypt should have included multiple "CA Issuers" in their cert but didn't. – AndrolGenhald Aug 11 '18 at 16:53
  • Very nice example since DST Root expired! https://eclecticlight.co/2021/10/01/why-wont-safari-open-that-web-page/ – Валерий Заподовников Oct 03 '21 at 04:15