Thursday, April 1, 2010

Ussing SSL in NMS.ActiveMQ

With the recent addition of SSL support into NMS.ActiveMQ and NMS.Stomp I thought it'd be a good idea to write an article covering how to use the new functionality and explain some of the things to watch out for.  At the time of this writing the SSL support is only in the trunk code, but will make its way into the NMS 1.3.0 release some time soon, until the release you can go to the NMS Site to get the latest code and find build instructions.  

Once you have your NMS and NMS.ActiveMQ builds in hand you need to do a few more things before you can connect to a broker via SSL.

Broker SSL Configuration


The default broker configuration doesn't enable SSL so the first thing you need to do is add configuration of the SSL Transport to your Broker's configuration file, there's a pretty good how-to on the ActiveMQ website showing how to do that, so I won't reproduce it all here.

Of SSL Certificates and Trust

Now that you've configured your broker to support SSL connections its time to setup the client machine so that your newly built NMS and NMS.ActiveMQ assemblies can actually connect.  When the NMS client tries to connect over SSL its going to want to validate that it can trust the server on the other end of the connection, this implies that the Certificate the broker sends the client when it connects is one that we trust.  The trust relationship between the .NET client and the Broker comes from the broker sending a certificate that is either signed by a trusted Certificate Authtority or by virtue of us having added the Certificate itself to our list of trusted Certificates.

To add the Broker's Certificate to the list of trusted Certificates that .NET clients are aware of can be a painful and mysterious process.  I'm working from a Linux box running Mono so I can tell you how to I did it, how its done on a Windows machine might be a bit different.  

By following the instructions on the ActiveMQ sites "How do I use SSL" article you should have exported your Broker's SSL Certificate to a file named broker_cert (I named mine broker.cer instead).  You can use the 'certmgr.exe' command to add that certificate to you list of Trusted Certificates like so:
certmgr -add -c Trust broker.cer
This add the Certificate to a list of trusted Certificates that should allow your NMS client to connect without encountering validation errors.  I'll give you a hint on another way to make the connection to the Broker without adding the Certificate to you Trust store later on.

Connecting over SSL with NMS.ActiveMQ

Like any other connection using NMS the way we specify what server to connect to and how we want to do so is done via the connection URI.  This means if you already have a working NMS client you can easily start using the SSL functionality simply by referencing the new Assemblies and updating you connection URI.  So what does the new URI look like?  Pretty much the same as the old one except where you would have put tcp you now put ssl.  Sounds easy, lets take a look at a URI that I use to connect to my Broker:
ssl://localhost:61617
That's it, same old URI, new protocol. If you added the Broker's certificate to the Trust store then your client should connect and run just like it always has.

Something Went Wrong!

Well you knew it was to good to be true, it couldn't be that easy.  You tried running your client and got a bunch of exceptions when it tried to connect, what to do.

A couple things can go wrong here, lets take a look:
  • The Broker Certificate wasn't in the Trust store.
  • The host name in the URI you used to connect doesn't match the common name of the Certificate your broker is using.
Earlier I showed you how to add the Broker's certificate to the Trust store, but maybe you didn't read that part, or maybe you couldn't figure out how to accomplish that for your particular version of Windows, well there's a workaround.  Since I didn't want to always have to put the dummy self signed Certificates that I test with in the Trust store I added an URI option in NMS.ActiveMQ to let me bypass this, its called 'transport.acceptInvalidBrokerCert' and your URI would look as follows if you decided to use it:
ssl://localhost:61617?transport.acceptInvalidBrokerCert=true
This options pretty much forces the NMS client to accept any old Certificate that your Broker sends, so best to only use this in test environments.

Now onto the other common problem, your Broker's Certificate could have something in its Common Name field that's not the same as the host name you put in your URI.  This could happen for a number of reasons especially when you are using self signed Certificates, fortunately we gave you a way around this one as well, if you need to override the name we use to look up the Server's Certificate from the host name use the 'transport.serverName' option:
ssl://localhost:61617?transport.serverName=\"My Test Cert\"
This will cause the NMS code to use "My Test Cert" as the name of lookup when authenticating the Server connection.  Normally the name in the Certificate would match the URL of the server but when testing you might just be using IP addresses so this is a convenient workaround.

Conclusion

That's about all there is to it, pretty easy right?  There's more to it if you want to do two way Client / Server authentication but I think I will save that for another posting.  Hopefully you found this somewhat helpful.  If you have questions or comments please let me know, I will update the posting if something is unclear or incorrect.