I'm trying to consume an IBM MQ (version 8.0.0.8) with SSL using a Java client built basically with:
我正在尝试使用基本构建的Java客户端使用SSL来使用IBM MQ(版本8.0.0.8):
Oracle JKD 8和IBM JRE 7(出于测试目的,每个客户端都有一个客户端)
The MQ is a Request/Reply type.
MQ是请求/回复类型。
I have the correct certificate and all MQ properties set, but for some reason the connection “drops” and I get no errors on my client side and my requests never get any response and keeps running “forever”, never getting any response. The only clue that I have is an error message in the MQ log that says:
我有正确的证书和所有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';
The strange thing is that the SSL Handshake happens, my certificate is accepted by the MQ, but for some reason something happens after this. I’m trying using both Oracle JRE 8 and IBM JRE 7. Maybe is something on MQ side (IBM MQ v8.0.0.8) or some configuration that I’m missing on my side.
奇怪的是SSL握手发生了,我的证书被MQ接受,但由于某种原因,事后发生了一些事情。我正在尝试使用Oracle JRE 8和IBM JRE 7.也许是在MQ端(IBM MQ v8.0.0.8)或者我缺少的一些配置。
I have already installed the JCE Unlimited Policies, so the problem is not CipherSpec X CipherSuite.
我已经安装了JCE Unlimited Policies,所以问题不在于CipherSpec X CipherSuite。
I'm using -Djavax.net.debug=all and I can see that my certificate is being used correctly and I can't see any problems there...
我正在使用-Djavax.net.debug = all,我可以看到我的证书使用正确,我看不到任何问题......
My contact point on the MQ Team told me that for some reason my application is revoking the certificate (something related with CLR), but I have no idea why this would happen.
我在MQ团队的联系人告诉我,由于某种原因,我的应用程序正在撤销证书(与CLR相关的东西),但我不知道为什么会发生这种情况。
My Java code:
我的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);
}
}
2
Since you are using the 9.1.0.0 com.ibm.mq.allclient.jar
you do not need all of the code you have related to the key store, for example:
由于您使用的是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);
}
}
You can instead replace that with setting the following two system properties, this will work with both Oracle and IBM Java:
您可以通过设置以下两个系统属性来替换它,这将适用于Oracle和IBM Java:
System.setProperty("javax.net.ssl.keyStore", "C:\\myplace\\Dev\\Certificates\\MY_KEYSTORE.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "changeit");
The above settings have always worked for IBM Java, but with Oracle Java this did not work with older versions of MQ. It was fixed for Oracle java in the following versions of IBM MQ (Base 9.0 and 9.1 have the same fix):
上述设置一直适用于IBM Java,但使用Oracle Java时,这不适用于旧版本的MQ。在以下版本的IBM MQ中为Oracle java修复了它(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 and Oracle Java have different CipherSuite names, these are documented in the IBM MQ v9.1 Knowledge center page "TLS CipherSpecs and CipherSuites in IBM MQ classes for JMS.
IBM Java和Oracle Java具有不同的CipherSuite名称,这些名称记录在IBM MQ v9.1知识中心页面“用于JMS的IBM MQ类中的TLS CipherSpecs和CipherSuite”中。
You have specified TLS_RSA_WITH_AES_256_CBC_SHA
in the posted code, this would be the SSLCIPH
value on the MQ Queue manager SVRCONN
channel, and would map to the following CipherSuites:
您已在发布的代码中指定了TLS_RSA_WITH_AES_256_CBC_SHA,这将是MQ队列管理器SVRCONN通道上的SSLCIPH值,并将映射到以下CipherSuite:
SSL_RSA_WITH_AES_256_CBC_SHA
IBM Java:SSL_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
Oracle Java:TLS_RSA_WITH_AES_256_CBC_SHA
Related to the above, if you are using Oracle Java you need to set the following system property so that the MQ JMS classes will be able to use the right mapping of the Oracle CipherSuite name:
与上述相关,如果您使用的是Oracle Java,则需要设置以下系统属性,以便MQ JMS类能够使用Oracle CipherSuite名称的正确映射:
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false");
The error you provided appears to be from the IBM i MQ Queue manager, but does not provide enough information to diagnose the problem.
您提供的错误似乎来自IBM i MQ队列管理器,但未提供足够的信息来诊断问题。
The error states the following:
该错误表明以下内容:
An unexpected SSL communications error occurred for a channel, as reported in the preceding messages.
Can you edit your question and provide the details from the "preceding messages".
您可以编辑您的问题并提供“之前的消息”中的详细信息。
You stated
for some reason my application is revoking the certificate (something related with CLR)
由于某种原因,我的申请正在撤销证书(与CLR相关的事情)
It could be that the MQ queue manager is attempting itself to connect to the OCSP server specified in the your client cert's AuthorityInfoAccess (AIA) certificate extension. If MQ can not reach this OCSP server with a default configuration the connection will be denied. If you are unable to update your network to allow connection to the OCSP server then you can disable this check but note that you will not know if a cert is revoked. To disable the checking the following can be added to the queue manager's qm.ini
file SSL
stanza:
可能是MQ队列管理器正在尝试连接到客户端证书的AuthorityInfoAccess(AIA)证书扩展中指定的OCSP服务器。如果MQ无法使用默认配置访问此OCSP服务器,则将拒绝连接。如果您无法更新网络以允许连接到OCSP服务器,则可以禁用此检查,但请注意您不知道是否撤销了证书。要禁用检查,可以将以下内容添加到队列管理器的qm.ini文件SSL节中:
SSL:
OCSPAuthentication=Optional
OCSPCheckExtensiOns=no
One last comment, the CipherSuite you listed in your example code TLS_RSA_WITH_AES_256_CBC_SHA
is a TLS1.0 CipherSuite. Like SSL before it this and TLS1.1 are commonly deprecated across many industries. I looked for reference to post and a google of "tls 1.0 end of life" gives many references.
最后一条评论,您在示例代码TLS_RSA_WITH_AES_256_CBC_SHA中列出的CipherSuite是TLS1.0 CipherSuite。就像之前的SSL一样,TLS1.1在很多行业中都经常被弃用。我寻找帖子和谷歌“tls 1.0生命终结”的参考提供了许多参考。
Quoting one "TLS 1.0 end-of-life on June 30th, 2018" below:
下面引用一个“2018年6月30日的TLS 1.0寿命结束”:
The Deadline The PCI Council is responsible for determining when older protocols are phased out. They initially decided TLS 1.0 would reach end of life on 30 June 2016, later extending the date to 30 June 2018. The final deadline has past and all web servers, web browsers, web software and email applications have had to discontinue TLS 1.0 support, or fall foul of important security updates.
截止日期PCI委员会负责确定何时淘汰旧协议。他们最初决定TLS 1.0将于2016年6月30日终止,之后将日期延长至2018年6月30日。最后截止日期已过,所有网络服务器,网络浏览器,网络软件和电子邮件应用程序都不得不停止TLS 1.0支持,或者重要的安全更新。
I would suggest choosing one listed as TLS1.2 in the Knowledge center page I linked to above for example TLS_RSA_WITH_AES_256_CBC_SHA256
.
我建议在我上面链接的知识中心页面中选择一个列为TLS1.2的版本,例如TLS_RSA_WITH_AES_256_CBC_SHA256。