{"id":417,"date":"2021-06-14T18:37:37","date_gmt":"2021-06-14T16:37:37","guid":{"rendered":"https:\/\/www.iot-embedded.de\/iot-2021\/?p=417"},"modified":"2021-06-14T18:43:21","modified_gmt":"2021-06-14T16:43:21","slug":"ota-updates-mit-signierten-update-artefakten","status":"publish","type":"post","link":"https:\/\/www.iot-embedded.de\/iot-2021\/beverage-monitoring\/ota-updates-mit-signierten-update-artefakten\/","title":{"rendered":"OTA Updates mit signierten Update Artefakten"},"content":{"rendered":"\n<p>In diesem Beitrag m\u00f6chten wir uns signierte Updates anschauen. Das hei\u00dft, an das Artefakt werden extra Information angeh\u00e4ngt, welche es uns erlauben die Validit\u00e4t und den Ursprung des Artefaktes zu \u00fcberpr\u00fcfen. Diese Funktionalit\u00e4t wird ben\u00f6tigt, um sicherzustellen, dass nur wir selbst Updates auf unseren ESP8622 durchf\u00fchren und kein Unbefugter Zugriff erlangen kann. Hierf\u00fcr ben\u00f6tigen wir:<\/p>\n\n\n\n<ul><li>Eine Umgebung f\u00fcr die Arduino Entwicklung: Wir nutzen das, wie bereits in <a href=\"https:\/\/www.iot-embedded.de\/iot-2021\/beverage-monitoring\/aufsetzen-verschiedener-entwicklungsumgebungen-fuer-den-esp8266\/\">diesem<\/a> Beitrag beschrieben, PlatformIO CLI Tool<\/li><li>Das Beispiel Projekt zum simplen OTA Update und den dort benutzten Code als Grundlage<\/li><li>Ein Schl\u00fcsselpaar aus privatem und \u00f6ffentlichem Schl\u00fcssel: Diese generieren wir mit mit <code>openssl<\/code><\/li><li>Ein Tool zum Signieren von gebauten Artefakten: Das bekommen wir vom offiziellen Arduino Repository<\/li><\/ul>\n\n\n\n<p>Zu Beginn erweitern wir das simple OTA Projekt um die Verifizierung einer Signatur beim Laden von neuen Artefakten vom Update Server. In unserem Fall Kopieren wir das alte Projekt, wer das alte Projekt nicht hat kann auch alternativ ein neues erstellen<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cp -r ota_project_simple ota_project_signing\n$ # Aufgrund meiner Ordnerstruktur schiebe ich das Projekt in den richtigen \u00dcberordner\n$ mv ota_project_signing ..\/signing-ota\/\n$ # Ich kopiere au\u00dferdem noch meine WiFi Configuration\n$ cp ota_project_simple\/src\/secret.h ..\/signing-ota\/ota_project_signing\/src\n$\n$ # Alternativ kann auch ein neues Projekt erstellt werden\n$ mkdir signing-ota\n$ cd signing-ota\n$ pio init --board nodemcuv2<\/code><\/pre>\n\n\n\n<p>Nun sollte <code>src\/main.cpp<\/code> den Code aus dem letzten Beitrag beinhalten, wenn dies nicht der Fall ist, kopieren wir ihn einfach hinein:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/**\n   httpUpdate.ino\n\n    Created on: 27.11.2015\n\n*\/\n\n#include &lt;Arduino.h&gt;\n\n#include &lt;ESP8266WiFi.h&gt;\n#include &lt;ESP8266WiFiMulti.h&gt;\n\n#include &lt;ESP8266HTTPClient.h&gt;\n#include &lt;ESP8266httpUpdate.h&gt;\n\n#include \"secret.h\"\n\nESP8266WiFiMulti WiFiMulti;\n\nvoid setup() {\n\n  Serial.begin(115200);\n  \/\/ Serial.setDebugOutput(true);\n\n  Serial.println();\n  Serial.println();\n  Serial.println();\n\n  for (uint8_t t = 4; t &gt; 0; t--) {\n    Serial.printf(\"&#091;SETUP] WAIT %d...\\n\", t);\n    Serial.flush();\n    delay(1000);\n  }\n\n  WiFi.mode(WIFI_STA);\n  WiFiMulti.addAP(APSSID, APPSK);\n\n\n}\n\nvoid update_started() {\n  Serial.println(\"CALLBACK:  HTTP update process started\");\n}\n\nvoid update_finished() {\n  Serial.println(\"CALLBACK:  HTTP update process finished\");\n}\n\nvoid update_progress(int cur, int total) {\n  Serial.printf(\"CALLBACK:  HTTP update process at %d of %d bytes...\\n\", cur, total);\n}\n\nvoid update_error(int err) {\n  Serial.printf(\"CALLBACK:  HTTP update fatal error code %d\\n\", err);\n}\n\n\nvoid loop() {\n  \/\/ wait for WiFi connection\n  if ((WiFiMulti.run() == WL_CONNECTED)) {\n\n    WiFiClient client;\n\n    \/\/ The line below is optional. It can be used to blink the LED on the board during flashing\n    \/\/ The LED will be on during download of one buffer of data from the network. The LED will\n    \/\/ be off during writing that buffer to flash\n    \/\/ On a good connection the LED should flash regularly. On a bad connection the LED will be\n    \/\/ on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second\n    \/\/ value is used to put the LED on. If the LED is on with HIGH, that value should be passed\n    ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);\n\n    \/\/ Add optional callback notifiers\n    ESPhttpUpdate.onStart(update_started);\n    ESPhttpUpdate.onEnd(update_finished);\n    ESPhttpUpdate.onProgress(update_progress);\n    ESPhttpUpdate.onError(update_error);\n\n    t_httpUpdate_return ret = ESPhttpUpdate.update(client, \"192.168.178.123\", 8080, \"file.bin\");\n\n    switch (ret) {\n      case HTTP_UPDATE_FAILED:\n        Serial.printf(\"HTTP_UPDATE_FAILD Error (%d): %s\\n\", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());\n        break;\n\n      case HTTP_UPDATE_NO_UPDATES:\n        Serial.println(\"HTTP_UPDATE_NO_UPDATES\");\n        break;\n\n      case HTTP_UPDATE_OK:\n        Serial.println(\"HTTP_UPDATE_OK\");\n        break;\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>Bevor wir tats\u00e4chlich den Code \u00e4ndern, schauen wir uns an welche Signatur die Arduino Bibliothek erwartet und wie wir diese erstellen k\u00f6nnen. Das Artefakt selbst wird erweitert durch ein SHA256 Hash des eigentlichen Artefakts, welcher durch einen RSA Key signiert wird. Letztendlich wird die L\u00e4nge der Signatur als uint32_t, also einem unsigned integer mit der Gr\u00f6\u00dfe 32 bit, an das Ende geh\u00e4ngt. Die finale Datei hat folgendes Layout:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>| Unsigned Plain Artefakt | Signed Hash | uint32_t length |<\/code><\/pre>\n\n\n\n<p>Das Signieren selbst kann eigentlich die Arduino IDE f\u00fcr uns \u00fcbernehmen, sobald wir die ben\u00f6tigten Schl\u00fcssel bereitstellen. Da wir allerdings das PlatformIO CLI Tool nutzen m\u00fcssen wir f\u00fcr diese Projekt selbst signieren. (Vielleicht kann das CLI Tool auch Signaturen selbst\u00e4ndig erstellen, ich habe aber nicht herausgefunden ob und wie)<\/p>\n\n\n\n<p>Die ben\u00f6tigten Schl\u00fcssel erstellen wir mit Hilfe von <code>openssl<\/code>. Wir erstellen innerhalb des Projekt Verzeichnisses einen neuen Ordner f\u00fcr unsere Keys, wechseln in dieses neue Verzeichnis und erstellen die ben\u00f6tigten RSA-2048 Keys. Eigentlich w\u00e4ren auch RSA-4096 m\u00f6glich, aber hierzu gibt es in einem sp\u00e4teren Blogbeitrag noch weiter Informationen.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ tree\n.\n\u251c\u2500\u2500 include\n\u2502&nbsp;&nbsp; \u2514\u2500\u2500 README\n\u251c\u2500\u2500 lib\n\u2502&nbsp;&nbsp; \u2514\u2500\u2500 README\n\u251c\u2500\u2500 platformio.ini\n\u251c\u2500\u2500 src\n\u2502&nbsp;&nbsp; \u251c\u2500\u2500 main.cpp\n\u2502&nbsp;&nbsp; \u2514\u2500\u2500 secret.h\n\u251c\u2500\u2500 test\n\u2502&nbsp;&nbsp; \u2514\u2500\u2500 README\n\u2514\u2500\u2500 update_server.sh\n$ mkdir keys\n$ cd keys\n$ openssl genrsa -out private.key 2048\n$ openssl rsa -in private.key -outform PEM -pubout -out public.key\n$ ls\nprivate.key\npublic.key<\/code><\/pre>\n\n\n\n<p>Als n\u00e4chstes laden wir das Signier-Tool herunter welches wir in einem neuen <code>tool<\/code> Ordner abspeichern. Des Weiteren erstellen wir ein <code>Makefile<\/code>, welches es uns vereinfacht Artefakte direkt nach dem Bau zu signieren.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ tree\n.\n\u251c\u2500\u2500 include\n\u2502&nbsp;&nbsp; \u2514\u2500\u2500 README\n\u251c\u2500\u2500 keys\n\u2502&nbsp;&nbsp; \u251c\u2500\u2500 private.key\n\u2502&nbsp;&nbsp; \u2514\u2500\u2500 public.key\n\u251c\u2500\u2500 lib\n\u2502&nbsp;&nbsp; \u2514\u2500\u2500 README\n\u251c\u2500\u2500 platformio.ini\n\u251c\u2500\u2500 src\n\u2502&nbsp;&nbsp; \u251c\u2500\u2500 main.cpp\n\u2502&nbsp;&nbsp; \u2514\u2500\u2500 secret.h\n\u251c\u2500\u2500 test\n\u2502&nbsp;&nbsp; \u2514\u2500\u2500 README\n\u2514\u2500\u2500 update_server.sh\n$ mkdir tools\n$ curl https:\/\/raw.githubusercontent.com\/esp8266\/Arduino\/master\/tools\/signing.py &gt; tools\/signing.py\n$ touch Makefile\n$ # F\u00fcllen des Makefiles, s.t.\n$ cat Makefile\nall:\n        pio run\n        python tools\/signing.py --mode sign \\\n            --publickey keys\/public.key \\\n            --privatekey keys\/private.key \\\n            --bin .\/.pio\/build\/nodemcuv2\/firmware.bin \\\n            --out .\/.pio\/build\/nodemcuv2\/firmware.bin.signed<\/code><\/pre>\n\n\n\n<p>Wenn nun <code>make<\/code> auf der Kommandozeile ausgef\u00fchrt wird, baut das Artefakt und wird im Nachhinein mit den soeben erstellen Schl\u00fcsseln signiert. Beim Erstellen des Makefiles muss man aufpassen. Makefiles sind sehr anf\u00e4llig f\u00fcr falsch gesetzte Leerzeichen. Nach dem Ziel <code>all:<\/code> m\u00fcssen die gew\u00fcnschten Kommandos einen Abstand von 8 Leerzeichen haben, zudem m\u00fcssen multiline Kommandos mit dem Zeichen <code>\\<\/code> ausgeschrieben werden, wobei nach dem <code>\\<\/code> kein Leerzeichen mehr stehen darf.<\/p>\n\n\n\n<p>Somit haben wir nun die M\u00f6glichkeit unsere Artefakte zu Signieren. Nun m\u00fcssen wir noch den Code anpassen, so dass auch \u00fcberpr\u00fcft wird, ob das gesendete Artefakt valide ist. Der Code braucht dabei unseren Public Key, denn bei asynchroner Kryptographie kann eine Nachricht mit dem privaten Key signiert werden und sp\u00e4ter mit einem \u00f6ffentlichen Schl\u00fcssel verifiziert werden. Wenn wir gleich den Code betrachten sehen wir des Weiteren ein paar Pr\u00e4prozessor Statements wie <code>if MANUAL_SIGNING<\/code>, diese werden ben\u00f6tigt, wenn die Arduino IDE den Code von sich selbst aus signiert, dann wird unser Zusatz nicht mit in das wirkliche kompilierte Artefakt eingebunden, da die Arduino IDE dies schon von sich ausmacht. Da wir allerdings das PlatformIO CLI Tool nutzen setzen wir <code>MANUAL_SIGNING<\/code> auf 1.<\/p>\n\n\n\n<p>Der erste Teil, den wir hinzuf\u00fcgen ist, eine Pr\u00e4prozessor Definition, unser \u00f6ffentlicher Schl\u00fcssel, und ein paar Deklarationen, die wir sp\u00e4ter noch nutzen:<\/p>\n\n\n\n<ul><li>ein Objekt f\u00fcr den \u00f6ffentlichen Schl\u00fcssel<\/li><li>ein Objekt f\u00fcr einen SHA256 Hash<\/li><li>ein Objekt f\u00fcr das verifizieren der Signatur<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>...\n#include &lt;ESP8266HTTPClient.h&gt;\n#include &lt;ESP8266httpUpdate.h&gt;\n\n#include \"secret.h\"\n\n+ #define MANUAL_SIGNING 1\n+\n+ const char pubkey&#091;] PROGMEM = R\"EOF(\n+ -----BEGIN PUBLIC KEY-----\n+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArSf4W99aciiCoDH427w5\n+ FE95jL7R\/2tC4pYOyZWq3yTVl0Kq6y33L9GgLS6kCILLBi0KSGykOQX3kEzOnZa2\n+ nesjLZXwTxWeRlq1f0OcRMXXNjbVg+kDepKoinW3ch1fD29sLpzUgtNwIt7fAahe\n+ eZGIsytNMnLPRUf0mjKbWe9xgyT88EETPLzsJ9Lw+CJUBxxenmzh5XbU8H\/VwUJq\n+ Kjd2ta8jnK6htBPPMvdYpTpCqE+QY4Tp8VmKv2hnCrb8XlIyEfD5y+y5qrIF4Bg1\n+ vRKQD82QmNZon2ASuqPUz45ZQwVqTQSt8Pg4QI7sViO5LTmJuqAAQecHVEZ8ae3J\n+ BwIDAQAB\n+ -----END PUBLIC KEY-----\n+ )EOF\";\n+ #if MANUAL_SIGNING\n+ BearSSL::PublicKey *signPubKey = nullptr;\n+ BearSSL::HashSHA256 *hash;\n+ BearSSL::SigningVerifier *sign;\n+ #endif\n\n\nESP8266WiFiMulti WiFiMulti;\n\nvoid setup() {\n...<\/code><\/pre>\n\n\n\n<p>Dies Objekte nutzen wir sp\u00e4ter in der <code>setup<\/code> Methode, um beim sp\u00e4teren Update die Signatur des Artefaktes mit Hilfe unseres \u00f6ffentlichen Schl\u00fcssels auch \u00fcberpr\u00fcfen zu k\u00f6nnen.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\n  for (uint8_t t = 4; t &gt; 0; t--) {\n    Serial.printf(\"&#091;SETUP] WAIT %d...\\n\", t);\n    Serial.flush();\n    delay(1000);\n  }\n\n  WiFi.mode(WIFI_STA);\n  WiFiMulti.addAP(APSSID, APPSK);\n\n  + #if MANUAL_SIGNING\n  + signPubKey = new BearSSL::PublicKey(pubkey);\n  + hash = new BearSSL::HashSHA256();\n  + sign = new BearSSL::SigningVerifier(signPubKey);\n  + #endif\n\n}\n...<\/code><\/pre>\n\n\n\n<p>Nun m\u00fcssen wir zuallerletzt dem Updater signalisieren, dass wir die Signatur \u00fcberpr\u00fcfen m\u00f6chten. Zudem \u00e4ndern wir die URL, welche der Updater anfragt, sodass das signierte Artefakt geladen wird.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\nvoid loop() {\n  \/\/ wait for WiFi connection\n  if ((WiFiMulti.run() == WL_CONNECTED)) {\n\n    WiFiClient client;\n\n    + #if MANUAL_SIGNING\n    + \/\/ Ensure all updates are signed appropriately.  W\/o this call, all will be accepted.\n    + Update.installSignature(hash, sign);\n    + #endif\n... ACHTUNG\n    - t_httpUpdate_return ret = ESPhttpUpdate.update(client, \"192.168.178.123\", 8080, \"file.bin\");\n    + t_httpUpdate_return ret = ESPhttpUpdate.update(client, \"192.168.178.123\", 8080, \"firmware.bin.signed\");\n...<\/code><\/pre>\n\n\n\n<p>Nun wird der ESP8266 jedes neue Artefakt auf eine valide Signatur \u00fcberpr\u00fcfen. Um dies auszuprobieren, m\u00fcssen wir nun diesen Code flashen und einen Update Server bereitstellen mit einem validen signierten Artefakt. Daher k\u00fcmmern wir uns erst einmal um das valide signierte Artefakt. Als Beispiel Artefakt nutzen wir wieder das Blink Beispiel aus dem Blogbeitrag zu den Entwicklungsumgebungen. Um dies zu Signieren kopieren wir unser erstelltes Makefile in den Ordner in welchem wir den Code zum Blink Beispiel haben, sowie den Ordner <code>.\/tools<\/code> in welchem das Signier-Tool liegt und <code>.\/keys<\/code> in welchem unsere Schl\u00fcssel liegen. Danach gehen wir in den root Ordner des Projektes, f\u00fchren <code>make<\/code> aus und starten wieder einen HTTP Server.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cp Makefile ..\/..\/ide\/blink_example\n$ cp -r tools  ..\/..\/ide\/blink_example\n$ cp -r keys  ..\/..\/ide\/blink_example\n$ cd ..\/..\/ide\/blink_example\n$ python -m http.server --directory .\/.pio\/build\/nodemcuv2\/ --bind 192.168.178.123 8080<\/code><\/pre>\n\n\n\n<p>Um den HTTP Server zu testen k\u00f6nnten wir wieder mit <code>curl<\/code> eine GET Anfrage schicken und mit <code>diff<\/code> oder <code>sha256sum<\/code> \u00fcberpr\u00fcfen, ob wir die richtige Datei erhalten. Falls etwas nicht funktioniert, ist dies immer ein guter Anhaltspunkt, um m\u00f6gliche Fehler auszuschlie\u00dfen.<\/p>\n\n\n\n<p>W\u00e4hrend der Update Server nun l\u00e4uft, k\u00f6nnen wir zur\u00fcck in das urspr\u00fcngliche Projekt gehen, welches die signierten Artefakte beinhaltet, und mit PlatformIO den Code kompilieren und flashen. Wir erwarten nun, dass wie beim einfachen OTA Beispiel der Updater zuerst wartet und dann eine Anfrage an unseren Update Server stellt. Die erhaltene Datei wird dann \u00fcberpr\u00fcft, sollte als g\u00fcltig empfunden werden und mit einem Neustart des Mikrocontrollers ausgef\u00fchrt werden.<\/p>\n\n\n\n<p>WICHTIG: Der HTTP Server muss auch von au\u00dfen erreichbare sein, d.h. der TCP Port 8080 muss ge\u00f6ffnet sein.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cd ${OTA_PROJECT_SIGNING}\n$ pio run --target upload; pio device monitor -b 115200\nProcessing nodemcuv2 (platform: espressif8266; board: nodemcuv2; framework: arduino)\n-----------------------------------------------------------------------------------------------------------------------\n...\nRAM:   &#091;===       ]  34.3% (used 28072 bytes from 81920 bytes)\nFlash: &#091;===       ]  32.1% (used 335628 bytes from 1044464 bytes)\n..\nWriting at 0x00000000... (6 %)\n...\nWriting at 0x0003c000... (100 %)\nWrote 339776 bytes (249783 compressed) at 0x00000000 in 21.9 seconds (effective 123.9 kbit\/s)...\nHash of data verified.\n\nLeaving...\nHard resetting via RTS pin...\n============================================ &#091;SUCCESS] Took 25.55 seconds ============================================\n...\n&#091;SETUP] WAIT 3...\n&#091;SETUP] WAIT 2...\n&#091;SETUP] WAIT 1...\nCALLBACK:  HTTP update process started\nCALLBACK:  HTTP update process at 0 of 261748 bytes..\n...\nCALLBACK:  HTTP update process at 261748 of 261748 bytes...\nCALLBACK:  HTTP update process finished\n\n ets Jan  8 2013,rst cause:2, boot mode:(3,6)\n\nload 0x4010f000, len 3584, room 16\ntail 0\nchksum 0xb0\ncsum 0xb0\nv2843a5ac\n@cp:0\nld<\/code><\/pre>\n\n\n\n<p>Wie man in dem Abschnitt aus dem gek\u00fcrzten Log Output sieht, war das Update erfolgreich. Aber um sicher zu gehen, dass ein unsigniertes Update oder eine invalide Signatur nicht funktioniert, sollten wir noch \u00fcberpr\u00fcfen, ob das Update fehlschl\u00e4gt, wenn wir ein invalides Artefakt bereitstellen. Hierf\u00fcr k\u00f6nnen wir im Build Ordner des Blink Projektes zum einen die unsignierte Version umbenennen, so dass der HTTP Server dies zur\u00fcckgibt.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cd ${BLINK_EXAMPLE}\n$ cd .pio\/build\/nodemcuv2\n$ cp firmware.bin firmware.bin.signed\n$ cd ${OTA_PROJECT_SIGNING}\n$ pio run --target upload; pio device monitor -b 115200\n...\nHTTP_UPDATE_FAILD Error (12): Update error: ERROR&#091;12]: Signature verification failed\n...<\/code><\/pre>\n\n\n\n<p>Unsignierte Artefakte werden also nicht mehr akzeptiert. Unser momentaner Code w\u00fcrde nach dem fehlgeschlagenen Update einfach wieder probieren zu updaten. Das ist im Betrieb nicht gew\u00fcnscht aber hier als Proof-of-Concept k\u00f6nnen wir das vorerst so lassen. Was wir allerdings noch \u00fcberpr\u00fcfen k\u00f6nnen w\u00e4re eine invalide Signatur. Um ein Artefakt mit invalider Signatur zu erhalten k\u00f6nnten wir entweder ein neues Schl\u00fcsselpaar erstellen und hiermit signieren oder das bestehende Artefakt in minimaler Weise ver\u00e4ndern. Zur Erinnerung hier das Layout:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>| Unsigned Plain Artefakt | Signed Hash | uint32_t length |<\/code><\/pre>\n\n\n\n<p>Nun m\u00fcssen wir die Signatur ver\u00e4ndern. Um auch wirklich zu zeigen, dass die Signatur nur minimal ge\u00e4ndert werden muss, um ein invalides Artefakt zu erhalten, wollen wir nun nur genau ein Byte des Artefaktes \u00e4ndern. Theoretisch gesehen ist es egal, wo wir das Byte \u00e4ndern, da entweder die Signatur invalide wird, die L\u00e4nge der Signatur nicht mehr stimmt, oder der SHA256 Hash sich unterscheidet.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cd ${blink_example}\n$ make\n$ cd .pio\/build\/nodemcuv2<\/code><\/pre>\n\n\n\n<p>Um ein Byte zu \u00e4ndern, \u00f6ffnen wir das Artefakt mit VIM. WICHTIG: Die Datei mit der Flagge <code>-b<\/code> \u00f6ffnen, ansonsten erwartet VIM UTF-8 encoding anstatt einer bin\u00e4re Datei, hierdurch w\u00fcrde das Umwandeln in HEX nicht richtig funktionieren. F\u00fcr dieses Beispiel \u00e4ndern wir nun wirklich die eigentliche Signatur, welche an das Artefakt angeh\u00e4ngt wurde.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ vim -b firmware.bin.signed<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\n1   &lt;e9&gt;^A^B@\\&lt;f4&gt;^P@^@&lt;f0&gt;^P@^@^N^@^@^@^P&lt;ff&gt;?^@ &lt;ff&gt;?^@^P^@^@^\\K^@@^P^P^@^@&lt;cc&gt;$^@@^H\n    ^P^@^@^@^@&lt;f0&gt;&lt;bf&gt;&lt;ff&gt;^?^@^@^@^@^@&lt;c0&gt;&lt;ff&gt;&lt;ff&gt;&lt;ff&gt;^_&lt;f0&gt;&lt;ff&gt;&lt;ff&gt;?&lt;ff&gt;^O^@^@^@&lt;f0&gt;&lt;f\n    f&gt;&lt;ff&gt;&lt;98&gt;&lt;f0&gt;^P@^@&lt;80&gt;&lt;fe&gt;?^@&lt;80&gt;^@^@^@^@&lt;ff&gt;?^@J^@@&lt;a8&gt;&lt;de&gt;^@@LJ^@@^@^G^@`^@^@^@&lt;\n    80&gt;&lt;e8&gt;+^@@&lt;f0&gt;0^@@&lt;a0&gt;\/^@@&lt;b7&gt;^]&lt;c1&gt;^D^@^R^@`^@&lt;ee&gt;&lt;ff&gt;&lt;9f&gt;&lt;80&gt;^R^@`^@^P^@&lt;eb&gt;|^R^\n    @`&lt;88&gt;&lt;dc&gt;^@@\" &lt;ff&gt;?^D &lt;ff&gt;?6 &lt;ff&gt;?r &lt;ff&gt;?&lt;90&gt; &lt;ff&gt;?^R&lt;c1&gt;&lt;f0&gt;1&lt;d9&gt;&lt;ff&gt;     1&lt;c9&gt;!&lt;\n    d9&gt;^Q&lt;cd&gt;^B&lt;d1&gt;&lt;d7&gt;&lt;ff&gt;9^B!&lt;d6&gt;&lt;ff&gt;A&lt;d6&gt;&lt;ff&gt;)^\\\"-^@^A&lt;d5&gt;&lt;ff&gt;&lt;c0&gt;^@^@(^M^H1\"&lt;d2&gt;^P)\n    ^M(^L&lt;d8&gt;^Q^&#091;29^L\"^B^@&lt;c8&gt;!^R&lt;c1&gt;^P^M&lt;f0&gt;^@1&lt;ce&gt;&lt;ff&gt;^R&lt;c1&gt;&lt;e0&gt;:\"^LD&lt;8b&gt;1&lt;c9&gt;a q^A&lt;c\n    9&gt;&lt;ff&gt;&lt;c0&gt;^@^@&lt;cd&gt;^B&lt;fc&gt;^B\"&lt;a0&gt;v\"A^@,R\"A^A&lt;^B\"A^B&lt;&lt;82&gt;\"A^C\"&lt;a0&gt;x\"A^D8!^L&lt;a2&gt;\"A^E^P!\n     &lt;c2&gt;A^F^A&lt;be&gt;&lt;ff&gt;&lt;c0&gt;^@^@&lt;86&gt;^@^@^@^L^\\^Hq-^L&lt;c8&gt;a^R&lt;c1&gt; ^M&lt;f0&gt;^@^@^@^R&lt;c1&gt;&lt;e0&gt;&lt;d9\n    &gt;Q&lt;8b&gt;1&lt;dd&gt;^B^L&lt;84&gt;\"&lt;d2&gt;^P   q&lt;c2&gt;a^F&lt;e2&gt;a^D^A&lt;b0&gt;&lt;ff&gt;&lt;c0&gt;^@^@V&lt;e2&gt;^F1&lt;b1&gt;&lt;ff&gt;&lt;cd&gt;^\n    B:&lt;dd&gt;&lt;ed&gt;^B^F^T^@^@-^M=^A^L&lt;84&gt;&lt;e9&gt;^A&lt;e9&gt;^Q^A&lt;a8&gt;&lt;ff&gt;&lt;c0&gt;^@^@&lt;fc&gt;^BA&lt;aa&gt;&lt;ff&gt;8^A&lt;8b\n NORMAL  firmware.bin.signed                        unix | utf-8 | no ft    0%    1:1<\/code><\/pre>\n\n\n\n<p>Wie wir sehen, ist die Datei voller unverst\u00e4ndlicher Zeichen, wenn wir hier etwas \u00e4ndern, kann es sein, dass mehr oder weniger als ein Byte ge\u00e4ndert wird. Daher nutzen wir <code>xxd<\/code> um die Datei in Hexadezimalen angezeigt zu bekommen. Wir tippen in VIM:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>:%!xxd<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\n00000000: e901 0240 5cf4 1040 00f0 1040 000e 0000  ...@\\..@...@....\n00000010: 0010 ff3f 0020 ff3f 0010 0000 1c4b 0040  ...?. .?.....K.@\n00000020: 1010 0000 cc24 0040 0810 0000 0000 f0bf  .....$.@........\n00000030: ff7f 0000 0000 00c0 ffff ff1f f0ff ff3f  ...............?\n00000040: ff0f 0000 00f0 ffff 98f0 1040 0080 fe3f  ...........@...?\n00000050: 0080 0000 0000 ff3f 004a 0040 a8de 0040  .......?.J.@...@\n00000060: 4c4a 0040 0007 0060 0000 0080 e82b 0040  LJ.@...`.....+.@\n00000070: f030 0040 a02f 0040 b71d c104 0012 0060  .0.@.\/.@.......`\n00000080: 00ee ff9f 8012 0060 0010 00eb 7c12 0060  .......`....|..`\n00000090: 88dc 0040 2220 ff3f 0420 ff3f 3620 ff3f  ...@\" .?. .?6 .?\n000000a0: 7220 ff3f 9020 ff3f 12c1 f031 d9ff 0931  r .?. .?...1...1\n000000b0: c921 d911 cd02 d1d7 ff39 0221 d6ff 41d6  .!.......9.!..A.\n000000c0: ff29 1c22 2d00 01d5 ffc0 0000 280d 0831  .).\"-.......(..1\n000000d0: 22d2 1029 0d28 0cd8 111b 3239 0c22 0200  \"..).(....29.\"..\n000000e0: c821 12c1 100d f000 31ce ff12 c1e0 3a22  .!......1.....:\"\n000000f0: 0c44 8b31 c961 0971 01c9 ffc0 0000 cd02  .D.1.a.q........\n00000100: fc02 22a0 7622 4100 2c52 2241 013c 0222  ..\".v\"A.,R\"A.&lt;.\"\n...<\/code><\/pre>\n\n\n\n<p>Nun gehen wir an das Ende der Datei durch das Dr\u00fccken der Taste <code>G<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\n0003fdd0: 4afb 82d9 76c5 206b 985f 801b cdd5 f4e1  J...v. k._......\n0003fde0: 42c2 2e32 fcf1 bb99 8125 7112 a577 88cd  B..2.....%q..w..\n0003fdf0: 40b3 4de4 ae68 8c11 902a 552b bd86 94a0  @.M..h...*U+....\n0003fe00: 5b57 c34b cd19 7d7e 9e41 e7e6 3e2b 0e7c  &#091;W.K..}~.A..&gt;+.|\n0003fe10: 1116 4711 7094 27f6 4162 0d7c 60d3 c951  ..G.p.'.Ab.|`..Q\n0003fe20: bfb5 b043 57f4 f943 53b4 4f3c dfc8 c250  ...CW..CS.O&lt;...P\n0003fe30: e746 00c6 419a 42a8 05f5 0f25 5049 556a  .F..A.B....%PIUj\n0003fe40: 612a f185 b242 9407 2de9 bec2 0e86 f7f5  a*...B..-.......\n0003fe50: 195d f87a 321b e15e 6fff 3d16 582d cb03  .].z2..^o.=.X-..\n0003fe60: 6664 01bb 55b7 6f52 20ce 04e0 d28f eee8  fd..U.oR .......\n0003fe70: 0001 0000                                ....\n          ^^^^ ^^^^<\/code><\/pre>\n\n\n\n<p>Um nun die Signatur zu finden, m\u00fcssen wir die L\u00e4nge eines uint32_t wissen. Diese ist 32 Bit also 8 Bytes. Ein Hexadezimale Tuple z.B. <code>fd<\/code> ist ein Byte. Zudem wissen wir, dass die L\u00e4nge ganz am Ende der Datei ist. D.h. <code>0001 0000<\/code> ist die L\u00e4nge der Signatur als uint32_t. Daher ist der Block zuvor die Signatur, welche mit RSA-2048 in diesem Fall eine L\u00e4nge von 256 Bytes haben m\u00fcsste.<\/p>\n\n\n\n<p>Nun \u00e4ndern wir einfach nur ein Byte der Signatur ab, z.B. das erste Byte in der Vorletzten Zeile <code>6<\/code>, welches wir in <code>7<\/code> ab\u00e4ndern.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\n0003fdd0: 4afb 82d9 76c5 206b 985f 801b cdd5 f4e1  J...v. k._......\n0003fde0: 42c2 2e32 fcf1 bb99 8125 7112 a577 88cd  B..2.....%q..w..\n0003fdf0: 40b3 4de4 ae68 8c11 902a 552b bd86 94a0  @.M..h...*U+....\n0003fe00: 5b57 c34b cd19 7d7e 9e41 e7e6 3e2b 0e7c  &#091;W.K..}~.A..&gt;+.|\n0003fe10: 1116 4711 7094 27f6 4162 0d7c 60d3 c951  ..G.p.'.Ab.|`..Q\n0003fe20: bfb5 b043 57f4 f943 53b4 4f3c dfc8 c250  ...CW..CS.O&lt;...P\n0003fe30: e746 00c6 419a 42a8 05f5 0f25 5049 556a  .F..A.B....%PIUj\n0003fe40: 612a f185 b242 9407 2de9 bec2 0e86 f7f5  a*...B..-.......\n0003fe50: 195d f87a 321b e15e 6fff 3d16 582d cb03  .].z2..^o.=.X-..\n0003fe60: 7664 01bb 55b7 6f52 20ce 04e0 d28f eee8  fd..U.oR .......   &lt;--- Hier\n          ^\n0003fe70: 0001 0000                                ....<\/code><\/pre>\n\n\n\n<p>Nun wechseln wir von der Hexadezimal Ansicht wieder in die bin\u00e4re Ansicht und speichern das Artefakt. Wir tippen in VIM:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>:%!xxd -r\n:wq<\/code><\/pre>\n\n\n\n<p>Wir k\u00f6nnen das ge\u00e4nderte Artefakt zus\u00e4tzlich noch mit der Kopie eines validen Artefaktes vergleichen mit Hilfe von <code>diff<\/code> oder <code>sha256sum<\/code>. Somit k\u00f6nnte man sichergehen, dass die Artefakte sich tats\u00e4chlich unterscheiden. Gleichzeitig k\u00f6nnen wir \u00fcberpr\u00fcfen, ob die Dateien gleichgro\u00df sind.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cd ${BLINK_EXAMPLE}\n$ # Wir gehen in das Build Verzeichnis\n$ cd .pio\/build\/nodemcuv2\n$ # Das abge\u00e4nderte Artefakt wird umbenannt\n$ cp firmware.bin.signed invalid.bin.signed\n$ # Wir erstellen eine neue signierte Version des Artefakts\n$ make -C ..\/..\/..\n$ diff firmware.bin.signed invalid.bin.signed\nBinary files firmware.bin.signed and invalid.bin.signed differ\n$ du -b firmware.bin.signed\n261748  firmware.bin.signed\n$ du -b invalid.bin.signed\n261748  invalid.bin.signed<\/code><\/pre>\n\n\n\n<p>Nun flashen wir den ESP wieder mit dem Code welcher ein valides signiertes Artefakt erwartet.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ cd ${OTA_PROJECT_SIGNING}\n$ pio run --target upload; pio device monitor -b 115200\n...\nHTTP_UPDATE_FAILD Error (12): Update error: ERROR&#091;12]: Signature verification failed\n...<\/code><\/pre>\n\n\n\n<p>Und auch hier ist das Update wie gew\u00fcnscht nicht erfolgreich. Somit haben wir nun OTA Updates, die sicher nur dann erfolgreich sind, wenn unser Artefakt mit dem von uns erstellten privaten Schl\u00fcssel signiert ist. Der private Schl\u00fcssel sollte daher nicht in die Versions Kontrolle mit eingecheckt werden. Generell sollten f\u00fcr die Produktion nicht die gleichen Schl\u00fcssel wie f\u00fcr den eigentlichen Betrieb genutzt werden. Das sch\u00fctzt den laufenden Betrieb und verhindert b\u00f6se Missgeschicke. Allen Code und die ben\u00f6tigten Dateien gibt es <a href=\"https:\/\/github.com\/buermarc\/iot-blog-posts\/tree\/main\/signing-ota\">hier<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In diesem Beitrag m\u00f6chten wir uns signierte Updates anschauen. Das hei\u00dft, an das Artefakt werden extra Information angeh\u00e4ngt, welche es uns erlauben die Validit\u00e4t und den Ursprung des Artefaktes zu \u00fcberpr\u00fcfen. Diese Funktionalit\u00e4t wird ben\u00f6tigt, um sicherzustellen, dass nur wir<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[6],"tags":[],"_links":{"self":[{"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/posts\/417"}],"collection":[{"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/comments?post=417"}],"version-history":[{"count":2,"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/posts\/417\/revisions"}],"predecessor-version":[{"id":419,"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/posts\/417\/revisions\/419"}],"wp:attachment":[{"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/media?parent=417"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/categories?post=417"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.iot-embedded.de\/iot-2021\/wp-json\/wp\/v2\/tags?post=417"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}