Skip to content

Commit 009ada8

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 009ada8

File tree

3 files changed

+180
-2
lines changed

3 files changed

+180
-2
lines changed

scripts/west_commands/sign.py

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