Wednesday, September 23, 2015

How WSO2 API Manager gateway to back end secure connection works and troubleshoot SSL gateway issues.

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
===========

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.

2 comments:

  1. Hi, I configured the SSL tomcat on the server where my tomcat and application is deployed. From Windows machine, it's connecting to SSL protected site fine, but from Ubuntu machine it's not connecting and giving the same error you mentioned above. What is the possible reason of failure ?

    ReplyDelete
  2. I think you can import certificate to client trust store(in your case its browser).

    ReplyDelete