Search code examples
asp.net-coresslssl-certificateowin

ssl.LoadClientCertAsync and ssl.ClientCertificateErrors in ASP.NET Core


I have to rewrite middleware in ASP.NET Core and this middleware makes use of some OWIN keys. Among them ssl.LoadClientCertAsync and ssl.ClientCertificateErrors. You can see similar middleware in this article. The essential part is this:

var task = (context.Environment["ssl.LoadClientCertAsync"] asFunc < Task > );  
awaitTask.Run(task); 
if (context.Environment.Keys.Contains("ssl.ClientCertificate"))
{
    var cert = context.Environment["ssl.ClientCertificate"] asX509Certificate;
    if (cert != null) context.Request.Environment.Add(SystemContants.OwinMannatechClientInfo, cert.Subject);
    else
    {
        context.Response.StatusCode = 403;
        return;
    }
}
else
{
    context.Response.StatusCode = 403;
    return;
}
// Exception certError;  
if (context.Environment.Keys.Contains("ssl.ClientCertificateErrors"))
{
    //certError = context.Environment[OwinCertError] as Exception;  
    context.Response.StatusCode = 403;
    return;
}

How can I convert it to use in ASP.NET Core? I know only that I can use context.Connection.ClientCertificate for context.Environment["ssl.ClientCertificate"].


Solution

  • We can create the CertificateAuthenticationMiddleware to implement this feature.

    using System.Security.Cryptography.X509Certificates;
    
    namespace WebApplication2
    {
        public class CertificateAuthenticationMiddleware
        {
            private readonly RequestDelegate _next;
            private readonly ILogger<CertificateAuthenticationMiddleware> _logger;
    
            public CertificateAuthenticationMiddleware(RequestDelegate next, ILogger<CertificateAuthenticationMiddleware> logger)
            {
                _next = next;
                _logger = logger;
            }
    
            public async Task InvokeAsync(HttpContext context)
            {
                try
                {
                    var clientCert = await context.Connection.GetClientCertificateAsync();
    
                    if (clientCert != null)
                    {
                        if (IsCertificateValid(clientCert))
                        {
                            context.Items["ClientCertificate"] = clientCert.Subject;
                        }
                        else
                        {
                            context.Response.StatusCode = StatusCodes.Status403Forbidden;
                            return;
                        }
                    }
                    else
                    {
                        context.Response.StatusCode = StatusCodes.Status403Forbidden;
                        return;
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error processing client certificate.");
                    context.Response.StatusCode = StatusCodes.Status403Forbidden;
                    return;
                }
    
                await _next(context);
            }
    
            private bool IsCertificateValid(X509Certificate2 certificate)
            {
                // add valid cert logic here
                return certificate.NotBefore <= DateTime.UtcNow && certificate.NotAfter >= DateTime.UtcNow;
            }
        }
    }