-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
workflows: Add workflow for DFU sanity check
This patch adds a GitHub workflow that checks the DFU images for correctness. For bootloader and application images, the workflow verifies the signature of the image. Furthermore, the workflow compares the partition table of the image with an old version. Signed-off-by: Maximilian Deubel <[email protected]>
- Loading branch information
1 parent
9b494b7
commit 52cd0cd
Showing
4 changed files
with
266 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
name: DFU image compatibility check | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
|
||
jobs: | ||
build: | ||
name: Build and analyze | ||
runs-on: ubuntu-latest | ||
container: ghcr.io/zephyrproject-rtos/ci:v0.26.12 | ||
env: | ||
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory | ||
CMAKE_PREFIX_PATH: /opt/toolchains | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
with: | ||
path: thingy91x-oob | ||
|
||
- name: Initialize | ||
working-directory: thingy91x-oob | ||
run: | | ||
west init -l . | ||
west config manifest.group-filter +bsec | ||
west update -o=--depth=1 -n | ||
- name: Install dependencies | ||
run: | | ||
pip install -r nrf/scripts/requirements-build.txt | ||
- name: Save paths | ||
run: | | ||
echo "CI_PROJECT_DIR=$(pwd)/thingy91x-oob" >> $GITHUB_ENV | ||
echo "CI_NRF_DIR=$(pwd)/nrf" >> $GITHUB_ENV | ||
echo "CI_ZEPHYR_DIR=$(pwd)/zephyr" >> $GITHUB_ENV | ||
echo "CI_MCUBOOT_DIR=$(pwd)/bootloader/mcuboot" >> $GITHUB_ENV | ||
- name: 'generate nsib verifying keys' | ||
working-directory: thingy91x-oob | ||
run: | | ||
python3 ${CI_NRF_DIR}/scripts/bootloader/keygen.py --public --in ${CI_NRF_DIR}/boards/nordic/thingy91x/nsib_signing_key.pem --out verifying_key_nrf91.pem | ||
python3 ${CI_NRF_DIR}/scripts/bootloader/keygen.py --public --in ${CI_NRF_DIR}/boards/nordic/thingy91x/nsib_signing_key_nrf5340.pem --out verifying_key_nrf53.pem | ||
- name: Build OOB FW | ||
working-directory: thingy91x-oob | ||
run: | | ||
west twister -T . -v -p thingy91x/nrf9151/ns --inline-logs | ||
- name: 'nrf91: check partition layout' | ||
working-directory: thingy91x-oob/twister-out/thingy91x_nrf9151_ns/app/app.build/ | ||
run: | | ||
ninja partition_manager_report > partition_manager_report.txt | ||
sed -i '1d' partition_manager_report.txt | ||
diff partition_manager_report.txt ${CI_PROJECT_DIR}/scripts/pmr_nrf91.txt | ||
- name: 'nrf91: check app image signature' | ||
working-directory: thingy91x-oob | ||
run: | | ||
python3 ${CI_MCUBOOT_DIR}/scripts/imgtool.py verify -k ${CI_MCUBOOT_DIR}/root-ec-p256.pem twister-out/thingy91x_nrf9151_ns/app/app.build/zephyr/app_update.bin | ||
- name: 'nrf91: check bootloader image signature' | ||
working-directory: thingy91x-oob | ||
run: | | ||
python3 scripts/nsib_signature_check.py -i twister-out/thingy91x_nrf9151_ns/app/app.build/zephyr/signed_by_b0_s0_image.hex -p verifying_key_nrf91.pem -a 0x00008200 | ||
- name: Build Connectivity Bridge | ||
working-directory: nrf/applications/connectivity_bridge | ||
run: | | ||
west twister -T ${CI_NRF_DIR}/applications/connectivity_bridge -v -p thingy91x/nrf5340/cpuapp --inline-logs | ||
- name: 'nrf53: check partition layout' | ||
working-directory: thingy91x-oob/twister-out/thingy91x_nrf5340_cpuapp/applications.connectivity_bridge/ | ||
run: | | ||
ninja partition_manager_report > partition_manager_report.txt | ||
sed -i '1d' partition_manager_report.txt | ||
diff partition_manager_report.txt ${CI_PROJECT_DIR}/scripts/pmr_nrf53.txt | ||
- name: 'nrf53: check app image signature' | ||
working-directory: thingy91x-oob | ||
run: | | ||
python3 ${CI_MCUBOOT_DIR}/scripts/imgtool.py verify -k ${CI_MCUBOOT_DIR}/root-rsa-2048.pem twister-out/thingy91x_nrf5340_cpuapp/applications.connectivity_bridge/zephyr/app_update.bin | ||
- name: 'nrf91: check bootloader image signature' | ||
working-directory: thingy91x-oob | ||
run: | | ||
python3 scripts/nsib_signature_check.py -i twister-out/thingy91x_nrf5340_cpuapp/applications.connectivity_bridge/zephyr/signed_by_b0_s0_image.hex -p verifying_key_nrf53.pem -a 0x00008200 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# Copyright (c) 2024 Nordic Semiconductor ASA | ||
# | ||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | ||
|
||
|
||
from intelhex import IntelHex | ||
|
||
import hashlib | ||
import argparse | ||
import struct | ||
import ecdsa | ||
|
||
def parse_args(): | ||
parser = argparse.ArgumentParser( | ||
description='Check NSIB signature of a given file', | ||
formatter_class=argparse.RawDescriptionHelpFormatter, | ||
allow_abbrev=False) | ||
parser.add_argument('-i', '--input', required=True, type=argparse.FileType('r', encoding='UTF-8'), | ||
help='Input hex file.') | ||
parser.add_argument('-p', '--public-key', required=True, type=argparse.FileType('r', encoding='UTF-8'), | ||
help='Public key file (PEM).') | ||
parser.add_argument('-a', '--start-address', required=False, type=str, default=None, help='Start address of the image (hex).') | ||
|
||
args = parser.parse_args() | ||
return args | ||
|
||
def check_signature(hex_file, public_key, start_address): | ||
public_key_bytes_expected = public_key.to_string() | ||
image = IntelHex(hex_file) | ||
|
||
signature_locations = [] | ||
offset = 0 | ||
while True: | ||
offset = image.find(b'\xde\xe6\x1e\x28\x83\x84\x51\x86', start=offset+1) | ||
if offset == -1: | ||
break | ||
signature_locations.append(offset) | ||
|
||
for offset in signature_locations: | ||
validation_info_version = image[offset + 8] | ||
info_hardware_id = image[offset + 9] | ||
validation_info_crypto_id = image[offset + 10] | ||
info_magic_compatibility_id = image[offset + 11] | ||
starting_address = struct.unpack('<I', image.tobinstr(start=offset + 12, size=4))[0] | ||
hash_bytes = image.tobinstr(start=offset + 16, size=32) | ||
public_key_bytes = image.tobinstr(start=offset + 48, size=64) | ||
signature_bytes = image.tobinstr(start=offset + 112, size=64) | ||
|
||
if start_address is not None and start_address != starting_address: | ||
raise Exception(f"Signature found at address 0x{starting_address:08x} but expected 0x{start_address:08x}") | ||
|
||
if public_key_bytes != public_key_bytes_expected: | ||
print(f"Image has signature for different public key: {public_key_bytes.hex()}") | ||
continue | ||
public_key.verify(signature_bytes, hash_bytes, hashfunc=hashlib.sha256) | ||
print(f"Signature verified for image starting at address 0x{starting_address:08x}") | ||
return | ||
raise Exception("No matching signature found in the image.") | ||
|
||
|
||
def main(): | ||
|
||
args = parse_args() | ||
public_key = ecdsa.VerifyingKey.from_pem(args.public_key.read()) | ||
|
||
check_signature(args.input, public_key, int(args.start_address, 16)) | ||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
flash_primary (0x100000 - 1024kB): | ||
+--------------------------------------------------+ | ||
+---0x0: b0_container (0x8000 - 32kB)--------------+ | ||
| 0x0: b0 (0x8000 - 32kB) | | ||
+---0x8000: s0 (0x14000 - 80kB)--------------------+ | ||
| 0x8000: s0_pad (0x200 - 512B) | | ||
+---0x8200: s0_image (0x13e00 - 79kB)--------------+ | ||
| 0x8200: mcuboot (0x13e00 - 79kB) | | ||
+---0x1c000: s1 (0x14000 - 80kB)-------------------+ | ||
| 0x1c000: s1_pad (0x200 - 512B) | | ||
| 0x1c200: s1_image (0x13e00 - 79kB) | | ||
+---0x30000: mcuboot_primary (0x64000 - 400kB)-----+ | ||
| 0x30000: mcuboot_pad (0x200 - 512B) | | ||
+---0x30200: app_image (0x63e00 - 399kB)-----------+ | ||
+---0x30200: mcuboot_primary_app (0x63e00 - 399kB)-+ | ||
| 0x30200: app (0x63e00 - 399kB) | | ||
+--------------------------------------------------+ | ||
| 0x94000: mcuboot_secondary (0x64000 - 400kB) | | ||
| 0xf8000: EMPTY_1 (0x4000 - 16kB) | | ||
| 0xfc000: settings_storage (0x2000 - 8kB) | | ||
| 0xfe000: EMPTY_0 (0x2000 - 8kB) | | ||
+--------------------------------------------------+ | ||
|
||
otp (0x2fc - 764B): | ||
+------------------------------------+ | ||
| 0xff8100: provision (0x280 - 640B) | | ||
| 0xff8380: otp (0x7c - 124B) | | ||
+------------------------------------+ | ||
|
||
ram_flash (0x40000 - 256kB): | ||
+------------------------------------------+ | ||
| 0x0: mcuboot_primary_1 (0x40000 - 256kB) | | ||
| 0x40000: ram_flash (0x0 - 0B) | | ||
+------------------------------------------+ | ||
|
||
sram_primary (0x80000 - 512kB): | ||
+-----------------------------------------------+ | ||
| 0x20000000: pcd_sram (0x2000 - 8kB) | | ||
| 0x20002000: sram_primary (0x6dc00 - 439kB) | | ||
| 0x2006fc00: rpmsg_nrf53_sram (0x10000 - 64kB) | | ||
| 0x2007fc00: sram_retained_mem (0x400 - 1kB) | | ||
+-----------------------------------------------+ | ||
|
||
CPUNET flash_primary (0x40000 - 256kB): | ||
+--------------------------------------------+ | ||
+---0x1000000: b0n_container (0x8800 - 34kB)-+ | ||
| 0x1000000: b0n (0x8580 - 33kB) | | ||
| 0x1008580: provision (0x280 - 640B) | | ||
+---0x1008800: app (0x37800 - 222kB)---------+ | ||
| 0x1008800: hci_ipc (0x37800 - 222kB) | | ||
+--------------------------------------------+ | ||
|
||
CPUNET sram_primary (0x10000 - 64kB): | ||
+-------------------------------------------+ | ||
| 0x21000000: sram_primary (0x10000 - 64kB) | | ||
+-------------------------------------------+ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
external_flash (0x2000000 - 32768kB): | ||
+---------------------------------------------+ | ||
+---0x0: external_flash (0x2000000 - 32768kB)-+ | ||
| 0x0: mcuboot_secondary (0xd0000 - 832kB) | | ||
+---0xd0000: nonsecure_storage (0x2000 - 8kB)-+ | ||
| 0xd0000: settings_storage (0x2000 - 8kB) | | ||
+---------------------------------------------+ | ||
|
||
flash_primary (0x100000 - 1024kB): | ||
+--------------------------------------------------+ | ||
+---0x0: b0_container (0x8000 - 32kB)--------------+ | ||
| 0x0: b0 (0x8000 - 32kB) | | ||
+---0x8000: s0 (0x14000 - 80kB)--------------------+ | ||
| 0x8000: s0_pad (0x200 - 512B) | | ||
+---0x8200: s0_image (0x13e00 - 79kB)--------------+ | ||
| 0x8200: mcuboot (0x13e00 - 79kB) | | ||
+---0x1c000: s1 (0x14000 - 80kB)-------------------+ | ||
| 0x1c000: s1_pad (0x200 - 512B) | | ||
| 0x1c200: s1_image (0x13e00 - 79kB) | | ||
+---0x30000: mcuboot_primary (0xd0000 - 832kB)-----+ | ||
+---0x30000: tfm_secure (0x8000 - 32kB)------------+ | ||
| 0x30000: mcuboot_pad (0x200 - 512B) | | ||
+---0x30200: app_image (0xcfe00 - 831kB)-----------+ | ||
+---0x30200: mcuboot_primary_app (0xcfe00 - 831kB)-+ | ||
| 0x30200: tfm (0x7e00 - 31kB) | | ||
+---0x38000: tfm_nonsecure (0xc8000 - 800kB)-------+ | ||
| 0x38000: app (0xc8000 - 800kB) | | ||
+--------------------------------------------------+ | ||
|
||
otp (0x2f4 - 756B): | ||
+------------------------------------+ | ||
| 0xff8108: provision (0x280 - 640B) | | ||
| 0xff8388: otp (0x74 - 116B) | | ||
+------------------------------------+ | ||
|
||
sram_primary (0x40000 - 256kB): | ||
+-------------------------------------------------+ | ||
+---0x20000000: mcuboot_sram (0xa000 - 40kB)------+ | ||
+---0x20000000: sram_secure (0xa000 - 40kB)-------+ | ||
| 0x20000000: tfm_sram (0xa000 - 40kB) | | ||
+---0x2000a000: sram_nonsecure (0x36000 - 216kB)--+ | ||
+---0x2000a000: nrf_modem_lib_sram (0x24e8 - 9kB)-+ | ||
| 0x2000a000: nrf_modem_lib_ctrl (0x4e8 - 1kB) | | ||
| 0x2000a4e8: nrf_modem_lib_tx (0x1000 - 4kB) | | ||
| 0x2000b4e8: nrf_modem_lib_rx (0x1000 - 4kB) | | ||
+-------------------------------------------------+ | ||
| 0x2000c4e8: sram_primary (0x33b18 - 206kB) | | ||
+-------------------------------------------------+ | ||
|