Connessione a WebSphere MQ in Java con SSL / Keystore

Mi piacerebbe connettermi a un MQ di Websphere 6.0 via Java. Ho già lavorato codice per una coda “normale”, ma ora ho bisogno di accedere a una nuova coda che è crittografata SSL (keystore). Mi è stato inviato un file chiamato something.jks, che presumo sia un certificato che ho bisogno di memorizzare da qualche parte. Ho cercato la rete, ma non riesco a trovare le informazioni giuste.

Questo è il codice che uso per la coda “normale”. Presumo che ho bisogno di impostare alcune proprietà, ma non sono sicuro quale.

MQQueueConnectionFactory connectionFactory = new MQQueueConnectionFactory(); connectionFactory.setChannel(channel_); connectionFactory.setHostName(hostname_); connectionFactory.setPort(port_); connectionFactory.setQueueManager(queueManager_); connectionFactory.setTransportType(1); connectionFactory.setSSsetSSLCertStores(arg0) Connection connection = connectionFactory.createConnection(); connection.setExceptionListener(this); session_ = connection.createSession(DEFAULT_TRANSACTED, DEFAULT_ACKMODE); connection.start(); javax.jms.Queue fQueue = session_.createQueue(queue_); consumer = session_.createConsumer(fQueue); 

Il tutorial di Alex Fehners su developerWorks è un po ‘vecchio (2005) ma contiene degli esempi di codice che dovrebbero funzionare per te.

Configurazione SSL del client Java / JMS Websphere MQ

La tua app Java autentificherà il QMgr in base al suo certificato. Ciò significa che il file jks che ti è stato fornito deve avere il certificato autofirmato di QMgr o avrà il certificato di origine di un’autorità di certificazione che ha firmato il certificato di QMgr. In entrambi i casi, si punta al file usando -Djavax.net.ssl.trustStore= come indicato nell’articolo collegato sopra. Se i jks hanno una password, sarà necessario specificare anche -Djavax.net.ssl.trustStorePassword= . L’autenticazione di QMgr con un truststore è sempre richiesta. La prossima parte può o non può essere richiesta.

L’altro pezzo del puzzle è che QMgr potrebbe richiedere alla tua app di presentare un certificato. In altre parole, il certificato QMgr è sempre autenticato, se l’app è richiesta per l’autenticazione è facoltativa. Se è così, hai ciò che è noto come “autenticazione reciproca”. Se il canale a cui ci si connette è stato configurato con SSLCAUTH(REQUIRED) l’autenticazione reciproca è stata abilitata e il QMgr deve avere il certificato autofirmato della propria applicazione o un certificato radice CA che ha firmato il certificato della propria app nel proprio archivio chiavi. Spero che chiunque abbia creato il file jks lo abbia già organizzato.

Supponendo che sia richiesta l’authorization reciproca, le tue jks avranno, oltre al certificato di fiducia di QMgr, un certificato privato che rappresenta la tua domanda. Per ottenere l’app per recuperare il certificato e presentarlo a QMgr, utilizzare i -Djavax.net.ssl.keyStore= e -Djavax.net.ssl.keyStorePassword= . Si noti che questi dicono key store mentre i precedenti paragrafi dicevano fiduciario .

La mia raccomandazione è di lavorare con l’amministratore WMQ per configurare e testare la connessione SSL. La prima fase dovrebbe essere quella di testare il canale con SSLCAUTH(OPTIONAL) . Ciò verifica che l’applicazione possa risolvere e autenticare il certificato di QMgr. Solo quando questo funziona, l’amministratore di WMQ cambia il canale in SSLCAUTH(REQUIRED) che verifica l’autenticazione nella direzione opposta.

Consiglio vivamente di utilizzare il client v7 WMQ per una nuova applicazione. Questo è per due motivi: 1) v6 è la fine della vita a partire da settembre 2011; 2) il codice v7 ha molte più funzionalità diagnostiche integrate. Il codice client v7 è completamente compatibile con un QMgr v6 e funziona come il client v6. Semplicemente non ottieni la funzionalità v7. Scarica qui il codice client WMQ gratuito:

IBM – MQC7: WebSphere MQ V7.0 Client

Sto gestendo il WMQ Hands-On Security Lab di IMPACT quest’anno e pubblicherò le sceneggiature e la guida del laboratorio durante il fine settimana su http://t-rob.net, quindi ricontrollalo.

Utilizzo di SSL da Oracle JVM (JSSE)

Vedi anche ” Quali crittografi TLS / ciphersuites sono supportati quando ci si connette da Oracle Java (non-IBM JRE) al gestore code MQ? ”

In MQ Client versione 8.0.0.2 è inclusa una patch per utilizzare TLS con Oracle JVM, questo funziona con le risposte delle corsie sopra

Per far funzionare tutto questo è necessario l’ultimo client MQ che contiene IV66840 : WMQ V7 JAVA / JMS: AGGIUNGI SUPPORTO PER CIPHERSPEC TLS SELEZIONATI DURANTE IL FUNZIONAMENTO IN AMBIENTE RUNTIME JAVA NON IBM
http://www-01.ibm.com/support/docview.wss?uid=swg1IV66840
( scarica )

A seconda della posizione, potrebbe essere necessario installare anche i file di criteri di giurisdizione illimitata di Java Cryptography Extension (JCE) 8 ( download )

Per usare questo devi configurare usando l’argomento JVM:

  -Dcom.ibm.mq.cfg.useIBMCipherMappings=false 

Si noti che il comportamento di implementazione della sicurezza predefinito differisce tra Oracle e IBM JVM:

La guida di riferimento Oracle JSSE dice:

Se il parametro KeyManager [] è null, per questo contesto verrà definito un KeyManager vuoto.

La guida di riferimento IBM JSSE dice:

Se il parametro KeyManager [] è nullo, i provider di sicurezza installati verranno ricercati per l’implementazione con la priorità più alta di KeyManagerFactory, da cui verrà ottenuto un KeyManager appropriato.

Il che significa che devi configurare il tuo contesto ssl

 SSLContext sslcontext = SSLContext.getInstance("TLS"); String keyStore = System.getProperty("javax.net.ssl.keyStore"); String keyStoreType = System.getProperty("javax.net.ssl.keyStoreType", KeyStore.getDefaultType()); String keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword",""); KeyManager[] kms = null; if (keyStore != null) { KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); KeyStore ks = KeyStore.getInstance(keyStoreType); if (keyStore != null && !keyStore.equals("NONE")) { fs = new FileInputStream(keyStore); ks.load(fs, keyStorePassword.toCharArray()); if (fs != null) fs.close(); char[] password = null; if (keyStorePassword.length() > 0) password = keyStorePassword.toCharArray(); kmf.init(ks,password); kms = kmf.getKeyManagers(); } sslcontext.init(kms,null,null); 

E quindi fornire questo al client JMS MQ:

  JmsConnectionFactory cf = ... MQConnectionFactory mqcf = (MQConnectionFactory) cf; mqcf.setSSLSocketFactory(sslcontext.getSocketFactory()); 

Se si utilizza un server applicazioni, questo potrebbe essere gestito dal server delle applicazioni.

Prova questo codice insieme alle spiegazioni di T.Robs sul certificato:

 import com.ibm.mq.jms.*; import java.io.FileInputStream; import java.io.Console; import java.security.*; import javax.jms.JMSException; import javax.jms.QueueConnection; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; import com.ibm.mq.jms.MQQueueConnectionFactory; public class SSLTest { public static void main(String[] args) { System.out.println(System.getProperty("java.home")); String HOSTNAME = "myhost"; String QMGRNAME = "MyQMGR"; String CHANNEL = "MY.SVRCONN"; String SSLCIPHERSUITE = "TLS_RSA_WITH_AES_256_CBC_SHA"; try { Class.forName("com.sun.net.ssl.internal.ssl.Provider"); System.out.println("JSSE is installed correctly!"); Console console = System.console(); char[] KSPW = console.readPassword("Enter keystore password: "); // instantiate a KeyStore with type JKS KeyStore ks = KeyStore.getInstance("JKS"); // load the contents of the KeyStore ks.load(new FileInputStream("/home/hudo/hugo.jks"), KSPW); System.out.println("Number of keys on JKS: " + Integer.toString(ks.size())); // Create a keystore object for the truststore KeyStore trustStore = KeyStore.getInstance("JKS"); // Open our file and read the truststore (no password) trustStore.load(new FileInputStream("/home/xwgztu2/xwgztu2.jks"), null); // 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(ks,KSPW); // Get an SSL context. // Note: not all providers support all CipherSuites. But the // "SSL_RSA_WITH_3DES_EDE_CBC_SHA" CipherSuite is supported on both SunJSSE // and IBMJSSE2 providers // Accessing available algorithm/protocol in the SunJSSE provider // see http://java.sun.com/javase/6/docs/technotes/guides/security/SunProviders.html SSLContext sslContext = SSLContext.getInstance("SSLv3"); // Acessing available algorithm/protocol in the IBMJSSE2 provider // see http://www.ibm.com/developerworks/java/jdk/security/142/secguides/jsse2docs/JSSE2RefGuide.html // 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(); // Create default MQ connection factory MQQueueConnectionFactory factory = new MQQueueConnectionFactory(); // Customize the factory factory.setSSLSocketFactory(sslSocketFactory); // Use javac SSLTest.java -Xlint:deprecation factory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP); factory.setQueueManager(QMGRNAME); factory.setHostName(HOSTNAME); factory.setChannel(CHANNEL); factory.setPort(1414); factory.setSSLFipsRequired(false); factory.setSSLCipherSuite(SSLCIPHERSUITE); QueueConnection connection = null; connection = factory.createQueueConnection("",""); //empty user, pass to avoid MQJMS2013 messages connection.start(); System.out.println("JMS SSL client connection started!"); connection.close(); } catch (JMSException ex) { ex.printStackTrace(); } catch (Exception ex){ ex.printStackTrace(); } } } 

Sii consapevole di quale JRE stai usando. Abbiamo avuto grossi problemi nell’utilizzo di Sun JDK, a causa di una determinata crittografia (TLS_RSA_WITH_AES_128_CBC_SHA) sul canale SSL per IBM MQ. Abbiamo usato un Xficity X509. Per farlo funzionare usiamo IBM JRE perché ha un supporto molto più grande per alcune suite di cifratura!