Objections sur la vulnérabilité CVE-2014-2734

Il a récemment été mis en lumière une vulnérabilité qui pourrait affecter Ruby, en l’occurrence CVE-2014-2734. Toutefois, sur la base d’une analyse détaillée retranscrite ci-dessous, nous considérons que Ruby n’est pas concerné par cette faille de sécurité.

Cette faille donne à un attaquant la possibilité de contrefaire n’importe lequel des certificats racine, en modifiant sa signature (ce qui revient dans les faits à remplacer la clé privée originelle du certificat par une autre clé, choisie par l’attaquant).

Démonstration du problème

Ce qui suit est notre analyse de CVE-2014-2734. Nous avons été en mesure de condenser notre prototype initial en quelques lignes qui démontrent le cœur du problème :

require 'openssl'

forge_key = OpenSSL::PKey::RSA.new(2048)
raw_certificate = File.read("arbitrary.cer")
cert = OpenSSL::X509::Certificate.new(raw_certificate)
resigned_cert = cert.sign(spoof, OpenSSL::Digest::SHA1.new)

resigned_cert.verify(key) #=> true

Il peut effectivement sembler étrange que X509Certificate#verify soit évalué à true. Le certificat original peut contenir des métadonnées de type Subject Public Key Info qui pointent vers la clé publique originelle, différente de la clé publique forge_key. Manifestement, la paire de clés (publique/privée) utilisée pour re-signer le certificat ne correspond plus à la clé publique originelle, référencée dans le hash de métadonnées. Pourquoi, dans ces conditions, #verify retournerait true ?

À propos de la vérification des clés

X509Certificate#verify fait usage de la méthode X509_verify d’OpenSSL, une fonction qui délègue en fait à ASN1_item_verify. Ces fonctions vérifient la validité de la signature, étant donnée une clé publique initiale. Cependant, elles ne vérifieront pas si la clé en question correspond à une éventuelle clé publique référencée dans le certificat. C’est pourquoi la valeur de retour true est bien le comportement attendu pour X509Certificate#verify, dans ce cas précis. Il faut bien comprendre que ne pas effectuer cette « double vérification » ne remet en aucun cas en cause la sécurité du modèle de confiance X.509.

La section 4.1.1.3 de la RFC 5280 rend explicite le fait que, en calculant la signature d’un certificat, la CA (Certificate Authority) confirme de facto la validité des informations contenues dans le-dit certificat. Bien que ce principe soit visiblement bafoué dans l’exemple ci-dessus, il n’implique en fait aucune faille de sécurité, du fait de l’implémentation de la procédure. Un certificat modifié de cette façon ne saurait être utilisé par un attaquant, à moins que l’attaque ne soit effectivement en mesure de vous faire explicitement admettre que le certificat est valide.

Les risques potentiels

Deux cas sont à considérer :

Le fait de signer à nouveau un certificat racine

En tant qu’utilisateurs de certificats, nous plaçons une confiance inconditionnelle dans les certificats racines. Quand bien même ils ne contiendraient pas des informations valides, le fait qu’ils aient été approuvés publiquement par une autorité de certification les rend digne de confiance. Ils agissent comment des valeurs pré-configurées dans nos navigateurs ou nos systèmes d’exploitation : le simple fait de les posséder leur donne le statut de référence. À ce titre, même OpenSSL ne prend pas la peine de vérifier la signature de ses propres certificats racines, arguant du fait qu’ils sont auto-signés (cf. X509_V_FLAG_CHECK_SS_SIGNATURE documentation).

À ce titre, un certificat racine re-signé est immédiatement considéré comme digne de confiance, même dans le cas où il contiendrait des informations erronées (Subject Public Key Info). Ce certificat étant racine, il n’y aucune différence avec un certificat racine « valide », donc aucune raison de procéder à une vérification. En principe, n’importe qui peut produire des certificats racines auto-signés qui correspondent point pour point à un certificat racine déjà existant, à l’exception bien sûr de la signature. On comprend alors qu’en jouant sur le fait que nous faisons confiance aux certificats racines que nous possédons, pour la simple raison que nous les possédons, il devient possible à quelqu’un en capacité de produire un vrai-faux certificat racine et de le mettre en place chez quelqu’un, de se créer un vecteur d’attaque important.

Le fait de re-signer un certificat intermédiaire

Si le fait de re-signer un certificat racine ne représente pas une faille de sécurité en tant que telle dans le modèle de confiance X.509, il en va de même pour le fait de re-signer un certificat intermédiaire, mais pour une raison tout à fait différente.

Nous ne possédons en général pas de certificats non-racine en avance. Une contrefaçon sur ce type de certificat sera par conséquent détectée lors de la procédure de validation (path validation procedure). Il s’agit ici de vérifier la signature de tout certificat non racine en utilisant la clé publique du certificat d’autorité correspondant. Si le certificat non racine en cours de vérification a été modifié, sa non conformité sera tout simplement détectée sous la forme d’une signature non valide. Il s’agit du modèle de confiance standard.

Conclusion

En résumé, nous sommes convaincus que X509Certificate#verify n’introduit pas de faille de sécurité d’un point de vue technique. D’autres analyses indépendantes sont arrivées à la même conclusion, de sorte que nous avons décidé de demander le retrait de CVE-2014-2734. Vous pouvez lire l’analyse complète sur le prototype original.