Mensagem de erro
The remote certificate was rejected by the provided RemoteCertificateValidationCallback.
O texto é o mesmo no .NET Core e no .NET 5–10; o HttpClient o encapsula em “The SSL connection could not be established, see inner exception.” O valor de SslPolicyErrors passado ao callback mostra se o próprio .NET também encontrou algum problema.
.NET SslStream / HttpClient — a custom validation callback returned false
O que significa
A aplicação instalou o próprio callback de validação de certificado (ServerCertificateCustomValidationCallback ou RemoteCertificateValidationCallback), e esse callback retornou false. As verificações internas do .NET podem ter passado; foi o seu código que decidiu rejeitar o certificado. É típico com fixação de certificado ou de chave depois que o certificado do servidor foi renovado ou trocado.
Por que acontece
O certificado fixado foi substituído
comumFixar a impressão digital de um certificado quebra a cada renovação (hoje, a cada poucos meses com CAs públicas); o novo certificado tem um novo hash.
A lógica do próprio callback rejeita certificados válidos
comumVerificações de um nome de emissor exato, de um titular ou de uma lista de impressões digitais que não correspondem mais, ou condições que ignoram o argumento errors.
O callback rejeita corretamente um problema real
ocasionalUm callback que retorna errors == SslPolicyErrors.None rejeita certificados não confiáveis, expirados ou com nome divergente; nesse caso, a causa é o próprio certificado.
Como corrigir
- 1.
Registrar no log o que o callback vê
Registre no callback SslPolicyErrors, titular, impressão digital SHA-256 e data de expiração; depois, atualize a lista de pins ou corrija o certificado.
csharp ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => { var thumbprint = cert!.GetCertHashString(HashAlgorithmName.SHA256); logger.LogWarning("TLS {Host}: errors={Errors} subject={Subject} sha256={Thumb} notAfter={NotAfter:u}", request.RequestUri?.Host, errors, cert.Subject, thumbprint, cert.NotAfter); return errors == SslPolicyErrors.None && pinnedThumbprints.Contains(thumbprint); }, - 2.
Fixar a chave pública e manter um pin de reserva
Pins SPKI continuam válidos em renovações que reutilizam a chave; sempre fixe pelo menos uma chave de reserva, para que uma rotação não deixe os clientes bloqueados.
bash # Pin the public key (SPKI) rather than the certificate: it survives renewals with the same key openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null \ | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64