Skip to content

Commit f9c082c

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 f9c082c

File tree

4 files changed

+184
-2
lines changed

4 files changed

+184
-2
lines changed

samples/basic/button/prj.conf

+5
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
CONFIG_GPIO=y
2+
# Enable Silicon Labs Commander signing
3+
CONFIG_SIWX91X_COMMANDER_SIGN=y
4+
CONFIG_M4_OTA_KEY="c2c538dad5d1992a49e427f743527382eb0225d6a6912f6292f240f62793b42b"
5+
CONFIG_M4_PRIVATE_KEY="/home/shaik-aasim/zephyrproject/zephyr/workspace/m4_private_key.pem"
6+
CONFIG_COMMANDER_PATH="commander" # Relies on PATH

scripts/west_commands/sign.py

+125-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
@@ -79,6 +78,20 @@
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+
89+
For this to work, either silabs_commander commander must be installed in your PATH.
90+
91+
The input binary (zephyr.bin.rps) is signed using the specified OTA key and private key,
92+
producing zephyr.bin.rps by default. If CONFIG_M4_OTA_KEY and CONFIG_M4_PRIVATE_KEY are set
93+
in your build configuration, they will be used unless overridden by command-line arguments.
94+
Additional arguments after '--' are passed to silabs_commander directly.
8295
'''
8396

8497
class ToggleAction(argparse.Action):
@@ -112,7 +125,7 @@ def do_add_parser(self, parser_adder):
112125

113126
# general options
114127
group = parser.add_argument_group('tool control options')
115-
group.add_argument('-t', '--tool', choices=['imgtool', 'rimage'],
128+
group.add_argument('-t', '--tool', choices=['imgtool', 'rimage', 'silabs_commander'],
116129
help='''image signing tool name; imgtool and rimage
117130
are currently supported (imgtool is deprecated)''')
118131
group.add_argument('-p', '--tool-path', default=None,
@@ -195,6 +208,8 @@ def do_run(self, args, ignored):
195208
signer = ImgtoolSigner()
196209
elif args.tool == 'rimage':
197210
signer = RimageSigner()
211+
elif args.tool == 'silabs_commander':
212+
signer = SilabsRPSSigner()
198213
# (Add support for other signers here in elif blocks)
199214
else:
200215
if args.tool is None:
@@ -633,3 +648,111 @@ def sign(self, command, build_dir, build_conf, formats):
633648

634649
os.remove(out_bin)
635650
os.rename(out_tmp, out_bin)
651+
652+
class SilabsRPSSigner(Signer):
653+
# Signer class for Silicon Labs Commander tool via west sign -t silabs_commander.
654+
def get_security_configs(self, build_conf, args, command):
655+
# Retrieve configurations, prioritizing command-line args, then build_conf
656+
m4_ota_key = getattr(args, 'm4-ota-key', build_conf.get('CONFIG_M4_OTA_KEY'))
657+
m4_private_key = getattr(args, 'm4-private-key', build_conf.get('CONFIG_M4_PRIVATE_KEY'))
658+
# Fallback to directly read prj.conf if build_conf values are missing
659+
if not m4_ota_key or not m4_private_key:
660+
prj_conf_path = pathlib.Path(build_conf.build_dir) / 'prj.conf'
661+
if prj_conf_path.exists():
662+
with open(prj_conf_path, 'r') as f:
663+
for line in f:
664+
if line.strip().startswith('CONFIG_M4_OTA_KEY='):
665+
m4_ota_key = line.split('=')[1].strip().strip('"')
666+
elif line.strip().startswith('CONFIG_M4_PRIVATE_KEY='):
667+
m4_private_key = line.split('=')[1].strip().strip('"')
668+
# Automatically detect Commander path, mimicking west flash
669+
commander_path = getattr(args, 'commander-path', None)
670+
if not commander_path:
671+
# Try system PATH first, as west flash likely does
672+
commander_path = shutil.which('commander')
673+
if not commander_path:
674+
# Fallback to common Silicon Labs default paths (adjust if known)
675+
default_paths = [
676+
'/usr/bin/commander',
677+
'/usr/local/bin/commander',
678+
'/opt/SiliconLabs/Commander/commander'
679+
]
680+
for path in default_paths:
681+
if os.path.isfile(path):
682+
commander_path = path
683+
break
684+
# Validate required settings with fallback to prj.conf
685+
if not m4_ota_key:
686+
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.")
687+
if not m4_private_key:
688+
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.")
689+
if not commander_path:
690+
command.die("Commander not found automatically. Please provide --commander-path=/path/to/commander or install it in your PATH.")
691+
692+
return m4_ota_key, m4_private_key, commander_path
693+
694+
def sign(self, command, build_dir, build_conf, formats):
695+
# Sign the Zephyr binary using Silicon Labs Commander.
696+
697+
self.command = command
698+
args = command.args
699+
b = pathlib.Path(build_dir) # BUILD_DIR from -d option
700+
701+
# Check if signing is needed
702+
if not formats:
703+
if not args.quiet:
704+
command.inf("No output formats specified, skipping signing.")
705+
return
706+
707+
# Use ZEPHYR_BASE as the workspace base, provided by Zephyr's build system
708+
zephyr_base = os.environ.get('ZEPHYR_BASE')
709+
if not zephyr_base:
710+
command.die("ZEPHYR_BASE environment variable not set. Ensure you are running within a Zephyr build environment.")
711+
workspace_base = pathlib.Path(zephyr_base)
712+
if not workspace_base.is_dir():
713+
command.die(f"Invalid ZEPHYR_BASE directory: {workspace_base}. Please check your Zephyr setup.")
714+
715+
# Get kernel binary name (default to 'zephyr')
716+
kernel_name = build_conf.get('CONFIG_KERNEL_BIN_NAME', 'zephyr')
717+
718+
# Input and output files (using BUILD_DIR)
719+
in_bin = b / 'zephyr' / f"{kernel_name}.bin.rps" # Raw binary input
720+
out_rps = args.sbin or (b / 'zephyr' / f"{kernel_name}.bin.rps") # Signed output
721+
722+
# Check if input binary exists
723+
if not in_bin.is_file():
724+
command.die(f"No unsigned .bin found at {in_bin}")
725+
726+
# Load configuration
727+
m4_ota_key, m4_private_key, commander_path = self.get_security_configs(build_conf, args, command)
728+
729+
# Resolve paths
730+
tool_path = pathlib.Path(commander_path)
731+
if not tool_path.is_file():
732+
command.die(f"Commander not found at {tool_path}. Please ensure it is installed or provide --commander-path.")
733+
734+
private_key_path = pathlib.Path(m4_private_key)
735+
if not private_key_path.is_file():
736+
command.die(f"Private key not found at {private_key_path}. Please ensure the path is correct.")
737+
738+
# Build the commander signing command
739+
sign_base = [
740+
str(tool_path),
741+
"rps",
742+
"convert",
743+
str(out_rps),
744+
"--app", str(in_bin),
745+
"--mic", m4_ota_key,
746+
"--encrypt", m4_ota_key,
747+
"--sign", str(private_key_path)
748+
]
749+
750+
sign_base.extend(args.tool_args)
751+
752+
try:
753+
subprocess.check_call(sign_base, stdout=subprocess.PIPE if args.quiet else None, stderr=subprocess.PIPE if args.quiet else None)
754+
except subprocess.CalledProcessError as e:
755+
command.die(f"Commander signing failed with exit code {e.returncode}")
756+
757+
if not args.quiet:
758+
command.inf(f"Successfully generated signed file: {out_rps}")

soc/silabs/silabs_siwx91x/CMakeLists.txt

+38
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_init.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,36 @@ 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 input and output files
24+
set(SIGNED_RPS ${PROJECT_BINARY_DIR}/zephyr/${KERNEL_BIN_NAME}.bin.rps)
25+
26+
# Define the west sign command with explicit working directory and environment
27+
set(WEST_SIGN_CMD
28+
${CMAKE_COMMAND} -E env "PATH=$ENV{PATH}:$ENV{WEST_ROOT}/bin" "ZEPHYR_WORKSPACE_ROOT=${CMAKE_CURRENT_SOURCE_DIR}"
29+
${WEST} sign
30+
-t silabs_commander
31+
-d ${CMAKE_BINARY_DIR}
32+
--sbin ${SIGNED_RPS}
33+
)
34+
35+
# Add custom command to invoke west sign during build
36+
add_custom_command(
37+
OUTPUT ${SIGNED_RPS}
38+
COMMAND ${CMAKE_COMMAND} -E echo "Forcing execution in ${PROJECT_BINARY_DIR}"
39+
COMMAND ${WEST_SIGN_CMD}
40+
DEPENDS zephyr_final
41+
WORKING_DIRECTORY ${PROJECT_BINARY_DIR} # Ensure working directory is set
42+
COMMENT "Signing binary with 'west sign -t silabs_commander' to generate ${KERNEL_BIN_NAME}.bin.rps"
43+
VERBATIM
44+
)
45+
46+
# Add custom target to ensure signing is part of the build
47+
add_custom_target(silabs_commander_sign
48+
ALL
49+
DEPENDS ${SIGNED_RPS}
50+
COMMENT "Ensuring signing with Silicon Labs Commander is complete"
51+
)
52+
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 "Enable signing of Zephyr binary with Silicon Labs Commander"
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)