GnuTLS vs. Debian OpenSSL
Par Trou,
lundi 8 décembre 2008 à 22:09 :: Invités
Lu 8706 fois :: #310
:: rss
:: atom
::
English

près la publicité, certes légitime, autour de la faille OpenSSL dans Debian du début de cette année, penchons-nous sur une vulnérabilité récente qui n'a absolument pas fait parler d'elle, malgré ses conséquences désastreuses.
Celle-ci affecte également une bibliothèque implémentant le protocole TLS : GnuTLS. Référencée par les identifiants GNUTLS-SA-2008-3 et CVE-2008-4989, cette faille permet à un attaquant de contourner la vérification de la chaîne de confiance d'un certificat. C'est-à-dire faire considérer comme légitime (signé par une autorité de confiance) un certificat qui ne devrait pas l'être (par exemple auto-signé).
Avant de voir les causes de cette faille, précisons qu'elle a été découverte par hasard, suite à une erreur : Martin von Gagern avait interverti deux certificats dans la chaîne présentée par son serveur Web au client.
La faille
En effet, la faille est due à la fonction _gnutls_x509_verify_certificate qui, comme son nom l'indique, vérifie une chaîne de certificats par rapport à une liste d'autorités de certification (AC) de confiance (trusted CA). En théorie, cette chaîne doit se terminer par un certificat signé par une autorité de confiance, ceci permettant d'authentifier l'autre partie d'une communication. Par la suite nous considérerons le cas d'un client se connectant à un serveur Web et voulant vérifier l'identité de ce dernier.
Dans le cas usuel, le serveur ne fournit qu'un seul certificat, signé par une AC reconnue par le navigateur du client, mais il est également possible de fournir une chaîne de certificats.
Voyons donc le corps de la fonction vulnérable :
static unsigned int _gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list, int clist_size, const gnutls_x509_crt_t * trusted_cas, int tcas_size, const gnutls_x509_crl_t * CRLs, int crls_size, unsigned int flags) { int i = 0, ret; unsigned int status = 0, output; /* Verify the last certificate in the certificate path * against the trusted CA certificate list. * * If no CAs are present returns CERT_INVALID. Thus works * in self signed etc certificates. */ ret = _gnutls_verify_certificate2 (certificate_list[clist_size - 1], trusted_cas, tcas_size, flags, &output); if (ret == 0) { [...] (return) } [...] /* Check if the last certificate in the path is self signed. * In that case ignore it (a certificate is trusted only if it * leads to a trusted party by us, not the server's). */ if (gnutls_x509_crt_check_issuer (certificate_list[clist_size - 1], certificate_list[clist_size - 1]) > 0 && clist_size > 0) { clist_size--; } /* Verify the certificate path (chain) */ for (i = clist_size - 1; i > 0; i--) { if (i - 1 < 0) break; [...] if ((ret = _gnutls_verify_certificate2 (certificate_list[i - 1], &certificate_list[i], 1, flags, NULL)) == 0) { status |= GNUTLS_CERT_INVALID; return status; } } return 0; }
En clair, les étapes sont les suivantes:
- Vérification du dernier certificat de la chaîne vis à vis des AC de confiance
- Si le certificat n'est pas signé par une AC reconnue, la fonction retourne une erreur
- Si le dernier certificat est auto-signé, alors on le supprime de la liste
- Vérification de la signature de chaque certificat de la chaîne par rapport à celui de niveau supérieur
Si l'on lit cette liste attentivement, on constate que si le dernier certificat de la chaîne est valide et auto-signé alors l'avant dernier sera implicitement considéré comme valide. A priori cela ne semble pas problématique ... sauf que tous (?) les certificats des AC standards sont auto-signés.
L'exploitation de la faille est donc extrêmement aisée, comme on peut le constater ici ou dans le programme de test rajouté dans GnuTLS.
Il suffit en effet pour usurper l'identité d'un serveur de présenter au client une chaîne de certificats ainsi constituée :
- Un certificat auto-signé ayant le même Common Name que le serveur légitime
- Un certificat de confiance auto-signé : par exemple celui de Thawte.
GnuTLS va vérifier si le certificat de Thawte est de confiance, puis le supprimer. Ensuite, la boucle de vérification ne sera même pas utilisée, clist_size vallant maintenant 0, la fonction va retourner 0 à l'appelant, la chaîne est donc considérée comme valide.
Il est également intéressant de rechercher l'origine de la faille. L'historique du dépôt GIT du projet nous permet de retrouver le commit responsable de la faille. Le message de commit dit "Corrected a bug in certificate verification that could lead to a trusted certificate path to be marked as non-trusted, if it included the last self-signed certificate in the chain". Le problème a donc été ajouté en tentant de renforcer la sécurité ! De plus, si on étudie attentivement le premier patch publié pour corriger la vulnérabilité (GnuTLS v2.6.1), celui-ci déplace la suppression du dernier certificat de la chaîne (si celui-ci est auto-signé) au début de la fonction, ce qui est complètement idiot : une chaîne terminée par un certificat auto-signé sera amputée et donc incomplète, y compris lorsque la chaîne n'a qu'un élément, cas qui provoque des segfaults. Au final, la correction, correspondant à la version 2.6.2, consiste à retirer complètement la suppression des certificats auto-signés de la chaîne de vérification, ce qui est logique, un utilisateur peut vouloir truster un certificat auto-signé !
Conséquences
Les problèmes liés à cette faille sont simples :
- un attaquant pouvant faire un man in the middle peut se faire passer pour le serveur légitime sans alerte
- un attaquant peut s'authentifier en temps que client légitime sur un serveur utilisant l'authentification par certificats
Le premier cas peut se combiner avec LA faille DNS ou alors n'importe quelle technique sur un réseau local. Le deuxième est plus problématique, vu qu'il ne nécessite pas de détournement de flux, cependant le nombre de serveurs utilisant l'authentification par certificat et GnuTLS doit être relativement faible.
Quels sont les logiciels impactés ? La réponse est relativement difficile à donner mais on peut se faire une idée sur Debian à l'aide de l'outil apt-rdepends : apt-rdepends -r libgnutls 26 retourne 193 packages dépendants directement de GnuTLS, notamment lftp, curl. De nombreux projets sont liés à GnuTLS au lieu de OpenSSL pour des questions de licence : la licence OpenSSL est incompatible avec la GPL. Certains projets choisissent donc GnuTLS, malgré ses performances atroces et son code parfois très moche.
Buzz ?
Plus que la vulnérabilité en elle-même, plusieurs points méritent selon moi l'attention. Premièrement, cette vulnérabilité n'a absolument pas fait parler d'elle ! Certes celle-ci n'est pas aussi critique que celle de OpenSSL dans Debian, mais GnuTLS est quand même très utilisée. Mais bon, il aurait sûrement suffi d'annoncer la plus grosse vulnérabilité du mois, ne pas releaser les détails, etc. pour la transformer en faille médiatisée ;) Je vous renvoie d'ailleurs sur un post plus ancien de Sid qui reprend des failles peu médiatisées et à celui de FX sur la perception des vulnérablités.
Mais le point le plus important reste la façon dont les développeurs de GnuTLS ont géré cette faille : la correction publiée a été complètement catastrophique, comme vu plus haut. Le premier patch a été sorti en vitesse sans même vérifier qu'il fonctionnait correctement ! Compte tenu de l'importance de cette bibliothèque, comme on dit, c'est ballot.
Enfin, je conclurai en vous invitant à ne pas utiliser GnuTLS dans vos logiciels (regardez le code pour vous en convaincre, si vous ne l'êtes pas déjà), utilisez OpenSSL (ou XySSL ;), rajoutez la clause qui va bien dans la GPL s'il le faut. Finalement, tout ça, c'est à cause de la licence d'OpenSSL, non compatible avec la GPL. Si celle-ci l'avait été, il n'y aurait probablement pas eu autant de volonté de créer une alternative sous licence GPL...
P.S. : Merci à Sid pour m'avoir laissé une petite place sur son (très bon) blog :)
Commentaires
1. Le mardi 9 décembre 2008 à 01:35, par jmdesp
Réponse de Sid
Réponse de Trou
2. Le mardi 9 décembre 2008 à 10:43, par goundoulf
3. Le mardi 9 décembre 2008 à 19:35, par nico_ze_poo
Réponse de Sid
4. Le jeudi 11 décembre 2008 à 11:40, par Al4mbic
5. Le jeudi 11 décembre 2008 à 15:42, par Kirikou
6. Le vendredi 12 décembre 2008 à 15:07, par goundoulf
7. Le lundi 15 décembre 2008 à 17:55, par Al4mbic
Ajouter un commentaire
Les commentaires pour ce billet sont fermés.