MQTTnet icon indicating copy to clipboard operation
MQTTnet copied to clipboard

Can't connect to a MQTT Server with supplied certificates

Open MVSAlex opened this issue 1 year ago • 6 comments

Hi there, I am sorry if this is the wrong place to ask this, but I have been trying for the last weeks to connect to a MQTT Server for an application I am working on.

From this Server I got 3 files used as certificates:

  • ca.pem
  • mqtt.pem
  • mqtt.key Both pem files start with -----BEGIN CERTIFICATE----- The .key file starts with -----BEGIN RSA PRIVATE KEY-----

My issue is that I can't seem to figure out how to connect to the Server with those certificates.

I did get an example from the Devs that made the Server, but it is in JavaScript:

var fs = require('fs');
const mqtt = require('mqtt')

console.log('mqtt test started...');

var KEY = fs.readFileSync('./cert/mqtt.key')
var CERT = fs.readFileSync('./cert/mqtt.pem')
var TRUSTED_CA_LIST = fs.readFileSync('./cert/ca.pem')

var PORT = 1883; // mqtt port
var HOST = '127.0.0.1'; // mqtt server

var options = {
    port: PORT,
    host: HOST,
    key: KEY,
    cert: CERT,
    rejectUnauthorized: false,
    ca: TRUSTED_CA_LIST,
    protocol: 'mqtts'
}

console.log('try to connect....');

const client = mqtt.connect(options)

The example I got works perfectly, but since my project is in C# I can't use the one they provided.

Am I just getting stuck with a somewhat simple issue or is this something else? I'd love to know how I should use those files in MQTTnet since everything I tried leads me to the error The remote certificate was rejected and I even tried the mqttMultimeter, but I get the same error. I even tried to convert the mqtt.pem and the mqtt.key to a .pfx file with openssl, but it still gets rejected.

Which project is your question related to?

  • Client

MVSAlex avatar Oct 25 '23 09:10 MVSAlex

MQTTnet uses the Windows plumbing to handle TLS. Did you add at least the CA certificate to the the machine’s certificate store?

On Wed, Oct 25, 2023, at 05:34, MVSAlex wrote:

Hi there, I am sorry if this is the wrong place to ask this, but I have been trying for the last weeks to connect to a MQTT Server for an application I am working on.

From this Server I got 3 files used as certificates:

• ca.pem • mqtt.pem • mqtt.key Both pem files start with -----BEGIN CERTIFICATE----- The .key file starts with -----BEGIN RSA PRIVATE KEY----- My issue is that I can't seem to figure out how to connect to the Server with those certificates.

I did get an example from the Devs that made the Server, but it is in JavaScript:

`var fs = require('fs'); const mqtt = require('mqtt')

console.log('mqtt test started...');

var KEY = fs.readFileSync('./cert/mqtt.key') var CERT = fs.readFileSync('./cert/mqtt.pem') var TRUSTED_CA_LIST = fs.readFileSync('./cert/ca.pem')

var PORT = 1883; // mqtt port var HOST = '127.0.0.1'; // mqtt server

var options = { port: PORT, host: HOST, key: KEY, cert: CERT, rejectUnauthorized: false, ca: TRUSTED_CA_LIST, protocol: 'mqtts' }

console.log('try to connect....');

const client = mqtt.connect(options) ` The example I got works perfectly, but since my project is in C# I can't use the one they provided.

Am I just getting stuck with a somewhat simple issue or is this something else? I'd love to know how I should use those files in MQTTnet since everything I tried leads me to the error The remote certificate was rejected and I even tried the mqttMultimeter, but I get the same error. I even tried to convert the mqtt.pem and the mqtt.key to a .pfx file with openssl, but it still gets rejected.

Which project is your question related to?

• Client

— Reply to this email directly, view it on GitHub https://github.com/dotnet/MQTTnet/issues/1863, or unsubscribe https://github.com/notifications/unsubscribe-auth/AARTX7NHNIOZWPWMZJCSJCTYBDMJDAVCNFSM6AAAAAA6PBX4FKVHI2DSMVQWIX3LMV43ASLTON2WKOZRHE3DAOJWGI2TGOI. You are receiving this because you are subscribed to this thread.Message ID: @.***>

ShawnStoddard avatar Oct 25 '23 11:10 ShawnStoddard

Yeah I did try to add both .pem certificates to the local machine certificate store and to the current user certificate store which both locations changed nothing. I also tried to import pfx file I created and it said it was imported, but it didn't change anything either.

var mqttFactory = new MqttFactory();

using (var mqttClient = mqttFactory.CreateMqttClient())
{
	// Use builder classes where possible in this project.
	var mqttClientOptions = new MqttClientOptionsBuilder().WithTcpServer("192.168.0.30", 1883).WithTlsOptions(o =>
	{
		o.UseTls(true);
		o.WithAllowUntrustedCertificates(true);
		o.WithClientCertificates(new List<X509Certificate2>
		{
			new X509Certificate2(File.ReadAllBytes("cert\\mqtt.pem"))
		});
		o.Build();
	}).Build();
	
	try
	{
		var response = await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);

		Console.WriteLine("The MQTT client is connected.");
	}
	catch (Exception ex)
	{
		Console.WriteLine(ex);
	}

	// Send a clean disconnect to the server by calling _DisconnectAsync_. Without this the TCP connection
	// gets dropped and the server will handle this as a non clean disconnect (see MQTT spec for details).
	var mqttClientDisconnectOptions = mqttFactory.CreateClientDisconnectOptionsBuilder().Build();

	await mqttClient.DisconnectAsync(mqttClientDisconnectOptions, CancellationToken.None);
}

This is the code I currently have and adding more than one certificate to the list doesn't change anything or causes the code to just stop right at the WithClientCertificates line without any errors. I tried multiple configurations, but apparently not the right one

MVSAlex avatar Oct 25 '23 12:10 MVSAlex

What’s the exception(s) you’re getting?

On Wed, Oct 25, 2023, at 08:22, MVSAlex wrote:

Yeah I did try to add both .pem certificates to the local machine certificate store and to the current user certificate store which both locations changed nothing. I also tried to import pfx file I created and it said it was imported, but it doesn't show up in the certificate store.

`var mqttFactory = new MqttFactory();

using (var mqttClient = mqttFactory.CreateMqttClient()) { // Use builder classes where possible in this project. var mqttClientOptions = new MqttClientOptionsBuilder().WithTcpServer("192.168.0.30", 1883).WithTlsOptions(o => { o.UseTls(true); o.WithAllowUntrustedCertificates(true); o.WithClientCertificates(new List<X509Certificate2> { new X509Certificate2(File.ReadAllBytes("cert\mqtt.pem")) }); o.Build(); }).Build();

try { var response = await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);

  Console.WriteLine("The MQTT client is connected.");

} catch (Exception ex) { Console.WriteLine(ex); }

// Send a clean disconnect to the server by calling DisconnectAsync. Without this the TCP connection // gets dropped and the server will handle this as a non clean disconnect (see MQTT spec for details). var mqttClientDisconnectOptions = mqttFactory.CreateClientDisconnectOptionsBuilder().Build();

await mqttClient.DisconnectAsync(mqttClientDisconnectOptions, CancellationToken.None); } `

This is the code I currently have and adding more than one certificate to the list causes the code to just stop right at the WithClientCertificates line without any errors. I tried multiple configurations, but apparently not the right one

— Reply to this email directly, view it on GitHub https://github.com/dotnet/MQTTnet/issues/1863#issuecomment-1779155003, or unsubscribe https://github.com/notifications/unsubscribe-auth/AARTX7JYNWW2657VHQ4DJATYBEAARAVCNFSM6AAAAAA6PBX4FKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTONZZGE2TKMBQGM. You are receiving this because you commented.Message ID: @.***>

ShawnStoddard avatar Oct 25 '23 13:10 ShawnStoddard

Oh yeah right. Sorry about that. Also my error message is in german so I translated it

MQTTnet.Exceptions.MqttCommunicationException: The remote certificate is invalid according to the validation procedure. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
   at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where the exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at MQTTnet.Implementations.MqttTcpChannel.<ConnectAsync>d__17.MoveNext()
--- End of stack trace from previous location where the exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at MQTTnet.Adapter.MqttChannelAdapter.<ConnectAsync>d__34.MoveNext()
   --- End of internal exception stack trace ---
   at MQTTnet.Adapter.MqttChannelAdapter.WrapAndThrowException(Exception exception)
   at MQTTnet.Adapter.MqttChannelAdapter.<ConnectAsync>d__34.MoveNext()
--- End of stack trace from previous location where the exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at MQTTnet.Client.MqttClient.<ConnectInternal>d__53.MoveNext()
--- End of stack trace from previous location where the exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at MQTTnet.Client.MqttClient.<ConnectAsync>d__41.MoveNext()
--- End of stack trace from previous location where the exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at MQTTnet.Client.MqttClient.<ConnectAsync>d__41.MoveNext()
--- End of stack trace from previous location where the exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at MVSXesarIntegration.MQTTClient.<Connect>d__0.MoveNext() in C:\_devA\MQTTTest\MQTTTest\MQTTClient.cs: Line 55.

If I run the MQTTMultimeter to the same Server I get a similar error:

MQTTnet.Exceptions.MqttCommunicationException: The remote certificate was rejected by the provided RemoteCertificateValidationCallback.
 ---> System.Security.Authentication.AuthenticationException: The remote certificate was rejected by the provided RemoteCertificateValidationCallback.
   at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception)
   at System.Net.Security.SslStream.CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions)
   at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken)
   at MQTTnet.Implementations.MqttTcpChannel.ConnectAsync(CancellationToken cancellationToken)
   at MQTTnet.Implementations.MqttTcpChannel.ConnectAsync(CancellationToken cancellationToken)
   at MQTTnet.Adapter.MqttChannelAdapter.ConnectAsync(CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at MQTTnet.Adapter.MqttChannelAdapter.WrapAndThrowException(Exception exception)
   at MQTTnet.Adapter.MqttChannelAdapter.ConnectAsync(CancellationToken cancellationToken)
   at MQTTnet.Client.MqttClient.ConnectInternal(CancellationToken cancellationToken)
   at MQTTnet.Client.MqttClient.ConnectAsync(MqttClientOptions options, CancellationToken cancellationToken)
   at MQTTnet.Client.MqttClient.ConnectAsync(MqttClientOptions options, CancellationToken cancellationToken)
   at mqttMultimeter.Services.Mqtt.MqttClientService.Connect(ConnectionItemViewModel item)
   at mqttMultimeter.Pages.Connection.ConnectionPageViewModel.Connect(ConnectionItemViewModel item)

MVSAlex avatar Oct 25 '23 13:10 MVSAlex

This issue https://github.com/dotnet/MQTTnet/issues/1857 address the same scenario.

In the meantime, you can configure MqttNet like in this sample

https://github.com/Azure-Samples/MqttApplicationSamples/blob/main/mqttclients/dotnet/MQTTnet.Client.Extensions/WithTlsSettings.cs

rido-min avatar Oct 25 '23 14:10 rido-min

Thank you for the Sample. I sadly can't try it out right now, but I am sure this will work and it looks promising.

MVSAlex avatar Oct 25 '23 16:10 MVSAlex