Skip to content

Commit 964683e

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 964683e

File tree

4 files changed

+169
-3
lines changed

4 files changed

+169
-3
lines changed

boards/silabs/radio_boards/siwx917_rb4338a/board.cmake

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
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(!CONFIG_SILABS_COMMANDER_SIGN)
6+
set(FLASH_FILE ${PROJECT_BINARY_DIR}/zephyr.bin.rps)
7+
endif()
48
board_runner_args(silabs_commander "--device=SiWG917M111GTBA" "--file-type=bin"
59
"--file=${PROJECT_BINARY_DIR}/${KERNEL_BIN_NAME}.rps")
610
include(${ZEPHYR_BASE}/boards/common/silabs_commander.board.cmake)

scripts/west_commands/sign.py

+115-2
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
@@ -23,6 +22,7 @@
2322
from runners.core import BuildConfiguration
2423
from zcmake import CMakeCache
2524
from zephyr_ext_common import Forceable, ZEPHYR_SCRIPTS
25+
from zephyr_ext_common import ZEPHYR_BASE
2626

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

8499
class ToggleAction(argparse.Action):
@@ -112,7 +127,7 @@ def do_add_parser(self, parser_adder):
112127

113128
# general options
114129
group = parser.add_argument_group('tool control options')
115-
group.add_argument('-t', '--tool', choices=['imgtool', 'rimage'],
130+
group.add_argument('-t', '--tool', choices=['imgtool', 'rimage', 'silabs_commander'],
116131
help='''image signing tool name; imgtool and rimage
117132
are currently supported (imgtool is deprecated)''')
118133
group.add_argument('-p', '--tool-path', default=None,
@@ -195,6 +210,8 @@ def do_run(self, args, ignored):
195210
signer = ImgtoolSigner()
196211
elif args.tool == 'rimage':
197212
signer = RimageSigner()
213+
elif args.tool == 'silabs_commander':
214+
signer = SilabsRPSSigner()
198215
# (Add support for other signers here in elif blocks)
199216
else:
200217
if args.tool is None:
@@ -633,3 +650,99 @@ def sign(self, command, build_dir, build_conf, formats):
633650

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

soc/silabs/silabs_siwx91x/CMakeLists.txt

+33
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
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)
7+
zephyr_include_directories(.)
8+
zephyr_sources_ifdef(CONFIG_SOC_SERIES_SIWG917 soc.c)
9+
zephyr_sources_ifdef(CONFIG_WISECONNECT_NETWORK_STACK nwp.c)
510

611
# Necessary to not overwrite NWP Firmware
712
math(EXPR FLASH_LOAD_ADDRESS "(${CONFIG_FLASH_BASE_ADDRESS}) + (${CONFIG_FLASH_LOAD_OFFSET})")
@@ -12,3 +17,31 @@ set_property(GLOBAL APPEND PROPERTY extra_post_build_commands
1217
${KERNEL_BIN_NAME}
1318
${KERNEL_BIN_NAME}.rps
1419
)
20+
21+
# Custom signing with Silicon Labs Commander
22+
if(CONFIG_SiWX91X_SILABS_COMMANDER_SIGN)
23+
# Define the west sign command to run along with west build command
24+
set(WEST_SIGN_CMD
25+
${CMAKE_COMMAND} -E env "PATH=$ENV{PATH}:$ENV{WEST_ROOT}/bin" "ZEPHYR_WORKSPACE_ROOT=${CMAKE_CURRENT_SOURCE_DIR}"
26+
${WEST} sign
27+
-t silabs_commander
28+
-d ${CMAKE_BINARY_DIR}
29+
--sbin ${PROJECT_BINARY_DIR}/${KERNEL_BIN_NAME}.rps
30+
)
31+
32+
# Add custom command to invoke west sign during build
33+
add_custom_command(
34+
OUTPUT ${KERNEL_BIN_NAME}.rps
35+
COMMAND ${CMAKE_COMMAND} -E echo "Forcing execution in ${PROJECT_BINARY_DIR}"
36+
COMMAND ${WEST_SIGN_CMD}
37+
DEPENDS zephyr_final
38+
VERBATIM
39+
)
40+
41+
# Add custom target to ensure signing is part of the build
42+
add_custom_target(silabs_commander_sign
43+
ALL
44+
DEPENDS ${KERNEL_BIN_NAME}.rps
45+
COMMENT "Ensuring signing with Silicon Labs Commander is complete"
46+
)
47+
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 the signing process for the Zephyr binary using Silicon Labs Commander during the build process.
23+
24+
config M4_OTA_KEY
25+
string "OTA Key for Commander (sourced from prj.conf)"
26+
help
27+
Specifies the OTA key (in hex format) for signing and encryption with Silicon Labs Commander, retrieved from prj.conf.
28+
29+
config M4_PRIVATE_KEY
30+
string "Private Key Path for Commander (sourced from prj.conf)"
31+
help
32+
Defines the path to the private key file for signing with Silicon Labs Commander, obtained from prj.conf, relative to the board directory.

0 commit comments

Comments
 (0)