我正尝试使用基本上通过以下方式构建的Java客户端使用SSL来使用IBM MQ(版本8.0.0.8):
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 JRE7。也许是MQ方面的东西(IBM MQ v8.0.0.8)或我缺少的某些配置。
我已经安装了JCE无限策略,所以问题不是CipherSpec X CipherSuite。
我正在使用-Djavax.net.debug = all,可以看到我的证书被正确使用,并且在那里看不到任何问题...
我与MQ团队的联系点告诉我,由于某种原因,我的申请正在吊销证书(与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);
}
}
答案 0 :(得分:3)
由于您使用的是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版本。在以下版本的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和Oracle Java具有不同的CipherSuite名称,这些名称记录在IBM MQ v9.1知识中心页面“ TLS CipherSpecs and CipherSuites in IBM MQ classes for JMS”中。
您在发布的代码中指定了TLS_RSA_WITH_AES_256_CBC_SHA
,这将是MQ队列管理器SSLCIPH
通道上的SVRCONN
值,并将映射到以下CipherSuites:
SSL_RSA_WITH_AES_256_CBC_SHA
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队列管理器可能正在尝试自身连接到客户端证书的AuthorityInfoAccess(AIA)证书扩展名中指定的OCSP服务器。如果MQ无法使用默认配置访问此OCSP服务器,则连接将被拒绝。如果您无法更新网络以允许连接到OCSP服务器,则可以禁用此检查,但是请注意,您将不知道证书是否被吊销。要禁用检查,可以将以下内容添加到队列管理器的qm.ini
文件SSL
节中:
SSL:
OCSPAuthentication=Optional
OCSPCheckExtensions=no
最后一条评论,您在示例代码TLS_RSA_WITH_AES_256_CBC_SHA
中列出的CipherSuite是TLS1.0 CipherSuite。像之前的SSL一样,许多行业通常不推荐使用此协议和TLS1.1。我寻找了要发布的参考,“ tls 1.0 end of life”的google提供了很多参考。
在下面加上一个“ TLS 1.0 end-of-life on June 30th, 2018”:
截止日期:PCI委员会负责确定何时淘汰较旧的协议。他们最初认为TLS 1.0将 将于2016年6月30日到期,之后将日期延长至6月30日 2018年。最后期限已经过去,所有Web服务器,Web浏览器,Web软件和电子邮件应用程序都必须停止使用TLS 1.0 支持或违反重要的安全更新。
我建议选择我上面链接到的知识中心页面中列为TLS1.2的一个,例如TLS_RSA_WITH_AES_256_CBC_SHA256
。