Hakanai
Hakanai

Reputation: 12670

How do I get the certificate chain given potentially only the leaf certificate?

I'm trying to implement a custom X509TrustManager which tells the user about the certificate and gives them the ability to continue to use the server despite the problem.

I have hooked almost everything together and started testing against various certificates on badssl.com.

When I visit expired.badssl.com in Safari, I see three certificates:

* COMODO RSA Certification Authority
    * COMODO RSA Domain Validation Secure Server CA
        * *.badssl.com 

And my application gets the full chain.

When I visit wrong.host.badssl.com, though, Safari still shows three certificates, but my application only sees two:

* DigiCert Global Root CA (Not in the array passed to the method!)
    * DigiCert SHA2 Secure Server CA
        * *.badssl.com

I assume I can use the "Issuer" name from the "DigiCert SHA2 Secure Server CA" certificate to find the root certificate somehow, but where do I find it?

Upvotes: 0

Views: 2020

Answers (1)

dave_thompson_085
dave_thompson_085

Reputation: 38771

The root certificate used to validate the server's chain (or in general any received chain) should be found in the local truststore. That's exactly what the default TrustManager does -- it looks in the local truststore, or more exactly it instantiates a CertPathValidator which (normally) defaults to PKIXValidator that looks in a truststore (a KeyStore containing cert entries) normally initialized from a local file defaulting to JRE/lib/security/cacerts, and then executes that validator which does validation by looking up the root from said truststore using a HashMap by subject name.

This is stated, albeit briefly, in RFC 5246 for TLS 1.2 (unchanged from 4346 for 1.1 and 2346 for 1.0).

If you look more closely you'll find that the cases aren't actually as different as you think.

wrong.host.badssl.com serves a cert chain consisting of:

  • https://crt.sh/?id=205900989 leaf *.badssl.com issued by DigiCert SHA2 SecServerCA
  • https://crt.sh/?id=1262388 intermediate issued by DigiCert GlobalRootCA
    which uses the root https://crt.sh/?id=853428 with SHA1 fingerprint A8985D3A65E5E5C4B2D7D66D40C6DD2FB19C5436 which you will find in most if not all common truststores, including Java (at least Oracle/Sun Java, OpenJDK may differ depending on how it was built). Note this cert valid for *.badssl.com fails for wrong.host.badssl.com because certificate wildcard-name matching only does one (leftmost) DNS label not more (this would need two).

expired.badssl.com serves a cert chain consisting of:

  • https://crt.sh/?id=7176112 leaf *.badssl.com issued by COMODO RSADomainValCA
  • https://crt.sh/?id=3509153 intermediate issued by COMODO RSACertAuth
  • https://crt.sh/?id=1044348 bridge issued 2000 (until 2020) by AddTrust ExternalRoot
    which as sent uses the AddTrust root https://crt.sh/?id=1 with SHA1 fingerprint 02FAF3E291435468607857694DF5E45B68851868 . However, COMODO RSA now has its own root https://crt.sh/?id=1720081 dated 2010 (until 2038) with SHA1 fingerprint AFE5D244A8D1194230FF479FE2F897BBCD7A8CB4 pretty widely accepted -- including by Oracle Java beginning 8u51. (AddTrust External goes back much further, at least 6u07 which is the oldest I can easily check.) I bet if you look you'll find Safari replaced the bridge cert for COMODO RSA at the top of the received chain with the (COMODO RSA) root; any relier is allowed to do this kind of shortcutting and my (nearly-current) Firefox, IE and Chrome/Windows all do in this case. (The latter two share the Windows truststore; Firefox uses Mozilla's.)

(PS for checklisters: I use SHA1 fingerprints because they're easier to cut&paste and are still good enough -- SHA1 collisions have been found for some data, but not full certs which are much harder because of the signature correlation, and anyway only second-preimage would actually be a problem and AFAIK no one has made any progress on that at all.)


The question in your title, 'given only the leaf cert', should never occur in TLS because of the RFCs referenced above. But if it does, this is nearly a duplicate of OpenSSL generate certificate chain and the same logic applies: follow CAIssuers, or (with luck) chain on the CT log(s) -- as I did manually for the above!

Upvotes: 5

Related Questions