GoogleSearchBox

Custom Search

Wednesday, June 19, 2013

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provid er.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

I got this exception, while my demo java web application tried to communicate CAS application (deployed in tomcat) using SSL.




I have my tomcat server already configured using SSL certificates and using a keystore file to have the  security certificate.




I got below stacktrace of the errors in my console:
Jun 19, 2013 4:26:27 PM org.jasig.cas.client.util.CommonUtils getResponseFromServer
SEVERE: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
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(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1611)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:187)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:181)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1035)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:124)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:516)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:454)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:884)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1112)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1139)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:418)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1041)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:326)
at org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:305)
at org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator.retrieveResponseFromServer(AbstractCasProtocolUrlBasedTicketValidator.java:50)
at org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java:207)
at org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:169)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:881)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:674)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:541)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
at java.lang.Thread.run(Thread.java:619)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:285)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:191)
at sun.security.validator.Validator.validate(Validator.java:218)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1014)
... 33 more


Below is my tomcat's "server.xml" section having SSL configuration details:

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               address="216.113.229.31"
               maxThreads="150" scheme="https" secure="true"
               truststoreFile="/usr/local/apache-tomcat-6.0.37/conf/cacerts.jks" truststorePass="changeit"
               keystoreFile="/usr/local/apache-tomcat-6.0.37/conf/myServerKeystore.jks" keystorePass="changeit"
               clientAuth="false" sslProtocol="TLS" />

Also, I have imported server Root CA certificate into my browsers.

The reason of the above error, I could figured out is that:
Though I have configured the tomcat to use, "myServerKeystore.jks" java keystore file.
But the Java web applications seems to use by default the security certificates available in the "cacerts" file (located at $JAVA_HOME/jre/lib/security/).

The 1st solutions is:
step 1.  
Copy your "cacerts" file (located at $JAVA_HOME/jre/lib/security/ ) to some safe backup location in case to be able to revert back to original.

step 2. 
Export the security certificates from your keystore file (in my case its "myServerKeystore.jks")  into  "cacerts" (located at $JAVA_HOME/jre/lib/security/ ) .

Using Below command in Linx (Similarly you can achieve it in Windows too) to import ssl certificate from one keystore into another keystore using keytool:

# keytool -importkeystore  -destkeystore /usr/java/default/jre/lib/security/cacerts  -srckeystore myServerKeystore.jks

For windows above can be some thing like this:
C:\certs> keytool -importkeystore  -destkeystore C:\Program Files\Java\jdk1.6.0_24\jre\lib\security\cacerts  -srckeystore  myServerKeystore.jks

Assuming "myServerKeystore.jks" is at "C:\certs"  or accordingly provide the path above for your keystore.
Result will be something like below:

Enter destination keystore password: [enter password here, default is "changeit"]
Enter source keystore password: [enter password here, default is "changeit"]
Entry for alias localhostservcert successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled

Marked in bold above are, meant to be changed if required as per your settings.

Now, restart your server and try again.
Above exception should have been resolved.



If still the issue has not resolved yet, Please consider below importing the root certificate into "cacerts" :

The 2nd solutions is:

step 1.  
Copy your "cacerts" file (located at $JAVA_HOME/jre/lib/security/ ) to some safe backup location in case to be able to revert back to original.

step 2.  
Sometimes, the certificate to be imported MUST be a DER-encoded file. If the contents of the certificate file are binary, it's likely DER-encoded; if the file begins with the text ---BEGIN CERTIFICATE---, it is PEM-encoded and needs to be converted to DER encoding.
So if your root certificate is a PEM encoded, Convert your to a DER format using below command:

# openssl x509 -in casRootCAcert.crt -out casRootCAcert.der -outform DER

Where "casRootCAcert.crt" is my original root CA certificate (the one you used while creating server certificates). As I created in this tutorial.
And where as "casRootCAcert.der" is the new DER formated root CA.

step 3.
 Now Export the DER formatted Root CA certificate  into  "cacerts" (located at $JAVA_HOME/jre/lib/security/ ).

# keytool -import -keystore $JAVA_HOME/jre/lib/security/cacerts -file casRootCAcert.der -alias myservercert

Now, restart your server and try again.
Above exception should have been resolved.

step 4.
List out to see if the $JAVA_HOME/jre/lib/security/cacerts  has your trusted certificate alias:
# keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts

Look for your server certificate alias name, like above, look for "myservercert" or by default it creates an alias named as "mykey".
If it exist, then time to test your ssl connection again.

Now, restart your server and try again.
Above exception should have been resolved.



If you are looking for how to automatically create certificates and import it into keystore, for your development environment, please follow this post.

References used:
https://wiki.jasig.org/display/CASUM/SSL+Troubleshooting+and+Reference+Guide
http://stackoverflow.com/questions/9619030/resolving-javax-net-ssl-sslhandshakeexception-sun-security-validator-validatore?rq=1