Sommaire
Bref historique
Cette faille a été découverte par Antoine Delignat-Lavaud, Karthikeyan Bhargavan et Alfredo Pironti de l’équipe de recherche Prosecco de l’INRIA Paris-Rocquencourt.
Cette découverte s’est faite dans le cadre du projet miTLS, dont le but est de créer une implémentation de référence vérifiée de TLS. Elle est réalisée en F# et, bien qu’encore trop immature pour un environnement de production, est utilisée sur le site web du projet. Ce projet compte également dans son équipe, en plus de membres de l’INRIA, des gens de Microsoft Research et du IMDEA software institute.
La faille a été présentée lors de la 89e rencontre de l’IETF, et un brouillon a été proposé pour corriger le protocole.
Enfin, cette faille est connue depuis au moins octobre 2013 et a été divulguée de façon responsable. Elle a seulement été dévoilée publiquement au début du mois de mars dernier.
Explication de la faille
Fonctionnement des poignées de main
TLS comporte deux sous-protocoles : le protocole d’échange de poignées de main (qui sert à l’authentification et l’échange de clés de chiffrement entre les deux machines) et le protocole d’échange qui utilise ces dernières pour échanger des données de manière sécurisée.
Il existe plusieurs types de poignées de main. Généralement, un client se connecte à un serveur et lui demande son certificat pour vérifier son identité. Mais il est possible que les deux (client et serveur) s’authentifient l’un auprès de l’autre.
Poignée de main de renégociation
TLS prend en charge une poignée de main de renégociation, qui permet de passer d’un mode à un autre, typiquement du mode « serveur authentifié seulement » au mode « client et serveur authentifiés ». Cela arrive par exemple lorsque le client veut accéder à une ressource protégée.
En 2009, une faille utilisant la poignée de main de renégociation a été découverte, permettant d’effectuer une attaque de l’homme du milieu. L’attaquant établissait une connexion non-sécurisée au serveur et, lorsque le serveur demandait une authentification, il pouvait simplement transmettre la poignée de main de renégociation à un client honnête. Le serveur avait alors l’impression que les deux trafics proviennent de la même personne (qui est alors authentifiée).
Pour corriger cela, une poignée de main de renégociation sécurisée a été proposée. Elle consiste à prouver que c’est bien la même personne qui a effectué la précédente poignée de main, en ajoutant un hachage du master secret (secret partagé entre le client et le serveur) et un hachage de la précédente poignée de main.
Des protections insuffisantes
La découverte de la faille 3Shake nous montre que ça n’était pas suffisant.
Dans certains systèmes, lorsqu’on essaie, lors d’une connexion sécurisée, d’accéder à une ressource protégée sur un serveur, le serveur peut demander une renégociation pour que le client s’authentifie lui aussi à l’aide d’un certificat. Cette faille permet, dans cette configuration précise, d’effectuer une attaque de l’homme du milieu.
Étape 1
Le master secret est censé n’être connu que par le client et le serveur et être unique à la connexion. Pourtant, un attaquant malin peut se débrouiller pour établir le même master secret sur deux connexions différentes.
Si le client se connecte par TLS à l’attaquant en pensant qu’il est le serveur, l’attaquant établit en même temps une connexion TLS avec le serveur, et peut alors se débrouiller pour que le client et le serveur utilisent le même master secret (ce qui est plutôt grave pour un secret).
Concrètement, ça se passe comme ça :
- Le client demande la connexion : il envoie des données aléatoires (que l’on appelera ici CR pour Client Random) qui serviront à établir le master secret ainsi que la liste des algorithmes qu’il connait.
- L’attaquant reçoit le CR et le transmet au serveur, mais en indiquant qu’il ne connait que RSA (ou DHE, mais cela ne semble pas fonctionner avec ECDHE).
- Le serveur envoie à l’attaquant le SR (pour Server Random) et le SID (identifiant de session) qui serviront eux aussi à la construction du master secret, et indique qu’il utilise RSA. Ce message est transmis sans modification au client.
- Le serveur envoie son certificat à l’attaquant et l’attaquant transmet son certificat au client.
Il faut noter que si l’attaquant avait transmis le certificat du serveur au client, le client aurait découvert que l’attaquant était un usurpateur en regardant dans sa base de certificat SSL, de la même façon qu’un navigateur web reconnait que le certificat appartient au site visité ou non.
- Le client créé et envoie une pre-master key (calculée à partir du CR, SR et d’autres choses encore), chiffrée avec la clé publique du certificat de l’attaquant, les deux parties génèrent alors le master secret et les clés de session. L’attaquant fait de même avec le serveur.
- Le client envoie un message pour demander au serveur de communiquer avec les clés de session qui viennent d’être créées.
L’attaquant peut communiquer avec le client et le serveur et faire passer les messages, mais le hachage des poignées de main entre le client et l’attaquant et entre l’attaquant et le serveur sont différentes car ça n’est pas le même certificat.
Étape 2
Il existe un autre type de poignée de main : la poignée de main de reprise (resumption handshake). Elle permet d’établir de nouvelles clés cryptographiques entre deux parties qui ont déjà établi un master secret entre eux et qui s’en rappellent. Cette poignée de main n’utilise pas de chiffrement à clé publique ou de certificat pour rendre l’opération plus rapide.
Lorsque le client veut reprendre sa communication, l’attaquant fait la même chose avec le serveur. L’attaquant a alors juste à transmettre les messages du client au serveur et inversement. On arrive au même point que l’étape 1, sauf que le hachage de la poignée de main des deux connexions sont désormais les mêmes.
Étape 3
Le client, en voulant accéder à une ressource qui nécessite une authentification par certificat, va provoquer une poignée de main de renégociation. Étonnamment, le serveur peut changer de certificat au cours de cette poignée de main.
L’attaquant transmet tous les messages de renégociation sans les changer. Sans détailler, c’est à peu près la même chose que l’étape 1 sauf que l’attaquant ne modifie pas le contenu de chaque échange. Du coup, le client a désormais le certificat du serveur et non plus celui de l’attaquant. Ce dernier ne connait alors pas la paire de clés utilisée par le client et le serveur pour communiquer.
À la fin de la renégociation, l’attaquant ne connait plus les clés de session ou le master secret ; ils sont seulement connus du client et du serveur. Par conséquent, l’attaquant ne peut plus lire ou envoyer de messages sur ces connexions. Cependant, ces précédents messages sur les deux connexions peuvent bien être préfixés par les messages envoyés après renégociation. De plus, l’attaquant peut toujours lire et écrire des données sur ces connexions en s’appuyant sur la politique de même origine (same origin policy).
Je vous avoue que moi-même que, malgré tous mes efforts, je n’ai pas bien compris l’intérêt de l’étape 3, ni l’étendue des attaques possibles ensuite.
Corrections appliquées
Apple a fait le communiqué suivant :
Pour empêcher les attaques fondées sur ce cas de figure, Secure Transport a été modifié pour que, par défaut, une renégociation doive présenter le même certificat serveur que celui qui a été présenté lors de la connexion originale. Ce problème ne touche pas les systèmes Mac OS X 10.7 et précédents.
Les autres logiciels (principalement les navigateurs) et bibliothèques qui ont corrigé la faille semblent tous avoir adopté une solution similaire. Certains ont limité les poignées de main à l’algorithme ECDHE.
Est-on vraiment protégé ?
Des implémentations buguées
Si Heartbleed a été très médiatisé, ça n'est ni la première, ni la dernière faille de sécurité qui sera découverte. Pire, on découvre régulièrement de nouvelles failles au sein de bibliothèques implémentant le protocole SSL/TLS et aucune implémentation n’est épargnée. C’est pourtant la base aujourd’hui de la communication « sécurisée » en ligne.
Les gens du projet ClearCrypt par exemple critiquent la qualité du code d’OpenSSL et de NSS. La description d’OpenSSL indique :
OpenSSL : […] Considéré par la communauté de la sécurité comme un énorme tas de merde fumant avec une interface de programmation byzantine et une implémentation surréaliste. Récemment victime de la faille Heartbleed, une erreur de programmation triviale qui permet de récupérer des clés privées. Sujet par le passé à des bugs encore pires, comme une vulnérabilité permettant l’exécution de code arbitraire à distance.
Et celle de NSS est dans le même style.
Un mauvais protocole ?
Mais cette faille remet également en cause la sécurité du protocole lui-même, pourtant utilisé et audité depuis des années. L’équipe qui a découvert la faille a fait une liste des fonctionnalités vulnérables qui ont permis à la faille d’exister. Et si TLS n’était pas si génial que ça ?
C’est en tout cas l’avis du cryptographe Matthew Green :
J’aime beaucoup TLS, mais le protocole est un sérieux bazar. Sur certains points, il hérite d'un sacré paquet de cryptographie de ses prédécesseurs (SSLv1–3). Pour d’autres, c’est seulement le véritable début d’une analyse formelle et rigoureuse.
et des gens du projet ClearCrypt :
[…] TLS est une putain de magie noire et réaliser une nouvelle implémentation de TLS interopérable peut seulement être fait par des magiciens de ce type de magie noire.
Le projet ClearCrypt
C'est pourquoi ce dernier veut remédier aux deux problèmes à la fois : implémenter un protocole plus sûr que TLS avec un langage très sûr. La complexité du format de certificat X.509 est aussi remise en question, notamment le fait que ce ne soit pas un format lisible par un humain, et que le format est vraiment complexe et alambiqué.
Un des protocoles étudié et discuté est une variante TCP de CurveCP (qui utilise à la base UDP). Le protocole Tcpcrypt est aussi mentionné, qui permettrait de chiffrer la couche transport et une partie de la couche réseau. Le langage Rust est envisagé pour l’implémentation car c’est un langage système et que sa gestion mémoire est sûre.
Pour plus d’informations, voir ici.
Conclusion
Les failles découvertes ces derniers temps nous rappellent que ni le protocole, ni les implémentations ne sont infaillibles. Il est peut-être temps d’analyser plus en profondeur TLS ou de penser à utiliser un autre protocole (un potentiel TLSv2 ou un tout autre protocole), mais aussi de promouvoir et utiliser les outils qui permettent d’obtenir du code sûr.