1

I'm trying to implement a client certification validation on a self-hosted web server. My first attempt was to check if the request contains a client certificate but I'm stuck here because Request.GetClientCertificate() always returns null.

This is my auth attribute class.

public class CustomAuthAttirbute : AuthorizationFilterAttribute
{
    public override void OnAuthorization(HttpActionContext actionContext)
    {
        X509Certificate2 cert = actionContext.Request.GetClientCertificate();
        if (cert == null)
        {
            actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
            {
                ReasonPhrase = "Client Certificate Required"
            };
        }
        else
        {
            // Validate the certificate
        }

        base.OnAuthorization(actionContext);
    }
}

I'm using Postman as REST client, with Postman I send client certitificate as documentated here Working with certificates. In the Postman console I can see that the certificate was sent successfully.

I created another server with nodejs following this tutorial to be sure that my certificates are ok and the Postman client are ok too. This server works fine and I can successfully authorize the Postman client.

So, I think the problem is related to C# self-hosted server only.

Unfortunately I can't use IIS or other web servers, I can only use a self-host setup like this or with OWIN Katana.

This is my current entry point and configuration:

class Program
{
    static void Main(string[] args)
    {
        var config = new MyHttpsSelfHostConfiguration("https://localhost:5005");

        config.Routes.MapHttpRoute(
            "API Default", "api/{controller}/{id}",
            new { id = RouteParameter.Optional });

        using (HttpSelfHostServer server = new HttpSelfHostServer(config))
        {
            server.OpenAsync().Wait();
            Console.WriteLine("Press Enter to quit.");
            Console.ReadLine();
        }
    }

    class MyHttpsSelfHostConfiguration : HttpSelfHostConfiguration
    {
        public MyHttpsSelfHostConfiguration(string baseAddress) : base(baseAddress) { }
        public MyHttpsSelfHostConfiguration(Uri baseAddress) : base(baseAddress) { }
        protected override BindingParameterCollection OnConfigureBinding(HttpBinding httpBinding)
        {
            httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
            httpBinding.Security.Mode = HttpBindingSecurityMode.Transport;
            return base.OnConfigureBinding(httpBinding);
        }
    }
}

These are some additional steps I took:

  • Bind the certificate to HTTPS. netsh http add sslcert ipport=0.0.0.0:5005 appid={ca7f9e45-f183-414f-8baf-b02d88310766} certhash=bd759f39dc966e0ef131cafde4ab273e9c2d5134 clientcertnegotiation=enable
  • Add a reservation entry for my URL. netsh http add urlacl url=https://localhost:5005/ user=Everyone
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
blow
  • 12,811
  • 24
  • 75
  • 112
  • TLS the certificate is never transmitted. The client sends a TLS message indicating the version of TLS that is being used. The server responds with a certificate block the contains the names of possible certificate. The client then looks up the certificate names in the stores to find matching certificate. Only TLS 1.2 or TLS 1.3 are valid. The others are obsolete and are disabled on server. You can use a sniffer like wireshark or fiddler to check version of TLS and get certificate names. TLS is sent before the request is sent and if TLS fails you will never see the request. – jdweng Oct 25 '22 at 09:45
  • @blow - Did you ever get this issue resolved? Encountering a similar issue. – Landon Crabtree Jul 16 '23 at 17:34

0 Answers0