Author |
Message
|
francoG |
Posted: Thu Mar 08, 2012 3:45 am Post subject: MQ Connection failed with SSL |
|
|
 Novice
Joined: 18 Aug 2011 Posts: 23
|
Hello dear friends,
I'm writing a Java application that send message over MQ.
the application is working fine, but now I have to add SSL security.
I followed instruction i found in the WebSphere MQ V6,... redpaper to set up connection on server and client and various certificate and keystore.
I used the amqsputc command in a cmd window and after some initial problem I get a successfull connection.
The only way I get to work is to define a ClientChannel and export the AMQCLCHL.TAB file from Server to client.
The first Question is : is this the only way to connect a client to a SSL MQ server?
Now I try to do the same with Java:
I defined a class for testing connection: here is the code I used in Java
Code: |
public class MyMQSender {
private MQQueueConnectionFactory qcf =new MQQueueConnectionFactory();
private MQQueueConnection connection;
private MQQueueSession session;
private MQQueue outQueue;
private MQQueue inQueue;
private String inQueueName;
public boolean startMQConnection(String host, String port, String queueManager, String sendQueue, String receiveQueue, String channelName) {
try {
System.out.println("Initial user.name="+System.getProperty("user.name"));
System.out.println("DBConfig.user.name="+DBConfig.MQ_USERNAME);
System.setProperty("user.name",DBConfig.MQ_USERNAME);
System.out.println("Authorisation required user.name="+System.getProperty("user.name"));
System.out.println("set Host name to "+host);
qcf.setHostName(host);
System.out.println("set MQ Channel to "+channelName);
qcf.setChannel(channelName);
System.out.println("set Port to "+port);
qcf.setPort(Integer.parseInt(port));
System.out.println("set QueueManager to "+queueManager);
qcf.setQueueManager(queueManager);
//qcf.setQueueManager("");
System.out.println("set TransportType to "+JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
qcf.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
System.out.println("Use SSL is "+myConfig._UseSSLCert );
if (myConfig._UseSSLCert){
System.out.println("trustStore "+myConfig._truststoragepath);
System.setProperty("javax.net.ssl.trustStore", myConfig._truststoragepath);
System.out.println("keyStore"+apiaConfig._keystoragepath);
System.setProperty("javax.net.ssl.keyStore", myConfig._keystoragepath);
System.out.println("keyStorePassword "+myConfig._keystoragepass);
System.setProperty("javax.net.ssl.keyStorePassword", myConfig._keystoragepass);
System.out.println("SSLCipherSuite "+myConfig._SSLCipherSuite);
qcf.setSSLCipherSuite(myConfig._SSLCipherSuite);
//
}
System.out.println("SSLPeerName "+qcf.getSSLPeerName());
System.out.println("Set Transport type to MQJMS_TP_CLIENT_MQ_TCPIP( "+JMSC.MQJMS_TP_CLIENT_MQ_TCPIP+")");
//qcf.setTransportType(JMSC.MQJMS_TP_BINDINGS_MQ);
qcf.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
System.out.println("setFailIfQuiesce(1)");
qcf.setFailIfQuiesce(1);
URL channelTable1 = null;
try {
channelTable1 = new URL("file:"+"C:/MQCLIENT/AMQCLCHL.TAB");
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e.getMessage());
return false;
}
System.out.println("set Channel Table to "+channelTable1.toString());
if (channelTable1 != null) {
qcf.setCCDTURL(channelTable1);
}
System.out.println("value of CCD "+qcf.getCCDTURL().toString());
System.out.println("value of CCS "+qcf.getCCSID());
System.out.println("value of QueueManager "+qcf.getQueueManager());
System.out.println("createQueueConnection()");
connection = (MQQueueConnection)qcf.createQueueConnection();
System.out.println("Starting MQ connection ");
connection.start();
System.out.println("create QueueSession ");
session = (MQQueueSession)connection.createQueueSession(true, Session.AUTO_ACKNOWLEDGE);
System.out.println("outPut Queue"+sendQueue);
outQueue = new MQQueue(qcf.getQueueManager(), sendQueue);
outQueue.setFailIfQuiesce(1);
outQueue.setTargetClient(1); //Setta la connessione JMS compliant
System.out.println("input Queue"+receiveQueue);
inQueue = new MQQueue(qcf.getQueueManager(), receiveQueue); //verificare il nome della coda
inQueue.setFailIfQuiesce(1);
inQueue.setTargetClient(1); //Setta la connessione JMS compliant
inQueueName = receiveQueue;
return true;
} catch (JMSException e) {
e.printStackTrace();
System.out.println("errore in startMQConnection", e.getMessage());
return false;
}
}
|
by running this code I get the following prinout:
Initial user.name=fgi
DBConfig.user.name=FGI
Authorisation required user.name=FGI
set Host name to 129.188.20.64
set MQ Channel to M00182S.SZEKWAS.O
set Port to 1416
set QueueManager to SZEKWAS
set TransportType to 1
Use SSL is true
trustStore C:\MQCLIENT\ClientKey.jks
keyStoreC:\MQCLIENT\ClientKey.jks
keyStorePassword franco
SSLCipherSuite SSL_RSA_WITH_AES_128_CBC_SHA
SSLPeerName null
Set Transport type to MQJMS_TP_CLIENT_MQ_TCPIP( 1)
setFailIfQuiesce(1)
set Channel Table to file:C:/MQCLIENT/AMQCLCHL.TAB
value of CCD file:C:/MQCLIENT/AMQCLCHL.TAB
value of CCS 819
value of QueueManager SZEKWAS
createQueueConnection()
javax.jms.JMSException: MQJMS2005: Creazione di MQQueueManager non riuscita per '129.188.20.64:SZEKWAS'
at com.ibm.mq.jms.services.ConfigEnvironment.newException(ConfigEnvironment.java:586)
at com.ibm.mq.jms.MQConnection.createQM(MQConnection.java:2110)
at com.ibm.mq.jms.MQConnection.createQMNonXA(MQConnection.java:1532)
at com.ibm.mq.jms.MQQueueConnection.<init>(MQQueueConnection.java:150)
at com.ibm.mq.jms.MQQueueConnectionFactory.createQueueConnection(MQQueueConnectionFactory.java:185)
at com.ibm.mq.jms.MQQueueConnectionFactory.createQueueConnection(MQQueueConnectionFactory.java:112)
(... more stack trace)
errore in startMQConnection on Queue =MALL.ONLINE.SZEKWASMQJMS2005: Creazione di MQQueueManager non riuscita per '129.188.20.64:SZEKWAS'
here some Parameters:
QueueManager name :SZEKWAS
IP Adress :129.18.8.20.64
Listening port :1416
Server connection channel :M00182S.SZEKWAS.O
local queue :M00182S.ONLINE.SZEKWAS
client connection channel :M00182S.SZEKWAS.O
client side"service directory": C:\MQCLIENT
Directory of c:\MQCLIENT
08.03.2012 10:40 <DIR> .
08.03.2012 10:40 <DIR> ..
08.03.2012 10:28 10'008 AMQCLCHL.TAB
08.03.2012 10:40 21'171 ClientKey.jks
08.03.2012 10:07 80 key.crl
08.03.2012 10:07 110'080 key.kdb
08.03.2012 10:07 80 key.rdb
08.03.2012 10:08 129 key.sth
6 File(s) 141'548 bytes
Can anybody help me? |
|
Back to top |
|
 |
mqjeff |
Posted: Thu Mar 08, 2012 3:50 am Post subject: |
|
|
Grand Master
Joined: 25 Jun 2008 Posts: 17447
|
You can set the CCDTURL property of the QCF to indicate the location of the client channel table.
The use of a client channel table is not strictly necessary to configure and use an SSL connection with MQ, it's just the easiest way to do so.
You can, even in C, configure it manually. In C this is done using the MQCONNX call. In Java this is done by setting the necessary pieces of MQEnvironment.
You're not using straight Java, however, you're using JMS. This is a different beast, and does not allow an individual programmer to have actual direct access to the low level connection objects, because JMS is supposed to make things *easier* by *abstracting* the messaging layer.
So please look into using CCDTURL on your connection factory. |
|
Back to top |
|
 |
zpat |
Posted: Thu Mar 08, 2012 5:00 am Post subject: |
|
|
 Jedi Council
Joined: 19 May 2001 Posts: 5866 Location: UK
|
|
Back to top |
|
 |
francoG |
Posted: Thu Mar 08, 2012 5:12 am Post subject: |
|
|
 Novice
Joined: 18 Aug 2011 Posts: 23
|
hi mqjeff,
in the Java code that I've attached you can see I've set the CCDTOURL .
see the line ->qcf.setCCDTURL(channelTable1);
I once try to connect even without using CCDTOURL but I get always the same error.
I even enabled the -Djavax.net.debug=all switch to see the SSL debug informations, but it seems it crash before starting SSL handshake.
Franco |
|
Back to top |
|
 |
francoG |
Posted: Thu Mar 08, 2012 5:26 am Post subject: |
|
|
 Novice
Joined: 18 Aug 2011 Posts: 23
|
Hi zpat ,
I 've already read the both documents: the first ends with this quote:
Quote: |
If you are using the MQ JMS client, you can set the CipherSuite on the connection factory using the setSSLCipherSuite() method:
MQConnectionFactory factory = new MQConnectionFactory();
factory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
factory.setQueueManager("MyQMgr");
factory.setSSLCipherSuite("SSL_RSA_WITH_NULL_MD5");
factory.setPort(1414);
factory.setHostName("127.0.0.1");
MQConnection connection = factory.createConnection(); |
that is my case:
I started developing with the code fragment in example.
I then read the second document ( and more others in the last two weeks ) but I think I'm lost.
 |
|
Back to top |
|
 |
francoG |
Posted: Thu Mar 08, 2012 6:50 am Post subject: |
|
|
 Novice
Joined: 18 Aug 2011 Posts: 23
|
I try again WITHOUT using setCCDTURL
the result is only little different: the
ssl log is now showing the first stage of negotiation...
createQueueConnection()
keyStore is : C:\MQCLIENT\key.jks
keyStore type is : jks
keyStore provider is :
init keystore
init keymanager of type SunX509
trustStore is: C:\MQCLIENT\key.jks
trustStore type is : jks
trustStore provider is :
init truststore
adding as trusted cert:
Subject: CN=VeriSign Class 4 Public Primary Certification Authority - G3, OU="(c) 1999 VeriSign, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
Issuer: CN=VeriSign Class 4 Public Primary Certification Authority - G3, OU="(c) 1999 VeriSign, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
Algorithm: RSA; Serial number: 0xeca0a78b6e756a01cfc47ccc2f945ed7
Valid from Fri Oct 01 02:00:00 CEST 1999 until Thu Jul 17 01:59:59 CEST 2036
adding as trusted cert:
....
here is the long list of all certificate found in the keystore
then continue with start connection....
trigger seeding of SecureRandom
done seeding SecureRandom
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
javax.jms.JMSException: MQJMS2005: Creazione di MQQueueManager non riuscita per '129.188.20.64:SZEKWAS'
at com.ibm.mq.jms.services.ConfigEnvironment.newException(ConfigEnvironment.java:586)
at com.ibm.mq.jms.MQConnection.createQM(MQConnection.java:2110)
at com.ibm.mq.jms.MQConnection.createQMNonXA(MQConnection.java:1532)
at com.ibm.mq.jms.MQQueueConnection.<init>(MQQueueConnection.java:150)
at com.ibm.mq.jms.MQQueueConnectionFactory.createQueueConnection(MQQueueConnectionFactory.java:185)
at com.ibm.mq.jms.MQQueueConnectionFactory.createQueueConnection(MQQueueConnectionFactory.java:112)
so the MQ CLient Software is able to read the keystore:
what I miss? |
|
Back to top |
|
 |
mqjeff |
Posted: Thu Mar 08, 2012 6:58 am Post subject: |
|
|
Grand Master
Joined: 25 Jun 2008 Posts: 17447
|
francoG wrote: |
I try again WITHOUT using setCCDTURL |
Right, so I didn't see the setCCDTURL because you were also calling a bunch of other things to set up the connection.
If you're using the CCDT, you only need to provide the queue manager name, so that it uses the right channel in the CCDT, and then the keystore/truststore information.
You also need to print the LinkedException from the JMSException.
This will give you the MQRC that tells you why the SSL is failing. |
|
Back to top |
|
 |
francoG |
Posted: Thu Mar 08, 2012 7:30 am Post subject: |
|
|
 Novice
Joined: 18 Aug 2011 Posts: 23
|
hi mqjeff
Quote: |
you were also calling a bunch of other things to set up the connection.
|
you're right btw it's alway difficult to give the right amount of information....
I changed a little my program, so when I use the CCDT I set only the MQserverName and the Truststore path.
I then add the stacktracePrintout of the lined exception....thank you!
here is the list...MQJE001 : code 2, cause 2009.....mhmm did you know what does it means?
com.ibm.mq.MQException: MQJE001: Codice completamento 2, Causa 2009
at com.ibm.mq.MQQueueManager.sequentialConstruct(MQQueueManager.java:978)
at com.ibm.mq.MQQueueManager.<init>(MQQueueManager.java:865)
at com.ibm.mq.MQSPIQueueManager.<init>(MQSPIQueueManager.java:83)
at com.ibm.mq.jms.MQConnection.createQM(MQConnection.java:2037)
at com.ibm.mq.jms.MQConnection.createQMNonXA(MQConnection.java:1532)
at com.ibm.mq.jms.MQQueueConnection.<init>(MQQueueConnection.java:150)
at com.ibm.mq.jms.MQQueueConnection.<init>(MQQueueConnection.java:60)
at com.ibm.mq.jms.MQQueueConnectionFactory.createQueueConnection(MQQueueConnectionFactory.java:171)
at com.ibm.mq.jms.MQQueueConnectionFactory.createQueueConnection(MQQueueConnectionFactory.java:112)
|
|
Back to top |
|
 |
Vitor |
Posted: Thu Mar 08, 2012 7:57 am Post subject: |
|
|
 Grand High Poobah
Joined: 11 Nov 2005 Posts: 26093 Location: Texas, USA
|
francoG wrote: |
here is the list...MQJE001 : code 2, cause 2009.....mhmm did you know what does it means? |
Yes.
If you look it up, you'll know too.
If you search for it in this forum, you'll find a wealth of useful discussion. _________________ Honesty is the best policy.
Insanity is the best defence. |
|
Back to top |
|
 |
mqjeff |
Posted: Thu Mar 08, 2012 8:04 am Post subject: |
|
|
Grand Master
Joined: 25 Jun 2008 Posts: 17447
|
francoG wrote: |
hi mqjeff
Quote: |
you were also calling a bunch of other things to set up the connection.
|
you're right btw it's alway difficult to give the right amount of information....
I changed a little my program, so when I use the CCDT I set only the MQserverName and the Truststore path. |
Let me be a bit more clear about what I mean.
Code: |
System.out.println("set QueueManager to "+queueManager);
qcf.setQueueManager(queueManager);
URL channelTable1 = null;
try {
channelTable1 = new URL("file:"+"C:/MQCLIENT/AMQCLCHL.TAB");
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, e.getMessage());
return false;
}
System.out.println("set Channel Table to "+channelTable1.toString());
if (channelTable1 != null) {
qcf.setCCDTURL(channelTable1);
}
System.out.println("trustStore "+myConfig._truststoragepath);
System.setProperty("javax.net.ssl.trustStore", myConfig._truststoragepath);
System.out.println("keyStore"+apiaConfig._keystoragepath);
System.setProperty("javax.net.ssl.keyStore", myConfig._keystoragepath);
System.out.println("keyStorePassword "+myConfig._keystoragepass);
System.setProperty("javax.net.ssl.keyStorePassword", myConfig._keystoragepass);
System.out.println("SSLCipherSuite "+myConfig._SSLCipherSuite);
qcf.setSSLCipherSuite(myConfig._SSLCipherSuite); |
Should be all you need.
The name of the *queue manager*, the *location of the CCDT* and the *locations* of the keystore/trust stores. |
|
Back to top |
|
 |
francoG |
Posted: Sun Mar 11, 2012 1:33 am Post subject: |
|
|
 Novice
Joined: 18 Aug 2011 Posts: 23
|
i'm Sorry for long delay in reply, I was cut off from log-in due a problem with my account.
thank you mqjeff, for your reply
indeed what you wrote is exactly what i done in the code: probably there is still a stupid error that crash everything.
what It should be right:
1 Keystores in client and server side.
2 key exchange
3 channel definition.
4accessibility of CCDT file
5 accessibility of server ( no firewall)
this becase ( as I wrote ) I could connect by using command line amqxxx commands.
Ok, in the next days, as soon I will be back in office, I will perform more test on this side.
On the other side, the fact I used CCDT, was only because I found only this as method to connect via SSL using Command line.
My final task is to connect using the java program.
Now I'm only in Testing phase, I use a testing MQ server on a VM on my computer, so ther's no problem for me to change any configuration I want and copy the CCDT table.
But I'm quite sure the owner of the productione MQ server I will have connect to, will not sent me the CCDT table. I suppose I should connect using another solution.
In another post of this forum I see the following code ( do you think it could work or there are other way?):
Code: |
SSLContext ctx;
KeyManagerFactory kmf;
TrustManagerFactory tmf;
File keystoreFile;
KeyStore ks;
char[] passphrase = "xxxxxxx".toCharArray();
ctx = SSLContext.getInstance("TLS");
kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
ks = KeyStore.getInstance("JKS");
kmf.init(ks, passphrase);
tmf.init(ks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
factory = ctx.getSocketFactory();
MQEnvironment.sslCipherSuite = "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
MQEnvironment.sslSocketFactory = factory;
|
|
|
Back to top |
|
 |
fjb_saper |
Posted: Sun Mar 11, 2012 2:13 am Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
No you don't need all that.
What you did not tell us is the CipherSpec of the SVRCONN channel on the qmgr. This will determine whether or not you need to set SSLFIPS to true...
O.K. so when you specify the CCDT URL you MUST have host, channel and port as blank/empty strings. Best would be to not set them at all...
Also keep in mind if you need a CipherSuite that is SSLFIPS your keysize needs to be at least 2048...
Have fun  _________________ MQ & Broker admin |
|
Back to top |
|
 |
francoG |
Posted: Wed Mar 14, 2012 10:15 am Post subject: |
|
|
 Novice
Joined: 18 Aug 2011 Posts: 23
|
After several test I finally get the connection with SSL without using the CCDT Table.
The only problem is that not all ciphersuite are working.
some ciphersuite returns this error
MQJE001: Si è verificata una MQException: Codice completamento 2, Causa 2400
MQJE011: Il tentativo di connessione socket è stato rifiutato
I see that 2400 is the code for "unsupported Ciphersuite".
typically do not work the TLS_RSA_*
the other with *DES* or even the NULL_MD5 and NULL_SHA works fine.
is there something different I have to specify when I use different cipher?
is there problem ith JVM or something like that?
thank you |
|
Back to top |
|
 |
fjb_saper |
Posted: Wed Mar 14, 2012 8:24 pm Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
francoG wrote: |
After several test I finally get the connection with SSL without using the CCDT Table.
The only problem is that not all ciphersuite are working.
some ciphersuite returns this error
MQJE001: Si è verificata una MQException: Codice completamento 2, Causa 2400
MQJE011: Il tentativo di connessione socket è stato rifiutato
I see that 2400 is the code for "unsupported Ciphersuite".
typically do not work the TLS_RSA_*
the other with *DES* or even the NULL_MD5 and NULL_SHA works fine.
is there something different I have to specify when I use different cipher?
is there problem ith JVM or something like that?
thank you |
Yes typically the "TLS_RSA*" Ciphersuites will require you to set the SSLFIPS flag on the connection factory to true, and also have a keysize of 2048 or bigger (need to specify when you create your cert request).
You also need to look into the SSLPEER setup. Depending on endianness of the platform, multiple entries of OU may need to appear in the inverse order from what you would expect....
There should be a nice set up on SSL on www.nynjmq.org
See if http://www.nynjmq.org/WMB%20V7%20administration%20with%20SSL.zip will help you any...
Have fun  _________________ MQ & Broker admin |
|
Back to top |
|
 |
francoG |
Posted: Wed Mar 14, 2012 11:51 pm Post subject: |
|
|
 Novice
Joined: 18 Aug 2011 Posts: 23
|
hello fjb_saper,
thank you for reply.
This means that my program works in the right direction, but I only need to add a parametrization switch in my program's configuration panel to set the SSLFIPS.
At present I do not set SSLPEER; btw the meaning of SSLPEER is not totally clear to me.
Beyond mutual autentication....
I actually use ony the server autentication, by specifying "SSL Client Aut" to "Optional" in the SSL parametrisation of the server channel.
Will I need to specify something more in the client softtware if I want to switch "SSL Client Aut" to "Required" ?
How the client software will decide what certificate will be presented to the server? it use the SSLPEER name or what?
thank you
franco |
|
Back to top |
|
 |
|