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

Mensaje de error

curl: (35) TLS connect error: error:0A000410:SSL routines::ssl/tls alert handshake failure

También se muestra como

  • curl: (35) error:0A000410:SSL routines::sslv3 alert handshake failure
  • curl: (35) error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

OpenSSL 3.3 y versiones posteriores escriben el motivo como «ssl/tls alert handshake failure»; OpenSSL 3.1 y anteriores imprimen «sslv3 alert handshake failure» (1.1.1, con el código 14094410 y el nombre de función ssl3_read_bytes). Las versiones recientes de curl anteponen «TLS connect error: ».

curl (OpenSSL backend) — CURLE_SSL_CONNECT_ERROR, TLS alert 40 (handshake_failure) received from the server

Qué significa

El servidor termina el handshake enviando la alerta TLS 40 (handshake_failure): no puede acordar parámetros con lo que ofrece curl. La alerta no incluye ningún motivo, así que la causa real solo es visible en los registros del servidor; en el lado del cliente solo puedes comparar lo que admite cada parte. En este punto el certificado aún no se ha comprobado.

Por qué ocurre

Cómo solucionarlo

  1. 1.

    Comparar lo que ofrece cada lado

    Enumera los conjuntos y las versiones de protocolo del servidor y compáralos con la lista de cifrados del cliente. La salida detallada de curl muestra hasta dónde llegó el handshake y qué versión se intentó.

    bash
    # What the server accepts (needs nmap) and what this client offers
    nmap --script ssl-enum-ciphers -p 443 api.example.com
    openssl ciphers -v 'DEFAULT' | head -20
    # Full handshake trace from curl's side
    curl -sv https://api.example.com/ -o /dev/null 2>&1 | grep -E '^\* (TLS|SSL)'
  2. 2.

    Propietarios del servidor: usar una configuración de cifrado actual

    Ofrece TLS 1.3 y TLS 1.2 con conjuntos ECDHE y AEAD (AES-GCM, ChaCha20-Poly1305). Todos los clientes de la última década los admiten, y nada moderno necesita intercambio de claves RSA ni CBC.

    text
    # nginx: TLS 1.2 with forward-secret AEAD suites + TLS 1.3
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers off;
  3. 3.

    Enviar el nombre de servidor correcto

    Usa el nombre de host en la URL, o conserva el nombre mientras fuerzas una dirección con --resolve. Con openssl s_client, pasa -servername al conectarte a una IP.

    bash
    # Use the host name in the URL (SNI is sent automatically); for IP targets keep the name:
    curl --resolve api.example.com:443:203.0.113.10 https://api.example.com/
    # openssl s_client sends SNI only with -servername (or a host name in -connect)
    openssl s_client -connect 203.0.113.10:443 -servername api.example.com </dev/null
  4. 4.

    Presentar el certificado de cliente para TLS mutuo

    Si el endpoint es una API mTLS, configura el certificado de cliente y la clave; los registros del servidor indicarán que el problema es un certificado del otro extremo ausente o que no se puede verificar.

    bash
    # Mutual TLS: present the client certificate and key the server expects
    curl --cert client.pem --key client.key https://mtls.example.com/

Errores relacionados

Explorar toda la base de datos de errores de firma