Перейти к содержимому
ecdsa.com
.NET SslStream / HttpClient.NET

Сообщение об ошибке

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

Также выводится как

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

Флаги после двоеточия берутся из X509ChainStatusFlags и могут сочетаться (например, «UntrustedRoot, RevocationStatusUnknown»). Самоподписанные сертификаты сервера тоже дают UntrustedRoot. В Linux .NET использует OpenSSL и хранилище сертификатов CA дистрибутива, в Windows и macOS — системные хранилища сертификатов.

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

Что это означает

.NET построил цепочку сертификатов сервера до корневого сертификата, но хранилище платформы этому корневому сертификату не доверяет (или цепочка заканчивается недоверенным самоподписанным сертификатом). Сам сертификат может быть в порядке: машина просто не доверяет центру сертификации, который за ним стоит. HttpClient сообщает об этой ошибке как о внутреннем исключении для «The SSL connection could not be established».

Почему это происходит

Как исправить

  1. 1.

    Linux: установите корневой сертификат в системное хранилище

    В Linux .NET читает хранилище OpenSSL, поэтому достаточно установить корневой сертификат через update-ca-certificates (или аналогичную команду дистрибутива); в контейнерах делайте это в 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 и macOS: сделайте корневой сертификат доверенным в системном хранилище

    Импортируйте корневой сертификат в LocalMachine\Root в Windows или в системную связку ключей (System) в macOS; .NET использует эти хранилища.

    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.

    Доверяйте частному корневому сертификату в одном клиенте

    SocketsHttpHandler.SslOptions.CertificateChainPolicy с CustomRootTrust сохраняет полную проверку, но использует в качестве якоря доверия ваш корневой сертификат. Пользовательская политика по умолчанию включает онлайн-проверку отзыва, поэтому задайте RevocationMode в соответствии с тем, что публикует ваш CA (в нашей проверке частные сертификаты без CRL/OCSP давали ошибку RevocationStatusUnknown, пока не задали 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.

    Для разработки: добавьте сертификат разработки ASP.NET Core в доверенные

    dotnet dev-certs https --trust устанавливает сертификат разработки для localhost и делает его доверенным в Windows и macOS (в Linux способ сделать его доверенным зависит от дистрибутива).

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

Связанные ошибки

Открыть всю базу ошибок подписей