In the past I introduced you to LifeCycle manager to manage you Firmware you made for your ESP8266 HomeKit accessories. Then I encountered some trouble with LCM (LifeCycle Manager). After contacting the the maker (HacK a.k.a. HomeACcessoryKid) of LifeCycle Manager, it turns out there is very small issue but the consequences are big, it’s an issues that has to be solved! For whom that reeds my blog regularly know that I use LCM for every HomeKit device I design. Read about here and here. But the the maker (HacK a.k.a. HomeACcessoryKid) of Life Cycle Manager has published LifeCycle Manager 2! Good news and bad news. Version 2.0.0+ is here and it works and is protected. But you have to solder a serial port again.
The LifeCycle Manager2 (LCM) tracks software and firmware versions. Firmware is software, inclusive of programs or data, that has been permanently written onto read-only memory (ROM) or programmable read-only memory (PROM). This is a program that allows any simple repository based on ESP-Open-RTos on a ESP8266 to solve its life cycle tasks. LifeCycle Manager2 enables you to:
- Assign a WiFi AccessPoint for internet connectivity
- Specify and install the user app without flashing over cable (once the LCM image is in)
- Update the user app over the air by using releases and versions on GitHub
The solution is dedicated to a particular set of repositories and devices, which I consider is worth solving.
- Many ESP8266 devices have only 1Mbyte of flash.
- Many people have no interest in setting up a software (web)server to solve their upgrade needs.
- Many repositories have no ram or flash available to combine the upgrade routines and the user routines.
- For repositories that will be applied by MANY people, a scalable software server is needed.
- Be able to setup WiFi securely while not depending on an electrical connection whenever WiFi needs setup.
In my opinion, for the target group of my blog, the typical solution doesn’t work and so LifeCycle Manager2 will handle it. Also it turns out that there are no out-of-the-box solutions of the typical case out there so we are fine with the limitations of LifeCycle Manager2!
With version 2.0.0 LifeCycle Manager2 has arrived to a new stage with its own adaptation of rboot – rboot4lcm – which counts powercycles. These are used to check updates, reset wifi clear or set LCM_beta or factory reset. It also gives access to the emergency mode. Setting a value for a led_pin visual feedback is possible.
New feature version 2
This new LifeCycle Manager2 code is able to load/update the bootloader from github. The new bootloader is able to count the amount of short power cycles (<1.5s) From the second cycle the cycles must be shorter than 4 seconds. Also a LED is lit if defined. The boot loader conveys the count to the loaded code using the rtc.temp_rom value User code is allowed the values from 1-4 1 : this is a normal boot 2-4: users choice in user code (communicate 3 to user or risk a bit and use 2, 3 and 4 separately) If count > 4 the bootloader launches LifeCycle Manager2 otamain.bin in rom.
For these values the behaviour is controlled through the sysparam string ota_count_step. The default value of 3 reduces the chance of user miscounting and triggering something else then intended or play full children.
Note that with LCM_beta mode and wifi erased you can set any emergency fallback server to collect a new signed version of otaboot.bin. This is to prevent a lockout as witnessed when Github changed their webserver.
If ota_count_step==”3″ (default)
5-7: check for new update (communicate 6 to user)
8-10: erase wifi info and clear LCM_beta mode (communicate 9 to user)
11-13: erase wifi info and set LCM_beta mode and gain access to emergency mode (communicate 12 to user)
14-16: factory reset (communicate 15 to user)
5-6: check for new code (communicate 5 to user)
7-8: erase wifi info and clear LCM_beta mode (communicate 7 to user)
9-10: erase wifi info and set LCM_beta mode and gain access to emergency mode (communicate 9 to user)
11-12: factory reset (communicate 11 to user)
5: check for new code (communicate 5 to user)
6: erase wifi info and clear LCM_beta mode (communicate 6 to user)
7: erase wifi info and set LCM_beta mode and gain access to emergency mode (communicate 7 to user)
8: factory reset (communicate 8 to user)
Missing or other ota_count_step values will be interpreted as 3
Having over the air firmware updates is very important to be able to close security holes and prevent others to introduce malicious code. The user app only requires a few simple lines of code so no increase in RAM usage or complexity and an overall smaller flash footprint. Through the use of cryptography throughout the life cycle manager, it is not possible for any outside party to squeeze in any malicious code nor to snoop the password of the WiFi AccessPoint *) The fact that it is hosted on GitHub means your code is protected by the https certificates from GitHub and that no matter how many devices are out there, it will scale. The code is publicly visible and can be audited at all times so that security is at its best. The user could add their own DigitalSignature (ecDSA) although it is not essential. (feature on todolist). The producer of hardware could preinstall the LCM code on hardware thereby allowing the final user to select any relevant repository. Many off-the-shelf hardware devices have OTA code that can be highjacked and replaced with LCM so no solder iron or mechanical hacks needed.
Having over the air firmware updates is very important to be able to close security holes and prevent others to introduce malicious code. The user app only requires a few simple lines of code so no increase in RAM usage or complexity and an overall smaller flash footprint. Through the use of cryptography throughout the life cycle manager, it is not possible for any outside party to squeeze in any malicious code nor to snoop the password of the WiFi Access Point.
The fact that it is hosted on GitHub means your code is protected by the https certificates from GitHub and that no matter how many devices are out there, it will scale. The code is publicly visible and can be audited at all times so that security is at its best. In this case we pre install the LCM code on the hardware thereby allowing the final user to select any relevant repository.
If you feel you need 100% control, you can fork this repository, create your own private key and do the life cycle of the LCM yourself. But since the code of LCM is public, by audit it is unlikely that malicious events will happen. It is up to you.
How it works
After installing LifeCycle Manager2 for the first time it will get the latest Software version from your GitHub. In this case Version X.
Main app(0) v.x
The user code Main app is running in boot slot 0 at Version X.
boot=slot1 baseURL=repo version=x
This represents that in sector 1 used by rboot, we will also store the following info
baseURL: everything is intended to be relative to https://github.com, so this info is the user/repo part
version: the version that this repo is currently running at.
After this we run the OTA code which will try to deposit in boot slot 0 the latest version (t) of the baseURL repo.
This represents an exponential hold-off to prevent excessive hammering on the GitHub servers. It resets at a power-cycle.
Download certificate signature: Certificate update? Download Certificates.
This is a file that contains the checksum of the sector containing three certificates/keys
- Public key of HomeACessoryKid that signs the certificate/key sector
- Root CA used by GitHub
- Root CA used by the DistributedContentProvider (Amazon in this case)
First, the file is intended to be downloaded with server certificate verification activated. If this fails, it is downloaded anyway without verification and server is marked as invalid. Once downloaded, the sha256 checksum of the active sector is compared to the checksum in the signature file. If equal, we move on. If not, we download the updated sector file to the standby sector.
From the sector containing up to date certificates the sha256 hash is signed by the private key of HomeACessoryKid. Using the available public key, the validity is verified
If in the previous steps the server is marked invalid, we return to the main app in boot slot 0 and we report by syslog to a server (to be determined) so we learn that GitHub has changed its certificate CA provider and HomeACessoryKid can issue a new certificate sector.
new OTA version? self-updater(0) update OTAapp➔1 checksum OK?
Now that the downloading from GitHub has been secured, we can trust whatever we download based on a checksum. We verify if there is an update of this OTA repo itself? If so, we use a self-updater (part of this repo) to ‘self update’. After this we have the latest OTA code.
OTA app(1) updates Main app➔0 checksum OK?
Using the base URL info and the version as stored in sector1, the latest binary is found and downloaded if needed. If the checksum does not work out, we return to the OTA app start point considering we cannot run the old code any more. But normally we boot the new code and the mission is done.
Note: that switching from boot=slot1 to boot=slot0 does not require a reflash
HomeACcessoryKid, life-cycle-manager (2020), Initial install, WiFi settings and over the air firmware upgrades for any esp-open-rtos repository on GitHub, https://github.com/HomeACcessoryKid/life-cycle-manager Maxim Kulkin, esp-wifi-config (2019), Library to bootstrap WiFi-enabled accessories WiFi config, https://github.com/maximkulkin/esp-wifi-config Paul Sokolovsky, esp-open-sdk (2019), Free and open (as much as possible) integrated SDK for ESP8266/ESP8285 chips, https://github.com/pfalcon/esp-open-sdk Espressif Systems, esptool (2019), ESP8266 and ESP32 serial bootloader utility, https://github.com/espressif/esptool