Le balayage a duré 41 minutes

Le 30 juillet, quelqu'un a parcouru 1 196 adresses bitcoin et les a vidées, emportant 1 082,65 bitcoins, soit environ 70,2 millions de dollars, dans une fenêtre de 41 minutes. Personne n'a crocheté de serrure. Aucun appareil n'a été touché, aucun utilisateur hameçonné, aucun serveur compromis. L'attaquant n'avait besoin de rien de tout cela, puisque les clés privées protégeant ces adresses pouvaient être reconstituées à partir de rien. Les premiers signalements situaient la perte près de 38 millions de dollars; une fois le décompte achevé, le chiffre atteignait presque le double.

Les appareils concernés étaient des portefeuilles matériels Coldcard fabriqués par Coinkite, c'est-à-dire précisément la catégorie de produit que l'on achète pour tenir ses clés à l'écart des réseaux. C'est ce qui rend l'incident digne d'une heure d'attention pour n'importe quel dirigeant, quoi qu'il pense du bitcoin. La défaillance n'a pas eu lieu sur le périmètre que tout le monde budgète. Elle a eu lieu à l'instant où le secret a été créé, des années avant que quiconque tente de le voler.

Une macro mise à zéro a activé le repli

Le récit technique de Coinkite elle-même est d'une franchise inhabituelle sur le mécanisme. En mars 2021, lors d'une migration vers la libsecp256k1 de Bitcoin Core, la génération de graines a été détournée de la routine qui appelait le générateur matériel de nombres aléatoires de l'appareil vers une fonction générique. Ce nouveau chemin se résolvait vers le repli logiciel de MicroPython plutôt que vers l'implémentation matérielle de Coldcard. Le code de repli existait depuis mai 2018 et n'avait jamais touché à la génération de graines avant cette migration.

La raison pour laquelle il a été compilé mérite d'entrer dans votre propre liste de contrôle. La garde entourant le repli vérifiait si une macro de configuration était définie, et non si elle valait un. Les développeurs l'avaient mise à zéro, estimant que le générateur matériel n'était pas nécessaire à cet endroit, et une macro mise à zéro reste une macro définie. La garde a lu la présence de la valeur au lieu de la valeur elle-même, et a activé le repli. Personne n'a écrit de cryptographie faible. Le générateur matériel existait et fonctionnait. Il a simplement cessé d'être ce dont la graine était tirée.

Cinq ans ont passé et tous les tests restaient au vert

Sur les appareils Mk2 et Mk3 dotés des micrologiciels 4.0.1 à 4.1.9, les graines obtenues portaient environ 40 bits d'entropie au lieu des 128 qu'une phrase de douze mots devrait comporter. Sur Mk4, Mk5 et Q, le tableau était meilleur sans être sûr: les ingénieurs avaient mêlé des valeurs issues des éléments sécurisés à l'état du générateur, selon l'expression de Coinkite une réserve de la réserve, ce qui portait ces graines à environ 72 bits. Les deux chiffres sont catastrophiques de la même manière. L'aléa ne se voit pas. Une clé adossée à 40 bits signe des transactions, vérifie des adresses et se restaure depuis une sauvegarde exactement comme une clé de 128 bits, si bien que tous les tests fonctionnels menés cinq années durant par l'entreprise et ses clients ont été réussis, à juste titre, alors que le produit était cassé.

Coinkite livre en outre un détail que la plupart des fournisseurs auraient enfoui. Il y a quelques semaines, écrit-elle, l'entreprise a utilisé l'un des meilleurs modèles d'intelligence artificielle disponibles pour relire son code à la recherche de problèmes de sécurité, et il n'a pas trouvé ce défaut. Il vaut la peine de s'y arrêter avant que le prochain fournisseur vous annonce que son code a été relu par un modèle. Le défaut n'était ni subtil rétrospectivement ni dissimulé, mais il logeait dans la jointure entre une configuration de compilation et une hypothèse cryptographique, soit exactement la couture qu'un relecteur attentif à la qualité du code traitera le moins volontiers comme une frontière de sécurité.

Le correctif protège la clé suivante, pas la précédente

Coinkite a publié le 31 juillet un micrologiciel corrigé pour chaque modèle et chaque branche concernés: 4.2.0 pour Mk2 et Mk3, 5.6.0 pour Mk4 et Mk5, 1.5.0Q pour Q, ainsi que les versions edge correspondantes. Puis elle a publié la phrase qui pèse plus lourd que le correctif. Mettre à jour le micrologiciel ne modifie ni ne répare une graine existante. La consigne est d'installer le micrologiciel corrigé, d'engendrer une nouvelle graine sur l'appareil mis à jour, de noter et vérifier sa sauvegarde avant tout dépôt, de confirmer une nouvelle adresse de réception sur l'écran de l'appareil, d'envoyer une petite transaction d'essai, et seulement alors de déplacer les fonds restants.

C'est une migration et non une mise à jour, et toute la leçon tient dans cette distinction. Deux choses pouvaient sauver un portefeuille créé pendant la fenêtre concernée: cinquante lancers de dés indépendants et privés saisis via la fonction dés de l'appareil, puisque Coldcard les intégrait à la graine, ou une phrase secrète forte et unique, qui forme une barrière distincte devant la graine faible. Coinkite invite malgré tout les utilisateurs protégés par une telle phrase à migrer dès que possible. TAPSIGNER, OPENDIME et SATSCARD reposent sur d'autres bases de code et ne sont pas concernés.

Inventoriez ce que vous avez engendré, pas seulement ce que vous exécutez

Presque tous les processus de correctifs qu'un dirigeant a validés traitent la version logicielle comme l'unité de risque. On apprend qu'une version est vulnérable, on la met à jour, l'exposition cesse. Les défauts d'entropie brisent entièrement ce modèle, car le dommage ne réside pas dans le code en exécution mais dans les objets que ce code a produits et remis: clés, jetons, identifiants de session, codes de récupération, secrets d'API, certificats. Ces objets survivent à la version qui les a fabriqués, gagnent les sauvegardes et les systèmes tiers, et emportent la faiblesse avec eux définitivement. Mettre à jour le générateur arrête la production de mauvais secrets. Cela ne fait rien pour le stock.

La question à poser à tout fournisseur dont le produit crée des secrets pour votre compte n'est donc pas seulement quelles versions sont touchées. C'est quels secrets ont été engendrés sur une version touchée, comment on les énumère et quel est le chemin de rotation. Cela dépasse largement les portefeuilles matériels: le HSM de la chaîne de paiement, l'autorité de certification, la ligne de provisionnement des appareils, le fournisseur d'identité qui émet des jetons de longue durée. Partout où une machine frappe quelque chose dont vous dépendrez ensuite, la fenêtre défectueuse est ce qu'il faut inventorier, et presque personne n'en tient le registre.