Search code examples
jmsibm-mqtls1.2self-signed-certificate

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


I'm trying to connect to a SSL enabled MQ channel in order to place a message using JMS(within Spring boot app) . below are the connection factory properties set before sending the message. I'm getting the following error when jms trying to put the message.

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)

** certificates are already installed at QM level. it seems jms client is not picking the root certificate from the specified location. the CA root certificate(myCAcertfile.cer) (self signed) was generated using runmqckm tool in IBM mq.

MQ channel information

   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 connection factory properties


            // 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");

Commands used to create CA's certificate

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

then created the keystore for the client using above certificate using key tool

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

30/02/2022 update > I have now added the certificates to the client side using below commands.

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

Solution

  • Djavax.net.ssl.trustStore is not a connection factory property. You need to pass it as a Java system property. The value of the property needs to be either a JKS or PKCS12 file.

    You can do this in two ways:

    1. As a -D command line option:
      -Djavax.net.ssl.trustStore=D:\mq-message-handler-1.0\ssl\myCAcertfile.jks
      
    2. Using System.setProperty:
      System.setProperty(javax.net.ssl.trustStore, "D:\mq-message-handler-1.0\ssl\myCAcertfile.jks");