Pular para o conteúdo
ecdsa.com
.NET SslStream / HttpClient.NET

Mensagem de erro

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

Também aparece como

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

As flags depois dos dois-pontos vêm de X509ChainStatusFlags e podem ser combinadas (por exemplo, “UntrustedRoot, RevocationStatusUnknown”). Certificados de servidor autoassinados também geram UntrustedRoot. No Linux, o .NET usa o OpenSSL e o repositório de CAs da distribuição; no Windows e no macOS, os repositórios de certificados do sistema.

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

O que significa

O .NET montou a cadeia de certificados do servidor até uma raiz, e essa raiz não é confiável para o repositório da plataforma (ou a cadeia termina em um certificado autoassinado que não é confiável). O certificado em si pode estar correto; a máquina só não confia na autoridade por trás dele. O HttpClient informa esse erro como a exceção interna de “The SSL connection could not be established”.

Por que acontece

Como corrigir

  1. 1.

    Linux: instalar a raiz no repositório do sistema

    No Linux, o .NET lê o repositório do OpenSSL, então basta o update-ca-certificates (ou o equivalente da distribuição); em contêineres, faça isso no 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 e macOS: confiar na raiz no repositório do sistema

    Importe a raiz para LocalMachine\Root no Windows ou para o keychain System no macOS; o .NET usa esses repositórios.

    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.

    Confiar em uma raiz privada para um único cliente

    SocketsHttpHandler.SslOptions.CertificateChainPolicy com CustomRootTrust mantém a validação completa, mas a ancora na sua raiz. Uma política personalizada ativa por padrão a verificação de revogação online, então defina RevocationMode de acordo com o que sua CA publica (no nosso teste, certificados privados sem CRL/OCSP falharam com RevocationStatusUnknown até que NoCheck fosse definido).

    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.

    Desenvolvimento: confiar no certificado de desenvolvimento do ASP.NET Core

    O comando dotnet dev-certs https --trust instala o certificado de desenvolvimento de localhost e confia nele no Windows e no macOS (no Linux, a confiança nele depende da distribuição).

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

Erros relacionados

Ver toda a base de erros de assinatura