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

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?

  • Some OS buffer intermediate CA certificates and may just handle them just like standard root CA certificates (after an initial verification).
    – SEJPM
    Mar 15, 2016 at 20:36

1 Answer 1


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, 2016 at 6: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, 2016 at 6:53
  • It should use them. In my setup, openssl s_client -verify 10 -connect www.google.com:443 works as expected.
    – user90696
    Mar 16, 2016 at 7: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. Mar 16, 2016 at 7: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.) Mar 16, 2016 at 8:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .