How to debug certificate chains with OpenSSL?

I am completely new to OpenSSL and I'm reading a tutorial on OpenSSL programming to connect to a server:

www.rtfm.com/openssl-examples/part1.pdf
www.rtfm.com/openssl-examples/part2.pdf

Somehow setting up the correct certificates is more tricky than expected... :(

When I test the message with openssl s_client:

openssl s_client -connect 123.456.789.0:666 -CAfile test.crt -debug

I get the error message

depth=2 C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = COMODO RSA Certification Authority verify error:num=20:unable to get local issuer certificate verify return:0

and then:

error:14094412:SSL routines:SSL3_READ_BYTES:sslv3 alert bad certificate:s3_pkt.c:1257:SSL alert number 42 140685406562208:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:177:

Here is the certificate chain:

 Certificate chain  
 0 
   s:myself    
   i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Organization Validation Secure Server CA  
 1 
   s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Organization Validation Secure Server CA    
   i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority  
 2 
   s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority    
   i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root

I am trying to get the system to recognize these certificates as correct for hours now but to no avail...

What i have tried until now:

  • various variations of adding the certificate of COMODO to the list of trusted certificates by using update-ca-trust.
  • adding the certificates to the list of trusted certificates in /etc/ssl/certs
  • creating pem files in a folder and adding them with -CApath.
  • The problem with google is that most tutorials discuss this from the point of view of a server admin, but I don't have access to the server.

The operating system is Fedora.

Is there a structured way to tackle this issue?


Edit: the certificate was created as follows:

 openssl req -new -x509 -sha256 -days 365 -key mykey.key -out test.crt

Solution 1:

Be sure to include all the intermediate certificates and see that they are up to date. If test.crt is in fact a file containing only /C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root, this is the correct approach. You can include the root as well, and most clients will accept such chains, but a few will choke.

In general it's best practice to include all the certificates from yours to the last one before the root, in case a client doesn't have the last intermediate.

It's also possible that test.crt contains things other than the correct chain. OpenSSL doesn't do partial chain validation by default (in older versions, it doesn't do it at all). When operating in this mode it doesn't care what is in /etc/ssl/certs.

Alternatively, you may be presenting an expired intermediary certificate. CAs often recertify their intermediates with the same key; if they do that, just download the updated intermediate CA certificate and replace the expired one in your chain.

Finally, with openssl s_client, you need to specify what it is validating against. For example, use the option -CApath /etc/ssl/certs or -CAfile your_ca.crt. For the first option use your system's trust store, and for the second option specify the root CA certificate.

Solution 2:

Check the cert files against each other.

By default we have 3 files (based on a regular CA or self-signed) :

  • (private) key
  • (public) certificate
  • (public) certificate authority (chain) file <- incl. all intermediaries

So, does the key fit to the cert, and the cert fit to the CA ? Annotation: Though the names are like *.crt or *.key the format is PEM

# (openssl x509 -noout -modulus \
  -in /path/to/server.crt | \
  openssl md5 ; openssl rsa  -noout -modulus \
  -in /path/to/server.key | openssl md5) | uniq

Expected outcome is exactly 1 line, e.g.

(stdin)= a634dfd21796c72dcf8c809d3bacc966

If you see 2 lines then key and cert do NOT match.

If ok, proceed with

# openssl verify -CAfile /path/to/ca.crt /path/to/server.crt

You want to see

server.crt: OK

If one of the two steps fail, you are advised to recreate the certs/keys. If both are ok you know that you have to search at another place to remove your obstacles (permissions, changed CA, does one side work with openssl and the other with GNUTls, ...)