2

How can I configure ASP.NET (Kestrel) to submit a list of acceptable distinguished CA names in SERVER HELLO of the mTLS handshake, to avoid the user to be presented with a list of client certificates in the browser of which most are not applicable?

According to RFC 2246 7.4.4. "A non-anonymous server can optionally request a certificate from the client (...) certificate_authorities: A list of the distinguished names of acceptable certificate authorities."

Lemon Sky
  • 677
  • 4
  • 10
  • Hi Have you found a solution for this? – Hans Kindberg Aug 12 '22 at 06:07
  • No, I think it's impossible in ASP.NET. I suppose what one could do is put a reverse proxy in front and operate ASP.NET without TLS. But that is not a solution as the question was worded. – Lemon Sky Aug 13 '22 at 07:24
  • Thank you for your answer. I think it "may" be possible, I am not sure at all. And it may also require net 7 as I understand the following links I found about it. I have hard to follow the issues and I have not found an example howto do it, but my "feeling" is that it should be possible. The links: https://github.com/dotnet/runtime/issues/45456, https://github.com/dotnet/runtime/issues/54219, https://github.com/dotnet/runtime/issues/55802. I will continue searching for it. – Hans Kindberg Aug 15 '22 at 08:19

1 Answers1

0

I have got this working now with NET 7 and running Kestrel on Linux. I have set up a solution where I run an application in a Docker Linux-container from Visual Studio. I have not got it working on Windows.

The solution is here: https://github.com/HansKindberg-Lab/Kestrel-mTLS-CTL-Example

NET 7 is required, at the time of writing NET 7 Preview 7.

I have started from this issue: Developers using Kestrel can configure the list of CAs per-hostname #45456, https://github.com/dotnet/runtime/issues/45456

Briefly:

appsettings.json

{
    "Kestrel": {
        "Certificates": {
            "Default": {
                "KeyPath": "Certificates/https-certificate.key",
                "Path": "Certificates/https-certificate.crt"
            }
        },
        "EndpointDefaults": {
            "ClientCertificateMode": "RequireCertificate",
        }
    }
}

Program.cs

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

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel((webHostBuilderContext, kestrelServerOptions) =>
{
    kestrelServerOptions.ConfigureHttpsDefaults(httpsConnectionAdapterOptions =>
    {
        httpsConnectionAdapterOptions.OnAuthenticate = (connectionContext, sslServerAuthenticationOptions) =>
        {
            if(!sslServerAuthenticationOptions.ClientCertificateRequired)
                return;

            sslServerAuthenticationOptions.CertificateChainPolicy = new X509ChainPolicy
            {
                TrustMode = X509ChainTrustMode.System
            };

            var certificates = new X509Certificate2Collection();
            certificates.ImportFromPemFile("Certificates/intermediate-certificate-1.crt");
            certificates.ImportFromPemFile("Certificates/intermediate-certificate-2.crt");

            var sslCertificateTrust = SslCertificateTrust.CreateForX509Collection(certificates, true);

            sslServerAuthenticationOptions.ServerCertificateContext = SslStreamCertificateContext.Create((X509Certificate2)sslServerAuthenticationOptions.ServerCertificate, null, false, sslCertificateTrust);
        };
    });
});

builder.Services.AddRazorPages();

var app = builder.Build();
app.UseRouting();
app.MapRazorPages();
app.Run();

It would be great if the code above could be accomplished by configuration. I do not know how. Now it is hard-coded.

There are more details in the github-repository.

Hans Kindberg
  • 510
  • 5
  • 10