title: How to connect to a WebSphere MQ Queue using SSL authentification in PHP
body: <p>I want to connect to a WebSphere MQ Queue using SSL authentification from a PHP application (script).</p>
  
  <ul>
  <li>Queue Manager Version is 7.0 or 7.5</li>
  <li>MQ Client  Version is 8.0</li>
  <li>PHP Version is 7.0 (docker)</li>
  <li>Using PHP mqseries pecl extension v0.15 (with custom fixes)</li>
  </ul>
  
  <p>So far I was able to connect without SSL connection.</p>
  
  <p>Here are the steps I have to done so far:</p>
  
  <ul>
  <li>I have installed the WebSphere MQ Client v8 for Linux (CentOS in my case) </li>
  <li>I have downloaded the PECL 0.15 version of the mqseries php extension. (There as a small bug in the extension, I had to recompile it to make it work properly. I used to get a segmentation fault on MQGET).</li>
  <li>I linked the the mqseries.so to php and enabled the extension.</li>
  </ul>
  
  <p>I succesfully (without SSL)</p>
  
  <ol>
  <li>Connect to the queue manager</li>
  <li>Open the queue for reading</li>
  <li>Get messages on the queue</li>
  <li>Close the connection</li>
  </ol>
  
  <p>When I set the <code>USE_SSL</code> in my script to true, I get the error code 2393 that means "<code>An MQCONN or MQCONNX call was issued with SSL configuration options specified, but an error occurred during the initialization of the SSL environment.</code>" This error message is very generic and does not help me pin point where is the problem.</p>
  
  <p>The <code>MQ_KEYSTORE</code> is set as <code>/path/to/my/key</code> and my filename is <code>key.kdb</code> and has at the same level <code>key.sth</code> as suggested by this <a href="https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_8.0.0/com.ibm.mq.ref.dev.doc/q099920_.htm" rel="nofollow noreferrer">documentation</a></p>
  
  <p>The <code>MQ_SSL_CIPHER_SPEC</code> is the same in the script than specified by on the queue manager for the specified <code>MQ_CHANNEL_SSL</code>. Checked multiple times. These are NOT the <a href="https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.dev.doc/q031290_.htm" rel="nofollow noreferrer">Cipher Suite</a> used with JMS connections</p>
  
  <p>The security cache has been refreshed on the queue manager.</p>
  
  <p>On the server side, I checked the error logs for the queue manager and didn't seem to see my channel name. I say "seem" because there was a lot of noise and there were a few <code>???</code> channel name in the lot. So I feel like it did not reach the queue manager for some reason.</p>
  
  <p>I also used the "<code>amqssslc</code>" command found in the MQ Client installation bin folder to test my ssl config. I get the same error than using the PHP script.</p>
  
  <p>I also used WireShark to sniff packets on the corresponding <code>MQ_PORT</code>. The content of the packages contained certificate information. So there is something that looks like a SSL hand shake going on.</p>
  
  <p>I am now out of ideas as of how to debug the case. Does anyone has an idea of what to check next? Is there connection logs on my MQ Client installation that I should check?</p>
  
  <p>Here is an example of a <a href="http://php.net/manual/en/function.mqseries-connx.php" rel="nofollow noreferrer">connection using SSL in PHP</a></p>
  
  <p>Here is a simplified version of my MQ script (I removed the outputs). Some of the constants are not disclosed for security purposes.</p>
  
  <p>All MQSERIES_* constants are defined in the extension</p>
  
  <p>All MQ_* are hardcoded parameters to test my script but their definition does not appear in the script excerpt.</p>
  
  <pre><code>&lt;?php
  
  // Constants defined here
  
  $options = [
      'Version' =&gt; MQSERIES_MQCNO_VERSION_4,
      'Options' =&gt; MQSERIES_MQCNO_STANDARD_BINDING,
      'MQCD' =&gt; [
          'Version' =&gt; 7,
          'ChannelName' =&gt; MQ_CHANNEL,
          'ConnectionName' =&gt; sprintf('%s(%s)', MQ_HOST, MQ_PORT),
          'TransportType' =&gt; MQSERIES_MQXPT_TCP,
      ]
  ];
  
  if (USE_SSL) {
      $options['MQSCO'] = [
          'KeyRepository' =&gt; MQ_KEYSTORE
      ];
  
      $options['MQCD']['ChannelName'] = MQ_CHANNEL_SSL;
      $options['MQCD']['SSLCipherSpec'] = MQ_SSL_CIPHER_SPEC;
  }
  
  mqseries_connx(MQ_QUEUE_MANAGER, $options, $conn, $comp_code, $reason );
  
  $mqods2 = [
      'ObjectType' =&gt; MQSERIES_MQOT_Q,
      'ObjectName' =&gt; MQ_QUEUE
  ];
  
  mqseries_open($conn, $mqods2, MQSERIES_MQOO_INPUT_AS_Q_DEF | MQSERIES_MQOO_FAIL_IF_QUIESCING, $obj, $comp_code, $reason);
  
  $gmd = [];
  
  $gmo = [
      'Options' =&gt; MQSERIES_MQGMO_FAIL_IF_QUIESCING | MQSERIES_MQGMO_WAIT, 'WaitInterval' =&gt; 3000
  ];
  
  $msg = "";
  $data_length = "";
  
  for ($i = 0; $i &lt; 1000; $i++) {
      mqseries_get($conn, $obj, $gmd, $gmo, 10000, $msg, $data_length, $comp_code, $reason);
  
      if ($reason === 2033) {
          printf("No more messages to process\n");
          break;
      }
  
      // Business logic
  }
  
  mqseries_disc($conn, $comp_code, $reason);
  
  ?&gt;
  </code></pre>
  
  <p><strong>UPDATE</strong></p>
  
  <p>Using the client side logs that I didn't know existed. We finally found out that our server was not using a proper certificate. The server's certificate was actually self-signed, thus not granting us access because our .kdb file didn't have it's public key. We added the server's own public key to the .kdb file making that step work out.</p>
  
  <p>As suggested in the comments from JoshMC, for our next problem, we suspect the label is wrong in the keystore file. We did not specify a specific label from the .kdb file. From the <a href="https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_8.0.0/com.ibm.mq.sec.doc/q014340_.htm" rel="nofollow noreferrer">docs</a> "<code>For queue managers and clients respectively, the following sources are searched in sequence for a non-empty value. The first non-empty value determines the certificate label. The certificate label must exist in the key repository. If no matching certificate in the correct case and format is found that matches a label, an error occurs and the SSL or TLS handshake fails.</code>"</p>
  
  <p>And it also states that "<code>The certificate label cannot contain spaces.</code>".</p>
  
  <p>I will try again tomorrow with proper label naming and sending a specific label name. I will try to see if the name convention <code>ibmwebspheremq&lt;user_that_runs_the_php_process&gt;</code> actually impacts the validity.</p>
  
  <p><strong>UPDATE 2</strong></p>
  
  <p>It finally worked out. As mentioned by JoshMC, the private key needs to have the specific label ibmwebspheremq. I didn't try the CertificateLabel yet. I might dig into that next week.</p>
  
  <p>At first we were using the GUI (ikeyman) from ibm to generate the .kdb file. But we found out it had quite a few bugs in it. For instance, it imports twice the private key with the same label (auto-generated label from the certificate). Editing the label name was not possible (hence the connection problems). To solve that part we used the command line tool <code>ikeycmd</code> that basically offers the same features on the command line (minus the bugs). To run the command, you need the IBM jre (Not verified, needs to be checked out) and run it as <code>java com.ibm.gsk.ikeyman.ikeycmd</code>. From here, there is a whole world of documentation on IBM web site about how to create a certificate, rename labels, check details, etc. Lots and lots of fun!</p>