Skip to content

Commit a56204b

Browse files
committed
suit: Build system changes needed for encryption
This commit contains changes to the SUIT build system allowing for encrypting images for update. Signed-off-by: Artur Hadasz <[email protected]>
1 parent 6586628 commit a56204b

File tree

8 files changed

+263
-23
lines changed

8 files changed

+263
-23
lines changed

cmake/sysbuild/suit.cmake

+50-19
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,12 @@ function(suit_create_package)
236236
set(CORE_ARGS)
237237
set(STORAGE_BOOT_ARGS)
238238
sysbuild_get(app_config_dir IMAGE ${DEFAULT_IMAGE} VAR APPLICATION_CONFIG_DIR CACHE)
239+
get_property(SUIT_KMS_SCRIPT GLOBAL PROPERTY SUIT_KMS_SCRIPT)
240+
# If the user has not provided the path to the kms script, use the default one.
241+
if(NOT SUIT_KMS_SCRIPT)
242+
set(SUIT_KMS_SCRIPT "${ZEPHYR_SUIT_GENERATOR_MODULE_DIR}/ncs/basic_kms.py")
243+
endif()
244+
239245

240246
if(NOT DEFINED SB_CONFIG_SUIT_ENVELOPE_SIGN)
241247
set(SB_CONFIG_SUIT_ENVELOPE_SIGN FALSE)
@@ -247,12 +253,40 @@ function(suit_create_package)
247253

248254
foreach(image ${IMAGES})
249255
unset(target)
256+
unset(encrypt)
250257
sysbuild_get(BINARY_DIR IMAGE ${image} VAR APPLICATION_BINARY_DIR CACHE)
251258
sysbuild_get(BINARY_FILE IMAGE ${image} VAR CONFIG_KERNEL_BIN_NAME KCONFIG)
252259
sysbuild_get(target IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TARGET KCONFIG)
260+
sysbuild_get(encrypt IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT KCONFIG)
253261

254262
set(BINARY_FILE "${BINARY_FILE}.bin")
255263

264+
if(encrypt)
265+
if(DEFINED target AND NOT target STREQUAL "")
266+
set(${image}_SUIT_ENCRYPT_DIR "${SUIT_ROOT_DIRECTORY}/${target}_encryption_artifacts")
267+
else()
268+
set(${image}_SUIT_ENCRYPT_DIR "${SUIT_ROOT_DIRECTORY}/${image}_encryption_artifacts")
269+
endif()
270+
271+
set(SUIT_ENCRYPT_ARGS)
272+
sysbuild_get(encrypt_string_key_id IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT_STRING_KEY_ID KCONFIG)
273+
sysbuild_get(encrypt_key_name IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_NAME KCONFIG)
274+
sysbuild_get(plaintext_hash_alg IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT_PLAINTEXT_HASH_ALG_NAME KCONFIG)
275+
276+
list(APPEND SUIT_ENCRYPT_ARGS --firmware ${BINARY_DIR}/zephyr/${BINARY_FILE})
277+
list(APPEND SUIT_ENCRYPT_ARGS --key-name ${encrypt_key_name})
278+
list(APPEND SUIT_ENCRYPT_ARGS --string-key-id ${encrypt_string_key_id})
279+
list(APPEND SUIT_ENCRYPT_ARGS --hash-alg ${plaintext_hash_alg})
280+
list(APPEND SUIT_ENCRYPT_ARGS --context ${SB_CONFIG_SUIT_ENVELOPE_KMS_SCRIPT_CONTEXT})
281+
list(APPEND SUIT_ENCRYPT_ARGS --kms-script ${SUIT_KMS_SCRIPT})
282+
283+
suit_encrypt_image("${SUIT_ENCRYPT_ARGS}" ${${image}_SUIT_ENCRYPT_DIR})
284+
285+
set(${image}_SUIT_PAYLOAD_BINARY ${${image}_SUIT_ENCRYPT_DIR}/encrypted_content.bin)
286+
else()
287+
set(${image}_SUIT_PAYLOAD_BINARY ${BINARY_DIR}/zephyr/${BINARY_FILE})
288+
endif()
289+
256290
list(APPEND CORE_ARGS
257291
--core ${image},${SUIT_ROOT_DIRECTORY}${image}.bin,${BINARY_DIR}/zephyr/edt.pickle,${BINARY_DIR}/zephyr/.config
258292
)
@@ -262,11 +296,11 @@ function(suit_create_package)
262296
--core ${target},${SUIT_ROOT_DIRECTORY}${image}.bin,${BINARY_DIR}/zephyr/edt.pickle,${BINARY_DIR}/zephyr/.config
263297
)
264298
endif()
265-
suit_copy_artifact_to_output_directory(${image} ${BINARY_DIR}/zephyr/${BINARY_FILE})
299+
suit_copy_artifact_to_output_directory(${image} ${${image}_SUIT_PAYLOAD_BINARY})
266300

267-
unset(CONFIG_SUIT_RECOVERY)
268-
sysbuild_get(CONFIG_SUIT_RECOVERY IMAGE ${image} VAR CONFIG_SUIT_RECOVERY KCONFIG)
269-
if(CONFIG_SUIT_RECOVERY)
301+
unset(recovery)
302+
sysbuild_get(recovery IMAGE ${image} VAR CONFIG_SUIT_RECOVERY KCONFIG)
303+
if(recovery)
270304
set_property(GLOBAL APPEND PROPERTY SUIT_RECOVERY_DFU_ARTIFACTS ${SUIT_ROOT_DIRECTORY}${image}.bin)
271305
else()
272306
set_property(GLOBAL APPEND PROPERTY SUIT_DFU_ARTIFACTS ${SUIT_ROOT_DIRECTORY}${image}.bin)
@@ -313,9 +347,9 @@ function(suit_create_package)
313347
suit_render_template(${INPUT_ENVELOPE_JINJA_FILE} ${ENVELOPE_YAML_FILE} "${TEMPLATE_ARGS}")
314348
suit_create_envelope(${ENVELOPE_YAML_FILE} ${ENVELOPE_SUIT_FILE} ${SB_CONFIG_SUIT_ENVELOPE_SIGN})
315349

316-
unset(CONFIG_SUIT_RECOVERY)
317-
sysbuild_get(CONFIG_SUIT_RECOVERY IMAGE ${image} VAR CONFIG_SUIT_RECOVERY KCONFIG)
318-
if(CONFIG_SUIT_RECOVERY)
350+
unset(recovery)
351+
sysbuild_get(recovery IMAGE ${image} VAR CONFIG_SUIT_RECOVERY KCONFIG)
352+
if(recovery)
319353
set_property(GLOBAL APPEND PROPERTY SUIT_RECOVERY_DFU_ARTIFACTS ${ENVELOPE_SUIT_FILE})
320354
else()
321355
set_property(GLOBAL APPEND PROPERTY SUIT_DFU_ARTIFACTS ${ENVELOPE_SUIT_FILE})
@@ -336,10 +370,10 @@ function(suit_create_package)
336370
if(EXTRACT_TO_CACHE)
337371
sysbuild_get(CACHE_PARTITION_NUM IMAGE ${image} VAR CONFIG_SUIT_DFU_CACHE_EXTRACT_IMAGE_PARTITION KCONFIG)
338372

339-
unset(CONFIG_SUIT_RECOVERY)
340-
sysbuild_get(CONFIG_SUIT_RECOVERY IMAGE ${image} VAR CONFIG_SUIT_RECOVERY KCONFIG)
373+
unset(recovery)
374+
sysbuild_get(recovery IMAGE ${image} VAR CONFIG_SUIT_RECOVERY KCONFIG)
341375

342-
if(CONFIG_SUIT_RECOVERY)
376+
if(recovery)
343377
list(APPEND RECOVERY_DFU_CACHE_PARTITIONS_USED ${CACHE_PARTITION_NUM})
344378
list(APPEND SUIT_RECOVERY_CACHE_PARTITION_${CACHE_PARTITION_NUM} ${image})
345379
else()
@@ -356,11 +390,10 @@ function(suit_create_package)
356390
foreach(CACHE_PARTITION_NUM ${DFU_CACHE_PARTITIONS_USED})
357391
set(CACHE_CREATE_ARGS "")
358392
foreach(image ${SUIT_CACHE_PARTITION_${CACHE_PARTITION_NUM}})
359-
sysbuild_get(BINARY_DIR IMAGE ${image} VAR APPLICATION_BINARY_DIR CACHE)
360-
sysbuild_get(BINARY_FILE IMAGE ${image} VAR CONFIG_KERNEL_BIN_NAME KCONFIG)
361393
sysbuild_get(IMAGE_CACHE_URI IMAGE ${image} VAR CONFIG_SUIT_DFU_CACHE_EXTRACT_IMAGE_URI KCONFIG)
394+
362395
list(APPEND CACHE_CREATE_ARGS
363-
"--input" "\"${IMAGE_CACHE_URI},${BINARY_DIR}/zephyr/${BINARY_FILE}.bin\""
396+
"--input" "\"${IMAGE_CACHE_URI},${${image}_SUIT_PAYLOAD_BINARY}\""
364397
)
365398
endforeach()
366399

@@ -382,11 +415,9 @@ function(suit_create_package)
382415
foreach(CACHE_PARTITION_NUM ${RECOVERY_DFU_CACHE_PARTITIONS_USED})
383416
set(CACHE_CREATE_ARGS "")
384417
foreach(image ${SUIT_RECOVERY_CACHE_PARTITION_${CACHE_PARTITION_NUM}})
385-
sysbuild_get(BINARY_DIR IMAGE ${image} VAR APPLICATION_BINARY_DIR CACHE)
386-
sysbuild_get(BINARY_FILE IMAGE ${image} VAR CONFIG_KERNEL_BIN_NAME KCONFIG)
387418
sysbuild_get(IMAGE_CACHE_URI IMAGE ${image} VAR CONFIG_SUIT_DFU_CACHE_EXTRACT_IMAGE_URI KCONFIG)
388419
list(APPEND CACHE_CREATE_ARGS
389-
"--input" "\"${IMAGE_CACHE_URI},${BINARY_DIR}/zephyr/${BINARY_FILE}.bin\""
420+
"--input" "\"${IMAGE_CACHE_URI},${${image}_SUIT_PAYLOAD_BINARY}\""
390421
)
391422
endforeach()
392423

@@ -544,9 +575,9 @@ function(suit_setup_merge)
544575
foreach(image ${IMAGES})
545576
set(ARTIFACTS_TO_MERGE)
546577

547-
unset(CONFIG_NRF_REGTOOL_GENERATE_UICR)
548-
sysbuild_get(CONFIG_NRF_REGTOOL_GENERATE_UICR IMAGE ${image} VAR CONFIG_NRF_REGTOOL_GENERATE_UICR KCONFIG)
549-
if(NOT DEFINED CONFIG_NRF_REGTOOL_GENERATE_UICR)
578+
unset(regtool_generate_uicr)
579+
sysbuild_get(regtool_generate_uicr IMAGE ${image} VAR CONFIG_NRF_REGTOOL_GENERATE_UICR KCONFIG)
580+
if(NOT DEFINED regtool_generate_uicr)
550581
continue()
551582
endif()
552583

cmake/sysbuild/suit_utilities.cmake

+65-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ set(SUIT_GENERATOR_BUILD_SCRIPT "${ZEPHYR_SUIT_GENERATOR_MODULE_DIR}/ncs/build.p
88
set(SUIT_GENERATOR_CLI_SCRIPT "${ZEPHYR_SUIT_GENERATOR_MODULE_DIR}/suit_generator/cli.py")
99
set(SUIT_OUTPUT_ARTIFACTS_DIRECTORY "DFU")
1010

11+
if(WIN32)
12+
set(SEP $<SEMICOLON>)
13+
else()
14+
set(SEP :)
15+
endif()
16+
1117
if(NOT DEFINED SUIT_ROOT_DIRECTORY)
1218
set(SUIT_ROOT_DIRECTORY ${APPLICATION_BINARY_DIR}/${SUIT_OUTPUT_ARTIFACTS_DIRECTORY}/)
1319
endif()
@@ -84,8 +90,17 @@ function(suit_create_envelope input_file output_file create_signature)
8490
endif()
8591
endfunction()
8692

93+
# Create a SUIT DFU cache partition file from a list of payloads.
94+
#
95+
# Usage:
96+
# suit_create_cache_partition(<args> <output_file> <partition_num> <recovery>)
97+
#
98+
# Parameters:
99+
# 'args' - list of arguments for the cache_create command
100+
# 'output_file' - path to output cache partition file
101+
# 'partition_num' - partition number
102+
# 'recovery' - if set to true, the cache partition contains recovery firmware payloads
87103
function(suit_create_cache_partition args output_file partition_num recovery)
88-
89104
list(APPEND args "--output-file" "${output_file}")
90105

91106
set_property(
@@ -110,6 +125,15 @@ function(suit_create_cache_partition args output_file partition_num recovery)
110125
endif()
111126
endfunction()
112127

128+
# Create a SUIT DFU cache partition with Nordic proprietary payloads
129+
# extracted from the top-level SUIT envelope.
130+
#
131+
# Usage:
132+
# suit_create_nordic_cache_partition(<args> <output_file>)
133+
#
134+
# Parameters:
135+
# 'args' - list of arguments for the cache_create command
136+
# 'output_file' - path to output cache partition file
113137
function(suit_create_nordic_cache_partition args output_file)
114138
list(APPEND args "--output-file" "${output_file}")
115139
list(APPEND args "--omit-payload-regex" "'(?!.*secdom.*\.bin|.*sysctl_v.*\.bin).*'")
@@ -143,3 +167,43 @@ function(suit_add_merge_hex_file)
143167
set_property(GLOBAL APPEND PROPERTY SUIT_MERGE_application_DEPENDENCIES ${arg_DEPENDENCIES})
144168
endif()
145169
endfunction()
170+
171+
# Create SUIT encryption artifacts for a given image.
172+
#
173+
# Usage:
174+
# suit_encrypt_image(<args> <output_directory>)
175+
#
176+
# Parameters:
177+
# 'args' - list of arguments for the encryption script
178+
# 'output_directory' - path to a directory where the encryption artifacts will be stored
179+
function(suit_encrypt_image args output_directory)
180+
get_property(
181+
encrypt_script
182+
GLOBAL PROPERTY
183+
SUIT_ENCRYPT_SCRIPT
184+
)
185+
# If the user has not provided the path to the encrypt script, use the default one.
186+
if(NOT encrypt_script)
187+
set(encrypt_script "${ZEPHYR_SUIT_GENERATOR_MODULE_DIR}/ncs/encrypt_script.py")
188+
endif()
189+
190+
if(NOT EXISTS ${encrypt_script})
191+
message(SEND_ERROR "DFU: ${encrypt_script} does not exist. Corrupted configuration?")
192+
return()
193+
endif()
194+
195+
list(APPEND args --output-dir ${output_directory})
196+
197+
set_property(
198+
GLOBAL APPEND PROPERTY SUIT_POST_BUILD_COMMANDS
199+
COMMAND ${CMAKE_COMMAND} -E make_directory ${output_directory}
200+
)
201+
set_property(
202+
GLOBAL APPEND PROPERTY SUIT_POST_BUILD_COMMANDS
203+
COMMAND
204+
PYTHONPATH=${ZEPHYR_SUIT_GENERATOR_MODULE_DIR}${SEP}$ENV{PYTHONPATH}
205+
${PYTHON_EXECUTABLE}
206+
${encrypt_script} encrypt-and-generate
207+
${args}
208+
)
209+
endfunction()

config/suit/templates/nrf54h20/default/v1/app_envelope.yaml.jinja2

+33
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
{%- set mpi_application_vendor_name = sysbuild['config']['SB_CONFIG_SUIT_MPI_APP_LOCAL_1_VENDOR_NAME']|default('nordicsemi.com') %}
22
{%- set mpi_application_class_name = sysbuild['config']['SB_CONFIG_SUIT_MPI_APP_LOCAL_1_CLASS_NAME']|default('nRF54H20_sample_app') %}
3+
{%- set suit_artifacts_base_dir = ( application['binary'].split('/')[:-1] | join('/') ) %}
4+
{%- if 'CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT' in application['config'] and application['config']['CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT'] != '' %}
5+
{%- set encrypted = True %}
6+
{%- set app_encryption_dir = ( suit_artifacts_base_dir ) + "/" + ( application['name'] ) + "_encryption_artifacts" %}
7+
{%- else %}
8+
{%- set encrypted = False %}
9+
{%- endif %}
310
SUIT_Envelope_Tagged:
411
suit-authentication-wrapper:
512
SuitDigest:
@@ -33,9 +40,17 @@ SUIT_Envelope_Tagged:
3340
suit-parameter-image-digest:
3441
suit-digest-algorithm-id: cose-alg-sha-256
3542
suit-digest-bytes:
43+
{%- if encrypted %}
44+
file_direct: {{ app_encryption_dir }}/plain_text_digest.bin
45+
{%- else %}
3646
file: {{ application['binary'] }}
47+
{%- endif %}
3748
suit-parameter-image-size:
49+
{%- if encrypted %}
50+
file_direct: {{ app_encryption_dir }}/plain_text_size.txt
51+
{%- else %}
3852
file: {{ application['binary'] }}
53+
{%- endif %}
3954
- suit-condition-vendor-identifier:
4055
- suit-send-record-success
4156
- suit-send-record-failure
@@ -102,6 +117,10 @@ SUIT_Envelope_Tagged:
102117
- suit-directive-set-component-index: 0
103118
- suit-directive-override-parameters:
104119
suit-parameter-source-component: 1
120+
{%- if encrypted %}
121+
suit-parameter-encryption-info:
122+
file: {{ app_encryption_dir }}/suit_encryption_info.bin
123+
{%- endif %}
105124
# When copying the data it is worth to retry the sequence of
106125
# suit-directive-copy and suit-condition-image-match at least once.
107126
# If a bit flip occurs, it might be due to a transport issue, not
@@ -138,8 +157,21 @@ SUIT_Envelope_Tagged:
138157
suit-digest-algorithm-id: cose-alg-sha-256
139158
suit-digest-bytes:
140159
file: {{ application['binary'] }}
160+
{%- if encrypted %}
161+
# For the encrypted image this fetch directive is used to verify the tag and the AAD
162+
# of the received encrypted image The target "CAND_IMG" behaves like a /dev/null device
163+
# and all the data is discarded.
164+
# This way even if the encrypted content is incorrect, the contents of the target memory
165+
# will not be affected.
166+
# Note that no digest checking is required on the encrypted content itself, as checking the tag
167+
# and the AAD verifies the integrity of the content. In fact, suit-condition-image-match
168+
# won't be able to work in this case, as the CAND_IMG won't contain any valid content.
169+
suit-parameter-encryption-info:
170+
file: {{ app_encryption_dir }}/suit_encryption_info.bin
171+
{%- endif %}
141172
- suit-directive-fetch:
142173
- suit-send-record-failure
174+
{%- if not encrypted %}
143175
- suit-directive-try-each:
144176
- - suit-condition-image-match:
145177
- suit-send-record-success
@@ -151,6 +183,7 @@ SUIT_Envelope_Tagged:
151183
- suit-send-record-failure
152184
- suit-send-sysinfo-success
153185
- suit-send-sysinfo-failure
186+
{%- endif %}
154187

155188
suit-manifest-component-id:
156189
- INSTLD_MFST

config/suit/templates/nrf54h20/default/v1/rad_envelope.yaml.jinja2

+33
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
{%- set mpi_radio_vendor_name = sysbuild['config']['SB_CONFIG_SUIT_MPI_RAD_LOCAL_1_VENDOR_NAME']|default('nordicsemi.com') %}
22
{%- set mpi_radio_class_name = sysbuild['config']['SB_CONFIG_SUIT_MPI_RAD_LOCAL_1_CLASS_NAME']|default('nRF54H20_sample_rad') %}
3+
{%- set suit_artifacts_base_dir = ( radio['binary'].split('/')[:-1] | join('/') ) %}
4+
{%- if 'CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT' in radio['config'] and radio['config']['CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT'] != '' %}
5+
{%- set encrypted = True %}
6+
{%- set rad_encryption_dir = ( suit_artifacts_base_dir ) + "/" + ( radio['name'] ) + "_encryption_artifacts" %}
7+
{%- else %}
8+
{%- set encrypted = False %}
9+
{%- endif %}
310
SUIT_Envelope_Tagged:
411
suit-authentication-wrapper:
512
SuitDigest:
@@ -33,9 +40,17 @@ SUIT_Envelope_Tagged:
3340
suit-parameter-image-digest:
3441
suit-digest-algorithm-id: cose-alg-sha-256
3542
suit-digest-bytes:
43+
{%- if encrypted %}
44+
file_direct: {{ rad_encryption_dir }}/plain_text_digest.bin
45+
{%- else %}
3646
file: {{ radio['binary'] }}
47+
{%- endif %}
3748
suit-parameter-image-size:
49+
{%- if encrypted %}
50+
file_direct: {{ rad_encryption_dir }}/plain_text_size.txt
51+
{%- else %}
3852
file: {{ radio['binary'] }}
53+
{%- endif %}
3954
- suit-condition-vendor-identifier:
4055
- suit-send-record-success
4156
- suit-send-record-failure
@@ -102,6 +117,10 @@ SUIT_Envelope_Tagged:
102117
- suit-directive-set-component-index: 0
103118
- suit-directive-override-parameters:
104119
suit-parameter-source-component: 1
120+
{%- if encrypted %}
121+
suit-parameter-encryption-info:
122+
file: {{ rad_encryption_dir }}/suit_encryption_info.bin
123+
{%- endif %}
105124
# When copying the data it is worth to retry the sequence of
106125
# suit-directive-copy and suit-condition-image-match at least once.
107126
# If a bit flip occurs, it might be due to a transport issue, not
@@ -138,8 +157,21 @@ SUIT_Envelope_Tagged:
138157
suit-digest-algorithm-id: cose-alg-sha-256
139158
suit-digest-bytes:
140159
file: {{ radio['binary'] }}
160+
{%- if encrypted %}
161+
# For the encrypted image this fetch directive is used to verify the tag and the AAD
162+
# of the received encrypted image The target "CAND_IMG" behaves like a /dev/null device
163+
# and all the data is discarded.
164+
# This way even if the encrypted content is incorrect, the contents of the target memory
165+
# will not be affected.
166+
# Note that no digest checking is required on the encrypted content itself, as checking the tag
167+
# and the AAD verifies the integrity of the content. In fact, suit-condition-image-match
168+
# won't be able to work in this case, as the CAND_IMG won't contain any valid content.
169+
suit-parameter-encryption-info:
170+
file: {{ rad_encryption_dir }}/suit_encryption_info.bin
171+
{%- endif %}
141172
- suit-directive-fetch:
142173
- suit-send-record-failure
174+
{%- if not encrypted %}
143175
- suit-directive-try-each:
144176
- - suit-condition-image-match:
145177
- suit-send-record-success
@@ -151,6 +183,7 @@ SUIT_Envelope_Tagged:
151183
- suit-send-record-failure
152184
- suit-send-sysinfo-success
153185
- suit-send-sysinfo-failure
186+
{%- endif %}
154187

155188
suit-manifest-component-id:
156189
- INSTLD_MFST

0 commit comments

Comments
 (0)