1
votes

I thought I understood, but it is not working!

I read among others http://binblog.info/2010/02/02/lengthy-chains/ which is the cleanest explanation I found.

Background: Comodo's cheap PositiveSSL server certificate came with a root and two intermediate CA certificates (I replaced my FQDN with myserver.com):

$ unzip ../myserver_com.commodo.certificate.zip 
Archive:  ../myserver_com.commodo.certificate.zip
 extracting: AddTrustExternalCARoot.crt  
 extracting: COMODORSAAddTrustCA.crt  
 extracting: COMODORSADomainValidationSecureServerCA.crt  
 extracting: myserver_com.crt           

Note that the alphabetical order resembles the inverted certificate chain from root CA to server certificate. The root CA is not Comodo, but that is not the point here.

Consider the following output:

openssl x509 -noout -subject -issuer -in myserver_com.crt 
subject= /OU=Domain Control Validated/OU=PositiveSSL/CN=myserver.com
issuer= /C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA

openssl x509 -noout -subject -issuer -in COMODORSADomainValidationSecureServerCA.crt 
subject= /C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
issuer= /C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority

openssl x509 -noout -subject -issuer -in COMODORSAAddTrustCA.crt 
subject= /C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority
issuer= /C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root

openssl x509 -noout -subject -issuer -in AddTrustExternalCARoot.crt 
subject= /C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
issuer= /C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root

The issuer of the former certificate is the subject of the latter - until the root CA certificate from AddTrust AB which is selfsigned. The chain is complete.

Verifying the single certificates gives:

$ openssl verify *.crt
AddTrustExternalCARoot.crt: OK
COMODORSAAddTrustCA.crt: OK
COMODORSADomainValidationSecureServerCA.crt: C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = COMODO RSA Domain Validation Secure Server CA
error 20 at 0 depth lookup:unable to get local issuer certificate
myserver_com.crt: OU = Domain Control Validated, OU = PositiveSSL, CN = myserver.com
error 20 at 0 depth lookup:unable to get local issuer certificate

The first two certificates are already installed on the server which leaves two certifcates to concatenate, but I chained them all anyway.

From RFC5246 http://tools.ietf.org/html/rfc5246#section-7.4.2

 certificate_list

 This is a sequence (chain) of certificates.  The sender's
 certificate MUST come first in the list.  Each following
 certificate MUST directly certify the one preceding it.  Because
 certificate validation requires that root keys be distributed
 independently, the self-signed certificate that specifies the root
 certificate authority MAY be omitted from the chain, under the
 assumption that the remote end must already possess it in order to
 validate it in any case.

When I chain the correct way the certificate is recognized as a server certificate for the TLS session, but not verified.

$ cat myserver_com.crt COMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt > chained.crt
$ openssl verify chained.crt 
chained.crt: OU = Domain Control Validated, OU = PositiveSSL, CN = das.email
error 20 at 0 depth lookup:unable to get local issuer certificate

When connecting to the server with

$ openssl s_client -crlf -connect myserver:465

The certificate is accepted and the chain is recognized, but the root certificate is not identified as trusted, although it is present among the trusted certificates in /etc/ssl/mozilla/.

What am I missing? Can I simply ignore the errors from the commandline openssl tool?

1
This question appears to be off-topic because it is not about programming or development. See What topics can I ask about here in the Help Center. Perhaps Super User or Information Security Stack Exchange would be a better place to ask.jww
@jww Thank you for pointing that out - I was wondering why nobody looked at it - so indeed it seem to be off-topic. Newbee, you see. I will take your hint into account. Honestly I did not look at the topic policy - I only happen to find the best answers to all of my uneducated-sparetime-serveradmin questions here.Reinhard Seifert

1 Answers

2
votes

openssl verify chained.crt does not (directly) verify a chain as you seem to think; it reads one (the first) cert from the file and verifies it against the truststore. Here the first cert is your server (leaf) cert which is issued by your first intermediate (Comodo DV-server) which is not in the truststore so lookup fails. To do (nearly) the validation done by an SSL client of a chain received in the protocol, do:

openssl verify -purpose sslclient -untrusted restofchain myserver.crt 

where restofchain is a file containing at least the other certs in the chain except that the root may be omitted, so in your case that is the two Comodo intermediate certs and optionally the AddTrust root cert. openssl does not require they be in upward order as 5246 does, but it's fine if they are. In fact if the leaf cert is present in this file it will be ignored, so you can just use chained.crt.

For s_client I'm not sure what you mean by "the certificate is accepted ... but the root certificate is not identified as trusted". If the libssl-client code which s_client calls verifies the received chain successfully, then the root used for that chain must be in the local truststore because that's the only case openssl considers verification successful -- at least through 1.0.1, and even in the very recent 1.0.2 it's still the default -- but it never outputs the word "trusted".

One possible source of confusion: unlike a real client such as a browser or Java program which will abort the connection if the received cert/chain does not validate, or at least require manual override to proceed, s_client is a test tool that always proceeds with the connection regardless of the certificate status. You have to look specifically for verify errors (near the top of the output) and/or the "Verify return code" (usually at the very bottom).

EDIT 4/21: OpenSSL through 1.0.2a at least has a bug; s_client (and s_server and s_time) doesn't actually use the default truststore as it should if you don't specify either -CAfile or -CApath argument(s). See https://serverfault.com/questions/607233/how-to-make-openssl-s-client-using-default-ca ; a fix is announced for dev, but unless you do your own build from head until this is released and distributed you need to specify the -CA* argument explicitly even though it appears redundant.