Сообщение об ошибке
The remote certificate is invalid because of errors in the certificate chain: NotTimeValid
HttpClient сообщает о ней как о внутреннем исключении для «The SSL connection could not be established, see inner exception.». Несколько флагов могут быть перечислены вместе, например «NotTimeValid, UntrustedRoot».
.NET SslStream / HttpClient — X509ChainStatusFlags.NotTimeValid
Что это означает
Один из сертификатов цепочки, которую построил .NET, по часам этой машины находится вне срока действия: он просрочен или ещё не действителен. NotTimeValid не говорит, какой именно сертификат; это показывают элементы цепочки в обратном вызове проверки. С корневым сертификатом и именем всё в порядке, иначе рядом появились бы и другие флаги.
Почему это происходит
Истёк срок действия сертификата сервера (или промежуточного)
частоПродление не состоялось или продлённый сертификат не привязан (привязка IIS, конфигурация Kestrel, ссылка на Azure/Key Vault, балансировщик нагрузки).
Совсем новый сертификат на клиенте с отстающими часами
иногдаСертификаты, действительные «с текущего момента», не проходят проверку на машинах, где часы отстают на несколько минут.
Часы клиента идут неверно
иногдаВиртуальные машины, восстановленные из снимков, устройства без NTP или контейнеры на хосте с уплывающими часами.
Как исправить
- 1.
Проверьте даты в отдаваемом сертификате
Сравните notBefore и notAfter с текущим временем в UTC.
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -subject -startdate -enddate - 2.
Записывайте в лог элемент цепочки, вызвавший ошибку
Обратный вызов проверки, который записывает ChainElementStatus в лог и возвращает решение по умолчанию, показывает, какой сертификат вне срока действия, и не ослабляет проверку.
csharp // Log which certificate failed and why, without accepting it var handler = new HttpClientHandler { ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => { foreach (var element in chain!.ChainElements) foreach (var status in element.ChainElementStatus) Console.WriteLine($"{element.Certificate.Subject}: {status.Status} {element.Certificate.NotAfter:u}"); return errors == System.Net.Security.SslPolicyErrors.None; }, }; - 3.
Продлите и заново привяжите
Продлите сертификат и обновите все привязки, через которые он отдаётся.
bash sudo certbot renew && sudo systemctl reload nginx # or renew in your CA / key vault and redeploy