Reputation: 51
I could successfully connect to IBM MQ from a camel route and initialize the connection factory bean but now I want to connect with SSL.
Here is what I tried:
<bean id="MyConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="transportType" value="${queue.transportType}" />
<property name="channel" value="${queue.channel}" />
<property name="hostName" value="${queue.hostName}" />
<property name="port" value="${queue.port}" />
<property name="queueManager" value="${queue.manager}" />
<property name="sSLCipherSuite" value="SSL_RSA_WITH_NULL_MD5" />
<property name="sSLCertStores" value="file:C:/Servers/TrustStore/truststore.jks" />
</bean>
But this doesn't work. The following exception was returned:
JMSWMQ0018: Failed to connect to queue manager 'QM_TEST_SSL'
with connection mode 'Client' and host name '10.3.13.161(1415)'.;
nested exception is com.ibm.mq.MQException: JMSCMQ0001:
WebSphere MQ call failed with compcode '2' ('MQCC_FAILED')
reason '2397' ('MQRC_JSSE_ERROR').
Can anyone please help to direct me how to do that?
Upvotes: 4
Views: 4138
Reputation: 10672
You do not state which version of IBM MQ or what JRE that you are using, if it is not the most current version of IBM MQ and is being used with an Oracle JRE then the APAR IT10837 may help here.
There is a good write up of the above APAR at the end of IBM developerWorks blog "MQ Java, TLS Ciphers, Non-IBM JREs & APARs IT06775, IV66840, IT09423, IT10837 -- HELP ME PLEASE!" posted by Tom Leend. He includes a work around for Java clients that do not have this fix.
I've got one final APAR to mention and that is IT10837 (targeted for V7.1.0.8 and V7.5.0.7 and shipped in V8.0.0.5). This APAR affects applications running within Oracle JREs that use TLS CipherSuites to connect to a queue manager where the server-connection channel being used has the SSLCAUTH attributed set to "REQUIRED" (the default value). This means that the client should pass a certificate to the queue manager such that the connecting client can be authenticated by the MQ server.
When the application was running in an Oracle JRE, the SunJSSE provider was not creating a default internal Key Manager object for TLS socket connections, meaning that the client's signed personal certificates were not available for client authentication during the handshake. The IBM JSSE provider does do this based off the information passed via the Java System Properties:
javax.net.ssl.keyStore
and
javax.net.ssl.keyStorePassword
Because a KeyManager object was not created by default, the client certificate was not passed to the queue manager (GSKit) for authentication. As such, the connection from the application would failed. In this scenario, the queue manager would write the following error message into its error log file:
AMQ9637 (Channel is lacking a certificate)
The fix for this APAR is for the MQ classes for JMS and classes for Java to read a certificate keystore, based on the information in the two Java System Properties noted above, and create a KeyManager based on that information in the case when com.ibm.mq.cfg.useIBMCipherMappings is set to the value false in the JVM . This can then be used when the SSLContext is created (which is subsequently used to create an SSLSocketFactory and eventually a secure socket object).
There is a local workaround which is for the application itself to create TrustManagerFactory and KeyManagerFactory factory objects for the appropriate certificate stores and to initialise an SSLContext object these objects. From this SSLContext object and SSLSocketFactory can be created and passed to the MQ classes for JMS (by setting it on the JMS Connection Factory) or to the classes for Java (by setting it on the MQEnvironment or in a Hashtable passed to the MQQueueManager constructor). For example:
---- Code Snippet Start ----
KeyStore keyStore = KeyStore.getInstance("JKS"); java.io.FileInputStream keyStoreInputStream = new java.io.FileInputStream("/home/tom/myKeyStore.jks"); keyStore.load (keyStoreInputStream, password_char_array); KeyStore trustStore trustStore = KeyStore.getInstance ("JKS"); java.io.FileInputStream trustStoreInputStream = new java.io.FileInputStream("/home/tom/myTrustStore.jks"); trustStore.load (trustStoreInputStream, password_char_array); keyStoreInputStream.close(); trustStoreInputStream.close(); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore,password); trustManagerFactory.init(trustStore); SSLContext sslContext = SSLContext.getInstance("TLSv1"); sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); // classes for JMS myJmsConnectionFactory.setObjectProperty( WMQConstants.WMQ_SSL_SOCKET_FACTORY, sslSocketFactory); // classes for Java MQEnvironment.sslSocketFactory = sslSocketFactory;
---- Code Snippet End ----
Upvotes: 1
Reputation: 774
From a security standpoint the Client should only receive generic error messages which could relate to a number of problems. The best place to find out exactly why you client was rejected is the Queue Manager logs. I would suggest looking there to see if there are any errors that help you further determine the problem. From the info given i can think of 3 problems it could be:
The Queue Manager channel is set with an attribute of SSLCAUTH(REQUIRED) however from the description you've given here the client doesn't appear to be using it's own certificate to connect. SSLCAUTH(REQUIRED) will mean that the Queue Manager will only accept connections on the particular channel where the client is connecting with a certificate it trusts. Check the channel definition and set SSLCAUTH(OPTIONAL)
Depending on your version of IBM MQ the CipherSpec you have used (SSL_RSA_WITH_NULL_MD5) is considered weak and will not be accepted by default. You can reenable these deprecated CipherSpecs and the instructions on how to do so can be found on the following Knowledge Center page
The truststore "C:/Servers/TrustStore/truststore.jks" is not being picked up by the client and so the client cannot trust the Queue Manager's certificate. Double check the path you have supplied and remove the "file:" you have added to the path (unless you were specifically instructed to include it).
Upvotes: 2