Unsuccessful TLS connection through MQTT-SPY

We’re looking to set up an RFID reader to send MQTT messages to a HiveMQ Cloud broker.

For the reader to use a TLS connection, the specific following files are required:

  • Device Certificate as ca.crt
  • Device Private Key as client.key
  • CA Certificate as client.crt

To easily test this connection, I’ve been using MQTT-SPY as it accepts the same inputs when the TLS mode is set to ‘CA certificate & client certificate/key’

I initially ran the suggested command from the pinned FAQ post (replacing the URL with my own):

openssl s_client -connect 4ad85b7fade04d07911be2ac1da2f5e4.s2.eu.hivemq.cloud:8883 -showcerts < /dev/null 2> /dev/null | sed -n '/BEGIN/,/END/p' > server.pem

but got the following error:
The system cannot find the path specified.

I then followed this blog post to generate the server.pem, client key and client certificate. When generating these files, on both commands I entered the same company and personal data requested, although I’m not certain if they should’ve been different (perhaps HiveMQ details when creating server.pem?).

Afterwards, I converted those files with openssl so they match the format I require. To do this, I ran the following commands:

openssl x509 -outform der -in server.pem -out ca.crt
openssl rsa -outform der -in mqtt-client-key.pem -out client.key
openssl x509 -outform der -in mqtt-client-cert.pem -out client.crt

This is likely where I am going wrong. Specifically I don’t think I should be converting the server.pem into a CA certificate. I initially tried to get an official CA certificate from gogetssl, but the CSR requires a domain name which my RFID reader won’t have.

Is it even possible to authenticate a HiveMQ connection without an official CA certificate? Throughout these guides I haven’t seen any mention of requesting a certificate from a CA, so I’m hoping that’s not the case.

Regardless, the connection always fails irrespective of TLS connection mode. Here’s the log output:

2022-02-10 15:26:05,977 WARN  [MQTT Con: Stephen163429166] [MqttConnectionResultHandler   ]  - Connecting to HiveMQ Private Connection failed
MqttException (0) - javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:38)
	at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:664)
	at java.lang.Thread.run(Unknown Source)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.ssl.Alert.createSSLException(Unknown Source)
	at sun.security.ssl.TransportContext.fatal(Unknown Source)
	at sun.security.ssl.TransportContext.fatal(Unknown Source)
	at sun.security.ssl.TransportContext.fatal(Unknown Source)
	at sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(Unknown Source)
	at sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(Unknown Source)
	at sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(Unknown Source)
	at sun.security.ssl.SSLHandshake.consume(Unknown Source)
	at sun.security.ssl.HandshakeContext.dispatch(Unknown Source)
	at sun.security.ssl.HandshakeContext.dispatch(Unknown Source)
	at sun.security.ssl.TransportContext.dispatch(Unknown Source)
	at sun.security.ssl.SSLTransport.decode(Unknown Source)
	at sun.security.ssl.SSLSocketImpl.decode(Unknown Source)
	at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(Unknown Source)
	at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
	at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
	at org.eclipse.paho.client.mqttv3.internal.SSLNetworkModule.start(SSLNetworkModule.java:93)
	at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:650)
	... 1 more
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 sun.security.validator.PKIXValidator.doBuild(Unknown Source)
	at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
	at sun.security.validator.Validator.validate(Unknown Source)
	at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source)
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
	... 15 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Source)
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
	at java.security.cert.CertPathBuilder.build(Unknown Source)
	... 21 more

I’ve also tried using just the CA certificate to secure the connection but that also fails to connect.

Communication with the broker using MQTT-CLI was successful, as shown below, but curiously the messages aren’t appearing when connected to the HiveMQ websocket client

I’ve been troubleshooting this for a good while now and I’m not sure what to try next, so any help with this would be greatly appreciated.

Hi Stephen,

Welcome to our community! This is great to see you’re interested in HiveMQ and MQTT.

In my examples I am using Linux, rather than Windows, hence my command looks like mqtt rather than mqtt-cli.exe.

In order to connect to the HiveMQ cloud broker with MQTT-CLI you can use the following command:

mqtt sub -t "#" -h 18b93f452b8445ba86ac0ec6d2228eb9.s2.eu.hivemq.cloud -p 8883 -u HiveUser1 -pw HivePassword1 -s -d -v -J

The -s flag specifies that encryption with default SSL settings should be used. Alternatively, you can use the following command:

mqtt sub -t "#" -h 18b93f452b8445ba86ac0ec6d2228eb9.s2.eu.hivemq.cloud -p 8883 -u HiveUser1 -pw HivePassword1 --cafile server.pem -d -v -J

Note that now there is no -s flag, but there is --cafile server.pem flag, where server.pem is the file that you have created with openssl s_client command.

I hope this helps?


Now my follow up question to you: You indicated that in your use case a client key and certificate are required. Could you please explain, where the requirement comes from and why username&password auth is insufficient?

Thanks,

Kind regards,
Dasha from HiveMQ

Hi Dasha,

Thanks for the quick response.

Just to clarify, the initial s_client command failed, so I resorted to using the commands in the blog post I linked. Is this command in a linux format?

I tried out the --cafile parameter along with my (likely malformed) server.pem, and got a similar error:

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Feb 11, 2022 10:08:03 AM io.netty.channel.DefaultChannelPipeline onUnhandledInboundException
WARNING: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:471)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:324)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:267)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:262)
        at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:641)
        at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:460)
        at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:360)
        at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:396)
        at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444)
        at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1260)
        at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1247)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:691)
        at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1192)
        at io.netty.handler.ssl.SslHandler.runAllDelegatedTasks(SslHandler.java:1550)
        at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1564)
        at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1448)
        at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1275)
        at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1322)
        at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501)
        at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:440)
        ... 17 more
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:384)
        at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:289)
        at java.base/sun.security.validator.Validator.validate(Validator.java:264)
        at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:285)
        at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:144)
        at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:619)
        ... 32 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:379)
        ... 37 more

I should also clarify that I initially tried to connect my reader to the broker using just my authentication credentials, but it failed to connect. I then tested my connection with mqtt-cli, and found that I could only connect to the broker when the ‘-s’ parameter was set. So I assumed that a TLS connection was required for me to connect to my cloud broker.

Before setting up my HiveMQ broker, the RFID reader would successfully publish messages to your HiveMQ public dashboard, and I had hoped a private connection would be just as simple.

Regarding your question, I’m not entirely certain whether I need all of those files, so I’ve messaged their support service to inquire whether each file is required for basic TLS. From what I do know, these are simply the files it expects to see in it’s ssl directory. But if you could help me get connected using the server.pem that’d be a great start.

I also tried using mqtt.fx as it was recommended to me as a good way to test my certificates. Using the HiveMQ Profile Type, it produced a ‘NOT AUTHORIZED’ error, even though I’m using the exact same credentials I used to successfully connect using mqtt-cli.

2022-02-11 11:58:07,426  INFO --- ScriptsController              : Clear console.
2022-02-11 11:58:07,428  INFO --- MqttFXClient                   : attempt to connect version: 5.0
2022-02-11 11:58:07,803  INFO --- MqttFXClient                   : broker disconnected: Broker connection is disconnected CONNECT failed as CONNACK contained an Error Code: NOT_AUTHORIZED.
2022-02-11 11:58:07,823  INFO --- ScriptsController              : Clear console.
2022-02-11 11:58:07,906  INFO --- ScriptsController              : Clear console.
2022-02-11 11:58:07,907 ERROR --- BrokerConnectService           : CONNECT failed as CONNACK contained an Error Code: NOT_AUTHORIZED.

Thanks for the help, and I look forward to your response.

Hi,

Thought I’d update this thread as I found a working solution.

I found success in running the original command, but removing the ‘showcerts’ segment (likely as I’m using Windows). So the command looked like this:

openssl s_client -connect 4ad85b7fade04d07911be2ac1da2f5e4.s2.eu.hivemq.cloud:8883  > server.pem

This file allows us to successfully connect within both MQTT-CLI and MQTT.fx

I converted the file to .crt with the following command:

openssl x509 -outform der -in server.pem -out ca.crt

This converted file works on both setups as well

Just gotta get it working on my RFID reader now, thanks for the assistance.