Mensaje de error
curl: (60) SSL: no alternative certificate subject name matches target hostname 'api.example.com'
También se muestra como
- curl: (60) SSL: no alternative certificate subject name matches target host name 'api.example.com'
curl 8.x imprime «target hostname»; curl 7.x imprimía «target host name». El host entre comillas es el que contenga la URL. Las versiones muy antiguas de curl (anteriores a 7.62.0) usaban el código de salida 51 para esta comprobación.
curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, hostname check in lib/vtls/openssl.c
Qué significa
La cadena de certificados es de confianza, pero ninguno de los nombres DNS (ni de las direcciones IP) de la extensión de nombre alternativo del sujeto (SAN) del certificado coincide con el host de la URL. curl solo compara el host de la URL con las entradas SAN; el nombre común del sujeto se ignora cuando existe una extensión SAN. El nombre entre comillas del final es el host al que se pidió a curl que se conectara.
Por qué ocurre
El certificado no incluye este nombre
frecuenteUn certificado para example.com no cubre www.example.com ni api.example.com a menos que cada nombre figure en la lista SAN. Los subdominios y entornos nuevos (staging, eu.) necesitan un certificado emitido de nuevo.
La URL usa una dirección IP, localhost o un alias interno
frecuentehttps://10.0.0.5, https://localhost o el nombre de un servicio de docker-compose llegan al servidor correcto, pero piden un nombre para el que nunca se emitió el certificado. Las direcciones IP solo coinciden con entradas SAN de tipo IP, nunca con las de tipo DNS.
El servidor devolvió el certificado de otro sitio
ocasionalEn IP compartidas, el certificado se elige por SNI. Si el nombre solicitado no tiene un bloque de servidor que le corresponda, el servidor responde con su certificado predeterminado, que nombra a otro sitio.
Se espera que un comodín cubra más de lo que cubre
ocasional*.example.com cubre api.example.com, pero no example.com ni v2.api.example.com: un comodín representa exactamente una etiqueta.
Cómo solucionarlo
- 1.
Comparar la lista SAN con la URL
Imprime la extensión subjectAltName del certificado servido. La solución es un certificado que incluya el nombre o una URL que use uno de los nombres incluidos.
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.
Volver a emitir el certificado con todos los nombres en uso
Solicita todos los nombres de host (y las direcciones IP, si los clientes se conectan por IP) como entradas SAN. Poner el nombre solo en el nombre común no funciona con ningún cliente actual.
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.
Mantener el nombre y cambiar solo la dirección
Si tienes que llegar a una dirección concreta (un nodo del balanceador de carga, un túnel, una IP de preproducción), --resolve o --connect-to mantienen el host de la URL, de modo que el SNI y la comprobación del nombre de host siguen usando el nombre del 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.
Propietarios del servidor: comprobar el enrutamiento por SNI
Si el certificado cambia entre solicitudes con y sin SNI, añade un bloque de servidor (o una regla de ingress) para el nombre y asegúrate de que los clientes no reciban el certificado predeterminado para los nombres de host reales.
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
Errores 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)