Home > Software engineering >  The remote certificate was rejected by the provided RemoteCertificateValidationCallback - how to get
The remote certificate was rejected by the provided RemoteCertificateValidationCallback - how to get

Time:10-21

I have prepared a test case for my problem - a very simple .NET 6 Console app:

using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

namespace CheckCert
{
    internal class Program
    {
        public const string jsonUrl = "https://wordsbyfarber.com/de/top-5";

        static void Main(string[] args)
        {
            Console.WriteLine($"jsonUrl = {jsonUrl}");
            HttpClientHandler handler = new()
            {
                ServerCertificateCustomValidationCallback = BackendCaValidation,
                CheckCertificateRevocationList = true,
            };
            HttpClient httpClient = new(handler);
            string jsonStr = httpClient.GetStringAsync(new Uri(jsonUrl)).Result;
            Console.WriteLine($"jsonStr = {jsonStr}");
        }

        private static bool BackendCaValidation(HttpRequestMessage message, 
                                                X509Certificate2? certificate, 
                                                X509Chain? chain, 
                                                SslPolicyErrors sslPolicyErrors)
        {
            Console.WriteLine($"sslPolicyErrors = {sslPolicyErrors}");
            return SslPolicyErrors.None == sslPolicyErrors;
        }
    }
}

When I run it, it works as expected, will print SslPolicyErrors.None and the JSON content from my private website, which uses a Let's Encrypt certificate.

However when I change the jsonUrl to the URL of my work server, which I am better not sharing in public, then I end up with SslPolicyErrors.RemoteCertificateChainErrors and a System.AggregateException.

The exception says "look at the inner exception".

So inspect the inner exception and it says:

The remote certificate was rejected by the provided RemoteCertificateValidationCallback

screenshot

So I keep looking at the certificate and the chain displayed by the Microsoft Edge browser - both for my private website and for the work server.

The work server uses a certificate issued by a self-signed work CA (and there is an intermediate certificate inbetween). All 3 certificates are not expired yet.

My question is: how to get more information here?

Why exactly do I get a SslPolicyErrors.RemoteCertificateChainErrors? is it because of that self-signed corporate CA or maybe because of some signing algorithm?

And also - similar code works for us in another project (an Azure Service Fabric application) without failing. I wonder, what could be the difference?

UPDATE:

I have followed the suggestion by Mr. Spiller (thank you!) and have added the code:

Console.WriteLine("-----------------------------------");
foreach (X509ChainStatus status in chain.ChainStatus)
{
    Console.WriteLine($"status = {status.Status}");
}

Now my private Let's Encrypt secured URL looks like this (why is there no chain printed? I can see the chain in the web browser):

screenshot 1

browser 1

And the "faulty" corporate URL looks like this:

screenshot 2

browser 2

My main question is: how to make my app work against the corporate URL, without making it insecure?

I.e. I would probably have to accept the returned SslPolicyErrors.RemoteCertificateChainErrors in my app, but can I still perform some checks?

CodePudding user response:

The parameter X509Chain? chain has a property ChainStatus which you can use to get the status for each element of the certification chain.

Each element in turn has a property Status of type System.Security.Cryptography.X509Certificates.X509ChainStatusFlags (cf. documentation) that should give you the status of each particular element of the certification chain.

In your case one (the only?) element most likely has the status UntrustedRoot.


If you want to connect to your corporate server even though the certificate is not trusted, you can simply return true from the callback. I.e. in BackendCaValidation check whether you are talking to the corporate server and return true even though sslPolicyErrors is not None.

The other (preferred?) way is to trust your corporate CA system-wide. I.e. add the CA to the cert store of your operating system and mark it as trusted.

  • Related