Message d’erreur
[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake failure
Également affiché sous la forme
- [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure
Le code de raison reste SSLV3_ALERT_HANDSHAKE_FAILURE, mais le texte dépend d’OpenSSL : « ssl/tls alert handshake failure » avec OpenSSL 3.3 et les versions ultérieures, « sslv3 alert handshake failure » avec les versions antérieures. Un emplacement dans le code source, comme « (_ssl.c:1082) », suit le message.
Python ssl module (OpenSSL) — ssl.SSLError, TLS alert 40 (handshake_failure) from the server
Ce que cela signifie
Le serveur a interrompu le handshake avec l’alerte TLS 40 (handshake_failure). Il n’a trouvé aucun paramètre acceptable dans le ClientHello de Python, ou il exigeait un certificat client qui n’a pas été présenté. L’alerte elle-même ne donne aucun détail : il faut donc trouver la cause en comparant ce que chaque côté prend en charge, ou en lisant le journal du serveur.
Pourquoi cela se produit
Aucune suite de chiffrement en commun
fréquenteDepuis Python 3.10, le contexte par défaut ne propose, au niveau de sécurité 2 d’OpenSSL, aucune suite sans confidentialité persistante ni aucune suite à MAC SHA-1. Les anciens serveurs limités aux suites à échange de clés RSA, aux suites CBC-SHA ou aux suites 3DES n’ont rien en commun avec lui.
Le serveur exige un certificat client
fréquenteEn TLS 1.2, les points de terminaison en TLS mutuel (API bancaires et B2B, services internes) répondent par cette alerte à un handshake sans certificat client.
SNI absent ou non configuré sur le serveur
occasionnelleSe connecter par adresse IP sans server_hostname, ou à un nom que le CDN ou le proxy ne sert pas, amène certains serveurs à interrompre le handshake avec handshake_failure.
Comment corriger l’erreur
- 1.
Comparer les listes de chiffrements
Affichez les suites de chiffrement que propose ce Python et comparez-les avec la liste du serveur (obtenue par exemple avec nmap --script ssl-enum-ciphers). S’il n’y a aucun élément en commun, le serveur doit être mis à jour.
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.
Présenter le certificat client
Pour les API en mTLS, chargez le certificat client et sa clé dans le contexte avec load_cert_chain() ; requests accepte 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.
Propriétaires de serveurs : proposer des suites actuelles
TLS 1.3, complété par TLS 1.2 en ECDHE avec AES-GCM ou ChaCha20-Poly1305, est accepté par tous les clients maintenus.
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;