Thunderboard – Secure Over The Air (OTA) Upgrades
In Thunderboard React – Over The Air (OTA) Upgrades and Thunderboard Sense 2 – Over The Air (OTA) Upgrades I explained how to enable OTA DFU, but in an insecure way. In this article I show you how to enable secure Device Field Upgrades (DFU) using the security features of the Gecko Bootloader.
Gecko Bootloader Security Features
The security features offered by the Gecko Bootloader are:
- Encrypted upgrade files: GBL files are encrypted
- Authenticated upgrade files: GBL files are signed
- Secure (authenticated) boot: the firmware binary is signed (the signature is appended to the binary) and this signature is checked on every boot
These features can all be enabled or disabled individually. In this article, all three will be enabled.
When the Application resets and boots into OTA DFU mode, the Gecko Bootloader runs the Apploader instead of the Application. Therefore, enabling Secure Boot means that both the Apploader and the Application need to be signed individually.
Likewise, as the Apploader and Application have separate GBL files, the encryption and authentication features mean that both the Apploader and Application GBL files need to be encrypted and signed separately.
Gecko Bootloader Configuration
Enabling these features in the Gecko Bootloader is dead easy. You just need to open the bootloader .isc file, go to Plugins->Core->Bootloader Core and select three checkboxes. Here’s how it looks for the Thunderborad React.
Save the .isc, Generate the project again and re-build the Gecko Bootloader.
For the Thunderboard Sense 2, the process is identical. The only minor difference is that the Prevent bootloader write/erase option is available in the Sense 2 (grayed out in the React). This is because the Gecko Bootloader is stored in the Information block of Flash on EFR32xG12 devices, instead of sharing the Main block of Flash, as is the case on EFR32xBG1 devices. Thus it is possible to prevent the application from inadvertently erasing the bootloader. I have enabled this feature for Thunderboard Sense 2.
Key Generation
The Simplicity Commander tool is used to generate the keys.
commander gbl keygen --type ecc-p256 --outfile key-signing commander gbl keygen --type aes-ccm --outfile key-encryption-tokens.txt
With the key names I’ve used above, you get the following four files:
- key-signing: Private key in PEM format
- key-signing.pub: Public key in PEM format
- key-signing-tokens.txt: The public key in so-called “manufacturing tokens” format (Silabs special sauce)
- key-encryption-tokens.txt: The AES-128 encryption key also in so-called “manufacturing tokens” format
The key-signing file should be held somewhere secure. It’s used to sign all your firmware files, and you don’t want anyone else impersonating you. I have included it in my repo merely for convenience and reference.
Key Injection
The two manufacturing tokens files are used to inject the public signing key and the encryption key into the Thunderboard using the Simplicity Commander tool. Here’s the script for the Sense 2.
commander flash --tokengroup znet --tokenfile key-encryption-tokens.txt --tokenfile key-signing-tokens.txt --device EFR32MG12P332F1024GL125
This flashes the keys into the so-called Lock Bits page of the Information block of the Flash. See the contents of key-encryption-tokens.txt and key-signing-tokens.txt for details of the tokens they contain, and refer to https://www.silabs.com/documents/public/application-notes/an961-custom-nodes-efr32.pdf for details of where they are stored. Here’s the potted summary:
Address | Token Name | Size | Description |
---|---|---|---|
0x0FE04286 | TOKEN_MFG_SECURE_BOOTLOADER_KEY | 16 | Encryption/decryption key |
0x0FE0434A | TOKEN_MFG_SIGNED_BOOTLOADER_KEY_X | 32 | X component of the public signing key |
0x0FE0436A | TOKEN_MFG_SIGNED_BOOTLOADER_KEY_Y | 32 | Y component of the public signing key |
React flash-keys.sh new file: https://github.com/gregbreen/uncannier-thunderboard-react/commit/b810205dfc9113409dd75f00a158b97956150fd2#diff-c6a3d8f02ec975735078243a1b6fa2b8
Sense 2 flash-keys.sh new file: https://github.com/gregbreen/uncannier-thunderboard-sense2/commit/9e556aec5d6ef26dfdb4b8ab880a23e713e3f108#diff-5a387770a8153cf5f72bc40c90cccb06
Signing & Encrypting The Firmware
Simplicity Commander is Silicon Labs’ answer to the Swiss army knife. If in doubt, Commander is your answer to almost anything in the Silabs’ universe. And yes, it’s what you use to sign and encrypt your application firmware.
As mentioned in previous articles, the stock projects generate the create_bl_files.sh script. This rolls up a bunch of Simplicity Commander operations, and can be used for signing and encrypting the firmware. As also mentioned in previous articles, I hate that script. Well, dislike. To the point of refusing to use it.
So anyway, I choose to sign and encrypt my firmware by modifying my custom post-build script postbuild.sh. Here’s the Thunderboard Sense 2 script:
# Extract S-record files for the apploader and application individually (so they can both be signed) arm-none-eabi-objcopy -O srec -j .text_apploader* "${1}/${2}.axf" "${1}/apploader.srec" >/dev/null arm-none-eabi-objcopy -O srec -j .text_application* "${1}/${2}.axf" "${1}/application.srec" >/dev/null # Names of the key files GBL_SIGNING_KEY_FILE="key-signing" GBL_ENCRYPT_KEY_FILE="key-encryption-tokens.txt" # Sign the apploader and application (so the bootloader can run them) commander convert "${1}/apploader.srec" --secureboot --keyfile ${GBL_SIGNING_KEY_FILE} -o "${1}/apploader-signed.srec" >/dev/null commander convert "${1}/application.srec" --secureboot --keyfile ${GBL_SIGNING_KEY_FILE} -o "${1}/application-signed.srec" >/dev/null # Create a combined image HEX file - bootloader (first and second stage), signed apploader and signed application - this is flashable commander convert ../uts-bootloader/Release/uts-bootloader-combined.s37 ./$1/apploader-signed.srec ./$1/application-signed.srec --outfile ./$1/uts-image.hex # Create signed and encrypted GBL files for OTA updates commander gbl create "${1}/uts-apploader.gbl" --app "${1}/apploader-signed.srec" --encrypt ${GBL_ENCRYPT_KEY_FILE} --sign ${GBL_SIGNING_KEY_FILE} >/dev/null commander gbl create "${1}/uts-application.gbl" --app "${1}/application-signed.srec" --encrypt ${GBL_ENCRYPT_KEY_FILE} --sign ${GBL_SIGNING_KEY_FILE} >/dev/null # Clean up the intermediate files rm ${1}/*.srec
React postbuild.sh changes: https://github.com/gregbreen/uncannier-thunderboard-react/commit/b810205dfc9113409dd75f00a158b97956150fd2#diff-f739473fbcd77bf3bab709bfb1154a56
Sense 2 postbuild.sh changes: https://github.com/gregbreen/uncannier-thunderboard-sense2/commit/9e556aec5d6ef26dfdb4b8ab880a23e713e3f108#diff-7d2b2c8d9784bda32311774f120d0262
Going Further
Additionally, the Silicon Labs OTA Control characteristic of the application could be changed. The Write property could be changed to Authenticated Write, Encrypted Write or Bonded Write. This would provide more security around who could make the Thunderboard enter OTA DFU mode in the first place.
However, this is delving into more general topics around BLE security. Let’s save that for another time.
Conclusion
That’s it. Flash in your new bootloader, flash in your keys, and use the Blue Gecko app to securely load firmware OTA.
Uncannier Pull Requests
- https://github.com/gregbreen/uncannier-thunderboard-react/pull/7
- https://github.com/gregbreen/uncannier-thunderboard-sense2/pull/7
References
- https://uncannier.com/thunderboard-react-over-the-air-ota-upgrades/
- https://uncannier.com/thunderboard-sense-2-over-the-air-ota-upgrades/
- https://www.silabs.com/documents/public/user-guides/ug266-gecko-bootloader-user-guide.pdf
- https://www.silabs.com/community/wireless/bluetooth/knowledge-base.entry.html/2017/06/22/secure_ota_dfu-Wb22
- https://www.silabs.com/documents/public/application-notes/an961-custom-nodes-efr32.pdf