访问 Azure Key Vaults 时出现客户端认证异常

Client Certification exception when accessing Azure Key Vaults

这个让我忙了一天。

我正在尝试使用我的 .net core 2.2 应用程序中的 Azure Key Vaults 服务,并使用证书作为安全措施。

我在启动应用程序时在同一代码中安装证书,使用 base64 编码字符串作为输入参数。

StoreLocation.LocalMachine(和 运行宁 VS 作为管理员)中安装时,应用程序工作正常并且检索到机密。

使用 StoreLocation.CurrentUser 时,应用程序会在尝试从保管库中检索机密时抛出 NullReferenceException

   at Microsoft.IdentityModel.Clients.ActiveDirectory.CryptographyHelper.SignWithCertificate(String message, X509Certificate2 certificate)
   at Microsoft.IdentityModel.Clients.ActiveDirectory.JsonWebToken.Sign(IClientAssertionCertificate credential)
   at Microsoft.IdentityModel.Clients.ActiveDirectory.ClientKey.AddToParameters(IDictionary`2 parameters)
   at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase.<SendTokenRequestAsync>d__64.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase.<RunAsync>d__55.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext
....

我看到人们在 2017 年迁移到 .NET 4.7 时提到了同样的异常 (Here and Here)。

我尝试 运行 使用 Microsoft.IdentityModel.Clients.ActiveDirectory 软件包的各种较新版本的应用程序,但没有成功。从 3.14 到 3.19,它抛出相同的异常。从 4.3 开始,它缺少包不再提供的 .Platforms dll。

最后,我从 Extensions repository 获取、编译和 运行 示例应用程序(它也使用 CurrentUser 位置,我有同样的异常。

我还没有尝试在 .NET Core 3.0 上 运行 它。但我认为最初的写作有问题。

我 运行 没有更多的资源来调查,所以我正在联系社区 :)

下面是我用来 write/read 证书的简单示例应用程序代码。

dotnet .\Certificates.dll -- -c {cert-base64-encoded-string} -p {cert-password}
public static Main(string[] args)
{
    //// Using CommandLineParser
    var options = Parser.Default.ParseArguments<Options>(args)
        .WithParsed(o =>
        {
            if (!string.IsNullOrEmpty(o.Certificate))
            {
                o.CertPassword = o.CertPassword ?? throw new ArgumentNullException("No certificate password provided.");

                var rawData = Convert.FromBase64String(o.Certificate);

                //// install certificate
                using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser, OpenFlags.ReadWrite))
                {
                    var cert = new X509Certificate2(rawData, o.CertPassword, X509KeyStorageFlags.PersistKeySet);
                    ThumbPrint = cert.Thumbprint;
                    store.Add(cert);
                }
            }
        });

    CreateWebHostBuilder(args).Build().Run();
}

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration(configHost =>
        {
            using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
            {
                store.Open(OpenFlags.ReadOnly);

                var certs = store.Certificates.Find(X509FindType.FindByThumbprint, ThumbPrint, false);

                configHost.AddAzureKeyVault(_vault, _key, certs.OfType<X509Certificate2>().Single());

            }
        })
        .UseStartup<Startup>();

当我为这个问题的示例编写 GitHub readme 文件时,我偶然发现了解决方案。

说这是人为错误让我很痛苦...

我为证书传递了错误的 Base64String。可能是我之前创建的。

在命令中传递正确生成的字符串后,代码开始运行。你可以在我的 GitHub

上看到它

简而言之,它失败了,因为我在客户端上使用的证书与服务器上的证书不一致。尽管例外情况可能更清楚。