Проблема при подключении клиента Java (JMS) к IBM MQ - PullRequest
0 голосов
/ 12 октября 2018

Я пытаюсь использовать IBM MQ (версия 8.0.0.8) с SSL, используя Java-клиент, построенный в основном из:

  • Oracle JKD 8 и IBM JRE 7 (для тестирования у меня естьодин клиент для каждого из них)
  • com.ibm.mq.allclient-9.1.0.0.jar
  • javax.jms-api-2.0.1.jarspring-jms-4.3.7.RELEASE.jar
  • spring-jms-4.3.7.RELEASE.jar

MQ - это тип запроса / ответа.

У меня есть правильный сертификат ивсе свойства MQ установлены, но по какой-то причине соединение «обрывается», и я не получаю ошибок на стороне клиента, и мои запросы никогда не получают никакого ответа и продолжают работать «вечно», никогда не получая никакого ответа.Единственная подсказка, которая у меня есть, - это сообщение об ошибке в журнале MQ, которое гласит:

Process(31600.16) User(QMQM) Jobname(JOB_NAME)
                    Host(HOST_NAME)
                    VRMF(8.0.0.8) QMgr(MANAGER_NAME)
                    AMQ9638: SSL communications error for channel 'CHANNEL_NAME'.   EXPLANATION:
    Cause . . . . . :   An unexpected SSL communications error occurred for a channel, as reported in the preceding messages. The
channel is 'CHANNEL_NAME';

Странно то, что происходит рукопожатие SSL, мой сертификат принят MQ,но по какой-то причине что-то происходит после этого.Я пытаюсь использовать Oracle JRE 8 и IBM JRE 7. Может быть, что-то на стороне MQ (IBM MQ v8.0.0.8) или какая-то конфигурация, которую мне не хватает на моей стороне.

У меня уже естьустановил JCE Unlimited Policies, поэтому проблема не в CipherSpec X CipherSuite.

Я использую -Djavax.net.debug = all, и я вижу, что мой сертификат используется правильно, и я не вижукакие-то проблемы ...

Мой контактный пункт в MQ Team сказал мне, что по какой-то причине мое приложение отзывает сертификат (что-то связанное с CLR), но я понятия не имею, почему это произойдет.

Мой код Java:

public Message callMQ() {

        Message message = null;

        try {

            MQConnectionFactory factory = mqQueueConnectionFactory();
            JMSContext context = factory.createContext();

            Destination requestQueue = context.createQueue("queue:///REQUEST_QUEUE");
            Destination replyQueue = context.createQueue("queue:///REPLY_QUEUE");

            JmsTemplate jmsTemplate = new JmsTemplate(factory);

            FIXMLRootInbound inbound = new FIXMLRootInbound();
            String xml = XmlUtil.xmlObjectToString(inbound);

            message = jmsTemplate.sendAndReceive(requestQueue,
                    session -> {
                        Message req = session.createTextMessage(xml);
                        req.setJMSCorrelationID(UUID.randomUUID().toString());
                        req.setJMSDestination(requestQueue);
                        req.setJMSReplyTo(replyQueue);
                        return req;
                    });

        } catch (Throwable e) {
            e.printStackTrace();
        }

        return message;
    }

    private MQConnectionFactory mqQueueConnectionFactory() throws NoSuchAlgorithmException, KeyStoreException,
            IOException, CertificateException, UnrecoverableKeyException, KeyManagementException, JmsException {

        SSLSocketFactory sslSocketFactory = sslContext().getSocketFactory();

        MQEnvironment.sslSocketFactory = sslSocketFactory;
        MQEnvironment.sslCipherSuite = "TLS_RSA_WITH_AES_256_CBC_SHA";
        MQEnvironment.sslFipsRequired = false;

        MQConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
        mqQueueConnectionFactory.setHostName(host);
        try {
            mqQueueConnectionFactory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
            mqQueueConnectionFactory.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE,
                    WMQConstants.WMQ_CM_CLIENT);
            mqQueueConnectionFactory.setQueueManager(queueManager);
            mqQueueConnectionFactory.setSSLCipherSuite("TLS_RSA_WITH_AES_256_CBC_SHA");
            mqQueueConnectionFactory.setCCSID(285);
            mqQueueConnectionFactory.setChannel(channel);
            mqQueueConnectionFactory.setPort(port);
            mqQueueConnectionFactory.setSSLSocketFactory(sslSocketFactory);
            mqQueueConnectionFactory.setSSLFipsRequired(false);
        } catch (Exception e) {
            log.error("Error creating MQQueueConnectionFactory.", e);
        }

        return mqQueueConnectionFactory;
    }

    private SSLContext sslContext() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {

        try (InputStream cert = new FileInputStream("C:\\myplace\\Dev\\Certificates\\MY_KEYSTORE.jks")) {

            final KeyStore caCertsKeyStore = KeyStore.getInstance("JKS");
            caCertsKeyStore.load(cert, "changeit".toCharArray());

            final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

            CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
            PKIXRevocationChecker rc = (PKIXRevocationChecker)cpb.getRevocationChecker();
            rc.setOptions(EnumSet.of(
                    PKIXRevocationChecker.Option.PREFER_CRLS,
                    PKIXRevocationChecker.Option.ONLY_END_ENTITY,
                    PKIXRevocationChecker.Option.SOFT_FAIL,
                    PKIXRevocationChecker.Option.NO_FALLBACK));

            PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(caCertsKeyStore, new X509CertSelector());
            pkixParams.addCertPathChecker(rc);

            kmf.init(caCertsKeyStore, "changeit".toCharArray());
            tmf.init( new CertPathTrustManagerParameters(pkixParams) );

            final SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());

            return sslContext;

        } catch (Exception e) {
            throw new RuntimeException("Exception creating SSLContext", e);
        }
    }

1 Ответ

0 голосов
/ 12 октября 2018

Поскольку вы используете 9.1.0.0 com.ibm.mq.allclient.jar, вам не нужен весь код, связанный с хранилищем ключей, например:

SSLSocketFactory sslSocketFactory = sslContext().getSocketFactory();

//Note that MQEnvironment is used with IBM MQ Classes for Java not IBM MQ Classes for JMS
MQEnvironment.sslSocketFactory = sslSocketFactory;
MQEnvironment.sslCipherSuite = "TLS_RSA_WITH_AES_256_CBC_SHA";
MQEnvironment.sslFipsRequired = false;

mqQueueConnectionFactory.setSSLSocketFactory(sslSocketFactory);

private SSLContext sslContext() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {

    try (InputStream cert = new FileInputStream("C:\\myplace\\Dev\\Certificates\\MY_KEYSTORE.jks")) {

        final KeyStore caCertsKeyStore = KeyStore.getInstance("JKS");
        caCertsKeyStore.load(cert, "changeit".toCharArray());

        final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

        CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
        PKIXRevocationChecker rc = (PKIXRevocationChecker)cpb.getRevocationChecker();
        rc.setOptions(EnumSet.of(
                PKIXRevocationChecker.Option.PREFER_CRLS,
                PKIXRevocationChecker.Option.ONLY_END_ENTITY,
                PKIXRevocationChecker.Option.SOFT_FAIL,
                PKIXRevocationChecker.Option.NO_FALLBACK));

        PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(caCertsKeyStore, new X509CertSelector());
        pkixParams.addCertPathChecker(rc);

        kmf.init(caCertsKeyStore, "changeit".toCharArray());
        tmf.init( new CertPathTrustManagerParameters(pkixParams) );

        final SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());

        return sslContext;

    } catch (Exception e) {
        throw new RuntimeException("Exception creating SSLContext", e);
    }
}

Вместо этого его можно заменить настройкойСледующие два системных свойства будут работать как с Oracle, так и с IBM Java:

System.setProperty("javax.net.ssl.keyStore", "C:\\myplace\\Dev\\Certificates\\MY_KEYSTORE.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "changeit");

Указанные выше настройки всегда работали для IBM Java, но с Oracle Java это не работало с более старыми версиями MQ.,Это было исправлено для Oracle Java в следующих версиях IBM MQ (Base 9.0 и 9.1 имеют одинаковое исправление):

Version    Maintenance Level
v7.1       7.1.0.8
v7.5       7.5.0.7
v8.0       8.0.0.5

IBM Java и Oracle Java имеют разные CipherSuiteимена, они описаны на странице центра знаний IBM MQ v9.1 " TLS CipherSpecs и CipherSuites в классах IBM MQ для JMS .

Вы указали TLS_RSA_WITH_AES_256_CBC_SHA в опубликованном коде,это будет значение SSLCIPH в канале диспетчера очереди MQ SVRCONN и будет соответствовать следующим CipherSuites:

  • IBM Java: SSL_RSA_WITH_AES_256_CBC_SHA
  • Oracle Java:TLS_RSA_WITH_AES_256_CBC_SHA

В связи с вышеизложенным, если вы используете Oracle Java, вам нужно установить следующее системное свойство, чтобы классы MQ JMS могли использовать правильное сопоставление имени Oracle CipherSuite.:

System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false");

Похоже, что вы указали ошибку от администратора очередей IBM i MQ, но не предоставили достаточно информации для диагностики проблемы.

В сообщении об ошибке указано следующее:

An unexpected SSL communications error occurred for a channel, as reported in the preceding messages.

Можете ли вы отредактировать свой вопрос и предоставить подробности из "предыдущих сообщений".


Вы указали

, по некоторым причинам мое заявлениеотзыв сертификата (что связано с CLR)

Возможно, администратор очередей MQ пытается подключиться к серверу OCSP, указанному в расширении сертификата AuthorityInfoAccess (AIA) сертификата вашего клиента.Если MQ не может подключиться к этому серверу OCSP с конфигурацией по умолчанию, в соединении будет отказано.Если вы не можете обновить свою сеть, чтобы разрешить подключение к серверу OCSP, вы можете отключить эту проверку, но учтите, что вы не будете знать, отменен ли сертификат.Чтобы отключить проверку, в файл qm.ini * * * * * * SSL можно добавить следующее:

SSL:
   OCSPAuthentication=Optional
   OCSPCheckExtensions=no

Последний комментарий: CipherSuite, который вы перечислили в своем примере кода TLS_RSA_WITH_AES_256_CBC_SHA:TLS1.0 CipherSuite.Как и SSL до него, этот и TLS1.1 обычно устарели во многих отраслях.Я искал ссылку на сообщение, и Google " TLS 1.0 конец жизни " дает много ссылок.

Цитируя один " TLS 1.0 конец жизни 30 июня,2018"ниже:

Крайний срок Совет PCI отвечает за определение того, когда устаревшие протоколы будут удалены.Первоначально они решили, что срок действия TLS 1.0 истечет 30 июня 2016 года, а затем продлит срок до 30 июня 2018 года. Последний срок истек, и все веб-серверы, веб-браузеры, веб-приложения и почтовые приложения должны были прекратить поддержку TLS 1.0,или не справьтесь с важными обновлениями безопасности.

Я бы предложил выбрать одно из них, указанное в списке TLS1.2 на странице центра знаний, на которую я ссылался выше, например, TLS_RSA_WITH_AES_256_CBC_SHA256.

...