Skip to content

Commit 505a62b

Browse files
committed
[nrf noup] west: runners: Add ncs-provision to west flash command
Added automatic KMU key provisioning for both NSIB and MCUboot. A new '--ncs-provision' command line option added to nrfutil runner. This enables automated key provisioning during the flashing process, to enable testing nRF54L aplications using Twister. Signed-off-by: Grzegorz Chwierut <[email protected]>
1 parent 59275b9 commit 505a62b

File tree

2 files changed

+85
-2
lines changed

2 files changed

+85
-2
lines changed

scripts/west_commands/runners/nrf_common.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False,
9797

9898
# Only applicable for nrfutil
9999
self.suit_starter = False
100+
self.ncs_provision = False
100101

101102
self.tool_opt = []
102103
if tool_opt is not None:
@@ -542,6 +543,10 @@ def do_exec_op(self, op, force=False):
542543
Throws subprocess.CalledProcessError with the appropriate
543544
returncode if a failure arises.'''
544545

546+
def do_ncs_provision(self):
547+
''' Provision default keys. Only applicable for nrfutil '''
548+
pass
549+
545550
def flush_ops(self, force=True):
546551
''' Execute any remaining ops in the self.ops array.
547552
Throws subprocess.CalledProcessError with the appropriate
@@ -589,6 +594,8 @@ def do_run(self, command, **kwargs):
589594
if self.recover:
590595
self.recover_target()
591596
self.program_hex()
597+
if self.ncs_provision:
598+
self.do_ncs_provision()
592599
if self.reset:
593600
self.reset_target()
594601
# All done, now flush any outstanding ops

scripts/west_commands/runners/nrfutil.py

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ class NrfUtilBinaryRunner(NrfBinaryRunner):
1919
def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False,
2020
erase_mode=None, ext_erase_mode=None, reset=True, tool_opt=None,
2121
force=False, recover=False, suit_starter=False,
22-
ext_mem_config_file=None):
22+
ext_mem_config_file=None, ncs_provision=False):
2323

2424
super().__init__(cfg, family, softreset, pinreset, dev_id, erase,
2525
erase_mode, ext_erase_mode, reset, tool_opt, force,
2626
recover)
2727

2828
self.suit_starter = suit_starter
2929
self.ext_mem_config_file = ext_mem_config_file
30+
self.ncs_provision = ncs_provision
3031

3132
self._ops = []
3233
self._op_id = 1
@@ -57,7 +58,8 @@ def do_create(cls, cfg, args):
5758
reset=args.reset, tool_opt=args.tool_opt,
5859
force=args.force, recover=args.recover,
5960
suit_starter=args.suit_manifest_starter,
60-
ext_mem_config_file=args.ext_mem_config_file)
61+
ext_mem_config_file=args.ext_mem_config_file,
62+
ncs_provision=args.ncs_provision)
6163

6264
@classmethod
6365
def do_add_parser(cls, parser):
@@ -68,6 +70,9 @@ def do_add_parser(cls, parser):
6870
parser.add_argument('--ext-mem-config-file', required=False,
6971
dest='ext_mem_config_file',
7072
help='path to an JSON file with external memory configuration')
73+
parser.add_argument('--ncs-provision',
74+
action='store_true',
75+
help='run ncs-provision with using default keys')
7176

7277
def _exec(self, args):
7378
jout_all = []
@@ -113,6 +118,75 @@ def do_get_boards(self):
113118
def do_require(self):
114119
self.require('nrfutil')
115120

121+
def _generate_ncs_provision_key_file(
122+
self,
123+
keys: list[str] | str,
124+
keyname: str, # UROT_PUBKEY, BL_PUBKEY, APP_PUBKEY
125+
output_file: Path
126+
):
127+
"""Generate a key file for ncs-provision.
128+
Currently uses the west ncs-provision command to generate the JSON file.
129+
Consider importing directly from sdk-nrf/scripts/west_commands/ncs_provision.py
130+
or sdk-nrf/scripts/generate_psa_key_attributes.py to call methods directly
131+
"""
132+
build_dir = Path(self.cfg.build_dir).parent
133+
ncs_keyfile = build_dir / 'keyfile.json'
134+
if ncs_keyfile.exists():
135+
ncs_keyfile.unlink()
136+
command = [
137+
'west', 'ncs-provision', 'upload',
138+
'--soc', 'nrf54l15',
139+
'--keyname', keyname,
140+
'--build-dir', str(build_dir),
141+
'--dry-run'
142+
]
143+
for key in keys:
144+
command += ["--key", key]
145+
self.check_call(command)
146+
147+
# move the generated ncs keyfile to the output_file
148+
if output_file.exists():
149+
output_file.unlink()
150+
ncs_keyfile.rename(output_file)
151+
152+
def _ncs_provision_for_nsib(self):
153+
if not self.sysbuild_conf.getboolean('SB_CONFIG_SECURE_BOOT_SIGNATURE_TYPE_ED25519'):
154+
return
155+
build_dir = Path(self.cfg.build_dir).parent
156+
key_file = self.sysbuild_conf.get('SB_CONFIG_SECURE_BOOT_SIGNING_KEY_FILE') or str(
157+
build_dir / 'GENERATED_NON_SECURE_SIGN_KEY_PRIVATE.pem')
158+
if not Path(key_file).exists():
159+
raise RuntimeError(f'Key file {key_file} does not exist')
160+
161+
ncs_keyfile = build_dir / 'keyfile_for_nsib.json'
162+
self._generate_ncs_provision_key_file(
163+
keys=[key_file],
164+
keyname='BL_PUBKEY',
165+
output_file=ncs_keyfile
166+
)
167+
self.exec_op('x-provision-keys', keyfile=str(ncs_keyfile))
168+
169+
def _ncs_provision_for_mcuboot(self):
170+
if not self.sysbuild_conf.getboolean('SB_CONFIG_MCUBOOT_SIGNATURE_USING_KMU'):
171+
return
172+
key_file = self.sysbuild_conf.get('SB_CONFIG_BOOT_SIGNATURE_KEY_FILE')
173+
if not Path(key_file).exists():
174+
raise RuntimeError(f'Key file {key_file} does not exist')
175+
176+
ncs_keyfile = Path(self.cfg.build_dir).parent / 'keyfile_for_mcuboot.json'
177+
self._generate_ncs_provision_key_file(
178+
keys=[key_file],
179+
keyname='UROT_PUBKEY',
180+
output_file=ncs_keyfile
181+
)
182+
self.exec_op('x-provision-keys', keyfile=str(ncs_keyfile))
183+
184+
def do_ncs_provision(self):
185+
if not self.ncs_provision:
186+
return
187+
self._ncs_provision_for_nsib()
188+
self._ncs_provision_for_mcuboot()
189+
116190
def _insert_op(self, op):
117191
op['operationId'] = f'{self._op_id}'
118192
self._op_id += 1
@@ -145,6 +219,8 @@ def _append_batch(self, op, json_file):
145219
cmd += ['--reset-kind', _op['kind']]
146220
elif op_type == 'erase':
147221
cmd.append(f'--{_op["kind"]}')
222+
elif op_type == 'x-provision-keys':
223+
cmd += ['--key-file', _op['keyfile']]
148224

149225
cmd += ['--core', op['core']] if op.get('core') else []
150226
cmd += ['--x-family', f'{self.family}']

0 commit comments

Comments
 (0)