Submitting SSL HttpWebRequests with client certificates on Azure App Services

2

I'm trying to do a very simple HTTP/SSL request with a client certificate in an Azure Web App (App Service) with .NET. For context, it's to write logs to an Elasticsearch cluster.

Enabling tracing for System.Net and System.Net.Sockets shows that the request fails while attempting to load the private key for the client certificate - which was loaded in memory.

System.Net Information: 0 : [4064] SecureChannel#49205706 - Certificate is of type X509Certificate2 and contains the private key.
System.Net Information: 0 : [4064] AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent  = Outbound, scc     = System.Net.SecureCredential)
System.Net Error: 0 : [4064] AcquireCredentialsHandle() failed with error 0X8009030D.
System.Net.Sockets Verbose: 0 : [0764] Socket#8628710::Dispose()
System.Net Error: 0 : [0764] Exception in the HttpWebRequest#53036123:: - The request was aborted: Could not create SSL/TLS secure channel.
System.Net Error: 0 : [0764] Exception in the HttpWebRequest#53036123::EndGetRequestStream - The request was aborted: Could not create SSL/TLS secure channel.

Searching for AcquireCredentialsHandle() failed with error 0X8009030D reveals that it's apparently to do with permissions in the certificate store - which I am not using.

My guess is that for some reason, AcquireCredentialsHandle tries to access a certificate store, which it fails to do because of the sandboxed environment of Azure Web Apps.

It definitely does not seem to be an IIS-specific issue, because again, it fails in a regular executable. The following code fails in a simple webjob.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace IFHM
{
    class Program
    {
        static void Main(string[] args)
        {
            Environment.CurrentDirectory = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));

            var req = (HttpWebRequest) WebRequest.Create("https://myapp.com");
            req.Method = "GET";
            req.ServerCertificateValidationCallback = (sender, cert, chain, errors) => true;
            req.ClientCertificates.Add(new X509Certificate2("client.pfx"));
            try
            {
                var resp = req.GetResponse();
                var respStr = new StreamReader(resp.GetResponseStream()).ReadToEnd();
                Console.WriteLine(respStr);
            }
            catch (WebException e)
            {
                Console.Error.WriteLine(e);
                var errRespStr = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
                Console.WriteLine(errRespStr);
            }
            
        }
    }
}
c#
azure-web-app-service
asked on Stack Overflow Feb 2, 2018 by makhdumi • edited Oct 17, 2020 by makhdumi

1 Answer

4

It seems that you need to upload the .pfx file to the Azure WebApp and first make it accessible to your application code. You do this with the WEBSITE_LOAD_CERTIFICATES app setting.

You could get the detail steps and demo code from azure official document.

answered on Stack Overflow Feb 2, 2018 by Tom Sun - MSFT

User contributions licensed under CC BY-SA 3.0