12

This is related to another question, How to verify a signature of one entity by another using OpenSSL CLI?

I used openssl s_client -showcerts -connect www.google.com:443 to collect three certificates from google. Call them g0, g1, g2, where:

  • g0 is a leaf cert signed by Google's intermediate CA
  • g1 holds the intermediate CA public key and is signed by GeoTrust CA
  • g2 holds the GeoTrust public key and is signed by EquiFax CA

My goal is to demonstrate that this is a valid signature chain, step-by-step, using the OpenSSL CLI. The intuitive try is this:

$ openssl verify -CAfile g1 g0

But it turns out that OpenSSL is using certs from its trusted store (see How to verify a signature of one entity by another using OpenSSL CLI?). So instead I kill the trusted store as @dave_thompson_085 suggested in a comment to the above-referenced question. But this doesn't seem to work:

$ openssl verify -CApath /dev/null -CAfile g1 g0
g1.crt: C = US, O = Google Inc, CN = Google Internet Authority G2
error 2 at 1 depth lookup:unable to get issuer certificate

So how do I correctly issue this verify command in such a way that I can specifically check whether g1 has signed g0?

$ openssl version
OpenSSL 1.0.1f 6 Jan 2014
Fixee
  • 1,565
  • 2
  • 15
  • 24

3 Answers3

9

I've more-or-less solved my problem as follows:

There is an option to verify called -partial_chain that allows verify to output OK without finding a chain that lands at self-signed trusted root cert. However, -partial_chain doesn't exist on the version of OpenSSL that I have, nor in any later version of 1.0.1. Here's the run-down:

  • OpenSSL 1.0.1f -- This is the latest for Ubuntu 14.04; it has the heartbleed fix
  • OpenSSL 1.0.1s -- This is the latest in the 1.0.1 line, and likely to be the last; must be installed by hand in Ubuntu 14.04
  • OpenSSL 1.0.2g -- Currently the latest in the 1.0.2 line; this does support -partial_chain
  • OpenSSL 1.1 -- This is currently in alpha and has even more options, but I didn't explore it

So, with 1.0.2g or later, one can do the following:

$ openssl verify -CApath /dev/null -partial_chain -trusted g1 g0
g0: OK
$ openssl verify -CApath /dev/null -partial_chain -trusted g2 g1
g1: OK
$ openssl verify -CApath /dev/null -trusted /etc/ssl/certs/EquiFax_Secure_CA.pem g2
g2: OK

(Note that -partial_chain was not needed in the last command since the Equifax root cert is self-signed.)

This satisfies my question, but requires a version of OpenSSL that is not yet available on some distros unless you hand-install. If you are stuck with a pre-1.0.2 version, you probably have to use @Anthony Geoghegan's method.

Note: There is an option listed in the verify docs called -no-CApath which purportedly obviates the need for -CApath /dev/null, but it's not available on 1.0.2g or earlier, based on my tests. I assume it is available in 1.1.

Fixee
  • 1,565
  • 2
  • 15
  • 24
8

The OpenSSL verify command builds up a complete certificate chain (until it reaches a self-signed CA certificate) in order to verify a certificate. From its man page:

Firstly a certificate chain is built up starting from the supplied certificate and ending in the root CA. It is an error if the whole chain cannot be built up.

It only returns a positive result if it can verify the complete chain.

If any operation fails then the certificate is not valid.

However, the following command results provide enough information to show that the g0 certificate is signed by the g1 certificate.

$ openssl verify -CApath /dev/null -CAfile g1 g0
g1.crt: C = US, O = Google Inc, CN = Google Internet Authority G2
error 2 at 1 depth lookup:unable to get issuer certificate

Error 2 indicates that one of the certificates in the chain could not be found.

2 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: unable to get issuer certificate

the issuer certificate of a looked up certificate could not be found. This normally means the list of trusted certificates is not complete.

The important thing here is that the depth is 1. This indicates that the certificate being checked was verified at the first level, depth 0 (by the g1 certificate).

If the g1 certificate was not used to sign the g0 certificate, the error would be at the first stage, depth 0 and you would instead receive Error 20:

error 20 at 0 depth lookup:unable to get local issuer certificate

20 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: unable to get local issuer certificate

the issuer certificate could not be found: this occurs if the issuer certificate of an untrusted certificate cannot be found.

  • My question was how to verify `g1` signed `g0`. Involving `g2` doesn't make sense to me here, nor does involving EquiFax's root cert from the trusted store. Can I not just verify this one sig without having to invoke the rest of the chain to some self-signed root? Or is this not supported by OpenSSL? – Fixee Mar 21 '16 at 05:20
  • Sorry @Fixee I misinterpreted your question (it was late at night for me and I only glanced at the related question). I've now changed my answer based on your clarification. – Anthony Geoghegan Mar 21 '16 at 11:48
0

To verify that issuer of cert1.crt is cert1Issuer.crt:

openssl verify -no-CAfile -no-CApath -partial_chain -trusted cert1Issuer.crt cert1.crt
# cert1.crt : OK
Marinos An
  • 191
  • 6