跳到主要内容
ecdsa.com
.NET SslStream / HttpClient.NET

错误信息

The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot

也可能输出为

  • System.Security.Authentication.AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot

冒号后面的标志来自 X509ChainStatusFlags,可以组合出现(例如“UntrustedRoot, RevocationStatusUnknown”)。自签名的服务器证书同样报告 UntrustedRoot。在 Linux 上,.NET 使用 OpenSSL 和发行版的 CA 存储;在 Windows 和 macOS 上,则使用系统证书存储。

.NET SslStream / HttpClient — AuthenticationException (X509ChainStatusFlags.UntrustedRoot)

含义

.NET 将服务器的证书链构建到了某个根证书,但平台的证书存储不信任该根证书(或者证书链终止于一张不受信任的自签名证书)。证书本身可能没有问题;只是这台机器不信任它背后的证书颁发机构。HttpClient 会把它报告为“The SSL connection could not be established”的内部异常。

原因

修复方法

  1. 1.

    Linux:将根证书安装到系统证书存储

    Linux 上的 .NET 读取 OpenSSL 的证书存储,因此运行 update-ca-certificates(或发行版中的等效命令)就够了;在容器中,要在 Dockerfile 里完成这一步。

    bash
    # Linux (incl. containers): .NET uses the OpenSSL system store
    sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt
    sudo update-ca-certificates
  2. 2.

    Windows 和 macOS:在系统证书存储中信任根证书

    在 Windows 上将根证书导入 LocalMachine\Root,在 macOS 上导入“系统”钥匙串;.NET 使用的就是这些存储。

    text
    # Windows (elevated PowerShell): trust the root machine-wide
    Import-Certificate -FilePath .\corp-root-ca.cer -CertStoreLocation Cert:\LocalMachine\Root
    # macOS
    sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain corp-root-ca.pem
  3. 3.

    只为一个客户端信任私有根证书

    将 SocketsHttpHandler.SslOptions.CertificateChainPolicy 与 CustomRootTrust 配合使用,可以保留完整的验证,只是以你的根证书作为信任锚。自定义策略默认启用在线吊销检查,因此要根据你的 CA 实际发布的内容设置 RevocationMode(在我们的测试中,没有 CRL/OCSP 的私有证书会因 RevocationStatusUnknown 而失败,直到设置为 NoCheck 为止)。

    csharp
    // Trust one private root for this client only; chain, dates and name are still verified.
    var root = X509CertificateLoader.LoadCertificateFromFile("corp-root-ca.pem");
    var handler = new SocketsHttpHandler();
    handler.SslOptions.CertificateChainPolicy = new X509ChainPolicy
    {
        TrustMode = X509ChainTrustMode.CustomRootTrust,
        // a custom policy defaults to online revocation checks; use NoCheck only if the CA publishes no CRL/OCSP
        RevocationMode = X509RevocationMode.NoCheck,
    };
    handler.SslOptions.CertificateChainPolicy.CustomTrustStore.Add(root);
    using var client = new HttpClient(handler);
  4. 4.

    开发环境:信任 ASP.NET Core 开发证书

    在 Windows 和 macOS 上,dotnet dev-certs https --trust 会安装并信任 localhost 开发证书(在 Linux 上,如何信任它取决于发行版)。

    bash
    # ASP.NET Core development certificate on localhost
    dotnet dev-certs https --trust

相关错误

浏览完整的签名错误库