Has anyone tried using the nio+ssl transport w/programatic keystore and trust store configuration similar to using SslBrokerService.addSslConnector(String, KeyManager[], TrustManager[], SecureRandom)?

I tried configuring the transport similarly in an extension:

<snip>
public class ExtBrokerService
    extends SslBrokerService
{
    @Override
    protected TransportServer createSslTransportServer(final URI brokerURI, final KeyManager[] km, final TrustManager[] tm, final SecureRandom random)
         throws IOException, KeyManagementException
    {
        if (brokerURI.getScheme().equals("ssl")) { //NON-NLS
            SslTransportFactory transportFactory = new SslTransportFactory();
            SslContext ctx = new SslContext(km, tm, random);
            SslContext.setCurrentSslContext(ctx);
            try {
                return transportFactory.doBind(brokerURI);
            }
            finally {
                SslContext.setCurrentSslContext(null);
            }
        }
        else if (brokerURI.getScheme().equals("nio+ssl")) { //NON-NLS
            SslContext ctx = new SslContext(km, tm, random);
            SslContext.setCurrentSslContext(ctx);
            NIOSSLTransportFactory transportFactory = new NIOSSLTransportFactory();
            try {
                return transportFactory.doBind(brokerURI);
            }
            finally {
                SslContext.setCurrentSslContext(null);
            }
        }
        else {
            return TransportFactory.bind(this, brokerURI);
        }
    }
}
</snip>

And then configuring with:

<snip>
        ExtBrokerService brokerService = new ExtBrokerService();
        TransportConnector connector = brokerService.addSslConnector("nio+ssl://0.0.0.0:0?needClientAuth=true",
            keyStoreManager.getKeyManagers(), keyStoreManager.getTrustManagers(), new SecureRandom());
</snip>

This does appear to start up the transport using nio+ssl.  I've confirmed that the overridden createSslTransportServer() is getting called and is using the "nio+ssl" logic branch.

Its unclear if the needClientAuth bits are getting configured however, since its difficult to inspect vs using the ssl transport via ((SslTransportServer)connector.getServer()).getNeedClientAuth().

Testing with a ssl:// client connection configured with the appropriate {key|trust}stores fails, complaining about "no cipher suites in common".  Some of the ssl debug output shows:

<snip>
...
ActiveMQ Task-1, READ:  SSL v2, contentType = Handshake, translated length = 113
*** ClientHello, TLSv1
RandomCookie:  GMT: 1308393557 bytes = { 81, 129, 30, 234, 206, 134, 210, 218, 170, 130, 85, 15, 37, 247, 89, 189, 135, 213, 205, 15, 19, 38, 77, 90, 224, 246, 175, 61 }
Session ID:  {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
***
ActiveMQ Task-2, fatal error: 40: no cipher suites in common
javax.net.ssl.SSLHandshakeException: no cipher suites in common
ActiveMQ Task-2, SEND TLSv1 ALERT:  fatal, description = handshake_failure
ActiveMQ Task-2, WRITE: TLSv1 Alert, length = 2
ActiveMQ Task-1, fatal: engine already closed.  Rethrowing javax.net.ssl.SSLHandshakeException: no cipher suites in common
...
</snip>

Running the *exact same test* changing only the brokers transport scheme from "nio+ssl" to "ssl" and the ssl connection is established correctly and the test behaves as expected wrt clientAuth, etc.

I was digging around a little, and I'm not really sure if this is correct... but it does not look like the nio+ssl transport server is getting the ssl serversocketfactory instead which NIOSSLTransportFActory.createSocketFactory() should be returning.  Actually when running the tests above I don't see that method called at all.  I also dropped a breakpoint at NIOSSLTransportFactory:51


( https://skitch.com/jasondillon/gw6ft/nio-ssl-w-programatic-key-trust-store-configuration )

And then started to inspect the variables in scope, and it looks like the serverSocketFactory instance given is from NIOTransportFactory.createServerSocketFactory() return:


https://skitch.com/jasondillon/gw6fu/nio-ssl-w-programatic-key-trust-store-configuration )

SSL makes my head want to explode some times.  The NIO transport code and the SSL version of it is a little more complex to follow how its supposed to work vs. the SSL layer on-top of the TCP transport.

Anyways, I'm not sure if the socket factory is an issue here or not, but it could be related?  I'm also guessing that programatic access using nio+ssl hasn't been used that muck since the SslBrokerFactory has not been updated to deal with setting the SslContext for nio+ssl scheme (as shown in ExtBrokerService above)?

The NIOSSLTransportBrokerTest appears to pass:

<snip>
-------------------------------------------------------
 T E S T S
-------------------------------------------------------

Running org.apache.activemq.transport.nio.NIOSSLTransportBrokerTest
Tests run: 129, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 261.187 sec
</snip>

... so I'm guessing that configuring the trust/keystore bits work okay when configuration them globally via javax.net.ssl.* properties?

 * * *

Does anyone have any idea what might be going on here which would cause "no cipher suites in common" errors when using "nio+ssl" when "ssl" works just fine?

Thanks,

--jason