Saltar al contenido
ecdsa.com
curl (OpenSSL backend)curl

Mensaje de error

curl: (60) SSL certificate problem: self-signed certificate

También se muestra como

  • curl: (60) SSL certificate problem: self signed certificate
  • curl: (60) SSL certificate OpenSSL verify result: self-signed certificate (18)

OpenSSL 3.0 y posteriores imprimen «self-signed certificate»; OpenSSL 1.1.1 imprime «self signed certificate». Las versiones más recientes de curl (8.22.0 en nuestra prueba) lo formulan como «SSL certificate OpenSSL verify result: self-signed certificate (18)». No lo confundas con «self-signed certificate in certificate chain», donde existe una cadena de CA que termina en una raíz que no es de confianza.

curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT (18)

Qué significa

El servidor presentó un único certificado firmado con su propia clave (el emisor es igual al sujeto), y curl no tiene ese certificado exacto en su almacén de confianza. No hay ninguna CA detrás que curl pueda buscar, así que la verificación se detiene en la profundidad 0. Es normal en servidores de desarrollo y dispositivos dedicados, y nunca se soluciona instalando un intermedio.

Por qué ocurre

Cómo solucionarlo

  1. 1.

    Confiar exactamente en este certificado, después de comprobarlo

    Para un único endpoint interno, guarda el certificado, confirma su huella digital SHA-256 por un canal de confianza (la consola del dispositivo, el administrador que lo creó) y pásalo con --cacert. Así, curl acepta este certificado y ningún otro en esa llamada.

    bash
    # Fetch the certificate once, compare its fingerprint out of band, then trust exactly that file
    openssl s_client -connect api.example.com:8443 -servername api.example.com </dev/null 2>/dev/null \
      | openssl x509 -out api.example.com.pem
    openssl x509 -in api.example.com.pem -noout -fingerprint -sha256
    curl --cacert api.example.com.pem https://api.example.com:8443/
  2. 2.

    Desarrollo: emitir certificados desde una CA local

    Una CA local (mkcert, step-ca o una raíz creada a mano) te permite confiar una sola vez en una raíz y emitir certificados para tantos hosts de desarrollo como quieras. Los certificados ya no son autofirmados, así que el error desaparece en todos los equipos donde esté instalada la raíz.

    bash
    # mkcert creates a local CA, installs it into the system and browser stores,
    # and issues certificates signed by it (no longer self-signed)
    mkcert -install
    mkcert api.example.test localhost 127.0.0.1
  3. 3.

    Hosts públicos: instalar un certificado de una CA pública

    Todo aquello a lo que accedan otras personas o clientes de terceros debería presentar un certificado de una CA de confianza pública; los clientes ACME como certbot, lego o Caddy obtienen y renuevan uno automáticamente.

    bash
    # Public names: get a certificate from a public CA, e.g. with certbot (ACME)
    sudo certbot certonly --nginx -d api.example.com
  4. 4.

    Diagnóstico temporal: comprobar el servicio con la verificación desactivada

    -k hace que curl omita las comprobaciones de certificados, así que un 200 confirma que solo falta la confianza. No lo dejes puesto: un certificado autofirmado aceptado sin comprobarlo puede sustituirse en cualquier momento por el de un atacante, y curl no lo notaría.

    bash
    # Diagnostic only: confirms the service answers when certificate checks are skipped
    curl -sS -k -o /dev/null -w '%{http_code}\n' https://api.example.com:8443/

Errores relacionados

Explorar toda la base de datos de errores de firma