3

I'm teaching a class about certificate chains, so I download the chain from www.google.com which has 4 certs. I want to demonstrate how the dependencies work from issuer to subject by showing that each entity signs the cert of the one below it.

Call the certs g3, g2, g1 and g0 where g3 is a self-signed root, g2 and g1 are intermediate CAs and g0 is a leaf cert. I try this:

$ openssl verify g0
error 20 at 0 depth lookup:unable to get local issuer certificate

This makes sense: the verify fails because this is a leaf cert with no CA given. So next I try this:

$ openssl verify -CAfile g1 g0
g0: OK

Great! With the intermediate, it now works! Continuing up the chain:

$ openssl verify -CAfile g2 g1
g1: OK

Awesome! Looks like g1 is properly signed by g2. But this is actually not what's being verified. Because g1 is also apparently signed by g3:

$ openssl verify -CAfile g3 g1
g1: OK

And in fact, g1 doesn't even need a CA:

$ openssl verify g1
OK

So it would appear that any cert with CA set to True in Basic Constraints will always pass verification!

Question: How do I verify that g2 actually signed g1 using OpenSSL from the CLI? And is this yet another OpenSSL bug? Or just counterintuitive behavior?

Fixee
  • 1,545
  • 2
  • 15
  • 24
  • Some OS buffer intermediate CA certificates and may just handle them just like standard root CA certificates (after an initial verification). – SEJPM Mar 15 '16 at 20:36

1 Answers1

2

I believe certs g2 and g3 are already present in the default trusted directory (/etc/ssl/certs/) which openssl uses to build the chain of trust and find the 'trust anchor'.

In my setup:

g2 = GeoTrust Global CA
g3 = Equifax Secure Certificate Authority

Both of these certs are present in the /etc/ssl/certs/ directory.

If you try out the same experiment with a self-generated chain of certs, you will find the behaviour that you expect.

  • I think you nailed it! I didn't set up the same chain (it would require I spin up multiple local CAs), but I did notice that renaming /etc/ssl/certs so that OpenSSL couldn't find the relevant roots did result in failed verification. And then adding explicit pointers to the cert files did result in valid verification. This is consistent with your answer above! Cheers. – Fixee Mar 16 '16 at 06:27
  • Curiously, `s_client -connect www.google.com:443` fails validation with the same chain. I guess it doesn't use the certs in `/etc/ssl/certs` like `verify` does?! – Fixee Mar 16 '16 at 06:53
  • It should use them. In my setup, `openssl s_client -verify 10 -connect www.google.com:443` works as expected. –  Mar 16 '16 at 07:11
  • The default truststore varies in different builds of OpenSSL, particularly on different distros; check `openssl version -d`. You also can specify *both* `-CAfile` and `-CApath` e.g. `verify -CAfile g1 -CApath /path/to/some_empty_dir g0` -- or in 1.1.0 (currently alpha) use `-no-CA-path`. Or use a system where the default store does not include these roots (in CApath format) but that may be harder to arrange. And note to show a cert *does* verify under a nontrivial path (i.e. g1 under g3) you'll need to supply the intermediate(s) with `-untrusted`. – dave_thompson_085 Mar 16 '16 at 07:57
  • 1
    For `s_client` check you have a recent version; until June 2015 `s_client` (and also `s_server` and `s_time`) had a bug that didn't correctly use the defaulted truststore (but does work with `-CApath` and/or `-CAfile` options, even if they point to the default locations). Except on RedHat builds, which patched this. (Also, `s_client` always verifies the server; you don't need to specify `-verify` unless you want to change the depth. OTOH `s_server` does not verify client by default.) – dave_thompson_085 Mar 16 '16 at 08:04
  • @dave_thompson_085 Thank you; very helpful. Rather than clutter this thread with ancillary comments, I have started a new question at http://security.stackexchange.com/questions/117651/why-doesnt-openssl-s-client-correctly-validate-google-com443 Would be very grateful if you could weigh in. – Fixee Mar 16 '16 at 19:37