0

for a class I'm looking at the TLS certificate chain for google.com. When I click in the Chrome or Firefox browser, the root certificate is shown as GTS Root R1 with a validity up to 2036, self-signed, so it must be a root-certificate.

However, if I check the same in Python using the following code, I get a GTS Root R1 certificate with a validity of 2028, which is signed by GlobalSign nv-sa, so this time it's NOT a root-certificate!

Is it possible that Google.com returns two different certificate chains, depending on which client does the request? If it supposes that the client accepts the GTS Root R1 as root certificate, it returns this one, else it returns one signed by GlobalSign nv-sa?

If so, why?

The following is the chain with the certificates and their digest/sha256. Now when I look at the certificate chain in the browser, the first two have the same digest / sha-256, but the third one has a different digest. So I definitely think I'm getting a different chain depending on the client...

Certificate #0
Subject b'CN': b'*.google.com'
notBefore: b'20211101021952Z'
notAfter: b'20220124021951Z'
version:2
sigAlg: b'sha256WithRSAEncryption'
digest: b'E9:7C:86:18:34:DE:F4:11:4D:2D:5E:6F:1A:49:22:A1:04:EE:9E:7C:8D:CB:72:3F:6D:67:58:8F:7E:F3:4B:AB'
issuer: <X509Name object '/C=US/O=Google Trust Services LLC/CN=GTS CA 1C3'>

Certificate #1
Subject b'C': b'US'
Subject b'O': b'Google Trust Services LLC'
Subject b'CN': b'GTS CA 1C3'
notBefore: b'20200813000042Z'
notAfter: b'20270930000042Z'
version:2
sigAlg: b'sha256WithRSAEncryption'
digest: b'23:EC:B0:3E:EC:17:33:8C:4E:33:A6:B4:8A:41:DC:3C:DA:12:28:1B:BC:3F:F8:13:C0:58:9D:6C:C2:38:75:22'
issuer: <X509Name object '/C=US/O=Google Trust Services LLC/CN=GTS Root R1'>

Certificate #2
Subject b'C': b'US'
Subject b'O': b'Google Trust Services LLC'
Subject b'CN': b'GTS Root R1'
notBefore: b'20200619000042Z'
notAfter: b'20280128000042Z'
version:2
sigAlg: b'sha256WithRSAEncryption'
digest: b'3E:E0:27:8D:F7:1F:A3:C1:25:C4:CD:48:7F:01:D7:74:69:4E:6F:C5:7E:0C:D9:4C:24:EF:D7:69:13:39:18:E5'
issuer: <X509Name object '/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA'>

The python code I used to fetch the certificate:

from OpenSSL import SSL, crypto
import socket, certifi

def dump_cert(cert):
    for component in cert.get_subject().get_components():
        print("Subject %s: %s" % (component))
             
    print("notBefore:", cert.get_notBefore())
    print("notAfter:", cert.get_notAfter())
    print("version:" + str(cert.get_version()))
    print("sigAlg:", cert.get_signature_algorithm())
    print("digest:", cert.digest('sha256'))
    print("issuer:", cert.get_issuer())
    print()
    
def get_connection_chain(host, port = 443):
    dst = (str.encode(host), port)
    ctx = SSL.Context(SSL.TLSv1_2_METHOD)
    s = socket.create_connection(dst)
    s = SSL.Connection(ctx, s)
    s.set_connect_state()
    s.set_tlsext_host_name(dst[0])

    s.sendall(b'HEAD / HTTP/1.2\n\n')
    s.recv(16)
    return (s, s.get_peer_cert_chain())

def dump_chain(chain):
    for pos, cert in enumerate(chain):
        print("Certificate #" + str(pos))
        dump_cert(cert)

conn, chain = get_connection_chain("google.ch")
dump_chain(chain)
ineiti
  • 324
  • 3
  • 11
  • It's likely that the same certificate chain is sent in both cases, it's just that browser's chain validation will stop at the first *trusted* certificate, which on the platform you're running the browser on is the GTS Root R1. If you temporarily remove that certificate from your platforms list of trusted certificates (but make sure the Globalsign one is still there) and reconnect with the browser you'll see the full chain. – President James K. Polk Nov 29 '21 at 21:15
  • I updated the question with the chain I get from python. When I look at the chain in the browser, only the two first certificates have the same digest. The third has a different digest, so it definitely sends a different certificate along when being asked by the browser. – ineiti Nov 30 '21 at 12:27
  • "The chain in the browser..." What I'm saying is that the chain you see *displayed* by the browser is not exactly the chain that is sent. – President James K. Polk Nov 30 '21 at 13:03
  • 1
    I just confirmed this with a test. The same chain is sent in both cases, the browser just displays a different root certificate according to its chain validation procedures. – President James K. Polk Nov 30 '21 at 13:15
  • See https://security.stackexchange.com/questions/265357/same-domain-same-local-network-different-certificate-chain/265363#265363 for a similar question. – mti2935 Oct 09 '22 at 18:20

1 Answers1

0

So thanks to President James K. Polk I think I better understand what's happening:

  • according to https://pki.goog/repository/, there are two versions of the GTS Root R1 certificate with the same public key:
    • A root certificate GTS Root R1
    • An intermediate certificate GTS Root R1 Cross, signed by GlobalSign nv-sa, which is a root certificate.

So the browser receives the certificate chain as given in the question. Then it starts by the leaf node of the certificate chain, which is the Certificate #0. The browser goes through its list of stored root certificates to validate the leaf certificate. If it doesn't find one, it goes to the next entry, Certificate #1.

In the example of google.com, it finds that it has a root certificate for the Certificate #1 and uses this one, ignoring the Certificate #2. Even though I'm not really sure why it does this:

  • does it hope to get rid of the GlobalSign certificate at some time?
  • is it for redundancy? If one certificate gets revoked, the other still works?

One blog entry which describes this is here: https://scotthelme.co.uk/cross-signing-alternate-trust-paths-how-they-work/

ineiti
  • 324
  • 3
  • 11
  • 1
    Cert chain validation is complicated, but a simplified version is this: start at the leaf cert. Is it well-formed, sensible, and not expired? Is it issued by a cert *I already trust completely*? If so, we're done. Otherwise, is the issuer the next certificate in the chain? If so, repeat all these tests with that cert, and so on – President James K. Polk Dec 01 '21 at 13:57
  • 1
    *does it hope to get rid of the GlobalSign certificate at some time?* Yes, that's why. Getting a new root certificate into the PKI ecosystem is a difficult and drawn out process. As it is happening there will be some platforms where your root is trusted and others where it isn't. During this transition period, you need to have your root cert signed by an already widely trusted root certificate, and deployed in precisely the manner as is done in your example. One question is: why would Globalsign help out a competitor? "For money" is one answer. Reality is more complicated. – President James K. Polk Dec 01 '21 at 14:05