.net-coremqttnet

MQTTnet : Unable to connect With TLS : Interop+AppleCrypto+SslException: bad protocol version


I am a new .NET core user trying to learn how to connect a managed client with TLS on MacOS Catalina, using MQTTnet.

I am trying to connect from ASP.NET Core 3 Background Service to a Mosquitto broker. Using MqttExplorer I am able to connect successfully to the server over TLS, with username, password and a server certificate (CA) file. So, I know the Mosquitto Broker is configured correctly.

However, I am unable to achieve this with MQTTnet.

using (var fileStream = new FileStream(_Config.Tls.CACerts, FileMode.Open))
                using (var memoryStream = new MemoryStream((int)fileStream.Length))
                {
                    fileStream.CopyTo(memoryStream);

                    _Logger.LogInformation($"Read file stream with length {memoryStream.Length} bytes, trying to connect with options:");
                    _Logger.LogInformation($"mqtt://{_Config.UserName}:{_Config.Password}/{_Config.Host}:{_Config.Port}");

                    _MqttOptions = new ManagedMqttClientOptionsBuilder()
                        .WithAutoReconnectDelay(TimeSpan.FromSeconds(5))
                        .WithClientOptions(new MqttClientOptionsBuilder()
                            .WithClientId(Guid.NewGuid().ToString())
                            .WithCredentials(_Config.UserName, _Config.Password)
                            .WithTcpServer(_Config.Host, _Config.Port)
                            .WithTls(
                                o =>
                                {
                                    o.UseTls = true;
                                    o.AllowUntrustedCertificates = true;
                                    o.SslProtocol = SslProtocols.Tls12;
#if WINDOWS_UWP
                                    o.Certificates = new List<byte[]>
                                    {
                                        new X509Certificate(memoryStream.ToArray()).Export(X509ContentType.Cert)
                                    };
#else
                                    o.Certificates = new List<X509Certificate>
                                    {
                                        new X509Certificate(memoryStream.ToArray())
                                    };
#endif

                                    o.CertificateValidationHandler = (context) =>
                                    {
                                        _Logger.LogInformation($"SSL POLICY ERRORS {context.SslPolicyErrors.ToString()}");
                                        return true;
                                    };
                                }
                            )
                            .Build())
                        .Build();
                }

I receive the following exception:

MQTTnet.Exceptions.MqttCommunicationException: Authentication failed, see inner exception.
 ---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
 ---> Interop+AppleCrypto+SslException: bad protocol version
   --- End of inner exception stack trace ---
   at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Security.SslStream.ThrowIfExceptional()
   at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)
   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
   at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__64_2(IAsyncResult iar)
   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 exception was thrown ---
   at MQTTnet.Implementations.MqttTcpChannel.ConnectAsync(CancellationToken cancellationToken)
   at MQTTnet.Implementations.MqttTcpChannel.ConnectAsync(CancellationToken cancellationToken)
   at MQTTnet.Internal.MqttTaskTimeout.WaitAsync(Func`2 action, TimeSpan timeout, CancellationToken cancellationToken)
   at MQTTnet.Adapter.MqttChannelAdapter.ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at MQTTnet.Adapter.MqttChannelAdapter.WrapException(Exception exception)
   at MQTTnet.Adapter.MqttChannelAdapter.ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
   at MQTTnet.Client.MqttClient.ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken)
>> [2020-10-02T16:07:03.9254330Z] [4] [MqttClient] [Verbose]: Disconnecting [Timeout=00:00:10]
>> [2020-10-02T16:07:03.9255750Z] [4] [MqttClient] [Verbose]: Disconnected from adapter.
>> [2020-10-02T16:07:03.9256240Z] [4] [MqttClient] [Info]: Disconnected.

Also, explictly tried adding WithProtocolVersion(MQTTnet.Formatter.MqttProtocolVersion.V311) to client options builder.

Is anyone able to help?


Solution

  • Managed to get it working!

    The problem was that the mosquitto broker was configured to use Tls v1.3 only. However, with dotnet core 3.1 tls1.3 does not appear to be supported on macOS environments? It is available on Linux environments if openssl 1.1.1 is available.

    I have downgraded the mosquitto broker configuration to use tls version 1.2 and the code above now connects.

    If anyone has managed to get a dotnet core 3.1 client connecting to mosquitto broker using tlsv1.3 then any details would be appreciated.