You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何使用客户端证书时需在Azure证书存储中添加服务器证书?

问题描述

我有一个使用HttpClient连接远程服务器的C#应用,服务器要求客户端证书认证。我已将公钥证书发送给服务器方,请求时加载了包含私钥的.pfx证书,但收到错误:

The credentials supplied to the package were not recognized

将服务器方的公钥证书添加到Azure证书存储的“公钥证书”区域后,问题解决。

我已通过设置ServerCertificateCustomValidationCallback忽略服务器端验证(因通过IP而非URL连接),配置代码如下:

var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback =
    (httpRequestMessage, cert, cetChain, policyErrors) =>
    {
        return true;
    };
handler.SslProtocols = SslProtocols.Tls12;
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
var certificate = new X509Certificate2(certificateData, password);
handler.ClientCertificates.Add(certificate);

using (var client = new HttpClient(handler))
{
    ...
}

完整错误堆栈从外到内为:

System.AggregateException: One or more errors occurred. (The SSL connection could not be established, see inner exception.)
System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
System.ComponentModel.Win32Exception (0x8009030D): The credentials supplied to the package were not recognized

疑问:为何添加服务器证书能解决问题?我遗漏了什么?


问题分析与解答

1. 错误的本质:双向TLS的系统层信任检查未被跳过

你设置的ServerCertificateCustomValidationCallback仅跳过了应用层的服务器证书验证,但.NET底层依赖的Windows Schannel安全包,在双向认证场景下仍会执行系统层的服务器证书信任链检查。

当服务器返回自身证书时,Schannel会尝试构建信任路径:如果服务器证书不在本地信任存储(如Azure证书存储的公钥区域),且无法追溯到受信任的根CA,Schannel会判定服务器身份不可信,直接终止TLS握手流程——此时客户端证书还没来得及提交给服务器,最终抛出的0x8009030D错误看似指向客户端凭据,实则是服务器证书信任问题引发的连锁反应。

2. 你遗漏的核心点:双向认证的握手顺序与隐式检查

双向TLS握手的流程是:

  1. 客户端验证服务器证书(应用层回调跳过,但系统层Schannel检查仍生效)
  2. 服务器验证客户端证书

如果第一步Schannel认为服务器证书不可信,会直接中断握手,不会进入第二步的客户端证书验证环节,最终错误信息会误导你以为是客户端证书的问题。

3. 添加服务器证书到存储的作用

将服务器公钥证书添加到Azure证书存储的“公钥证书”区域,相当于告知Schannel:这个服务器的证书是可信的,无需追溯到根CA。Schannel通过信任检查后,才会继续完成握手流程,包括提交你的客户端证书,最终建立连接。

4. 无需修改证书存储的替代方案

如果不想依赖系统证书存储,可以在回调中手动验证服务器证书的合法性,同时彻底跳过系统层的信任链检查,示例代码如下:

handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) =>
{
    // 验证服务器证书的指纹是否符合预期(替换为实际的服务器证书指纹)
    if (cert.Thumbprint.Equals("YOUR_SERVER_CERT_THUMBPRINT", StringComparison.OrdinalIgnoreCase))
    {
        // 手动构建信任链,允许未知CA(跳过根CA验证)
        var chainPolicy = new X509ChainPolicy
        {
            VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority
        };
        chain.ChainPolicy = chainPolicy;
        return chain.Build(cert);
    }
    return false;
};

内容的提问来源于stack exchange,提问作者Simon Parker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 05:26:03