Secure boot sur microcontrôleur : chaîne de confiance, clés et anti-rollback
Un démarrage sécurisé garantit qu'un microcontrôleur n'exécute que du code dont l'origine est prouvée. La plupart des implémentations échouent non pas sur la cryptographie, qui est la partie facile, mais sur ce qui l'entoure : où vit la clé publique, qui peut la remplacer, et ce qui se passe quand on veut installer une version antérieure.
La chaîne de confiance, étage par étage
Le principe est une récurrence : chaque étage vérifie le suivant avant de lui donner la main.
Étage 0, la racine de confiance. Du code en ROM masquée, gravé au moment de la fabrication du silicium, donc physiquement non modifiable. C'est le seul maillon qu'on ne peut pas vérifier, il faut lui faire confiance par construction. Il contient, ou sait retrouver, l'empreinte de la clé publique du fabricant du produit.
Étage 1, le chargeur d'amorçage. Souvent MCUboot sur Cortex-M. Il est vérifié par la ROM, puis vérifie à son tour l'application.
Étage 2, l'application. Signée, vérifiée avant exécution.
Le maillon faible n'est jamais la signature elle-même. C'est le stockage de l'empreinte de la clé publique : si un attaquant peut la remplacer, il signe ce qu'il veut et toute la chaîne devient décorative.
Où vit la clé publique, et pourquoi c'est la vraie question
L'empreinte de la clé publique doit être immuable après provisionnement. Trois mécanismes existent selon le silicium.
La mémoire OTP, ou one-time programmable : des fusibles que l'on brûle une fois. C'est le mécanisme le plus solide, et il est définitif. Une erreur de provisionnement transforme la carte en presse-papier.
Les octets d'option verrouillés, sur STM32 par exemple, avec un niveau de protection en lecture qui interdit ensuite la modification.
Une zone de flash protégée en écriture par le contrôleur mémoire. C'est la solution la plus faible : elle repose sur une configuration logicielle, donc sur l'absence de faille dans le code qui l'applique.
On ne stocke jamais la clé publique complète en OTP, seulement son empreinte SHA-256, pour économiser des fusibles. La clé complète vit dans l'en-tête du firmware, et la ROM vérifie que son empreinte correspond.
La clé privée, elle, ne doit jamais quitter un module matériel de sécurité ou un service de signature. Une clé privée dans un dépôt Git, même privé, compromet toute la gamme jusqu'à la fin de sa vie de support.
Anti-rollback, l'oubli le plus courant
Sans protection anti-rollback, votre démarrage sécurisé s'effondre au premier correctif publié.
Le scénario : vous corrigez une vulnérabilité critique en version 1.4. Un attaquant récupère la version 1.3, qui est signée avec votre vraie clé, la réinstalle, et exploite la faille corrigée. La signature est valide, la chaîne de confiance ne voit rien d'anormal.
La parade est un compteur de version monotone stocké dans un espace non réversible, généralement des fusibles OTP dédiés. Le chargeur refuse toute image dont le numéro de sécurité est inférieur au compteur.
Deux précautions dans la mise en œuvre. Le numéro de version de sécurité doit être distinct du numéro de version produit : on ne l'incrémente que sur un correctif de sécurité, sinon les fusibles disponibles sont épuisés en deux ans. Et le compteur ne doit être avancé qu'après confirmation que la nouvelle image démarre et fonctionne, jamais avant, sinon un échec de mise à jour bloque définitivement le retour à une version fonctionnelle.
La mise à jour, double banque ou swap
Le CRA impose un mécanisme de mise à jour. Deux architectures dominent.
Double banque : deux emplacements de taille identique, l'un actif, l'autre recevant la nouvelle image. Le chargeur bascule après vérification. C'est simple, robuste, et le retour arrière est immédiat, mais cela coûte deux fois la taille du firmware en flash.
Swap avec zone de travail : MCUboot échange les contenus en utilisant un secteur tampon, en journalisant chaque étape pour survivre à une coupure d'alimentation en cours d'échange. Plus économe en flash, nettement plus délicat, et l'usure du flash augmente puisque chaque mise à jour réécrit les deux emplacements.
Dans les deux cas, prévoyez le test de démarrage : la nouvelle image est marquée provisoire, doit se confirmer elle-même après un démarrage réussi, faute de quoi le chargeur revient à l'ancienne. Sans ce mécanisme, une mise à jour défectueuse déployée sur le parc entier est irrécupérable sans intervention physique.
Le débogage, à couper au bon moment
Une chaîne de confiance parfaite ne sert à rien si le port SWD ou JTAG reste ouvert : on lit la flash, on écrit dans la RAM, on contourne tout.
La désactivation est en général irréversible, ce qui pose un problème industriel réel : plus de retour d'analyse sur les cartes défaillantes du terrain. Les niveaux intermédiaires, du type RDP niveau 1 sur STM32, autorisent le débogage mais interdisent la lecture de la flash, au prix d'un effacement complet à toute tentative de passage en mode ouvert.
C'est un arbitrage entre sécurité et maintenabilité, à trancher avant la production, pas après.
Les erreurs qui annulent tout
| Erreur | Effet |
|---|---|
| Empreinte de clé en flash non verrouillée | L'attaquant remplace la clé et signe ce qu'il veut |
| Pas d'anti-rollback | Réinstallation d'une version vulnérable signée |
| Clé privée hors module matériel | Compromission de toute la gamme |
| Port de débogage ouvert en production | Contournement complet de la chaîne |
| Vérification après copie en RAM | Fenêtre d'attaque entre la copie et le contrôle |
| Chargeur non couvert par le SBOM | Vulnérabilité du chargeur invisible à la veille |
| Compteur avancé avant confirmation | Retour arrière impossible après un échec |
La cinquième ligne mérite un mot. Vérifier la signature d'une image déjà chargée en mémoire vive laisse un intervalle pendant lequel une attaque par injection de fautes, par exemple une impulsion sur l'alimentation, peut modifier le contenu entre le contrôle et l'exécution. Les implémentations sérieuses vérifient en place, puis contrôlent une seconde fois des points critiques après le saut.
Références
- MCUboot documentation, modes swap et overwrite, compteur de sécurité anti-rollback
- Arm, Platform Security Model, racine de confiance et chaîne de vérification
- STMicroelectronics, Introduction to STM32 security, AN5156, niveaux RDP et octets d'option
- NIST, SP 800-193, Platform Firmware Resiliency, protection, détection et récupération
Pour aller plus loin
Ces mécanismes deviennent concrets quand on a provisionné une carte réelle, brûlé des fusibles, et constaté qu'une erreur de provisionnement ne se rattrape pas. C'est ce que couvrent nos formations sur le développement et la sécurité avancée des systèmes embarqués.