Skip to content

Commit 69b832a

Browse files
committed
Scripts: Security enablement during west build
Added changes to automate the signing of zephyr security using customtool during the west build process. Signed-off-by: Aasim Shaik <[email protected]>
1 parent e7d5905 commit 69b832a

File tree

4 files changed

+165
-5
lines changed

4 files changed

+165
-5
lines changed

boards/silabs/radio_boards/siwx917_rb4338a/board.cmake

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
# Copyright (c) 2024 Silicon Laboratories Inc.
22
# SPDX-License-Identifier: Apache-2.0
3-
3+
# Set the flash file based on signing is enabled or not.
4+
set(FLASH_FILE ${PROJECT_BINARY_DIR}/zephyr_signed.bin.rps)
5+
if(NOT EXISTS ${FLASH_FILE})
6+
set(FLASH_FILE ${PROJECT_BINARY_DIR}/zephyr.bin.rps)
7+
endif()
48
board_runner_args(silabs_commander "--device=SiWG917M111GTBA" "--file-type=bin"
5-
"--file=${PROJECT_BINARY_DIR}/${KERNEL_BIN_NAME}.rps")
9+
"--file=${FLASH_FILE}")
610
include(${ZEPHYR_BASE}/boards/common/silabs_commander.board.cmake)
711

812
# It is not possible to load/flash a firmware using JLink, but it is possible to

scripts/west_commands/sign.py

+113-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import sys
1414

1515
from elftools.elf.elffile import ELFFile
16-
1716
from west import manifest
1817
from west.commands import Verbosity
1918
from west.util import quote_sh_list
@@ -22,7 +21,7 @@
2221
FIND_BUILD_DIR_DESCRIPTION
2322
from runners.core import BuildConfiguration
2423
from zcmake import CMakeCache
25-
from zephyr_ext_common import Forceable, ZEPHYR_SCRIPTS
24+
from zephyr_ext_common import Forceable, ZEPHYR_SCRIPTS, ZEPHYR_BASE
2625

2726
# This is needed to load edt.pickle files.
2827
sys.path.insert(0, str(ZEPHYR_SCRIPTS / 'dts' / 'python-devicetree' / 'src'))
@@ -79,6 +78,21 @@
7978
[rimage] sections in your west config file(s); this is especially useful
8079
when invoking west sign _indirectly_ through CMake/ninja. See how at
8180
https://docs.zephyrproject.org/latest/develop/west/sign.html
81+
82+
silabs_commander
83+
-----
84+
85+
To create a signed binary with the silabs_commander tool, run this from your build directory:
86+
87+
west sign -t silabs_commander -- --mic YOUR_OTA_KEY --encrypt YOUR_OTA_KEY --sign YOUR_PRIVATE_KEY.pem
88+
or west sign -t silabs_commander
89+
90+
For this to work, Silabs Commander tool must be installed in your PATH.
91+
92+
The input binary (zephyr.bin.rps) is signed using the specified OTA key and private key,
93+
producing zephyr.bin.rps by default. If CONFIG_SIWX91X_OTA_KEY and CONFIG_SIWX91X_PRIVATE_KEY are set
94+
in your build configuration, they will be used unless overridden by command-line arguments.
95+
Additional arguments after '--' are passed to silabs_commander directly.
8296
'''
8397

8498
class ToggleAction(argparse.Action):
@@ -112,7 +126,7 @@ def do_add_parser(self, parser_adder):
112126

113127
# general options
114128
group = parser.add_argument_group('tool control options')
115-
group.add_argument('-t', '--tool', choices=['imgtool', 'rimage'],
129+
group.add_argument('-t', '--tool', choices=['imgtool', 'rimage', 'silabs_commander'],
116130
help='''image signing tool name; imgtool and rimage
117131
are currently supported (imgtool is deprecated)''')
118132
group.add_argument('-p', '--tool-path', default=None,
@@ -195,6 +209,8 @@ def do_run(self, args, ignored):
195209
signer = ImgtoolSigner()
196210
elif args.tool == 'rimage':
197211
signer = RimageSigner()
212+
elif args.tool == 'silabs_commander':
213+
signer = SilabsRPSSigner()
198214
# (Add support for other signers here in elif blocks)
199215
else:
200216
if args.tool is None:
@@ -633,3 +649,97 @@ def sign(self, command, build_dir, build_conf, formats):
633649

634650
os.remove(out_bin)
635651
os.rename(out_tmp, out_bin)
652+
653+
class SilabsRPSSigner(Signer):
654+
# Signer class for Silicon Labs Commander tool via west sign -t silabs_commander.
655+
def find_commandertool(self, cmd, args):
656+
if args.tool_path:
657+
commandertool = args.tool_path
658+
if not os.path.isfile(commandertool):
659+
cmd.die(f'--tool-path {commandertool}: no such file')
660+
else:
661+
commandertool = shutil.which('commander')
662+
if not commandertool:
663+
cmd.die('commander not found')
664+
return commandertool
665+
666+
def get_security_configs(self, build_conf, args, command):
667+
# Retrieve configurations, prioritizing command-line args, then build_conf
668+
siwx91x_ota_key = getattr(args, 'siwx91x-ota-key', build_conf.get('CONFIG_SIWX91X_OTA_KEY'))
669+
siwx91x_private_key = getattr(args, 'siwx91x-private-key', build_conf.get('CONFIG_SIWX91X_PRIVATE_KEY'))
670+
671+
# Use west sign's --tool-path to find the commander tool
672+
commander_path = self.find_commandertool(command, args)
673+
674+
# Validate required settings
675+
if not siwx91x_ota_key:
676+
command.die("SIWX91X_OTA_KEY not provided. Use --siwx91x-ota-key=your_key or add CONFIG_SIWX91X_OTA_KEY in prj.conf.")
677+
if not siwx91x_private_key:
678+
command.die("SIWX91X_PRIVATE_KEY not provided. Use --siwx91x-private-key=/path/to/key or add CONFIG_SIWX91X_PRIVATE_KEY in prj.conf.")
679+
680+
return siwx91x_ota_key, siwx91x_private_key, commander_path
681+
682+
def sign(self, command, build_dir, build_conf, formats):
683+
"""Sign the Zephyr binary using Silicon Labs Commander.
684+
685+
:param command: The Sign instance (provides args and utility methods)
686+
:param build_dir: The build directory path
687+
:param build_conf: BuildConfiguration object for the build directory
688+
:param formats: List of formats to generate (e.g., ['bin', 'rps'])
689+
"""
690+
self.command = command
691+
args = command.args
692+
b = pathlib.Path(build_dir)
693+
694+
# Check if signing is needed
695+
if not formats:
696+
if not args.quiet:
697+
command.inf("No output formats specified, skipping signing.")
698+
return
699+
700+
zephyr_base = ZEPHYR_BASE
701+
if not zephyr_base:
702+
command.die("ZEPHYR_BASE could not be retrieved. Ensure you are running within a Zephyr build environment.")
703+
workspace_base = pathlib.Path(zephyr_base)
704+
if not workspace_base.is_dir():
705+
command.die(f"Invalid ZEPHYR_BASE directory: {ZEPHYR_BASE}. Please check your Zephyr setup.")
706+
707+
# Get kernel binary name (default to 'zephyr')
708+
kernel_name = build_conf.get('CONFIG_KERNEL_BIN_NAME', 'zephyr')
709+
710+
# Setting the input and output file directories
711+
input_rps = b / 'zephyr' / f"{kernel_name}.bin.rps"
712+
output_rps = args.sbin or (b / 'zephyr' / f"{kernel_name}_signed.bin.rps")
713+
714+
# Check if input binary exists
715+
if not input_rps.is_file():
716+
command.die(f"No .rps found at {input_rps}. Ensure the build generated {kernel_name}.bin.rps in {b / 'zephyr'}")
717+
718+
# Load configuration
719+
siwx91x_ota_key, siwx91x_private_key, commander_path = self.get_security_configs(build_conf, args, command)
720+
721+
# Resolve paths
722+
tool_path = pathlib.Path(commander_path)
723+
724+
private_key_path = pathlib.Path(siwx91x_private_key)
725+
if not private_key_path.is_file():
726+
command.die(f"Private key not found at {private_key_path}. Please ensure the path is correct.")
727+
728+
# Build the Silicon Labs Commander signing command
729+
sign_base = [
730+
str(tool_path),
731+
"rps",
732+
"convert",
733+
str(output_rps),
734+
"--app", str(input_rps),
735+
"--mic", siwx91x_ota_key,
736+
"--encrypt", siwx91x_private_key,
737+
"--sign", str(private_key_path)
738+
]
739+
740+
sign_base.extend(args.tool_args)
741+
742+
try:
743+
subprocess.check_call(sign_base, stdout=subprocess.PIPE if args.quiet else None, stderr=subprocess.PIPE if args.quiet else None)
744+
except subprocess.CalledProcessError as e:
745+
command.die(f"Silicon Labs Commander signing failed with exit code {e.returncode}")

soc/silabs/silabs_siwx91x/CMakeLists.txt

+30
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Copyright (c) 2024 Silicon Laboratories Inc.
22
# SPDX-License-Identifier: Apache-2.0
33

4+
include(west) # Add this at the top or before using ${WEST}
5+
46
add_subdirectory(siwg917)
57

68
# Necessary to not overwrite NWP Firmware
@@ -12,3 +14,31 @@ set_property(GLOBAL APPEND PROPERTY extra_post_build_commands
1214
${KERNEL_BIN_NAME}
1315
${KERNEL_BIN_NAME}.rps
1416
)
17+
18+
# Custom signing with Silicon Labs Commander
19+
if(CONFIG_SiWX91X_SILABS_COMMANDER_SIGN)
20+
# Define the west sign command to run along with west build command
21+
set(WEST_SIGN_CMD
22+
${CMAKE_COMMAND} -E env "PATH=$ENV{PATH}:$ENV{WEST_ROOT}/bin" "ZEPHYR_WORKSPACE_ROOT=${CMAKE_CURRENT_SOURCE_DIR}"
23+
${WEST} sign
24+
-t silabs_commander
25+
-d ${CMAKE_BINARY_DIR}
26+
--sbin ${PROJECT_BINARY_DIR}/${KERNEL_BIN_NAME}.rps
27+
)
28+
29+
# Add custom command to invoke west sign during build
30+
add_custom_command(
31+
OUTPUT ${KERNEL_BIN_NAME}.rps
32+
COMMAND ${CMAKE_COMMAND} -E echo "Forcing execution in ${PROJECT_BINARY_DIR}"
33+
COMMAND ${WEST_SIGN_CMD}
34+
DEPENDS zephyr_final
35+
VERBATIM
36+
)
37+
38+
# Add custom target to ensure signing is part of the build
39+
add_custom_target(silabs_commander_sign
40+
ALL
41+
DEPENDS ${KERNEL_BIN_NAME}.rps
42+
COMMENT "Ensuring signing with Silicon Labs Commander is complete"
43+
)
44+
endif()

soc/silabs/silabs_siwx91x/Kconfig

+16
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,19 @@ config SOC_SILABS_SLEEPTIMER
1414
bool
1515
help
1616
The Sleeptimer HAL module is used for SIWX91X.
17+
18+
config SIWX91X_SILABS_COMMANDER_SIGN
19+
bool "Silicon Labs Commander Signing Support"
20+
depends on BUILD_OUTPUT_BIN
21+
help
22+
Activates signing of Zephyr binary with Silicon Labs Commander during build process.
23+
24+
config SIWX91X_OTA_KEY
25+
string "OTA Key for Encryption (sourced from prj.conf)"
26+
help
27+
Specifies OTA key (hex) for signing/encryption with Silicon Labs Commander, from prj.conf.
28+
29+
config SIWX91X_PRIVATE_KEY
30+
string "Private Key Path for Signing (sourced from prj.conf)"
31+
help
32+
Path to private key file for signing with Silicon Labs Commander, from prj.conf, relative to board directory.

0 commit comments

Comments
 (0)