Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The client and server cannot communicate, because they do not possess a common algorithm #1095

Closed
KMcNickel opened this issue Feb 16, 2021 · 9 comments · Fixed by #1271
Closed
Labels
question It is a question regarding the project

Comments

@KMcNickel
Copy link

Describe your question

I recently shifted a project from .Net Core 3.1 to .Net 5.0 and updated MQTTNet to 3.0.14. Since making the change, I have been unable to use the MQTTNet client to connect to my Mosquitto broker. During the call to ConnectAsync, the code throws the exception: "The client and server cannot communicate, because they do not possess a common algorithm".

I am not sure why this is happening after the upgrade, one thought I had was to back the TLS version down to v1.2 instead of 1.3, but I get a remote certificate validation error (also new since the root for that certificate is in my Trusted Root Certificate Authority store and nothing on the other end changed)

I am running it on my (Windows) development computer, and have yet to try it on an Ubuntu box (same as the production server)

For reference, the MQTTClient options:

            List<X509Certificate> certs = new List<X509Certificate>
            {
                new X509Certificate2(config.GetValue<string>("DeviceCertificate"), config.GetValue<string>("CertificatePassword"))
            };
            IMqttClientOptions options = new MqttClientOptionsBuilder()
                .WithTcpServer("Server FQDN", 8883)
                .WithTls(new MqttClientOptionsBuilderTlsParameters
                {
                    UseTls = true,
                    Certificates = certs
                })
                .WithCleanSession()
                .Build();

The Mosquitto v2.0.7 config:

listener 1883 localhost

listener 8883
certfile /etc/mosquitto/certs/server.pem
capath /etc/mosquitto/ca_certificates/
keyfile /etc/mosquitto/certs/server_key.pem
require_certificate true
use_identity_as_username true
acl_file /etc/mosquitto/conf.d/aclfile

log_type all
log_timestamp_format %Y-%m-%dT%H:%M:%S

user mosquitto

Which project is your question related to?

  • Client
@KMcNickel KMcNickel added the question It is a question regarding the project label Feb 16, 2021
@KMcNickel
Copy link
Author

In regards to TLSv1.2, it looks like theres an issue with it trying to connect to the revocation server which is odd since the server is running and the links are correct in the certificates, but is also an issue I can manage separately.

I still cannot seem to figure out why 1.3 doesn’t work but I would like to know if there is a way to find what algorithms are able to be / are actually being tried by the system and if there might be something else Im missing.

@SeppPenner
Copy link
Collaborator

SeppPenner commented Mar 1, 2021

That is strange. I had the same error and just downgraded the server to TLS1.2 explicitely in the options and the client as well, e.g.:

Client:

var options = new MqttClientOptionsBuilder()
    .WithClientId("ClientId")
    .WithTcpServer("mybroker.com", 8883)
    .WithCredentials("Username", "Password")
    .WithTls(new MqttClientOptionsBuilderTlsParameters()
    {
        UseTls = true,
        SslProtocol = SslProtocols.Tls12
    })
    .WithCleanSession()
    .Build();
var factory = new MqttFactory();
var mqttClient = factory.CreateMqttClient();
await mqttClient.ConnectAsync(options);

Server:

var optionsBuilder = new MqttServerOptionsBuilder()
    .WithoutDefaultEndpoint()
    .WithEncryptedEndpoint()
    .WithEncryptedEndpointPort(8883)
    .WithEncryptionSslProtocol(SslProtocols.Tls12);
var mqttServer = new MqttFactory().CreateMqttServer();
await mqttServer.StartAsync(optionsBuilder.Build());

(Of course some more logic like adding certificates, if needed).

But this worked for me...

@vukovinski
Copy link

Happened to me also, but when changed to Tls12, I'm getting a different error:

Authentication failed because the remote party has closed the transport stream.

Still investigating. Note that I'm using .Net Core 3.1.

@vukovinski
Copy link

So I was trying to use TLS with credentials only. Works when toggling TLS off. Will test later with certificates and TLS.

sleevezipper added a commit to sleevezipper/hass-workstation-service that referenced this issue Mar 15, 2021
@amelkor
Copy link

amelkor commented May 24, 2021

Faced the same issue with TLS1.3, was following this doc, the certificate created with openssl
Switching to TLS1.2 works fine
The server code the same as there, client's one below:

var tlsOptions = new MqttClientOptionsBuilderTlsParameters
{
    UseTls = true,
    SslProtocol = SslProtocols.Tls13,
    AllowUntrustedCertificates = true,
    IgnoreCertificateChainErrors = true,
    IgnoreCertificateRevocationErrors = true,
};
_options = new MqttClientOptionsBuilder()
    .WithTcpServer("localhost", 8883)
    .WithClientId("some_id")
    .WithCredentials("login", "pass")
    .WithProtocolVersion(MqttProtocolVersion.V500)
    .WithTls(tlsOptions)
    .Build();

getting this:

MQTTnet.Exceptions.MqttCommunicationException: The client and server cannot communicate, because they do not possess a common algorithm.
 ---> System.ComponentModel.Win32Exception (0x80090331): The client and server cannot communicate, because they do not possess a common algorithm.
   at System.Net.SSPIWrapper.AcquireCredentialsHandle(ISSPIInterface secModule, String package, CredentialUse intent, SCH_CREDENTIALS* scc)
   at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(CredentialUse credUsage, SCH_CREDENTIALS* secureCredential)
   at System.Net.Security.SslStreamPal.AcquireCredentialsHandleSchCredentials(X509Certificate certificate, SslProtocols protocols, EncryptionPolicy policy, Boolean isServer)
   at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(SslStreamCertificateContext certificateContext, SslProtocols protocols, EncryptionPolicy policy, Boolean isServer)
   at System.Net.Security.SecureChannel.AcquireClientCredentials(Byte[]& thumbPrint)
   at System.Net.Security.SecureChannel.GenerateToken(ReadOnlySpan`1 inputBuffer, Byte[]& output)
   at System.Net.Security.SecureChannel.NextMessage(ReadOnlySpan`1 incomingBuffer)
   at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
   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 ---

@vukovinski
Copy link

This is probably due to TLS 1.2 -> TLS 1.3 changes.

https://www.microsoft.com/security/blog/2020/08/20/taking-transport-layer-security-tls-to-the-next-level-with-tls-1-3/

@SeppPenner
Copy link
Collaborator

@amelkor That's correct since you're using SslProtocol = SslProtocols.Tls13, with the client and .WithEncryptionSslProtocol(SslProtocols.Tls12) with the server (Following the doc under https://github.com/chkr1011/MQTTnet/wiki/Server#using-a-certificate). There is a TLS mismatch.

If you follow my code above (#1095 (comment)), this should work properly...

@patagonaa
Copy link
Contributor

This is also pretty bad as this causes connections to MQTT brokers to fail when the server doesn't support TLS 1.3.

Here (and in a few other places), the only supported TLS Version (by default) is set to TLS 1.3:
https://github.com/chkr1011/MQTTnet/blob/8f1d4e3c22f3226570eec681bccef3a88c4ebd16/Source/MQTTnet/Client/Options/MqttClientTlsOptions.cs#L29-L33

This causes all connections to TLS 1.2 Brokers to fail by default after upgrading to MQTTnet version v3.0.14 (on .NET Core >3.1).

In my opinion (and, reading the docs, in Microsoft's Opinion as well), the default should be SslProtocols.None to let the OS select the best protocol to use:
https://docs.microsoft.com/en-us/dotnet/api/system.security.authentication.sslprotocols?view=net-5.0

None: Allows the operating system to choose the best protocol to use, and to block protocols that are not secure. Unless your app has a specific reason not to, you should use this field.

@patagonaa
Copy link
Contributor

From a library user perspective, it just doesn't make sense to force any TLS standard here, really. Just like you don't expect HttpClient to just throw exceptions because the HTTPS server doesn't support TLS 1.3 (it is of course okay to throw if the server only supports insecure standards).

This is also reinforced by the number of issues in this repo regarding this single issue (see #1231, #1207, #1211 and possibly more).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question It is a question regarding the project
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants