错误信息
The remote certificate is invalid because of errors in the certificate chain: PartialChain
常与其他标志同时出现,例如“PartialChain, RevocationStatusUnknown”。HttpClient 会把它包装在外层异常“The SSL connection could not be established, see inner exception.”中。
.NET SslStream / HttpClient — X509ChainStatusFlags.PartialChain: the chain could not be built up to a root
含义
.NET 无法从服务器证书一路构建出通往任何根证书的证书链:缺少中间证书。即使根证书受信任(如复现示例中那样),叶子证书与根证书之间的缺口也会导致验证无法完成。如果证书的颁发机构信息访问(Authority Information Access)扩展中有 URL 且可以访问,.NET 能从那里下载缺失的中间证书,因此这个错误主要出现在私有 CA、网络受限的环境和容器中。
原因
服务器只发送了叶子证书
常见Kestrel、IIS 绑定或反向代理配置的证书文件或 PFX 中只有叶子证书。
无法获取中间证书
偶见私有 CA 往往没有 AIA URL,而处在防火墙之后的主机或容器又无法访问公共 CA 的 AIA URL,因此 .NET 无法自行补上缺口。
中间证书只存在于其他机器上
偶见在 Windows 上,缓存或安装在 CertificateAuthority 存储中的中间证书,会让证书链在某些机器上正常,而在新装的服务器或 Linux 容器中失败。
修复方法
- 1.
检查服务器发送的内容
如果握手中只有一张证书,且它由中间证书签发,就证实了这个问题。
bash openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:' - 2.
让服务器发送完整证书链
在我们的测试中,只通过 ServerCertificate 提供完整证书链 PEM 时,Kestrel(.NET 10)只发送了叶子证书;按示例设置 ServerCertificateChain 后,它才发送中间证书。对于 IIS,把中间证书安装到服务器的“中间证书颁发机构”存储中,Windows 就会发送它。
csharp // Kestrel sends intermediates only when they are given as ServerCertificateChain builder.WebHost.ConfigureKestrel(k => k.ConfigureHttpsDefaults(o => { o.ServerCertificate = X509Certificate2.CreateFromPemFile("fullchain.pem", "server.key"); var chain = new X509Certificate2Collection(); chain.ImportFromPemFile("fullchain.pem"); // leaf + intermediates o.ServerCertificateChain = chain; })); - 3.
找出缺失的中间证书
叶子证书的 AIA 扩展指向颁发者证书;把该证书添加到服务器配置中。
bash # The leaf names where its issuer can be downloaded (Authority Information Access) openssl x509 -in server.pem -noout -ext authorityInfoAccess