问题
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:
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.
来源:https://stackoverflow.com/questions/29436967/how-to-chain-a-ssl-server-certificate-with-the-intermediate-and-root-ca-certific