CVE-2020-0601 (CurveBall) : usurper un certificat par la courbe elliptique
La CryptoAPI de Windows vérifiait la clé publique d'un certificat ECC, mais pas le générateur de sa courbe. Une faute d'arithmétique, et n'importe quelle racine de confiance devenait usurpable.
Windows faisait confiance à un certificat à courbe elliptique dès que sa clé publique correspondait à celle d'une autorité racine de confiance, sans vérifier que la courbe présentée était bien la courbe standard. En choisissant lui-même le générateur, un attaquant pouvait fabriquer un certificat qui porte la clé publique d'une racine de confiance tout en en connaissant la clé privée. De quoi signer du code ou usurper un site HTTPS au nom d'une autorité en qui tout Windows avait confiance. Signalée par la NSA, corrigée le 14 janvier 2020 : le correctif Windows est la seule protection.
Fiche d'identité
| Champ | Valeur |
|---|---|
| CVE | CVE-2020-0601 (« CurveBall », « ChainOfFools », « NSACrypt ») |
| Publication | 14 janvier 2020, Patch Tuesday Microsoft ; signalée par la NSA |
| Produits | Windows 10, Windows Server 2016 et 2019 (versions antérieures non affectées) |
| Composant | crypt32.dll (Windows CryptoAPI) |
| Type | validation incorrecte de paramètres cryptographiques, usurpation (CWE-295) |
| Score | CVSS 3.1 : 8.1, élevé (AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N) |
| Prérequis | aucun privilège ; une interaction (ouvrir un fichier signé, visiter un site) |
| Impact | usurpation d'une AC racine ECC : signature de code, MITM TLS |
| Exploitation | au catalogue KEV de la CISA ; CISA ED 20-02 imposait le correctif sous 10 jours |
| Contournement | aucun : seul le correctif de janvier 2020 protège |
Rappel : comment Windows fait confiance à un certificat ECC
Un certificat à courbe elliptique porte une clé publique qui est un point Q sur une courbe. Cette clé est liée à une clé privée d (un simple entier) par la relation :
où G est le générateur (ou point de base) de la courbe, et d · G l'addition de G avec lui-même d fois. Connaître Q et G ne permet pas de retrouver d : c'est tout l'intérêt de l'ECC.
Normalement, une courbe est désignée par un nom (un OID, par exemple nistP256). Ce nom fige tous ses paramètres, générateur compris : les deux bouts de la connexion partent du même G officiel. Mais le format X.509 autorise aussi des courbes à paramètres explicites : le certificat embarque lui-même le corps, les coefficients de l'équation et le générateur G. C'est cette option qui ouvre la faille.
Pour valider une chaîne, la CryptoAPI devait vérifier que le certificat se rattache à une autorité racine de confiance. Elle retrouvait la racine en comparant la clé publique Q présentée à celles des racines connues.
Le bug : la clé publique vérifiée, le générateur oublié
La faute tient en une phrase : quand la courbe était donnée en paramètres explicites, crypt32.dll vérifiait que la clé publique Q correspondait à une racine de confiance, mais ne vérifiait pas que le générateur G était bien celui de la courbe standard. Elle acceptait le G fourni par le certificat.
Or une clé publique Q ne détermine pas le couple (d, G) : pour un même Q, il existe une infinité de couples valides. L'attaquant part donc de la clé publique Qₓₐ d'une racine de confiance (elle est publique, dans le magasin de certificats), et choisit ses propres paramètres :
⇒ d′ · G′ = 1 · Qₓₐ = Qₓₐ
Le certificat forgé déclare donc le générateur G′ = Qₓₐ et une clé publique égale à Qₓₐ — exactement celle de la racine de confiance. Windows retrouve la racine par cette clé publique, ne contrôle pas G′, et accepte la chaîne. Et comme l'attaquant a fixé d′ = 1, il connaît la clé privée du certificat forgé : il peut signer tout ce qu'il veut au nom de cette autorité. (On peut prendre n'importe quel d′ connu en posant G′ = (d′)⁻¹ · Qₓₐ ; d′ = 1 est le cas le plus simple.)
Le mot « générateur » est trompeur : avec G′ = Qₓₐ, le point de base ne génère plus forcément tout le groupe, mais la vérification de signature, elle, passe quand même. C'est ce qui suffit à tromper Windows.
Ce que ça donne concrètement
L'exploit public fabrique, à partir d'une AC racine ECC de confiance (par exemple une racine de signature de code), un certificat intermédiaire usurpé, puis signe avec lui :
- un exécutable : il apparaît alors signé par un éditeur de confiance, SmartScreen et la vérification de signature Authenticode ne bronchent pas ;
- un certificat de serveur TLS : couplé à une position de MITM, le navigateur qui s'appuie sur la CryptoAPI (Edge, IE, beaucoup de clients Windows) accepte le faux certificat d'un site en HTTPS.
Chrome et Firefox, qui n'utilisent pas la CryptoAPI pour cette validation, étaient moins exposés sur le volet TLS ; la signature de code Windows, elle, passe par crypt32.dll.
Patcher
Il n'y a pas de contournement : il faut la mise à jour cumulative de janvier 2020 (ou une plus récente) sur tout Windows 10, Server 2016 et Server 2019. Après correctif, la CryptoAPI valide les paramètres explicites d'une courbe — générateur compris — contre la courbe nommée attendue, et rejette un G qui ne correspond pas.
- Vérifier le niveau de patch :
Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 5 - Ou contrôler la version de
crypt32.dll:(Get-Item C:\Windows\System32\crypt32.dll).VersionInfo.ProductVersion
Détecter
Le correctif ajoute aussi de la journalisation : un Windows à jour qui rencontre un certificat exploitant la faille écrit un évènement, ce qui en fait un bon signal de tentative.
| Signal | Où le voir |
|---|---|
| Tentative d'usurpation détectée par un hôte patché | Journal Application, source Microsoft-Windows-Audit-CVE, Event ID 1 |
| Certificat ECC à paramètres explicites (rare et suspect en usage normal) | inspection des certificats présentés, logs TLS, proxy |
| Exécutable signé par une racine ECC inattendue | vérification Authenticode, EDR |
Côté durcissement : pousser le correctif en priorité (c'est une faille de confiance, pas d'exécution directe), remonter l'Event ID 1 au SIEM, et se méfier de tout certificat à paramètres de courbe explicites, qui n'a presque aucune raison d'exister dans une PKI saine.
Pourquoi ce bug est intéressant
CurveBall ne casse pas l'ECC : la cryptographie sous-jacente reste solide. Il casse une vérification. C'est l'illustration qu'un schéma cryptographique n'est sûr que si l'on valide tous ses paramètres, pas seulement ceux qu'on regarde d'habitude. Oublier de contrôler le générateur revient à vérifier une signature sans vérifier de quelle clé elle vient. La leçon se généralise : valider l'intégralité des paramètres d'un algorithme (courbe, groupe, nonce, longueurs) est aussi important que l'algorithme lui-même.
Références
Faits vérifiés par recoupement de plusieurs sources ; date, score et mécanisme concordent.
- CVE-2020-0601, NVD : score CVSS 8.1, vecteur, CWE-295
- Avis Microsoft (MSRC) : produits affectés, correctif
- Advisory de la NSA : description de la faille et de l'impact
- A Technical Analysis of CurveBall, Trend Micro : mécanisme des paramètres explicites
- CISA Emergency Directive 20-02 : délai de correctif imposé
- Catalogue KEV de la CISA