1

Overview

I seem to have a variant of the problem listed in this post. However, the answers there don't really help me, and my situation is different.

I'm working for a large corporate, who have decided to trust themselves as a root certificate authority. I've developed a web application, that needs to link to an API hosted in a VM in Azure.

My Approach

As I can't install the certificate in the trusted store, I was trying to do this by code. I'm using ASP.NET Web API v2, and I've added the following code to the startup section:

    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
        var options = CorsOptions.AllowAll;
        app.UseCors(options);

        // Override certificate check
        ServicePointManager.ServerCertificateValidationCallback =   MyRemoteCertificateValidationCallback;
    }

My callback looks like this:

public bool MyRemoteCertificateValidationCallback(
        object sender,
        X509Certificate certificate,
        X509Chain chain,
        SslPolicyErrors sslPolicyErrors)
    {
        switch (sslPolicyErrors)
        {
            case SslPolicyErrors.RemoteCertificateChainErrors:                    
                return IsTheCertificateOriginAcceptable(chain);
            case SslPolicyErrors.None:
                return true;
            default:
                return false;
        }
    }

The certificate origin acceptable function is checking to see if the problem was due to an Unknown Root, and then to see if the unkown root is an extra one the code knows about (because I can't add trusted roots to the Azure Web App - if I had a VM installing the certificate would be the way to go).

If not, it throws a web exception:

bool IsTheCertificateOriginAcceptable(X509Chain chain)
{
   // checks to see if the initail problem is an untrusted root,
   // and to extract the origin certificate
   if (certificate.IssuerName.Name == expectedIsserName)
   {
       return true;
   }
   else
   {
       throw new WebException($"Certificate origin unacceptable Actual Issue Name '{certificate.IssuerName.Name}', expected issuer name '{expectedIssuerName}'");
   }

The plan is to find the issuer name from the VM, and then put that into the code - this is exploratory code, to work out how to get the connection done.

Running locally

I then set myself up with IIS with two websites. One running this code, and one on a differnt port, with the default self-signed certificate running a trivial mock of the API I am trying to call.

When I do that, if I don't use the above code, I get the same error I get on Azure:

The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)
at System.Net.HttpWebRequest.GetRequestStream()

If I do use the code, I get the following message

Certificate origin unacceptable Actual Issue Name 'CN=localhost', expected issuer name ''

In the Azure Web App

When I deploy the above code to Azure, I always get the certificate trust error, which suggests that the callback isn't getting called.

I can't check the SSL settings of the remote server easily, as it isn't connected to the internet (I've connected my azure web app to the VNET the VM is hosted on).

So given all that, how can I connect, other than suggesting that the remote server gets a proper certificate from a known and trusted RCA?

  • As webApp is [sandbox](https://github.com/projectkudu/kudu/wiki/Azure-Web-App-sandbox), many operations are limited for security, I am not sure whether it could be executed on the Azure WebApp. If is possible, please have a try to move it to Azure Visual Machine as workaround. – Tom Sun - MSFT Jun 30 '17 at 08:56
  • I'd suggest trying to follow [this answer](https://stackoverflow.com/a/18624335/319151) to see if setting it PER connection would potentially make a difference? – Anže Vodovnik Jul 04 '17 at 13:10

1 Answers1

1

It turns out that the behaviour of the framework was not what I expected.

The situation I had was a self-signed root certficate, and a child certificate of that self-signed certificate. In this case, I had expected one certificate to be marked as UntrustedRoot.

However, the behaviour of the framework in this case it to only give the leaf certificate, so the chain is length 1. The chain then gets classified as PartialChain.

My logic was looking for an UntrustedRoot, not a PartialChain, so although the callback was called, I was returning lacking permission earlier.

So my logic was wrong - which I confirmed by setting the callback to always return true. I then set two self-signed certificates up and used a second website on localhost - which replicated the error and allowed me to see where my logic error was.

Thanks to those who commented, I should have checked the callback being set true resolved the issue before posting.

  • I am having issues with this. But in my case the Callback never gets called if the root certificate is not in the store. did it do that on yours? – João Antunes Apr 18 '18 at 21:42