- IoT et embarqué
- Cybersécurité
- Développement et outillage
Télémétrie IoT sécurisée
Une télémétrie MQTT durcie en trois étapes, jusqu’au TLS mutuel avec la clé privée de chaque objet dans un élément sécurisé ATECC608B
Contexte
SecureLink IoT était un projet de trois étudiants sur la sécurité des objets connectés, mené dans le cadre de la SAÉ 5.12 à l’IUT de Blagnac. J’ai piloté l’équipe et porté le volet MQTT ; mes deux coéquipiers ont traité LoRa avec un élément sécurisé, et les attaques Wi-Fi et Bluetooth.
L’objectif de ma partie : une télémétrie de capteurs qui reste confidentielle sur le réseau et que seul un objet authentique peut publier, même si un attaquant met la main sur son firmware. Je l’ai atteint en trois étapes, chacune comblant la faiblesse laissée par la précédente, et j’ai prouvé chaque étape par des captures et des tests.
Tout le projet est documenté sur un site que j’ai codé à la main, avec une analyse de paquets interactive, une simulation d’attaque, une analyse STRIDE par étape et la procédure de reproduction complète.
Architecture
Du capteur à l’écran, via un broker qui authentifie
Un durcissement en trois étapes
Chaque étape comble la faiblesse de la précédente, et chaque affirmation s’appuie sur une preuve.
Étape 1 Port 1883
MQTT en clair
Ni confidentialité, ni authentification
Le M5Go publie une charge utile JSON (température, humidité, pression) toutes les cinq secondes en TCP clair. N’importe quel client peut se connecter avec n’importe quel identifiant : une simple capture lit le topic et toutes les valeurs, et un attaquant actif peut modifier les mesures ou prendre la session avec un identifiant client dupliqué.
Preuve Wireshark : le topic m5go/env et la charge utile JSON sont lisibles dans la capture.
STRIDE
- Usurpation: exposé
- Falsification: exposé
- Répudiation: exposé
- Divulgation d’information: exposé
- Déni de service: exposé
- Élévation de privilèges: exposé
Étape 2 TLS 1.2 · port 8883
TLS mutuel, clé dans le firmware
Canal sécurisé, identité encore copiable
J’ai monté une PKI privée avec OpenSSL (une autorité de certification EC P-256, un certificat pour le broker et un certificat client par objet) et passé Mosquitto en TLS mutuel : clients anonymes refusés, certificat signé par l’AC exigé, et son nom commun utilisé comme nom d’utilisateur MQTT. Le trafic est désormais chiffré et authentifié dans les deux sens. Mais la clé privée est compilée dans le firmware : avec un adaptateur USB-UART et esptool, un dump du firmware la révèle et permet de cloner l’identité de l’objet.
Preuve Wireshark : uniquement des données applicatives TLS 1.2 ; le suivi du flux TCP ne montre que du texte chiffré.
STRIDE
- Usurpation: exposé
- Falsification: couvert
- Répudiation: exposé
- Divulgation d’information: couvert
- Déni de service: couvert
- Élévation de privilèges: exposé
Étape 3 ATECC608B · slot 8
TLS mutuel, clé dans l’élément sécurisé
Clé hors du firmware, identité liée à la puce
La clé de chaque objet est convertie en PKCS#8 DER, précédée de sa longueur et écrite dans le slot de données 8 d’un ATECC608B (416 octets, 13 blocs de 32) par un sketch de provisionnement ; le firmware ne la contient plus. Au démarrage, l’ESP32 vérifie la puce à l’adresse I²C 0x35, lit le slot, reconstruit la clé PEM et la confie à la pile TLS. Sans la puce, l’objet s’arrête ; avec une autre puce, le broker refuse la poignée de main.
Preuve Journal du broker : « bad signature » avec le mauvais élément sécurisé ; avec le bon, le TLS mutuel et l’abonnement aboutissent.
STRIDE
- Usurpation: atténué, avec une réserve
- Falsification: couvert
- Répudiation: atténué, avec une réserve
- Divulgation d’information: couvert
- Déni de service: couvert
- Élévation de privilèges: atténué, avec une réserve
Testé sur le banc
La dernière étape a été éprouvée face à ses modes de défaillance, pas seulement dans le cas nominal.
-
Élément sécurisé retiré
Le firmware ne trouve aucune puce à l’adresse 0x35 et s’arrête avant toute connexion réseau.
-
Mauvais élément sécurisé
La signature de la poignée de main ne correspond pas au certificat : le broker répond « bad signature » et ferme la connexion.
-
Matériel authentique
Le TLS mutuel aboutit ; le broker vérifie le certificat et acquitte l’abonnement à m5go/env.
-
Publisher et subscriber ensemble
Les mesures publiées toutes les cinq secondes s’affichent sur l’écran du subscriber via le canal chiffré.
Ce que j’ai fait
- Piloté le projet : découpage du travail en trois packs, planification et suivi dans ClickUp (Gantt et Kanban), et deux replanifications quand les échéances ont changé.
- Construit la chaîne de télémétrie : un publisher M5Go avec une unité ENV II (SHT30 et BMP280), un broker Mosquitto et un subscriber M5Stack qui affiche les mesures.
- Mis en place la PKI avec OpenSSL : une autorité de certification EC P-256, un certificat pour le broker et un certificat client par objet (m5go-pub et m5sub-display).
- Configuré Mosquitto en TLS mutuel sur le port 8883 : clients anonymes refusés, certificat client exigé, son nom commun utilisé comme nom d’utilisateur MQTT.
- Écrit les sketches de diagnostic, de provisionnement et les clients (C++ sous Arduino, bibliothèque SparkFun ATECCX08a) qui stockent chaque clé dans le slot 8 et la reconstruisent au démarrage.
- Prouvé chaque étape par des captures Wireshark, une analyse STRIDE et des tests de défaillance (puce retirée, mauvaise puce).
- Codé le site du projet à la main, et aidé mes coéquipiers à intégrer l’élément sécurisé à leur liaison LoRa.
Livrables
- Le site du projet, qui fait office de rapport final : une page interactive par étape, un analyseur de paquets et une simulation d’attaque
- Une analyse de menaces STRIDE pour chaque étape
- Une procédure de reproduction pas à pas, de la création de l’autorité de certification au flashage des objets
- Le code source complet : sept sketches Arduino en C++ et la configuration du broker
- Une vidéo de présentation et un diaporama
Piloter le projet
En plus de mon volet, j’ai piloté l’équipe de trois, du premier planning en octobre 2025 au rapport final en janvier 2026.
Trois packs de travail, un par membre
-
Attaques sans fil et transport LoRa
Flipper Zero et M5StickC Plus2 comparés par des tests Wi-Fi et Bluetooth, puis la couche de transport LoRa.
-
Élément sécurisé et chiffrement LoRa
L’ATECC608B étudié en profondeur (protections physiques, générateur d’aléa, I²C), puis utilisé pour chiffrer et signer les messages LoRa.
-
MQTT, en trois étapes (le mien)
Texte clair, puis TLS mutuel avec une PKI privée, puis la clé privée dans l’élément sécurisé.
Un planning qui a changé deux fois
-
Octobre 2025
Rotation des packs
Chaque membre devait changer de kit matériel toutes les deux semaines, pour travailler sur toutes les parties du projet.
-
Échéance avancée au 5 décembre
Spécialisation
Beaucoup moins de temps : fin des rotations, chacun a gardé son pack jusqu’au bout, pour aller plus loin en moins de temps.
-
Rapport final repoussé au 23 janvier
D’abord le MVP, ensuite la documentation
La soutenance du 5 décembre s’est concentrée sur un MVP fonctionnel ; les semaines gagnées ont servi au rapport et au site.
Outils et décisions
- ClickUp pour le planning et les tâches (Gantt, Kanban), GitHub pour le code et son historique, Google Drive pour les documents.
- Le cahier des charges imposait un CMS. Après un essai avec WordPress et Divi, j’ai codé le site à la main (HTML, Tailwind CSS, JavaScript) pour des démonstrations interactives et aucune interface d’administration à attaquer ; mes coéquipiers ont fait de même.
- Avec du recul : une phase de recherche plus longue sur l’élément sécurisé, en amont, nous aurait fait gagner du temps.
Problèmes résolus
-
Une identité pré-provisionnée trop rigide pour les tests
L’ATECC608B-TNGTLSU (Trust&GO) est livré avec ses propres clés et certificats, trop complexes à exploiter pendant le développement. J’ai stocké nos propres clés dans le slot de données généraliste 8, pour pouvoir les régénérer aussi souvent que les tests l’exigeaient.
-
Des bibliothèques qui ne pilotaient pas la puce
Ni ArduinoECCX08 ni CryptoAuthLib de Microchip ne fonctionnaient avec la puce dans notre environnement. Après de nombreux essais, la bibliothèque SparkFun ATECCX08a y est parvenue, ce qui a débloqué l’intégration, pour mon étape comme pour la partie LoRa du projet.
-
Une clé de longueur variable dans des blocs fixes de 32 octets
Les clés EC en DER varient légèrement en longueur, et la puce ne lit et n’écrit que par blocs de 32 octets. J’ai préfixé la clé de sa longueur sur deux octets (big-endian) et relu le slot en entier, pour que le firmware sache où la clé se termine et où commence le remplissage.
Limites et suites
Ce que ce lab ne fait pas encore, et ce qu’un objet en production demanderait.
-
La clé est lue en RAM
L’ESP32 charge la clé en RAM pour sa pile TLS logicielle : le stockage est protégé, l’exécution ne l’est pas.
Signer la poignée de main dans la puce (PKCS#11 ou callbacks ECDSA), pour que la clé n’en sorte jamais.
-
Une brève exposition au démarrage
La clé existe un instant en RAM pendant le démarrage, avant d’être confiée au moteur TLS.
Effacer les tampons après usage et activer le Secure Boot de l’ESP32.
-
Un bus I²C non chiffré
Le bus entre l’ESP32 et la puce n’est pas chiffré : un attaquant déterminé pourrait l’écouter.
Utiliser un élément sécurisé intégré à la carte, comme celui du M5Stack Core2 for AWS IoT, pour supprimer le câblage exposé.
Compétences mobilisées
Chaque compétence renvoie à la carte des compétences de l’accueil.