2

I have been stuck for around 3 days trying to connect to a server that has a certificate which hasn't been signed by a trusted CA - you can add the CA's certificate through Azure Portal - but to no affect.

apparently everything HTTP uses a kernel module (!) HTTP.SYS.

All of the suggestions I have seen to override this either use:

ServicePointManager.ServerCertificateValidationCallback = Communicator.CustomServiceCertificateValidation;

(or its less global counterpart on the request itself)

or something like this:

 client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication =
                 new X509ServiceCertificateAuthentication()
                 {
                     CertificateValidationMode = X509CertificateValidationMode.Custom,
                     RevocationMode = X509RevocationMode.NoCheck,

                     //TrustedStoreLocation = StoreLocation.CurrentUser,
                     CustomCertificateValidator = new PermissiveCertificateValidator()

                 };

yet, neither gets invoked!!

Some more important details:

This works:

  try
        {
            ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
            using (var wc = new WebClient())
            {
                var res = wc.DownloadString("https://untrusted-root.badssl.com/");
                return Content(res);
            }
        }
        catch (Exception ex)
        {
            return Content(ex.ToString());
        }

Yet, I need to authenticate myself with a client certificate - so, following the instructions found here: How can you add a Certificate to WebClient (C#)?

I end up with the following code:

class ATWebClient : WebClient
{
    protected override WebRequest GetWebRequest(Uri address)
    {
        HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
        request.Headers.Add("SOAPAction", "https://servicos.portaldasfinancas.gov.pt/sgdtws/documentosTransporte/");
        X509Certificate2 cert = new X509Certificate2();
        //From user installed Certificates
        //cert.Import(_pathCertificate, _passwordCertificate, X509KeyStorageFlags.DefaultKeySet);
        //From FileSystem "Resources\Certificates"
        cert.Import(Common.Properties.Resources.testewebservices_novo, "TESTEwebservice", X509KeyStorageFlags.Exportable);

        // Output Certificate 
        //Utils.Log(string.Format("Cert Subject: [{0}], NotBefore: [{1}], NotAfter: [{2}]", cert.Subject, cert.NotBefore, cert.NotAfter));

        request.ClientCertificates.Add(cert);
        request.Method = "POST";
        request.ContentType = "text/xml; charset=utf-8";
        request.Accept = "text/xml";


        return request;
    }

And now I invoke the service with:

   try
    {

        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
        ServicePointManager.CheckCertificateRevocationList = false;
        ServicePointManager.UseNagleAlgorithm = false;
        using (var wc = new ATWebClient())
        {
            //var res = wc.DownloadString("https://servicos.portaldasfinancas.gov.pt:701/sgdtws/documentosTransporte");
            var res = wc.UploadString("https://servicos.portaldasfinancas.gov.pt:701/sgdtws/documentosTransporte", "Test of content");
            return Content(res);
        }


    }
    catch (Exception ex)
    {
        return Json(ex);
    }

Note, yes, this is a SOAP endpoint - I tried sending valid SOAP content, yet the result is in both cases the same, I get the following exception:

The underlying connection was closed: An unexpected error occurred on a send.

Stacktrace:

   at System.Net.WebClient.UploadDataInternal(Uri address, String method, Byte[] data, WebRequest& request)
   at System.Net.WebClient.UploadString(Uri address, String method, String data)
   at System.Net.WebClient.UploadString(String address, String data)
   at MagniWebApp.Controllers.HomeController.NonTrustedCATestEndpoint() in C:\Users\joao.antunes.Office2\source\repos\07. Platform\WebApp\MagniWebApp\Controllers\HomeController.cs:line 1154

Inner exception's message:

Authentication failed because the remote party has closed the transport stream.

Any ideas?! Halp!

João Antunes
  • 811
  • 9
  • 16

1 Answers1

2

What about hardcode returning true in your custom callback like this?

 public string Ssl()
    {
        try
        {
            ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
            using (var wc = new WebClient())
            {
                var res = wc.DownloadString("https://untrusted-root.badssl.com/");
                Console.WriteLine(res);
                return res;
            }
        }
        catch (Exception ex)
        {
            return ex.ToString();
        }
    }
  • It doesn't even get invoked! but it does locally when I add the untrusted CA to the store - however - that doesn't work on an Azure Web App!! – João Antunes Apr 18 '18 at 22:02
  • Did I understand correctly, that you call untrusted https server from azure web app? What about try to install it on your host like this `X509Certificate2Collection certificates = new X509Certificate2Collection(); certificates.Import(certName, password, X509KeyStorageFlags.PersistKeySet );` – Artem Kurianov Apr 18 '18 at 22:08
  • Yes! I did that, @Artem Kurianov and it gives out a File not found - which has to do with the store AFAIK - because I actually have the certificates (the pfx) as a byte array on the Resources – João Antunes Apr 19 '18 at 09:01
  • It's very strange.In my azurewebapp it works` public string Ssl() { try { ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; using (var wc = new WebClient()) { var res = wc.DownloadString("https://untrusted-root.badssl.com/"); return res; } } catch (Exception ex) { return ex.ToString(); } }` – Artem Kurianov Apr 19 '18 at 12:37
  • Finally progress!! thanks! So, your code works - which is different from mine, which used a HTTPWebRequest: //Prepare Request HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_urlWebService); request.ServerCertificateValidationCallback += Communicator.CustomServiceCertificateValidation; Now I just have to figure out how to add client cert and other things with the WebClient!! Any idea? – João Antunes Apr 19 '18 at 14:59
  • I'm onto it!!: https://stackoverflow.com/questions/2066489/how-can-you-add-a-certificate-to-webclient-c?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa Thanks @Artem Kurianov – João Antunes Apr 19 '18 at 15:01
  • Edit your answer and add the webclient part and I'll upvote it! – João Antunes Apr 19 '18 at 15:02
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/169358/discussion-between-joao-antunes-and-artem-kurianov). – João Antunes Apr 19 '18 at 17:12