简体   繁体   中英

How to fix RevocationStatusUnknown in asp.net core 3.1 with self-signed client certificate

  1. I try to implement an asp.net core WebAPI application secured with client certificates. I've used sample code from the Internet from docs.microsoft and other sites. In order to test what I'd built, I've generated CA certificate, server certificate and client certificate. Both server and client certificates were created using that one CA. I also added CA certificate to TrustedRoot storage.
    After running the application I receive 403 error Unathorized for each call to that endpoint with the client certificate (tried from Chrome and Firefox). Along with 403 I can see in console a message " Certificate validation failed, subject was ... " and " RevocationStatusUnknown The revocation function was unable to check revocation for the certificate. "
  2. I don't understand where this error comes from so I cannot trace it. I tried searching asp.net core sources for parts of the phrase or debug with using source code symbols from microsoft pdb servers but I haven't understand where the error comes from. I suspect it is because I use self-signed certificate but then the error message is misleading.
  3. Here's my code: Program.cs
using System.IO;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using Microsoft.Extensions.Hosting;

namespace AuthEndpoint
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder
                    .UseStartup<Startup>()
                    .ConfigureKestrel(options =>
                    {
                        options.ConfigureHttpsDefaults(opt =>
                        {
                            opt.ServerCertificate = new X509Certificate2(Path.Combine("c:\\server\\server.pfx"),  "Password");
                            opt.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
                            opt.CheckCertificateRevocation = false;
                            opt.AllowAnyClientCertificate();
                        });
                    });
            });
    }
}

Startup.cs

using System;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Certificate;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace AuthEndpoint
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services
                .AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)

                .AddCertificate(options =>
                {
                    options.AllowedCertificateTypes = CertificateTypes.All;
                    options.Events = new CertificateAuthenticationEvents
                    {
                        OnCertificateValidated = context =>
                        {
                            Console.WriteLine(context.ClientCertificate.IssuerName);
                            context.Success();
                            return Task.CompletedTask;
                        },
                        OnAuthenticationFailed = context =>
                        {
                            Console.WriteLine(context.Exception);
                            return Task.CompletedTask;

                        }
                    };
                })
                ;
            services.AddCertificateForwarding(options =>
                {
                    options.CertificateHeader = "X-ARR-ClientCert";
                    options.HeaderConverter = (headerValue) =>
                    {
                        X509Certificate2 clientCertificate = null;
                        if (!string.IsNullOrWhiteSpace(headerValue))
                        {
                            byte[] bytes = Encoding.UTF8.GetBytes(headerValue);
                            clientCertificate = new X509Certificate2(bytes);
                        }
                        return clientCertificate;
                    };
                });
            services.AddAuthorization();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseCertificateForwarding();
            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

And a WeatherForecastController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace AuthEndpoint.Controllers
{
    [ApiController]
    [Route("[controller]")]
    [Authorize]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}

So, I'd like to get an answer on how can I make asp.net core use my certificate or if there's no way of using self-signed ones

在 AddCertificate 选项中需要设置下一行:options.RevocationMode = X509RevocationMode.NoCheck;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM