question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Client Certificate in ASP.NET Core 3.1 web app always null

See original GitHub issue

Describe the bug

I am working on prototyping an ASP.NET Core 3.1 web application using Kestrel, hosted in Azure Kubernetes Service. One of the requirements is Client Certificate authentication. I followed the guidelines provided in this wiki, however, client certificate on server side is always retrieved as null. This usage is new to me and I apologize for any obvious missing elements which I am hoping to figure out and learn.

To Reproduce

Following is what I have in my local setup:-

Created and trusted local self signed chained client certificates for experimentation as per Create Certificates in Powershell page.

Added the following in startup.cs:-

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<HttpsConnectionAdapterOptions>(options =>
    {
        options.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
        options.CheckCertificateRevocation = false;
        options.ClientCertificateValidation = (certificate2, chain, policyErrors) =>
        {
            // accept any cert (testing purposes only)
            return true;
        };
    });
    ...
    services.AddAuthentication(
        CertificateAuthenticationDefaults.AuthenticationScheme)
        .AddCertificate(options =>
        {
            options.AllowedCertificateTypes = CertificateTypes.All;
        });

    ...
}
...

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseAuthentication();
    ...
}

Added the following in Program.cs:-

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        ...
        .ConfigureKestrel(serverOptions =>
        {
            serverOptions.ConfigureHttpsDefaults(listenOptions =>
            {
                listenOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;

                // Enforcing TLS 1.2 and disabling previous TLS versions.
                listenOptions.SslProtocols = SslProtocols.Tls12;
                // Configuring cipher suite ordering
                ...
            });
        })

I am trying to retrieve the certificate in the middleware with following. The clientCertificate object retrieved is always null:-

using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Http;

public class AuthorizationMiddleware
{
    ...

    public async Task InvokeAsync(HttpContext httpContext)
    {
        ...

        X509Certificate2 clientCertificate = await httpContext.Connection.GetClientCertificateAsync();
        //OR
        clientCertificate = httpContext.Connection.ClientCertificate;
        ...
    }
    ...
}

Client test code to make the HTTPS request with client cert:-

try
    {
        var cert = new X509Certificate2("E:\\certs\\clientcert.pfx");
        var handler = new HttpClientHandler();
        handler.ClientCertificates.Add(cert);
        var client = new HttpClient(handler);

        var request = new HttpRequestMessage()
        {
            RequestUri = new Uri("https://localhost:44322/apipattern"),
            Method = HttpMethod.Get,
        };
        Task<HttpResponseMessage> responseTask = client.SendAsync(request);
        Task.WaitAll(responseTask);
        HttpResponseMessage response = responseTask.Result;
        if (response.IsSuccessStatusCode)
        {
            Task<string> responseContentTask = response.Content.ReadAsStringAsync();
            string responseContent = responseContentTask.Result;
            Console.WriteLine(responseContent);
         }
   }
   catch (Exception e)
   {
       Console.WriteLine(e.Message);
   }

Further technical details

  • ASP.NET Core version - 3.1
  • Include the output of dotnet --info
.NET Core SDK (reflecting any global.json):
 Version:   3.1.100
 Commit:    cd82f021f4

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  18.04
 OS Platform: Linux
 RID:         ubuntu.18.04-x64
 Base Path:   /home/mawagle/dotnetcore/sdk/3.1.100/

Host (useful for support):
  Version: 3.1.0
  Commit:  65f04fb6db

.NET Core SDKs installed:
  3.1.100 [/home/mawagle/dotnetcore/sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.App 3.1.0 [/home/mawagle/dotnetcore/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.0 [/home/mawagle/dotnetcore/shared/Microsoft.NETCore.App]

To install additional .NET Core runtimes or SDKs:
  https://aka.ms/dotnet-download
  • The IDE (VS / VS Code/ VS4Mac) you’re running on, and it’s version - VS 2019

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
shirhatticommented, Dec 18, 2020

@mawagle Sounds like this has been answered via email by @BrennanConroy. Feel free to re-open if your issue persists

0reactions
mawaglecommented, Dec 19, 2020

Thanks a ton @BrennanConroy for the offline help. Adding the following config into the IISExpress applicationhost.config did the trick:-

<security>
   <access sslFlags="Ssl, SslNegotiateCert” />
  …

Also I could get it working in Kestrel with the following config in Program.cs:-

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                 …
                .ConfigureKestrel(serverOptions =>
                {
                    serverOptions.ConfigureHttpsDefaults(listenOptions =>
                    {
                        // Allowing client certificates in Kestrel.
                        listenOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
                        listenOptions.AllowAnyClientCertificate();
                        listenOptions.ClientCertificateValidation = (cert, chain, policyErrors) =>
                        {
                            return true;
                        };

                        // Enforcing TLS 1.2 and disabling previous TLS versions.
                        listenOptions.SslProtocols = SslProtocols.Tls12;
                        …
                    }
                }  
Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - Request.HttpContext.Connection.ClientCertificate is ...
I have an ASP.Net core website deployed on Azure app service for Linux. In the controller, I am trying to get the client...
Read more >
Configure certificate authentication in ASP.NET Core
If the app is using self-signed certificates, this option needs to ... can return a null certificate if the client declines to provide...
Read more >
Request.HttpContext.Connection.ClientCertificate is always null
Coding example for the question Request.HttpContext.Connection.ClientCertificate is always null.
Read more >
Enforce HTTPS in ASP.NET Core
Learn how to require HTTPS/TLS in an ASP.NET Core web app.
Read more >
Certificate Authentication in ASP.NET Core 3.1
In this example, a shared self signed certificate is used to authenticate one application calling an API on a second ASP.NET Core application....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found