14

I'm attempting to connect to a SignalR server with an invalid certificate. Unsurprisingly I get the following error:

    System.Net.Http.HttpRequestException : An error occurred while sending the request.
----> System.Net.WebException : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
  ----> System.Security.Authentication.AuthenticationException : The remote certificate is invalid according to the validation procedure.

With the normal .Net HttpClient you can construct it with a WebRequestHandler that has a ServerCertificateValidationCallback delegate, allowing you to change the certificate validation behaviour. The SignalR HttpClient appears to have none of this.

Dan
  • 3,229
  • 2
  • 21
  • 34

2 Answers2

17

You should register a method for ServerCertificateValidationCallback event.

This code just registers an anonymous method which returns true when the event is fired.

ServicePointManager.ServerCertificateValidationCallback +=
                  (sender, certificate, chain, sslPolicyErrors) => true;

Be careful, this is a global setting. So all ssl/tls request signalr or http will use this setting.

Erkan Demirel
  • 4,302
  • 1
  • 25
  • 43
  • That works, thanks. The global isn't great but I'm using this in a testing assembly, so it's good enough. – Dan Feb 25 '16 at 14:16
  • This won't work for .NET Core. To always verify the SSL in .NET Core when using SignalR, see https://stackoverflow.com/a/59835125/1549918 – Chris Halcrow May 10 '21 at 04:09
8

I believe that I have found a way that seems to work but isn't global like the ServicePointManager.ServerCertificateValidationCallback approach that is typically recommended. I started by making a subclass of the SignalR "DefaultHttpClient" class as follows:

class CustomHttpClient : DefaultHttpClient
    {
        private readonly System.Net.Security.RemoteCertificateValidationCallback _serverCertificateValidationCallback;

        public CustomHttpClient (System.Net.Security.RemoteCertificateValidationCallback serverCertificateValidationCallback) : base()
        {
            this._serverCertificateValidationCallback = serverCertificateValidationCallback;
        }

        protected override HttpMessageHandler CreateHandler()
        {
            var rv = base.CreateHandler() as WebRequestHandler;
            if (this._serverCertificateValidationCallback != null)
                rv.ServerCertificateValidationCallback = this._serverCertificateValidationCallback;
            return rv;
        }
    }

Now I can use my custom HttpClient implementation when I call "Start" on my HubConnection instance as follows:

var hubConnection = new HubConnection("my server url");
var myHub = hubConnection.CreateHubProxy("my hub name");
hubConnection.Start(new CustomHttpClient((sender, certificate, chain, sslPolicyErrors) =>
                {
                    //put some validation logic here if you want to.
                    return true;
                }));

This should allow you to validate the server certificate as you see fit, but keep the scope to the current HubConnection instead of affecting all HTTP traffic from your app.

Bryan Bosley
  • 131
  • 2
  • 2