directory-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Emmanuel Lecharny <elecha...@gmail.com>
Subject [MINA 3] SSL
Date Wed, 23 Nov 2011 18:26:24 GMT
Hi guys,

yesterday, I faced a very dire issue with the way we handle SSL in MINA 2.

Basically, SSL is managed through the SslFilter, which is added in the 
chain. The problem is that the filter can only be added on an existing 
session. What are the consequences of such a choice ?

Basically, the first time you will send some data, the handshake will 
occur. That mans some data will be exchanged from the server to the 
client (and vice-versa), each of those data being processed by the 
SslFilter in the messageReceived() method.

Just like the data you will send.

Now, what happens when you try to use an asynchronous mode ? Let's look 
at some sample code :

         ...
         // Build the connection address
         SocketAddress address = new InetSocketAddress( 
config.getLdapHost(), config.getLdapPort() );

         // And create the connection future
         ConnectFuture connectionFuture = connector.connect( address );

         // Wait until it's established
         connectionFuture.awaitUninterruptibly();

         boolean isConnected = connectionFuture.isConnected();

         if ( !isConnected )
         {
          ...

Here, if we suppose that we haven't injected a TrustManager in the SSL 
context, we will get an exception during the Handshake :
javax.net.ssl.SSLHandshakeException: SSL handshake failed.
     at 
org.apache.mina.filter.ssl.SslFilter.messageReceived(SslFilter.java:495)
     at 
org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:434)
     at 
org.apache.mina.core.filterchain.DefaultIoFilterChain.access$5(DefaultIoFilterChain.java:429)
     at 
org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.messageReceived(DefaultIoFilterChain.java:796)
     at 
org.apache.mina.core.filterchain.IoFilterAdapter.messageReceived(IoFilterAdapter.java:119)
     at 
org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:434)
     at 
org.apache.mina.core.filterchain.DefaultIoFilterChain.fireMessageReceived(DefaultIoFilterChain.java:426)
     at 
org.apache.mina.core.polling.AbstractPollingIoProcessor.read(AbstractPollingIoProcessor.java:715)
     at 
org.apache.mina.core.polling.AbstractPollingIoProcessor.process(AbstractPollingIoProcessor.java:668)
     at 
org.apache.mina.core.polling.AbstractPollingIoProcessor.process(AbstractPollingIoProcessor.java:657)
     at 
org.apache.mina.core.polling.AbstractPollingIoProcessor.access$9(AbstractPollingIoProcessor.java:654)
     at 
org.apache.mina.core.polling.AbstractPollingIoProcessor$Processor.run(AbstractPollingIoProcessor.java:1141)
     at 
org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:64)
     at 
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
     at 
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
     at java.lang.Thread.run(Thread.java:680)
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
     at 
com.sun.net.ssl.internal.ssl.Handshaker.checkThrown(Handshaker.java:1015)
     at 
com.sun.net.ssl.internal.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:485)
     at 
com.sun.net.ssl.internal.ssl.SSLEngineImpl.writeAppRecord(SSLEngineImpl.java:1128)
     at 
com.sun.net.ssl.internal.ssl.SSLEngineImpl.wrap(SSLEngineImpl.java:1100)
     at javax.net.ssl.SSLEngine.wrap(SSLEngine.java:452)
     at org.apache.mina.filter.ssl.SslHandler.handshake(SslHandler.java:575)
     at 
org.apache.mina.filter.ssl.SslHandler.messageReceived(SslHandler.java:349)
     at 
org.apache.mina.filter.ssl.SslFilter.messageReceived(SslFilter.java:476)
     ... 15 more
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
     at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
     at 
com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1528)
     at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:243)
     at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
     at 
com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206)
     at 
com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)
     at 
com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
     at com.sun.net.ssl.internal.ssl.Handshaker$1.run(Handshaker.java:533)
     at java.security.AccessController.doPrivileged(Native Method)
     at 
com.sun.net.ssl.internal.ssl.Handshaker$DelegatedTask.run(Handshaker.java:952)
     at org.apache.mina.filter.ssl.SslHandler.doTasks(SslHandler.java:767)
     at org.apache.mina.filter.ssl.SslHandler.handshake(SslHandler.java:541)
     ... 17 more
Caused by: sun.security.validator.ValidatorException: No trusted 
certificate found
     at 
sun.security.validator.SimpleValidator.buildTrustedChain(SimpleValidator.java:330)
     at 
sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:110)
     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:1185)
     ... 24 more

Fine... But the key here is that the *isConnected* boolean will be 
*true* ! And that means we can send data to the other end, without 
getting an error. What happens in our case is that when we try to bind, 
the writeBindRequest() method blocks forever (well, until we reach the 
timeout) :

     private void writeBindRequest( BindRequest bindRequest ) throws 
LdapException
     {
         // Send the request to the server
         WriteFuture writeFuture = ldapSession.write( bindRequest );

         // Wait for the message to be sent to the server
         if ( !writeFuture.awaitUninterruptibly( timeout ) )


         {
             // We didn't received anything : this is an error
             LOG.error( "Bind failed : timeout occured" );

             throw new LdapException( TIME_OUT_ERROR );
         }
     }

Nothing will unlock the writeFuture, because we won't get any message 
indicating that the write has been successful - or not, as the session 
is not valid when the handshake fails.

There is no way with MINA to workaround this (I tried may possible 
solution), because the MINA session is always connected as soon as it's 
created. Even if the handshake is failing, the session can be 
invalidated, but we may already be waiting on it in the writeBindRequet 
method.

The best solution would be to modify MINA so that when the session is 
invalidated, the awaitUniterruptiby() is interrupted. But the way MINA 
is coded is so bloody horrible that I don't want to spend 2 weeks doing 
that in MINA 2.

I applied a workaround, and ugly one : I check every 100 ms to see if 
the connection is still valid. If the SSL handshake fails, I invalidate 
the session, so we are fine.

I must say MINA 2 is depressing ...

-- 
Regards,
Cordialement,
Emmanuel L├ęcharny
www.iktek.com


Mime
View raw message