tomcat doesn't deliver intermediate certificat

2019-01-21 17:14发布

问题:

I created a key and a csr on console, using the openssl executable. Then I sent the csr to a CA and got the certificate back. Now I want to import it into tomcat.

So I created a PKCS#12 file out of my key and my certificate:

openssl pkcs12 -export -in mycert.cert -inkey mykey.pem -out key_and_cert.p12

and then created a keystore containing it:

keytool -importkeystore -deststorepass [password] -destkeystore keystore.jks -srckeystore key_and_cert.p12 -srcstoretype PKCS12 -srcstorepass [password]

Then I import the intermediate certificate chain.crt:

keytool -import -trustcacerts -alias root -file chain.crt -keystore keystore.jks

Here the output of "keytool -keystore keystore.jks -list":

Keystore-Typ: JKS
Keystore-Provider: SUN

Ihr Keystore enthält 2 Einträge.

root, 14.11.2011, trustedCertEntry,
Zertifikatsfingerabdruck (MD5): [fingerprint]
1, 14.11.2011, PrivateKeyEntry, 
Zertifikatsfingerabdruck (MD5): [fingerprint]

The tomcat server.xml contains:

<Connector port="443" protocol="HTTP/1.1" SSLEnabled="true"
           maxThreads="150" scheme="https" secure="true"
           clientAuth="false" URIEncoding="UTF-8" compression="on"
           sslProtocol="TLS"
           keystoreFile="/[absolute-path]/keystore.jks"
           keystorePass="[password]" />

When I restart tomcat, it logs no errors in catalina.out, everything seems to be ok. But when I run firefox, it reports

[domain] uses an invalid security certificate.
The certificate is not trusted because no issuer chain was provided.
(Error code: sec_error_unknown_issuer)

Running "openssl s_client -connect [domain]:443 -showcerts" returns

CONNECTED(00000003)
depth=0 C = DE, OU = Domain Control Validated, CN = [domain]
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 C = DE, OU = Domain Control Validated, CN = [domain]
verify error:num=27:certificate not trusted
verify return:1
depth=0 C = DE, OU = Domain Control Validated, CN = [domain]
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:/C=DE/OU=Domain Control Validated/CN=[domain]
   i:/C=BE/O=GlobalSign nv-sa/CN=GlobalSign Domain Validation CA - G2
-----BEGIN CERTIFICATE-----
[certificate from mycert.cert]
-----END CERTIFICATE-----
---
Server certificate
subject=/C=DE/OU=Domain Control Validated/CN=[domain]
issuer=/C=BE/O=GlobalSign nv-sa/CN=GlobalSign Domain Validation CA - G2
---
No client certificate CA names sent
---
SSL handshake has read 1777 bytes and written 289 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : SSLv3
    Cipher    : ECDHE-RSA-AES256-SHA
    Session-ID: [session-id]
    Session-ID-ctx: 
    Master-Key: [master-key]
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    Start Time: 1321268519
    Timeout   : 7200 (sec)
    Verify return code: 21 (unable to verify the first certificate)
---

I think tomcat doesn't deliver the intermediate certificate although it knows it. What can I do to make tomcat deliver it?

Additional information: When importing the pkcs12 certificate, there is no certificate chain error, because the -importkeystore command doesn't checks the chain. I also tried to import the intermediate certificate first and then call -importkeystore. I got the same results.

edit: I just tried another way by inserting the chain directly in the PKCS#12 certificate and get the following error:

$ openssl pkcs12 -export -CAfile chain.pem -in mycert.cert -inkey mykey.pem -out key_and_cert.p12 -name tomcat -chain
Error unable to get issuer certificate getting chain.

But the chain certificate is ok:

$ openssl verify chain.pem
chain.pem: OK

回答1:

I had to create a CA file by finding the root cert for my issuer and then putting the intermediate cert above it in the same file. Then I ran:

openssl pkcs12 -export -chain -inkey mykey.key -in mye.crt -name "tomcat" -CAfile intermediate_plus_root.crt -out key_and_cert.p12


回答2:

There is even a more simple solution as asked for in some comments (without saving root and intermediate certs in /etc/ssl/certs)

First copy all the needed root and intermediate certificates in a folder (in our example the folder is '~/certs' and our two certificates are named 'PrimaryCA.pem' and 'SecondaryCA.pem'):

mkdir ~/certs
mv PrimaryCA.pem ~/certs/PrimaryCA.pem
mv SecondaryCA.pem ~/certs/SecondaryCA.pem

Then 'c_rehash' the folder:

c_rehash ~/certs

Now the certs folder will contain two new symlinks named regarding the following scheme '{hash-value}.{n}' where {hash-value} is an 8 symbol hash value and {n} is an integer. If that's the case for you continue to the following command which creates your .p12 using '-CApath' instead of going the long way round copying the certificates to /etc/ssl/certs:

openssl pkcs12 -export -in cert.pem -inkey key.key -out key_and_cert.p12 -chain -CApath ~/certs

Finally convert it to jks as Heinzi already perfectly described in his answer:

keytool -importkeystore -deststorepass [password] -destkeystore keystore.jks -srckeystore key_and_cert.p12 -srcstoretype PKCS12 -srcstorepass [password]


回答3:

Finally I got it working. It's not a clean solution, but it works. I added the intermediate certificate to my local /etc/ssl/certs and then called

openssl pkcs12 -export -in cert.pem -inkey key.key -out key_and_cert.p12 -chain

The resulting pkcs12 certificate I converted to jks via

keytool -importkeystore -deststorepass [password] -destkeystore keystore.jks -srckeystore key_and_cert.p12 -srcstoretype PKCS12 -srcstorepass [password]

This resulting file seems to work now, tomcat delivers the certificate chain also to clients that don't have the intermediate certificate in their /etc/ssl/certs directory. But I think there must also be a way without changing /etc/ssl/certs.



回答4:

It works for me using APR. See http://tomcat.apache.org/tomcat-7.0-doc/config/http.html#SSL_Support_-_APR/Native

  <Connector port="3573" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" 
               SSLCertificateFile="/my/pem/encoded/certificate/file"
               SSLCertificateKeyFile="/my/pem/encoded/certificate/private_key"
               SSLPassword="yourKeyFilePassword"
               SSLCertificateChainFile="/my/pem/encoded/certificate/authorities/file"
               />


回答5:

make sure you copy the openssl ca files into the intermediate files.

on RHEL concat following file to your issuer ca file.

/etc/pki/tls/certs/ca-bundle.crt