Hi all, I’ve haven’t posted anything since my last contract…sorry about that (what can I say, I’ve been busy…Ma, AgileJoe’s been abusing me!). In any case, this is as much for my benefit (and documentation for the current team) as it is for the community at large (I never remember this stuff so I want to be able to google it). I did see some other blogs that tackle this subject…but alas…the web Nazis have blocked most technical blogs here.
I was recently tasked with getting an MQSeries .net client to support mutual authentication. I’d done the same the week before for a couple of web services (which was relatively easy) and figured this would be a snap. In reality the only snap was the sound of my morale being crushed. First off, let me say that we wasted about a week trying to get things working with what was later found to be a mis-configured queue manager. We tried to get the team responsible for the queues to ensure they were set up correctly but encountered show-stoppers on two occasions before they finally got it right. Overall, the .Net documentation is spotty and left us to figure out a number of critical steps. If you yourself are trying to setup SSL/Mutual Authentication for a .Net client, be sure to be familiar with the basics of SSL first. It helps quite a bit.
Note: IBM’s on-line publication library doesn’t update the URL in your address bar, so if you find a useful page and want to bookmark it be sure to get the target URL from the document frame and use that to create the bookmark.
On our end, we were trying to get things set up using the XMS client for 6.0 (we switched to the XMS client later in the game). We had already integrated the client successfully with an unsecured queue and figured that the following was all we needed to add to get up and running:connectionFactory.SetStringProperty(XMSC.WMQ_SSL_CIPHER_SUITE, “SSL_RSA_WITH_NULL_SHA”);
Simple enough…we used CIPHER_SUITE (instead of CIPHER_SPEC) as a good client should, set the path to the key store(created using the “IBM Key Management” tool that comes with the client, and we caught on fairly quickly to how the Peer Name is used.
Fog of War:
The basic client configuration was pretty simple, but we were constantly getting MQExceptions that were akin to getting null pointer exceptions. The exceptions basically said “Something has gone terribly wrong in your application”…well I figured as much…I’m getting exceptions after all! Logging the exceptions was useless because we were logging all Exception types. I later found that the MQExceptions (most, not all…some have the exception reason codes in the message itself) had a couple Properties that gave a bit more information, namely “Reason Code”. Once I started capturing the reason codes I found (after a little digging) a couple of reason code lists that gave a little (often precious little) information about the codes. One list was useful for client-specific reason codes and the other was for subscriber-specific reason codes. Also, I found that I couldn’t turn on the client trace with the .Net client library, but we did stumble over the Web Sphere client error log(C:Program FilesIBMWebSphere MQerrors), which was often much more useful than any information found in the exceptions (although you still end up using the reason codes).
Setting up the key store was fun too. In the aforementioned link, you’ll see in Figure 4 the following next to Key Label: “<client identifier of your choice>”. I’m not sure if this is due to our MQ guys, but we had no choice here. First off, the example was for Self Signed certs, so they didn’t really apply in our case. We were using a pfx (p12) cert store with the client key, the trust cert, and the exported private key. I soon learned that the IBM Key Manager requires that the pfx is password protected (I know, it’s a good practice anyway). Then we had to ensure that the Peer Name on the server end matched the common name found in the certificate’s distinguished name. Finally, we found that our “client identifier of choice” had to be the string “ibmwebspheremq” followed by the name of the account under which the process was running…all in lower caps…not much of a choice (e.g. ibmwebspheremqsvcacctname). We probably never would have figured the last one without the help if the MQ team’s manager. If the Key Label isn’t set up correctly we get the following:
CWSMQ0006E: An exception was received during the call to the method ConnectionFactory.CreateConnection: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at IBM.WMQ.MQClient.MQCONNX(String qMgrName, MQCNO& mqcno, Int32& pHconn, Int32& pCompCode, Int32& pReason)
at IBM.WMQ.MQClientConnector.MQCONNX(String qMgrName, MQConnectOptions& cno, Int32& hConn, Int32& compCode, Int32& reason)
at IBM.WMQ.MQQueueManager.Connect(String queueManagerName)
at IBM.WMQ.MQQueueManager..ctor(String queueManagerName, Hashtable properties)
at IBM.WMQ.MQSPIQueueManager..ctor(String queueManagerName, Hashtable properties)
at IBM.XMS.WMQ.WmqConnection.CreateQueueManager(String qmgrName, Boolean isSessionHConn)
at IBM.XMS.WMQ.WmqConnection.CreateQueueManager(String qmgrName)
at IBM.XMS.WMQ.WmqConnection..ctor(WmqConnectionFactory cf, String userName, String password)
at IBM.XMS.WMQ.WmqConnectionFactory.CreateConnection(String userName, String password). During execution of the specified method an exception was thrown by another component. See the linked exception for more information.
…Clear as mud…we wasted some time fiddling with directory permissions, recreating the key store, etc. To make it work with our unit tests (without requiring each developer to set up a private key store for each development workstation that they work on) I threw together an Impersonator class based on an MSDN article. We configured the Key Label using the service account, included the dev key store in source control, and impersonated the service account in our unit test Setup and Tear Down methods. Worked like a charm.
Finally, we’d run across something earlier in IBM’s document “WebShpere MQ Using .Net Version 6.0″ that didn’t quite make sense at first. We had brushed over this until we started getting the following:
“CWSMQ0046E: An environment error occurred when a connection to specified queue manager was attempted. Current libraries are not supported with the specified queue manager. Ensure that appropriate libraries and appropriate versions of these libraries are in use.”
Great, I think, I must have downloaded the wrong client. Before I do anything rash, however, I consult my handy-dandy IBM documentation. On page 24 you see the following: “The following section does not apply to the fully-managed client.“ Okay, so I search for “unmanaged client”…no matches. Then I search for “fully-managed client”…the only match is the line above and one other place (BTW, if you are using XMS, don’t confuse yourself with this document…use the XMS doc first…although the XMS documentation refers you to it for “in-depth information”…lol). I check “managed client” with a few more IBM docs and finally find what I’m looking for in the XMS documentation (“Message Service Clients for C/C++ and .Net”):
“XMSC_WMQ_CM_CLIENT_UNMANAGED (for .NET only) A connection to a queue manager which forces an unmanaged client stack.”
I find an answer in the on-line documentation, but am still a little unsure what this means…Are we supposed to use ‘unsafe’ blocks?…Do I have to rewrite this using pointers?…Do I make external DLL calls like we do with Win32API calls?…What’s going on here?!? Well, in the end it turns out the answer is “not much” We simply had to set another connection property. Why this isn’t included in the documentation’s SSL code examples is another question. Add this call to your ConnectionFactory instance and the pain will go away:
Okay, now Victory!
And that’s it! Aside from the Key Store setup and the basic queue configuration that was already complete, all we needed were the four horsemen of MQSeries:
Make sure you’ve specified a Cipher Suite that is compatible with the Queue’s Cipher Spec
Provide a valid path to your Key Store (.kdb) (and effective know Key Label conventions for the client cert)
Also, we couldn’t get the client to work with the Windows cert store…one of you can figure this out and educate me
Setup the Peer Name so that the server certificate will be accepted by the client during the SSL handshake
Set connection mode to unmanaged so that you can actually use SSL with the queue
There’s really not much to it…I’m not sure why they didn’t just tell me what to do in the documentation. I know that this is really geared toward a small set of .Net developers, but I hope this can be of use. This little task was pretty painful and took a couple of weeks to resolve.
As far as why the documentation for this is so bad…I think, ultimately, that the Java guys basically just hate us. They are in it with the Canadians (yeah you Scott). This is all part of their twisted plan to dominate the Earth.
In fact, I’ll be a Java developer again on my next contract…I’m already starting to hate my .Net self.