- What
--securedoes - Prerequisites
- Secure boot signing key
- Build secured firmware
- First provisioning / flashing a secured device
- Important downsides and operational constraints
- Build signed firmware for OTA
- OTA update compatibility
- Recommended process
This document explains how to build and flash F1 firmware with security enabled, what changes after provisioning a secured device, and how to produce OTA-updatable signed firmware images. It is assumed that sg-sdk was cloned in your home directory ($HOME/sg-sdk).
When you pass --secure to the firmware builder:
- The F1 secure config file
src/platforms/F1/configs/sdkconfig.secureis included. - Secure Boot V2 (RSA signed images) is enabled.
- Flash Encryption (AES-256, release mode) is enabled.
- If the command is
flash, the builder internally upgrades it to a full-flash flow so the bootloader is also flashed.
Before using --secure, verify:
- The
esp-idfsubmodule is initialised (this happens automatically on the firstfw_builder.shbuild run). The signing key atCONFIG_SECURE_BOOT_SIGNING_KEYis auto-generated if absent. - Partition table includes
nvs_keys(already done for F1). - You are using the correct board and serial port.
In src/platforms/F1/configs/sdkconfig.secure, the key path is:
CONFIG_SECURE_BOOT_SIGNING_KEY="../../../secure_boot_signing_key.pem"
The builder runs ESP-IDF with working directory src/platforms/F1, so this resolves to:
$HOME/sg-sdk/secure_boot_signing_key.pem
When --secure is passed to fw_builder.sh, the builder automatically checks whether the signing key exists. If it does not, it generates one using espsecure.py before the build starts. This means no manual key-generation step is needed.
Note: Auto-generation requires that the
esp-idfsubmodule is already initialised, which happens automatically as part of the normal build flow the first time you run./fw_builder.sh ... build.
If you prefer to generate the key yourself before the first build:
cd $HOME/sg-sdk
bash -c ". ext/esp-idf/export.sh && espsecure.py generate_signing_key --version 2 secure_boot_signing_key.pem"Either way, store this private key securely and do not commit it to git.
Example (MicroPython variant):
Please close your terminal after running the above command and start a new terminal.
cd $HOME/sg-sdk
./fw_builder.sh --board SGW3501-F1-StarterKit --secure buildThis produces a security-enabled build where app images are signed for secure boot.
Use flash together with --secure:
cd $HOME/sg-sdk
./fw_builder.sh --board SGW3501-F1-StarterKit --port /dev/ttyUSB0 --secure flashNotes:
- With
--secure,flashis internally converted to a full-flash operation. - This includes bootloader flashing (required when enabling secure boot for the first time).
After the firmware has been flashed, do not disconnect or reset the device manually. The device needs several minutes to complete its internal flash encryption process. Interrupting this process (e.g. by power-cycling or resetting the device prematurely) may render the device permanently unusable.
Wait until the device resets itself automatically — this signals that encryption is complete.
While encryption is in progress, you may see error messages like the following in the serial output:
E (27528) esp_image: image at 0x2a0000 has invalid magic byte (nothing flashed here?) E (27528) esp_image: image at 0x520000 has invalid magic byte (nothing flashed here?)These errors are expected and harmless. They occur because the OTA firmware image slots are empty (no OTA update has been applied yet). You can safely ignore them.
After secure boot + flash encryption are enabled on a device:
- You can no longer treat the chip like a normal development target for arbitrary raw flashing.
- Generic
esptool.py write_flashworkflows become restricted/not practical for normal development updates. - Debug and recovery options are reduced compared to insecure/development mode.
- If signing keys are lost, producing valid update images becomes impossible.
- The NVS partition is erased during the first boot after flashing. This includes all LoRaWAN
provisioning parameters (DevEUI, AppEUI, AppKey, etc.) and the
devNoncecounter. The device will need to be re-provisioned after secure boot is enabled. See the ESP-IDF NVS Encryption documentation for technical background on why this happens.
In short: once secured, firmware lifecycle must follow signed update paths.
To generate OTA payloads, run a secure build:
cd $HOME/sg-sdk
./fw_builder.sh --board SGW3501-F1-StarterKit --secure buildThe OTA image to distribute is the generated application.bin from the build directory, for example:
build/sdk-default/F1/SGW3501-F1-StarterKit/micropython/application.bin
If you build from a custom project dir or variant, the path changes accordingly under build/<app>/<platform>/<board>/<variant>/application.bin.
For a secured device, OTA update images must be:
- Signed with the same trusted key chain expected by secure boot.
- Built with secure settings compatible with the running device.
If signature verification fails, the image will not boot.
- Keep signing keys in secure storage and back them up safely.
- Use
--secure buildin CI for release artifacts. - Use
--secure flashonly for provisioning / controlled service flows. - Use OTA with signed
application.binfor field updates.