Mensaje de error
[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake failure
También se muestra como
- [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure
El código de motivo sigue siendo SSLV3_ALERT_HANDSHAKE_FAILURE, pero el texto depende de OpenSSL: «ssl/tls alert handshake failure» con OpenSSL 3.3 y posteriores, «sslv3 alert handshake failure» con versiones anteriores. Le sigue una ubicación en el código fuente como «(_ssl.c:1082)».
Python ssl module (OpenSSL) — ssl.SSLError, TLS alert 40 (handshake_failure) from the server
Qué significa
El servidor abortó el handshake con la alerta TLS 40 (handshake_failure). No encontró parámetros aceptables en el ClientHello de Python, o exigía un certificado de cliente que no se presentó. La alerta en sí no trae detalles, así que la causa hay que buscarla comparando lo que admite cada lado o leyendo el registro del servidor.
Por qué ocurre
Ningún conjunto de cifrado en común
frecuenteDesde Python 3.10, el contexto predeterminado usa el nivel de seguridad 2 de OpenSSL y no ofrece conjuntos sin forward secrecy ni conjuntos con MAC SHA-1. Los servidores antiguos limitados a conjuntos con intercambio de claves RSA, con CBC-SHA o con 3DES no tienen nada en común con él.
El servidor exige un certificado de cliente
frecuenteLos endpoints de TLS mutuo (API bancarias y B2B, servicios internos) responden con esta alerta en TLS 1.2 a un handshake sin certificado de cliente.
SNI ausente o no configurado en el servidor
ocasionalConectarse por IP sin server_hostname, o a un nombre que la CDN o el proxy no sirve, hace que algunos servidores aborten con handshake_failure.
Cómo solucionarlo
- 1.
Comparar las listas de cifrados
Imprime los cifrados que ofrece este Python y compáralos con la lista del servidor (por ejemplo, la de nmap --script ssl-enum-ciphers). Si no coinciden en nada, hay que actualizar el servidor.
python import ssl ctx = ssl.create_default_context() print(sorted(c["name"] for c in ctx.get_ciphers())) # what this Python offers (TLS 1.2 names) - 2.
Presentar el certificado de cliente
Para las API mTLS, carga el certificado de cliente y la clave en el contexto con load_cert_chain(); requests acepta cert=("client.pem", "client.key").
python import ssl, urllib.request ctx = ssl.create_default_context() ctx.load_cert_chain(certfile="client.pem", keyfile="client.key") # mutual TLS urllib.request.urlopen("https://mtls.example.com/", context=ctx) - 3.
Propietarios del servidor: ofrecer conjuntos actuales
TLS 1.3, más TLS 1.2 con ECDHE y AES-GCM o ChaCha20-Poly1305, lo aceptan todos los clientes que siguen recibiendo mantenimiento.
text # Server side: offer TLS 1.3 and TLS 1.2 ECDHE + AEAD suites 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;