I'm trying to connect my .NET (8.0) application to IBM MQ over TLS using X.509 certificate-based authentication, but running into issues during the SSL handshake.
Using Python + pymqi, I was able to successfully establish a secure connection with IBM MQ using TLS. IBM provides the GSKit-based .kdb keystore mechanism. The connection uses a .kdb trust store generated from .pem files and works well with the pymqi library and the underlying GSKit.
Here’s a simplified version of my working Python setup:
cd = pymqi.CD() cd.ChannelName = b'SSL.CHANNEL' cd.ConnectionName = b'mqhost.example.com(1414)' cd.SSLCipherSpec = b'TLS_RSA_WITH_AES_128_CBC_SHA256' cd.ChannelType = pymqi.CMQC.MQCHT_CLNTCONN cd.TransportType = pymqi.CMQC.MQXPT_TCP sco = pymqi.SCO() sco.KeyRepository = b'/path/to/keystore' # .kdb, .rdb, .sth files qmgr = pymqi.QueueManager(None) qmgr.connect_with_options(b'QM1', cd, sco, user=b'mquser', password=b'securepass') queue = pymqi.Queue(qmgr, b'TEST.QUEUE') queue.put(b'Hello from Python!') queue.close() qmgr.disconnect()* In .NET 8, the IBM MQ client does not use GSKit the same way. Instead, it relies on the Windows certificate store (or .pfx files) for managing X.509 certificates.
Here’s what I’ve tried:
Installed the root and intermediate certificates in the CurrentUser store.
Set up SSL_CIPHER_SPEC and basic connection properties.
Verified the certs are visible in the Windows store.
Yet, the .NET client fails during the TLS handshake, with generic errors — possibly due to missing private key linkage, or incompatible keystore handling.
Here’s the representative code:
using IBM.WMQ; using System.Collections; using System.Security.Cryptography.X509Certificates; X509Store rootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser); rootStore.Open(OpenFlags.ReadWrite); rootStore.Add(new X509Certificate2("path/to/root.crt")); rootStore.Close(); X509Store caStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser); caStore.Open(OpenFlags.ReadWrite); caStore.Add(new X509Certificate2("path/to/intermediate.crt")); caStore.Close(); Hashtable queueProperties = new Hashtable { { MQC.HOST_NAME_PROPERTY, "mqhost.example.com" }, { MQC.CHANNEL_PROPERTY, "SSL.CHANNEL" }, { MQC.PORT_PROPERTY, 1414 }, { MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED }, { MQC.SSL_CIPHER_SPEC_PROPERTY, "TLS_RSA_WITH_AES_128_CBC_SHA256" } }; using var queueManager = new MQQueueManager("QM1", queueProperties); // Receive or send logic here... Python (via pymqi) uses IBM's GSKit and .kdb file for SSL trust configuration. .NET does not use .kdb, instead expects certs in Windows/ User cert store or PKCS#12 (.pfx) format if done programmatically.
There’s no built-in way to load .kdb directly in .NET using IBM’s client (unlike Python).
How can I successfully connect a .NET Core / .NET 8 application to IBM MQ using X.509 certificates? I need to resolve these TLS handshake or trust issues.
Edit 1
Since our application is containerized, running on a Linux distro, we have tried two separate mechanisms to register the certificate:
FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base COPY /keystore/aa_root.crt /usr/local/share/ca-certificates/ COPY /keystore/aa_intermediate.crt /usr/local/share/ca-certificates/ RUN chmod 644 /usr/local/share/ca-certificates/aa_root.crt RUN chmod 644 /usr/local/share/ca-certificates/aa_intermediate.crt RUN update-ca-certificates USER $APP_UID WORKDIR /app To the user certificates in the deployment script
X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadWrite); store.Add(new X509Certificate2(X509Certificate2.CreateFromCertFile("./keystore/aa_root.crt"))); store.Close(); store = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadWrite); store.Add(new X509Certificate2(X509Certificate2.CreateFromCertFile("./keystore/aa_intermediate.crt"))); store.Close(); We have also tried setting some of the extended SSL properties as below with no luck:
string strQueueManagerName = "QM1"; string strChannelName = "DEV.APP.SVRCONN"; string strQueueName = "DEV.QUEUE.1"; string strServerName = "192.168.1.13"; string strUserID = "app"; string strPassword = "passw0rd"; int intPort = 1414; /*string strQueueManagerName = "EMQSCGW1"; string strChannelName = "UNILODE.01"; string strQueueName = "CGOOPSHDLG.UNILODE.OPSDATA.01"; string strServerName = "mqiptstage.aa.com"; string strUserID = ""; string strPassword = ""; int intPort = 1442;*/ var factoryFactory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ); var cf = factoryFactory.CreateConnectionFactory(); cf.SetStringProperty(XMSC.WMQ_HOST_NAME, strServerName); cf.SetStringProperty(XMSC.USERID, strUserID); cf.SetStringProperty(XMSC.PASSWORD, strPassword); cf.SetIntProperty(XMSC.WMQ_PORT, intPort); cf.SetStringProperty(XMSC.WMQ_CHANNEL, strChannelName); cf.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT); cf.SetIntProperty(XMSC.WMQ_CLIENT_RECONNECT_OPTIONS, XMSC.WMQ_CLIENT_RECONNECT_Q_MGR); cf.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, strQueueManagerName); //cf.SetStringProperty(XMSC.WMQ_SSL_CIPHER_SPEC, "TLS_RSA_WITH_AES_128_CBC_SHA256");
{ MQC.SSL_CERT_STORE_PROPERTY, "*USER" }to your queueProperties. You can use the export option of your kdb tool to export the private key to a pkcs12 format which can be imported into windows by opening the file with a pfx extension.{ MQC.SSL_CERT_STORE_PROPERTY, "*USER" }to your queueProperties.