3

i have two https web applications app1 and app2 installed on two different tomcats t1 and t2(t1 and t2 are on different machines). when in app1 i make an url connection to app2 i get the SSL handshake error. The reason is i am using the self signed certificate in app2 which is not present in app1 jvm truststore. So proper approach to fix it install the self signed certificate in JAVA-HOME/jre/lib/security . To do the same , I have followed the steps given at http://www.mkyong.com/webservices/jax-ws/suncertpathbuilderexception-unable-to-find-valid-certification-path-to-requested-target/. Same steps are suggested across the different forums. But still i get the same SSL handshake error which is

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path   building failed: sun.security.
provider.certpath.SunCertPathBuilderException: unable to find valid certification path to   requested target
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)

Though it i got rid of this SSLHandshakeException by mentioning below parameters in JVM trustore. -Djavax.net.ssl.trustStore=C:.keystore -Djavax.net.ssl.trustStorePassword=changeit

My question here is why first approach(which is proper approach) i.e putting the jssecacerts file under /lib/security is not working? Another point is what is different between first and second approach ?

M Sach
  • 33,416
  • 76
  • 221
  • 314

2 Answers2

7

Though it i got rid of this SSLHandshakeException by mentioning below parameters in JVM trustore. -Djavax.net.ssl.trustStore=C:.keystore -Djavax.net.ssl.trustStorePassword=changeit

It's not clear what you were trying to do with these options. Either you use the default truststore (normally jssecacerts, if it exists; otherwise, cacerts) or you specify your own. .keystore tends to be used as a keystore, not truststore (although there is no default JSSE value). (I would also specify the full path instead of C:.keystore, by the way.)

It's probably better to make a copy of your original cacerts (or jssecacerts) file (remove the extra one you've put, if you've changed something) and add your remote certificate to it (i.e. app2's cert in app1's copy and app1's cert in app2's copy, if needed).

You can list the certificates using keytool -list -keystore keystore.jks (see help for more options if needed).

You can export a certificate using keytool -export -keystore server1-keystore.jks -alias server_alias -file server1.crt.

Then, import it in the other truststore: keytool -import -keystore client2-truststore.jks -file server1.crt. (Here, client2-truststore.jks will be a copy of cacerts.) Then, configure your JVM running Apache Tomcat (not necessarily the Tomcat connector) to use it. You should be able to set the JVM parameters in catalina.sh (JAVA_OPTS=-D...).

EDIT:

My question here is why first approach(which is proper approach) i.e putting the jssecacerts file under /lib/security is not working?

To answer your question more directly, I've just double-checked on a clean Oracle JRE 6 installation (1.6.0_31), and jssecacerts takes precedence over cacerts when present (as documented in the JSSE Ref Guide, so there doesn't seem to be a bug). I'm not sure where Oracle have moved Andreas Sterbenz's Sun blog, so I'm not sure which copy of InstallCert you've used. I guess something my have gone wrong there.

As far as I'm aware, InstallCert connects to the server to get its certificate (replacing the export step above): you effectively assume that the certificate you get on your first connection is the right one (and can be trusted). You could also get that certificate using OpenSSL. However, in your case, you seem to have control over the two servers and their respective keystores, so you might as well use keytool -export to be sure.

Another point is what is different between first and second approach ?

The first approach (changing jssecacerts) sets the configuration for all applications that will use this installation of the JRE, whereas the second will apply those settings to the JVM once it's running Apache Tomcat only.

Note, that if you didn't have a jssecacerts but only a cacerts file, if you only import your certificate into jssecacerts, cacerts will be ignored, so you won't be able to connect to servers that have a certificate issued by a CA that would normally be trusted by default. That's why starting with a copy of the default file can be useful. (In addition, if your application also connects to other sites that would normally be trusted by default, this could also explain why you'd get this error message, at a different place this time.)

Ultimately, it's your responsiblity to check what's in jssecacerts or cacerts:

IMPORTANT NOTE: The JDK ships with a limited number of trusted root certificates in the /lib/security/cacerts file. As documented in keytool, it is your responsibility to maintain (that is, add/remove) the certificates contained in this file if you use this file as a truststore.

Depending on the certificate configuration of the servers you contact, you may need to add additional root certificate(s). Obtain the needed specific root certificate(s) from the appropriate vendor.

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
  • @ Bruno Thanks for your informative reply. At last it worked(after restart of my local box). I used the InstallCert.java at http://code.google.com/p/java-use-examples/source/browse/trunk/src/com/aw/ad/util/InstallCert.java. I have on more question. This program generated the jssecacerts which will get precedence over cacerts. So is there a way instead of generating new truststore i.e jssecacerts i can add my self signed certificate in the existing cacerts file (so that old cerfitificates by verified CA's in existing cacerts file does not get ingnored). – M Sach Mar 26 '12 at 05:29
  • For your information:-I have cacerts file by default inside jre\lib\security directory not jssecacerts file – M Sach Mar 26 '12 at 05:29
  • @MSach. Looking at the `InstallCert` code, it will generate a `jssecacerts` file, but load from `jssecacerts` or `cacerts`, so it makes a copy anyway. Not sure why you had to restart your box. Had you not restarted Tomcat after making those changes? – Bruno Mar 26 '12 at 09:09
  • As you said Looking at the InstallCert code, it will generate a jssecacerts file, but load from jssecacerts or cacerts, so it makes a copy anyway. I think what you are trying to say here is, InstallCert code is making copy of all certificates present in cacerts file to new jssecacets file. So previous certificates present in cacerts file will not be ignored. Right? – M Sach Mar 27 '12 at 05:08
  • Indeed, they should be copied too. – Bruno Mar 27 '12 at 09:49
0

The difference is that you added the certificate to the incorrect truststore file :). JRE's system truststore file is not jssecacerts but simply cacerts under ${JRE_HOME}/lib/security/. You were creating a new trustore which the JRE isn't aware of. Adding the certificate to the proper store will resolve your problem. However, let me warn you that it is not a good idea to add your custom CA certificates to the system truststore. Add them to the user truststore and use it the way you are using in the second option.

Drona
  • 6,886
  • 1
  • 29
  • 35
  • If we go thru Nic Brough post at http://forums.atlassian.com/thread.jspa?threadID=52713, looks like jssecacerts is the first one in search order for the locating the trust store . But if go by your words that JRE is only aware of jssecacerts not of jssecacerts .Then if i run the program InstallCert given at http://code.google.com/p/java-use-examples/source/browse/trunk/src/com/aw/ad/util/InstallCert.java and mention the file name as cacert instead of jssecacerts won't it override the default root certificate already present in cacert ? – M Sach Mar 24 '12 at 18:07
  • I am not aware of the search paths JRE goes through to find the stores. Nic might be correct but since you already tried doing it and it didnt work, I would be forced to believe that it doesnt work that way. The Truststore is simply a collection of trusted certificates of authorities in a specific order. Adding a new self signed certificate to the collection will not harm it. It is just a simple addition. – Drona Mar 24 '12 at 18:29
  • But again dont add your certificates to the system truststore because it would affect all JVM instances using that JRE. Using your own custom store is a good idea. – Drona Mar 24 '12 at 18:31
  • when you say add to user truststore you mean adding these parameters i.e -Djavax.net.ssl.trustStore=C:.keystore -Djavax.net.ssl.trustStorePassword=changeit in jvm options of tomcat. Right? – M Sach Mar 25 '12 at 15:37
  • This answer is completely incorrect. See the JSSE Reference Guide. Java will use jssecacerts if found, otherwise cacerts. If you don't know these details you shouldn't be posting about it. – user207421 Mar 25 '12 at 20:44
  • Yes. I think you should go with @Bruno 's comment. He has put things elaborately and nicely. – Drona Mar 26 '12 at 05:40