mohaqeq / M2MqttDotnetCore

MQTT client based on M2Mqtt 4.3.0 for .NETStandard 1.5
19 stars 8 forks source link

Handshake-Error while connecting to Mosquitto with TLS #3

Open adrha opened 6 years ago

adrha commented 6 years ago

Hey guys i'm building an UWP Application. I'm able to connect unencrypted to the broker, publish and subscribe.

Whenever i try to use TLS, i'm getting a handshake error and in my code i got "The remote certificate is invalid according to the validation procedure". Wireshark told me "TLS Alert 21".

I can connect with MQTTfx without any problems with a CA-certificate or a client certificate.

What could be wrong?

Thanks!

image

My code: (I made a .PFX certificate via openssl to combine key and cert / to reference "clientCert" with null does not change anything...) image

Working MQTTfx config: image

martin-weber commented 6 years ago

Same problem. Tried with different CNs for the server certificate, but it thows alway the "One or more errors occurred. (The remote certificate is invalid according to the validation procedure.)" exception.

adrha commented 6 years ago

Hey i wasn't able to solve the problem with untrusted certificates.

I'm now using a valid certificate from "Let's Encrypt" and everything is working fine.

Follow the instructions here, if you are using the mosquitto broker: https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-the-mosquitto-mqtt-messaging-broker-on-ubuntu-16-04

Make sure that your certbot installed properly with the backport on jessie. Afterwards, if everything is setted up on the broker-side, you can simply connect without a client-cert on MQTT.fx and in your application you can set "null" to both certificates.

martin-weber commented 6 years ago

Thank you. But it would be really great if self signed ca certificates would work.

martin-weber commented 6 years ago

I was able to validate the self signed root ca certificate by adding a RemoteCertificateValidationCallback

            MqttClient mqtt = new MqttClient(MqttOptions.Host, MqttOptions.Port, 
                true, _caCert, _clientCert, MqttSslProtocols.TLSv1_2, ValidateRemoteCertificate);

This ValidateRemoteCertificate callback is implemented according to this post on stackoverflow

        private bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            var certificateToValidate = new X509Certificate2(certificate);

            chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
            chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; // We have an untrusted root ca certificate
            chain.ChainPolicy.VerificationTime = DateTime.Now;
            chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 0, 0);

            chain.ChainPolicy.ExtraStore.Add(_caCert);
            bool isChainValid = chain.Build(certificateToValidate);
            if (!isChainValid)
            {
                string[] errors = chain.ChainStatus
                    .Select(x => $"{x.StatusInformation.Trim()} ({x.Status})")
                    .ToArray();

                string certificateErrorsString = "Unknown errors.";
                if (errors.Length > 0)
                {
                    certificateErrorsString = string.Join(", ", errors);
                }

                throw new Exception("Trust chain did not complete to the known authority anchor. Errors: " + certificateErrorsString);
            }

            // Check if chain contains our root ca certificate
            var valid = chain.ChainElements
                .Cast<X509ChainElement>()
                .Any(x => x.Certificate.Thumbprint == _caCert.Thumbprint);

            return valid;
        }

The two most important parts are:

chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; // We have an untrusted root ca certificate`

which allows unkown CertificateAuthority, and the check of the thumbprint of the cacertificate in the last line:

            var valid = chain.ChainElements
                .Cast<X509ChainElement>()
                .Any(x => x.Certificate.Thumbprint == _caCert.Thumbprint);