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

Mensaje de error

curl: (60) SSL certificate problem: unable to get local issuer certificate

También se muestra como

  • curl: (60) SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
  • SSL certificate problem: unable to get local issuer certificate

El curl basado en OpenSSL (Linux, Homebrew en macOS, Git for Windows) imprime este texto; las versiones más recientes (8.22.0 en nuestra prueba, mientras que 8.14.1 aún usaba el texto de arriba) lo formulan como «SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)», con el código de verificación de OpenSSL añadido. El curl compilado con Schannel en Windows notifica la misma situación como «schannel: SEC_E_UNTRUSTED_ROOT (0x80090325)», y el libcurl basado en GnuTLS (el que usa git en Debian y Ubuntu), como «server verification failed: certificate signer not trusted». Las herramientas basadas en libcurl, como PHP y git, imprimen la parte posterior a «(60) » con su propio prefijo.

curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY (20)

Qué significa

curl recibió los certificados del servidor, pero no encontró en su propio bundle de CA el certificado que emitió el último de la cadena. Puede que el certificado sea perfectamente válido; simplemente, curl no puede enlazarlo con ninguna raíz en la que confíe, así que rechaza la conexión (código de salida 60). La pieza que falta es un intermedio que el servidor olvidó enviar o una CA raíz que tu equipo no tiene.

Por qué ocurre

Cómo solucionarlo

  1. 1.

    Ver qué envía realmente el servidor

    Lista los certificados del handshake. Si solo aparece uno (profundidad 0) y su emisor es una CA intermedia, la configuración del servidor está incompleta y hay que corregirla en el servidor. Si la cadena termina en una raíz de la empresa o creada por uno mismo, al cliente le falta esa raíz.

    bash
    # Which certificates does the server send, and who issued the last one?
    openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \
      | grep -E '^ *[0-9]+ s:|^ *i:'
    #  0 s:CN=api.example.com
    #    i:C=US, O=Example Trust Services, CN=Example TLS Issuing CA   <- leaf only: intermediate missing
  2. 2.

    Corregir el servidor: servir la cadena completa

    Configura el servidor web con un bundle que contenga el certificado hoja seguido de todos los intermedios. Así se corrige el error para todos los clientes a la vez, incluidas las aplicaciones móviles y los clientes de API que no controlas.

    bash
    # Leaf first, then each intermediate in order; the root itself is optional
    cat api.example.com.crt intermediate.crt > fullchain.pem
    
    # nginx:   ssl_certificate     /etc/nginx/tls/fullchain.pem;
    # Apache:  SSLCertificateFile  /etc/apache2/tls/fullchain.pem
    # certbot: use live/<name>/fullchain.pem, never cert.pem
  3. 3.

    Instalar una CA raíz privada en el almacén del sistema

    Si la cadena termina legítimamente en una raíz de la empresa o interna, añade esa raíz al bundle del sistema operativo. Obtén la raíz de tu equipo de TI o de plataforma, o de la propia CA; nunca del certificado que presentó la conexión fallida, porque es justo aquello en lo que todavía no puedes confiar.

    bash
    # Debian, Ubuntu, Alpine (the file must end in .crt)
    sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt
    sudo update-ca-certificates
    
    # RHEL, Fedora, Amazon Linux
    sudo cp corp-root-ca.pem /etc/pki/ca-trust/source/anchors/
    sudo update-ca-trust
  4. 4.

    Indicar a curl un bundle para un solo comando o una sola shell

    --cacert añade confianza para una sola llamada sin tocar el sistema; CURL_CA_BUNDLE establece el bundle para todas las llamadas de curl del entorno. El archivo puede contener varios certificados PEM.

    bash
    curl --cacert corp-root-ca.pem https://api.example.com/
    
    # or for every curl command in this shell (a file may hold several PEM certificates)
    export CURL_CA_BUNDLE=/opt/certs/corp-and-public-roots.pem
  5. 5.

    Instalar el bundle de CA en contenedores mínimos

    Si incluso los sitios públicos fallan dentro de un contenedor, la imagen no tiene bundle. Instala ca-certificates en la imagen (o copia /etc/ssl/certs/ca-certificates.crt desde una etapa de compilación) en lugar de desactivar la verificación.

    bash
    # Debian/Ubuntu-based images
    apt-get update && apt-get install -y --no-install-recommends ca-certificates
    # Alpine
    apk add --no-cache ca-certificates
  6. 6.

    Diagnóstico temporal: confirmar que es un problema de confianza

    -k (--insecure) desactiva la verificación de certificados, así que una respuesta correcta solo demuestra que la ruta de red funciona y que el fallo es de confianza. Nunca lo dejes en los scripts: con -k, cualquiera en la ruta puede leer y alterar el tráfico, incluidas las credenciales y el código descargado.

    bash
    # Diagnostic only: if this works, the problem is trust, not the network.
    curl -sS -k -o /dev/null -w '%{http_code}\n' https://api.example.com/

Errores relacionados

Explorar toda la base de datos de errores de firma