Most discussions on using SSL with WMQ Java applications (using the WMQ Classes for Java) talk about using the javax.net.ssl.keyStore etc. Java System Properties to specify a certificate store and password.

This works well for most applications.
However, there are a few limitations to this approach:

  • The SSL context is initialised only once – the first time it is used.
    If the path/password is incorrect, the JVM must be terminated before trying again.
  • Debugging is only available through using javax.net.debug system property.
    This produces a large amount of output on the console.
  • Only one certificate store can be used per JVM.
    You might want to use different certificates to connect to different queue managers.

So, this post has the starting point for an alternative.

Simple example class

The following class connects to a queue manager, and queries the description.
The main thing missing is exception handling.
However, if you get a failure, it does show how you can get useful exceptions from this approach rather than just 2393 MQRC_SSL_INITIALIZATION_ERROR.

package hursleyonwmq;

// Standard Java API imports 
import java.io.FileInputStream;
import java.util.Hashtable;

// Standard Java SSL API imports
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

// WMQ imports
import com.ibm.mq.MQC;
import com.ibm.mq.MQQueueManager;

/**
 * Simple command line class to create an SSL connection
 * to a queue manager, with the WMQ Base Java classes.
 * @author hursleyonwmq blogger
 * @see https://hursleyonwmq.wordpress.com
 */
public class WmqSslTest {

  /**
   * Main method
   * Example MQSC to define SVRCONN:
   *   DEF CHL(TEST.SSL.CHL) CHLTYPE(SVRCONN) SSLCIPH(RC4_MD5_US)
   * @param args Unused
   * @throws Exception No exception handling
   */
  public static void main(String[] args) throws Exception {
    
    // Queue manager details
    String qmgrName = "TEST.SSL";
    Hashtable props = new Hashtable();
    props.put(MQC.CHANNEL_PROPERTY,   "TEST.SSL.CHL");
    props.put(MQC.HOST_NAME_PROPERTY, "localhost");
    props.put(MQC.PORT_PROPERTY,      new Integer(1414));
    
    // SSL details
    props.put(MQC.SSL_CIPHER_SUITE_PROPERTY, "SSL_RSA_WITH_RC4_128_MD5");
    String  keyStorePath   = "keystore.jks";
    String  trustStorePath = "keystore.jks";
    String  password       = "passw0rd";

    // Create a keystore object for the keystore
    KeyStore keyStore = KeyStore.getInstance("JKS");

    // Open our file and read the keystore
    FileInputStream keyStoreInput = new FileInputStream(keyStorePath);
    try {
      keyStore.load(keyStoreInput, password.toCharArray());
    } finally { keyStoreInput.close(); }               

    // Create a keystore object for the truststore
    KeyStore trustStore = KeyStore.getInstance("JKS");
    
    // Open our file and read the truststore (no password)
    FileInputStream trustStoreInput = new FileInputStream(trustStorePath);
    try {
      trustStore.load(trustStoreInput, null);
    } finally { trustStoreInput.close(); }               

    // Create a default trust and key manager
    TrustManagerFactory trustManagerFactory =
      TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    KeyManagerFactory keyManagerFactory =
      KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

    // Initialise the managers
    trustManagerFactory.init(trustStore);
    keyManagerFactory.init(keyStore,password.toCharArray());

    // Get an SSL context. For more information on providers see:
    // http://www.ibm.com/developerworks/library/j-ibmsecurity.html
    // Note: Not all providers support all CipherSuites.
    SSLContext sslContext = SSLContext.getInstance("SSL_TLS");
    System.out.println("SSLContext provider: " +
                       sslContext.getProvider().toString());

    // Initialise our SSL context from the key/trust managers  
    sslContext.init(keyManagerFactory.getKeyManagers(),
                    trustManagerFactory.getTrustManagers(), null);

    // Get an SSLSocketFactory to pass to WMQ
    SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
    
    // Set the socket factory in our WMQ parameters
    props.put(MQC.SSL_SOCKET_FACTORY_PROPERTY, sslSocketFactory);
    
    // Connect to WMQ
    MQQueueManager qmgr = new MQQueueManager(qmgrName, props);
    try {
    
      // Query the description
      String desc = qmgr.getDescription();
      
      // Output the description
      System.out.println("Queue Manager DESCR: \"" + desc + "\"");

    } finally { qmgr.disconnect(); }
  }
  
}
Advertisements