@@ -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