Mensaje de error
The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot
También se muestra como
- System.Security.Authentication.AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot
Los indicadores que siguen a los dos puntos proceden de X509ChainStatusFlags y pueden combinarse (por ejemplo, «UntrustedRoot, RevocationStatusUnknown»). Los certificados de servidor autofirmados también dan UntrustedRoot. En Linux, .NET usa OpenSSL y el almacén de CA de la distribución; en Windows y macOS, los almacenes de certificados del sistema.
.NET SslStream / HttpClient — AuthenticationException (X509ChainStatusFlags.UntrustedRoot)
Qué significa
.NET construyó la cadena de certificados del servidor hasta una raíz, y esa raíz no es de confianza para el almacén de la plataforma (o la cadena termina en un certificado autofirmado que no es de confianza). Puede que el certificado en sí sea correcto; simplemente, el equipo no confía en la autoridad que lo respalda. HttpClient lo notifica como excepción interna de «The SSL connection could not be established».
Por qué ocurre
Una CA corporativa o privada
frecuenteLas API internas, SQL Server con un certificado de la CA del dominio o los servicios de un laboratorio usan raíces que el equipo (a menudo un contenedor Linux) no tiene.
Un proxy que inspecciona TLS
frecuenteLas conexiones que el proxy vuelve a firmar se encadenan a la raíz del proxy. Los equipos Windows suelen tenerla gracias a la política de grupo; los contenedores Linux y WSL, no.
Un certificado de servidor autofirmado
frecuenteLos certificados autofirmados (incluidos los de los servidores de desarrollo) terminan en sí mismos y se notifican como UntrustedRoot.
A la imagen del contenedor le falta la raíz
ocasionalUna raíz instalada en el host o en Windows no está dentro del contenedor Linux en el que se ejecuta la aplicación .NET.
Cómo solucionarlo
- 1.
Linux: instalar la raíz en el almacén del sistema
.NET en Linux lee el almacén de OpenSSL, así que basta con update-ca-certificates (o el equivalente de la distribución); en contenedores, hazlo en el 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 y macOS: confiar en la raíz en el almacén del sistema
Importa la raíz en LocalMachine\Root en Windows o en el llavero Sistema en macOS; .NET usa esos almacenes.
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 en una raíz privada para un solo cliente
SocketsHttpHandler.SslOptions.CertificateChainPolicy con CustomRootTrust mantiene la validación completa, pero la ancla en tu raíz. Una política personalizada activa por defecto la comprobación de revocación en línea, así que establece RevocationMode de acuerdo con lo que publica tu CA (en nuestra prueba, los certificados privados sin CRL/OCSP fallaban con RevocationStatusUnknown hasta que se estableció 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.
Desarrollo: confiar en el certificado de desarrollo de ASP.NET Core
dotnet dev-certs https --trust instala el certificado de desarrollo de localhost y lo marca como de confianza en Windows y macOS (en Linux, cómo confiar en él depende de la distribución).
bash # ASP.NET Core development certificate on localhost dotnet dev-certs https --trust
Errores 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)