I seldom use mutual authentication in the context of SSL. Recently, in our derived project (integration with MyOSG), we need to enforce use of mutual SSL authentication.
Enable client authentication in Tomcat server
At first, I enabled it in tomcat server configuration file
An important option is "clientAuth”.
Note: before this step, I have generated and imported a certificate for tomcat server.
Import user certificate
This is done by the end users who wish to access the protected services. They need to
- import received certificate from CA to their browser
Actually, both the private key and certificate need to be imported.
For Firefox, only pkcs#12 format is supported. If the private key has been imported, you just need to import certificate whose format can be PEM, binary, etc. - import server’s certificate into trusted ca repository in browser
The aim is to make the browser trust the certificate received from remote service. It’s useful when the service certificate is not issued by a well-known top-level CA.
After those two steps, I directed my browser to the service url. Unfortunately, I got the following error:
After digging a little bit, I found out the cause was that tomcat server does not trust certificate sent by my browser. So the solution is simple: add certificate chain related to my certificate to tomcat keystore.
I got the certificate chain from the issuer of my certificate. It’s in PKCS#7 format and contains two certificates in the file. You can view PKCS7-formatted file using following commands:
1) openssl pkcs7 -print_certs -text < pkcs7_cert_chain.pem
2) keytool -printcert –file pkcs7_cert_chain.pem
When I tried to import it into keystore using following command
keytool -importcert -file pkcs7_cert_chain.pem -keystore keystore -alias test-cert –trustcacerts
I got the following error
keytool error: java.lang.Exception: Input not an X.509 certificate
I am sure keytool can recognize the file because the following command prints out information in the file correctly.
keytool -printcert –file pkcs7_cert_chain.pem
Solution
After reading keytool manual carefully, I found following statements:
Importing a New Trusted Certificate
Before adding the certificate to the keystore, keytool tries to verify it by attempting to construct
a chain of trust from that certificate to a self-signed certificate (belonging to a root CA), using
trusted certificates that are already available in the keystore.Importing a Certificate Reply
……
o If the reply is a PKCS#7 formatted certificate chain, the chain is first ordered (with the user
certificate first and the self-signed root CA certificate last), before keytool attempts to
match the root CA certificate provided in the reply with any of the trusted certificates in the
keystore or the "cacerts" keystore file (if the -trustcacerts option was specified). If no match
can be found, the information of the root CA certificate is printed out, and the user is
prompted to verify it, e.g., by comparing the displayed certificate fingerprints with the fin-
gerprints obtained from some other (trusted) source of information, which might be the root CA
itself. The user then has the option of aborting the import operation. If the -noprompt option
is given, however, there will be no interaction with the user.
So, what I was doing is to import a trusted certificate chain. This is not allowed directly. keytool just accepts cert file that includes a single certificate.
So I extracted two certificates into two files, and fed them into keytool one by one. Details:
Use command
openssl pkcs7 -print_certs < pkcs7_cert_chain.pem
to display the two certificates in the original pkcs7 file. And then copied and pasted each cert into an individual file.
Note: when you are importing a certificate reply from a CA, certificate chain can be imported directly into keystore. However, before doing that, you must guarantee that the corresponding private key has already been imported in to the same keystore.