Saltar al contenido
ecdsa.com
.NET SslStream / HttpClient.NET

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

Cómo solucionarlo

  1. 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. 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. 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. 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

Explorar toda la base de datos de errores de firma