Mensagem de erro
curl: (60) SSL: no alternative certificate subject name matches target hostname 'api.example.com'
Também aparece como
- curl: (60) SSL: no alternative certificate subject name matches target host name 'api.example.com'
O curl 8.x imprime “target hostname”; o curl 7.x imprimia “target host name”. O host entre aspas é o que estiver na URL. Versões muito antigas do curl (anteriores à 7.62.0) usavam o código de saída 51 para essa verificação.
curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, hostname check in lib/vtls/openssl.c
O que significa
A cadeia de certificados é confiável, mas nenhum dos nomes DNS (ou endereços IP) na extensão Subject Alternative Name do certificado corresponde ao host da URL. O curl compara o host da URL apenas com as entradas SAN; o Common Name do titular é ignorado quando há uma extensão SAN. O nome entre aspas no final é o host que o curl foi instruído a acessar.
Por que acontece
O certificado não lista este nome
comumUm certificado para example.com não cobre www.example.com nem api.example.com, a menos que cada nome esteja na lista de SANs. Novos subdomínios e novos ambientes (staging, eu.) precisam de um certificado reemitido.
A URL usa um endereço IP, localhost ou um alias interno
comumhttps://10.0.0.5, https://localhost ou o nome de um serviço do docker-compose chegam ao servidor certo, mas pedem um nome para o qual o certificado nunca foi emitido. Endereços IP só correspondem a entradas SAN do tipo IP, nunca às de DNS.
O servidor retornou o certificado de outro site
ocasionalEm IPs compartilhados, o certificado é escolhido pelo SNI. Se o nome solicitado não tem um bloco server correspondente, o servidor responde com o certificado padrão, que traz o nome de outro site.
Um curinga cobre menos do que se espera
ocasional*.example.com cobre api.example.com, mas não example.com nem v2.api.example.com: um curinga corresponde a exatamente um rótulo.
Como corrigir
- 1.
Comparar a lista de SANs com a URL
Imprima a extensão subjectAltName do certificado servido. A correção é um certificado que liste o nome ou uma URL que use um dos nomes listados.
bash # Names the served certificate actually covers echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -subject -ext subjectAltName - 2.
Reemitir o certificado com todos os nomes em uso
Solicite todos os nomes de host (e endereços IP, se os clientes se conectam por IP) como entradas SAN. Colocar o nome apenas no Common Name não funciona com nenhum cliente atual.
bash # ACME: list every name the certificate must cover sudo certbot certonly --nginx -d example.com -d www.example.com -d api.example.com # Private CA: put all names into subjectAltName (CN is ignored for matching) openssl req -new -key server.key -out server.csr -subj "/CN=api.example.com" \ -addext "subjectAltName=DNS:api.example.com,DNS:www.example.com,IP:10.0.0.5" - 3.
Manter o nome e trocar só o endereço
Quando você precisa chegar a um endereço específico (um nó do balanceador de carga, um túnel, um IP de homologação), --resolve ou --connect-to mantém o host da URL, então o SNI e a verificação do nome de host continuam usando o nome do certificado.
bash # Keep the certificate's name in the URL and steer the connection to another address curl --resolve api.example.com:443:10.0.0.5 https://api.example.com/ curl --connect-to api.example.com:443:lb-internal.example.net:443 https://api.example.com/ - 4.
Donos do servidor: verificar o roteamento por SNI
Se o certificado muda entre requisições com e sem SNI, adicione um bloco server (ou uma regra de ingress) para o nome e garanta que os clientes não recebam o certificado padrão para nomes de host reais.
bash # Compare what the server returns with and without SNI openssl s_client -connect 10.0.0.5:443 -servername api.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject openssl s_client -connect 10.0.0.5:443 -noservername </dev/null 2>/dev/null | openssl x509 -noout -subject
Erros relacionados
x509: certificate is valid for example.com, not api.example.comGo crypto/x509Hostname/IP does not match certificate's altnames: Host: api.example.com. is no…Node.js tls.checkServerIdentity()[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch,…Python ssl module (OpenSSL host check)No subject alternative DNS name matching api.example.com found.Java (JSSE HostnameChecker)fatal: unable to access 'https://git.example.com/team/app.git/': SSL: certifica…git over HTTPS with libcurl-gnutls (Debian, Ubuntu)