23

I have a ASP.NET Web API which I'd like to use with ssl. Currently the server is using a self-signed cert, and at this moment both http and https are allowed. I have a very basic test client which works fine for http, but does not work for https. I'd like to know how to modify the client code below so that it will work with https. Currently IE, Firefox, and Chrome can all connect to the Web API using both http and https (with cert warnings), so this makes me believe that I should not have to modify anything on the server, just in the client code. Here's the client code:

static void Main(string[] args)
{
    try
    {
        if (args.Length != 1)
        {
            Console.WriteLine("Please provide a url, and only a url.");
            return;
        }

        var url = new Uri(args[0]);
        var urlAuthority = url.GetLeftPart(UriPartial.Authority);
        var urlPathQuery = args[0].Substring(urlAuthority.Length);
        HttpClient client = new HttpClient();
        client.BaseAddress = new Uri(urlAuthority);
        HttpResponseMessage response = client.GetAsync(urlPathQuery).Result;
        if (response.IsSuccessStatusCode)
            Console.WriteLine(response.Content.ReadAsAsync<string>().Result); // expecting scalar results only
        else
            Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
    }
    catch (Exception ex)
    {
        Exception tempEx = ex;
        while (tempEx != null)
        {
            Console.WriteLine(tempEx.Message);
            tempEx = tempEx.InnerException;
        }
    }
}

When I run the above code with my http url, it works fine. When I change the url to https the following errors are printed:

One or more errors occurred.
An error occurred while sending the request.
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
The remote certificate is invalid according to the validation procedure.

One question I have is if the client must manually send a public key to the server so it knows how to send back an encrypted response, or if this happens automatically behind the scenes? And second, now after seeing the last error I'm wondering if I also have to do something else within the client to ignore cert warnings and just trust that this cert is OK to proceed with?

TTT
  • 22,611
  • 8
  • 63
  • 69

3 Answers3

45

Take a look at the C# Ignore certificate errors SO question. I believe you can add a certificate validation handler using ServicePointManager to circumvent certificate validation. It would probably be a good idea to use a signed certificate within your production environment though.

ServicePointManager
    .ServerCertificateValidationCallback += 
    (sender, cert, chain, sslPolicyErrors) => true;
Community
  • 1
  • 1
Oppositional
  • 11,141
  • 6
  • 50
  • 63
  • 1
    And I agree with using signed certs in prod, though in this case, our prod Web API will not be public, since it is only being connected to from automated clients under our control, but it is still over the internet which is why we need SSL in the first place. – TTT Mar 04 '13 at 17:05
  • I have 2 points, 1. This solution require code difference between Dev and Prod environment. I mean Prod does not need this code, which ignore certificate error. 2. This is app/language specific fix. what if jquery AJAX request need to access this API. In my opinion, as @Devin mentioned, Self Signed cert should be made trusted on development machine by promoting to Root cert. Refer this link which setup development environment with IIS Express and SSL without warning http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx – Arvind Dhasmana Jun 16 '16 at 20:06
24

This worked for me. Just add the following before the call to GetAsync.

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

This will ignore the SSL errors. This is only recommended in an intranet environment or other closed network where server identities can't be forged.

Rick Arthur
  • 2,410
  • 21
  • 15
5

This error message means that the client does not trust the server cert during the SSL handshake. Some browsers are a little more forgiving and give you a "Red bar", but calling from code will result in a 401 and a rejected call.

You do not need to do anything with the client cert settings in IIS (because I assume you are not using a client cert).

This exception message is telling you that the self-signed cert chain is rejected when validating on the client. You might be about to get around this by exporting (without the private key), the self-signed cert and installing it on the client machine as a root cert.

If this doesn't work, you need to make a new CA (certificate authority cert) and then generate a new server cert that is signed with the CA. This CA would finally have to be installed on the client machine as a root cert.

This is a good post that shows the process using makecert and pvk2pfx.

EDIT: It looks like there might be a way to configure HttpClient to ignore SSL errors. But, I would strongly suggest that you try to not to have SSL errors from the start.

Davin Tryon
  • 66,517
  • 15
  • 143
  • 132
  • So is there nothing you can do in the client code to tell it to allow it? How do all the browsers accomplish this without the cert being installed on the client machine as a root cert? – TTT Mar 04 '13 at 16:22
  • @TTT All clients have certain root certs installed. For example Verisign root certs. If a cert is signed (or in the chain) by the Verisign root cert, then the browser client trusts the cert. This is core to how SSL works. – Davin Tryon Mar 04 '13 at 16:24
  • I understand that. But all 3 browsers I've tried can connect to the same url with SSL, but my client cannot. I want to do what the browsers are doing. If the unsigned cert is not trusted on my machine, then its not trusted for the browsers either, but the browsers can still continue. – TTT Mar 04 '13 at 16:37
  • No worries. Thanks for the link. Rick's solution would probably work, though is obsolete in 4.0. @Oppositional's post has the newer version of Rick's code. – TTT Mar 04 '13 at 17:03