13

I'm trying to use C# to get RabbitMQ 3.6.2 to use SSL/TLS on Windows 7 against Erlang 18.0. I'm running into errors when I'm enabling SSL in my C# code. I have gone through the steps to set up SSL/TLS here. I've also gone through the [troubleshooting steps][2] which show turn up successful (except I couldn't do the stunnel step due to lack of knowledge of stunnel). Here's my C# code trying to connect to RabbitMQ:

var factory = new ConnectionFactory()
{
    // NOTE: guest username ONLY works with HostName "localhost"!
    //HostName = Environment.MachineName,
    HostName = "localhost",
    UserName = "guest",
    Password = "guest",
};

// Without this line, RabbitMQ.log shows error: "SSL: hello: tls_handshake.erl:174:Fatal error: protocol version"
// When I add this line to go to TLS 1.2, .NET throws an exception: The remote certificate is invalid according to the validation procedure.
//      https://stackoverflow.com/questions/9983265/the-remote-certificate-is-invalid-according-to-the-validation-procedure:
//      Walked through this tutorial to add the client certificate as a Windows Trusted Root Certificate: http://www.sqlservermart.com/HowTo/Windows_Import_Certificate.aspx
factory.Ssl.Version = SslProtocols.Tls12;

factory.Ssl.ServerName = "localhost"; //System.Net.Dns.GetHostName();
factory.Ssl.CertPath = @"C:\OpenSSL-Win64\client\keycert.p12";
factory.Ssl.CertPassphrase = "Re$sp3cMyS3curi1ae!";
factory.Ssl.Enabled = true;
factory.Port = 5671;

// Error: "The remote certificate is invalid according to the validation procedure."
using (var connection = factory.CreateConnection())
{
}

There's a StackOverflow post regarding the "The remote certificate is invalid according to the validation procedure." exception, but the hack fix doesn't seem to take effect as the callback method suggested is never called. I think that I've added my certificate generated via OpenSSL to the Windows Trusted Root Certification Authorities certificates list for local computer. So I'm at a loss here. Any ideas on how to proceed?

Edit: Here's the final working code for anyone struggling to implement SSL on Rabbit:

var factory = new ConnectionFactory();
factory.HostName = ConfigurationManager.AppSettings["rabbitmqHostName"];

factory.AuthMechanisms = new AuthMechanismFactory[] { new ExternalMechanismFactory() };
// Note: This should NEVER be "localhost"
factory.Ssl.ServerName = ConfigurationManager.AppSettings["rabbitmqServerName"];
// Path to my .p12 file.
factory.Ssl.CertPath = ConfigurationManager.AppSettings["certificateFilePath"];
// Passphrase for the certificate file - set through OpenSSL
factory.Ssl.CertPassphrase = ConfigurationManager.AppSettings["certificatePassphrase"];
factory.Ssl.Enabled = true;
// Make sure TLS 1.2 is supported & enabled by your operating system
factory.Ssl.Version = SslProtocols.Tls12;
// This is the default RabbitMQ secure port
factory.Port = 5671;
factory.VirtualHost = "/";
// Standard RabbitMQ authentication (if not using ExternalAuthenticationFactory)
//factory.UserName = ConfigurationManager.AppSettings["rabbitmqUsername"];
//factory.Password = ConfigurationManager.AppSettings["rabbitmqPassword"];

using (var connection = factory.CreateConnection())
{
    using (var channel = connection.CreateModel())
    {
        // publish some messages...
    }
}

Thanks,

Andy

Andy
  • 2,709
  • 5
  • 37
  • 64
  • 2
    So your certificate is issued for "localhost"? Because Ssl.ServerName mush match. Also, why you provide CertPath and especially CertPassphrase? This is for client authentication, and I suppose you are trying to setup server-side ssl (or not?) – Evk Sep 22 '16 at 15:25
  • The issue was the servername not matching... By default "localhost" is used, but my certificate was created for my machine name (Environment.MachineName in C#). I'm using the client cert because that's what's in the example C# at https://www.rabbitmq.com/ssl.html. Thanks very much for your help! – Andy Sep 22 '16 at 15:30
  • Does the ssl plugin need to be installed for this? – Tophat Gordon Sep 24 '18 at 08:17
  • @TophatGordon yes, SSL auth requires the aptly-named plugin: rabbitmq_auth_mechanism_ssl – Andy Sep 24 '18 at 14:17

5 Answers5

10

Usual problem is mismatch between what you provide in Ssl.ServerName and host SSL certificate was issued for.

Also note that server-side SSL (encrypted connection between your client and server) and client-side authentication with certificate (you provide server with information which confirms that you have certificate it expects) are two different things. By providing Ssl.CertPath you intent to authorize at server using this certificate, which might or might not be what you want.

Evk
  • 98,527
  • 8
  • 141
  • 191
3

My problem was related to using self signed certificates. I had to add the SslOption AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch | SslPolicyErrors.RemoteCertificateChainErrors

In the example connection factory creation code sslEnabled is true.

new ConnectionFactory()
            {
                Uri = uri,
                ClientProvidedName = clientProvidedName,
                AutomaticRecoveryEnabled = true,
                Ssl = new SslOption(){
                    Enabled = sslEnabled,
                 AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch |
                                                SslPolicyErrors.RemoteCertificateChainErrors} ,

                NetworkRecoveryInterval = TimeSpan.FromSeconds(networkRecoveryIntervalSecs)
            }
3

It can be done as simple as this

        const string RabbitMqServerHostname = "myserver.northeurope.cloudapp.azure.com";

        var factory = new ConnectionFactory()
        {
            HostName = RabbitMqServerHostname,
            UserName = "myuser",
            Password = "mypassword",

            // The settings below turn on SSL
            Port = 5671,
            Ssl = new SslOption
            {
                Enabled = true,
                ServerName = RabbitMqServerHostname
            }
        };
1

I just went through a similar frustrating exercise with the .NET 4.5 client (v. 3.6.6) and the RabbitMQ broker/service on Windows (v. 3.6.6, Erlang 19.2).

The correct combination of RabbitMQ config file options and client settings is not intuitive and the client factory object has changed since the documentation was last updated. Now there's an SslOption class.

Are you still having problems? Perhaps I can help you.

MikeZ
  • 1,155
  • 1
  • 13
  • 20
  • Thanks for the reply - I got it sorted out. I completely agree that the setup/configuration is not intuitive. There's definitely an opportunity for someone to write a wizard to wrap the RabbitMQ installer that optionally includes OpenSSL and configures security since it's such a pain. – Andy Feb 26 '17 at 14:12
  • @Andy : I know this is a fairly old thread. I am facing the same problem with a x509 certificate I generated using openssl. If you can post your code for the SslOption object (the required properties and its values) I can probably stop pulling my hair. Also, I did not add my certificate (.p12) to any certificate store. It is simply sitting in the folder where I created it. Does it make any difference? Any help would be highly appreciated. Thanks. – Babu Mannavalappil Apr 19 '17 at 16:54
  • @Babu - sorry it's so late, but I've updated with my final code that should work. I'm using MassTransit to abstract away a lot of the RabbitMQ specifics and would highly recommend if you're not already using it. SSL+RabbitMQ is tricky to implement though regardless of whether you use MassTransit. – Andy May 01 '17 at 00:51
0

I've resolved the problem changing only the Ssl.ServerName to the Common Name (CN) of the issued certificate, because it was different of the server which hosts the service.

factory.Ssl.ServerName = "[certificate cn]";

I had tried with python (because the provider used that language) and it worked, I suppose then that Python doesn't validate that features of the certificates (it's more insecure?).

Marc
  • 1,359
  • 1
  • 15
  • 39
  • I can't speak to python, but when I tried this approach in C# I got the same behavior as when the hostname and common name didn't match. – Ryan Gates Aug 06 '18 at 16:11