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
Uma CA da empresa ou privada
comumAPIs internas, SQL Server com certificado de uma CA de domínio ou serviços de laboratório usam raízes que a máquina (muitas vezes um contêiner Linux) não tem.
Um proxy com inspeção de TLS
comumConexões reassinadas encadeiam até a raiz do proxy. Máquinas Windows normalmente a recebem por política de grupo; contêineres Linux e o WSL, não.
Um certificado de servidor autoassinado
comumCertificados autoassinados (inclusive os de servidores de desenvolvimento) terminam neles mesmos e são informados como UntrustedRoot.
Falta a raiz na imagem do contêiner
ocasionalUma raiz instalada no host ou no Windows não está dentro do contêiner Linux em que o aplicativo .NET roda.
Como corrigir
- 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.
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.
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.
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
The SSL connection could not be established, see inner exception..NET HttpClientThe remote certificate is invalid because of errors in the certificate chain: P….NET SslStream / HttpClientThe remote certificate was rejected by the provided RemoteCertificateValidation….NET SslStream / HttpClientcurl: (60) SSL certificate problem: self-signed certificate in certificate chaincurl (OpenSSL backend)