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?