Zum Inhalt springen
ecdsa.com
.NET SslStream / HttpClient.NET

Fehlermeldung

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

Auch ausgegeben als

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

Die Flags nach dem Doppelpunkt stammen aus X509ChainStatusFlags und können kombiniert auftreten (zum Beispiel „UntrustedRoot, RevocationStatusUnknown“). Auch selbstsignierte Serverzertifikate melden UntrustedRoot. Unter Linux verwendet .NET OpenSSL und den CA-Speicher der Distribution, unter Windows und macOS die Zertifikatsspeicher des Systems.

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

Was der Fehler bedeutet

.NET hat die Zertifikatskette des Servers bis zu einem Root-Zertifikat aufgebaut, und diesem Root-Zertifikat vertraut der Zertifikatsspeicher der Plattform nicht (oder die Kette endet in einem selbstsignierten Zertifikat, dem nicht vertraut wird). Das Zertifikat selbst kann in Ordnung sein; der Rechner vertraut nur der Zertifizierungsstelle dahinter nicht. HttpClient meldet den Fehler als innere Exception von „The SSL connection could not be established“.

Warum der Fehler auftritt

So behebst du den Fehler

  1. 1.

    Linux: Root-Zertifikat im Zertifikatsspeicher des Systems installieren

    .NET unter Linux liest den OpenSSL-Speicher, daher genügt update-ca-certificates (oder das Gegenstück der Distribution); in Containern erledigst du das im 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 und macOS: dem Root-Zertifikat im Zertifikatsspeicher des Systems vertrauen

    Importiere das Root-Zertifikat unter Windows nach LocalMachine\Root oder unter macOS in den Schlüsselbund „System“; .NET verwendet diese Speicher.

    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.

    Einem privaten Root-Zertifikat für einen einzelnen Client vertrauen

    SocketsHttpHandler.SslOptions.CertificateChainPolicy mit CustomRootTrust behält die vollständige Validierung bei, verankert sie aber in deinem Root-Zertifikat. Eine eigene Richtlinie aktiviert standardmäßig die Online-Prüfung auf Widerruf, setze RevocationMode daher passend zu dem, was deine CA veröffentlicht (in unserem Test scheiterten private Zertifikate ohne CRL/OCSP mit RevocationStatusUnknown, bis NoCheck gesetzt war).

    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.

    Entwicklung: dem Entwicklungszertifikat von ASP.NET Core vertrauen

    dotnet dev-certs https --trust installiert das Entwicklungszertifikat für localhost unter Windows und macOS und vertraut ihm (unter Linux hängt das Vertrauen von der Distribution ab).

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

Verwandte Fehler

Gesamte Signaturfehler-Datenbank durchsuchen