Whenever Java(here in this care WSO2 API Manager act as JVM) attempts to connect to another application over SSL, it will only be able to connect to that application if it can trust it. The way trust is handled in the Java world is that you have a key store (typically $JAVA_HOME/lib/security/cacerts), also known as the trust store. This contains a list of all known Certificate Authority (CA) certificates, and Java will only trust certificates that are signed by one of those CAs or public certificates that exist within that key store.
This problem is therefore caused by a certificate that is self-signed (a CA did not sign it) or a certificate chain that does not exist within the Java key store. Java does not trust the certificate and fails to connect to the application.
We can simply test it with following commands. Here i will use external class to perform SSL poke(class) using our client trust store.
For 1st URL
===========
For 2nd URL
===========
As you can see first will print "Successfully connected". Then clearly 2nd one is self signed certificate which does not reside in our trust store. And that cause issue here.
Even if we have host name verification or not it doesn't matter here.
Host name verifier will come next.
If we didn't put host name verifier AllowAll in axis2.xml for first end point (https://test.com/posts) then you will see following.
During handshaking, if the URL's host name and the server's identification host name mismatch, the verification mechanism can call back to implements of interface(what we have done is override it with property defined in axis2.xml file and return true if property is there) to determine if this connection should be allowed. The policies can be certificate-based or may depend on other authentication schemes. Here second URL failed not because host name issue its failing because its self signed certificate and java does not trusted it. Even first one will fail if we didn't enabled host name verification.
Please refer SSLPoke(class) class for your reference.
This problem is therefore caused by a certificate that is self-signed (a CA did not sign it) or a certificate chain that does not exist within the Java key store. Java does not trust the certificate and fails to connect to the application.
We can simply test it with following commands. Here i will use external class to perform SSL poke(class) using our client trust store.
For 1st URL
===========
sanjeewa@sanjeewa-ThinkPad-T530:~/Downloads$ java -Djavax.net.ssl.trustStore=/home/sanjeewa/work/packs/wso2am-1.9.0/repository/resources/security/client-truststore.jks SSLPoke test.com 443
Successfully connected
For 2nd URL
===========
sanjeewa@sanjeewa-ThinkPad-T530:~/Downloads$ java -Djavax.net.ssl.trustStore=/home/sanjeewa/work/packs/wso2am-1.9.0/repository/resources/security/client-truststore.jks SSLPoke test-one.com 443
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:385)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1323)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:702)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:136)
at SSLPoke.main(SSLPoke.java:31)
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
... 15 more
As you can see first will print "Successfully connected". Then clearly 2nd one is self signed certificate which does not reside in our trust store. And that cause issue here.
Even if we have host name verification or not it doesn't matter here.
Host name verifier will come next.
If we didn't put host name verifier AllowAll in axis2.xml for first end point (https://test.com/posts) then you will see following.
[2015-09-22 18:36:36,765] ERROR - TargetHandler I/O error: Host name verification failed for host : test.com
javax.net.ssl.SSLException: Host name verification failed for host : test.com
at org.apache.synapse.transport.http.conn.ClientSSLSetupHandler.verify(ClientSSLSetupHandler.java:152)
at org.apache.http.nio.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:285)
at org.apache.http.nio.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:380)
at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:118)
at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:160)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:342)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:320)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:280)
at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106)
at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:604)
at java.lang.Thread.run(Thread.java:745)
During handshaking, if the URL's host name and the server's identification host name mismatch, the verification mechanism can call back to implements of interface(what we have done is override it with property defined in axis2.xml file and return true if property is there) to determine if this connection should be allowed. The policies can be certificate-based or may depend on other authentication schemes. Here second URL failed not because host name issue its failing because its self signed certificate and java does not trusted it. Even first one will fail if we didn't enabled host name verification.
Please refer SSLPoke(class) class for your reference.