JMS to MQ message publishing error: "unable to find valid certification path to requested target"

JMS to MQ message publishing error: "unable to find valid certification path to requested target"

我正在尝试连接到支持 SSL 的 MQ 通道,以便使用 JMS(在 Spring 启动应用程序中)放置消息。下面是发送消息之前设置的连接工厂属性。我得到了 jms 尝试放置消息时出现以下错误。

Caused by: com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2397' ('MQRC_JSSE_ERROR')....
.....
    at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:203)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439)
    at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306)
    at java.base/sun.security.validator.Validator.validate(Validator.java:264)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132)
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:638)
    ... 81 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
    at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
    at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297)
    at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434)

** 证书已安装在 QM 级别。 jms 客户端似乎没有从指定位置选择根证书。 CA 根证书(myCAcertfile.cer)(自签名)是使用 IBM mq 中的 runmqckm 工具生成的。

MQ通道信息

   CHANNEL(KAU.CONN)                       CHLTYPE(SVRCONN)
   ALTDATE(2014-02-28)                     ALTTIME(17.28.55)
   CERTLABL( )                             COMPHDR(NONE)
   COMPMSG(NONE)
   DESCR(Server-connection to windows host)
   DISCINT(0)                              HBINT(300)
   KAINT(AUTO)                             MAXINST(999999999)
   MAXINSTC(999999999)                     MAXMSGL(4194304)
   MCAUSER( )                              MONCHL(QMGR)
   RCVDATA( )                              RCVEXIT( )
   SCYDATA( )                              SCYEXIT( )
   SENDDATA( )                             SENDEXIT( )
   SHARECNV(10)                            SSLCAUTH(REQUIRED)
   SSLCIPH(TLS_RSA_WITH_AES_128_CBC_SHA256)
   SSLPEER( )                              TRPTYPE(TCP)

JMS 连接工厂属性


            // Create a connection factory
            JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
            JmsConnectionFactory cf = ff.createConnectionFactory();

            // Set the properties
            cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, HOST);
            cf.setIntProperty(WMQConstants.WMQ_PORT, PORT);
            cf.setStringProperty(WMQConstants.WMQ_CHANNEL, CHANNEL);
            cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
            cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, QMGR);
            cf.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "Manual message publihser");
            cf.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
            cf.setStringProperty(WMQConstants.USERID, "");
            cf.setStringProperty(WMQConstants.PASSWORD, "");


            System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false" );
            
            cf.setStringProperty("Djavax.net.ssl.trustStore", "D:\mq-message-handler-1.0\ssl\myCAcertfile.cer");
            cf.setStringProperty(WMQConstants.WMQ_SSL_CIPHER_SUITE, "TLS_RSA_WITH_AES_128_CBC_SHA256");

用于创建 CA 证书的命令

runmqckm -keydb -create -db myCA.kdb -type cms  -pw mycakeypassword -stash
runmqckm -cert -create -db myCA.kdb -type cms -label "myCAcertificate" -dn "CN=demmoCA,O=DemmoOrg,OU=DemmoDepartment,L=DemmoLocation,C=UK" -expire 1000 -size 1024
runmqckm -cert -extract -db myCA.kdb -type cms -label "myCAcertificate" -target myCAcertfile.cer -format ascii -stashed

然后使用密钥工具使用上述证书为客户端创建密钥库

keytool -keystore kautstclient.jks -genkey -alias winclientcert -storepass clientpassword
keytool -import -keystore kautstclient.jks -file myCAcertfile.cer -alias theCARoot

30/02/2022 更新 > 我现在已经使用以下命令将证书添加到客户端。

generating client side's CA to self sign the client's certificate
================================================================
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365


creating certificate request from the jks in order to signed by the above CA.
===========================================================================

 keytool -certreq -v -alias winclientcert -file kauclient.csr -keypass clientpassword -storepass clientpassword -keystore kautstclient.jks
 
signing the certificate requst(csr file) using the generated CA key 
==================================================
openssl x509 -req -in kauclient.csr -CA cert.pem -CAkey key.pem -CAcreateserial -out kauclientown.crt


 Import the the signed and then provided certificate  certificate into your keystore using the following command:
========================================================================================

keytool -import -v -alias kauclientowncert -file kauclientown.crt -keystore kautstclient.jks -keypass clientpassword -storepass clientpassword


adding the client's key signed root CA in to queue manager's key.db
=================================================================
runmqckm -cert -add -db  myqmgr.kdb -file cert.pem -label kauclientsignercertificate

Djavax.net.ssl.trustStore 不是连接工厂 属性。您需要将其作为 Java 系统 属性 传递。 属性 的值必须是 JKS 或 PKCS12 文件。

您可以通过两种方式执行此操作:

  1. 作为 -D 命令行选项:
    -Djavax.net.ssl.trustStore=D:\mq-message-handler-1.0\ssl\myCAcertfile.jks
    
  2. 使用System.setProperty
    System.setProperty(javax.net.ssl.trustStore, "D:\mq-message-handler-1.0\ssl\myCAcertfile.jks");