Skip to content

Commit

Permalink
suit: Build system changes needed for encryption
Browse files Browse the repository at this point in the history
This commit contains changes to the SUIT build system
allowing for encrypting images for update.

Signed-off-by: Artur Hadasz <[email protected]>
  • Loading branch information
ahasztag committed Dec 27, 2024
1 parent 66b211a commit b40b0a3
Show file tree
Hide file tree
Showing 8 changed files with 299 additions and 23 deletions.
75 changes: 56 additions & 19 deletions cmake/sysbuild/suit.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,52 @@ function(suit_create_package)

foreach(image ${IMAGES})
unset(target)
unset(encrypt)
sysbuild_get(BINARY_DIR IMAGE ${image} VAR APPLICATION_BINARY_DIR CACHE)
sysbuild_get(BINARY_FILE IMAGE ${image} VAR CONFIG_KERNEL_BIN_NAME KCONFIG)
sysbuild_get(target IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TARGET KCONFIG)
sysbuild_get(encrypt IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT KCONFIG)

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

if(encrypt)
if(DEFINED target AND NOT target STREQUAL "")
set(${image}_SUIT_ENCRYPT_DIR "${SUIT_ROOT_DIRECTORY}/${target}_encryption_artifacts")
else()
set(${image}_SUIT_ENCRYPT_DIR "${SUIT_ROOT_DIRECTORY}/${image}_encryption_artifacts")
endif()

if(SB_CONFIG_SUIT_ENVELOPE_KMS_SCRIPT_BASIC AND NOT default_kms_warning_displayed)
message(WARNING "
-----------------------------------------------------------------------------------
--- WARNING: Using default file-based basic KMS implementation for encryption. ---
--- It should not be used for production unless the build is performed in ---
--- a secure environment. ---
-----------------------------------------------------------------------------------
\n"
)
set(default_kms_warning_displayed TRUE)
endif()

set(SUIT_ENCRYPT_ARGS)
sysbuild_get(encrypt_string_key_id IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT_STRING_KEY_ID KCONFIG)
sysbuild_get(encrypt_key_name IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_NAME KCONFIG)
sysbuild_get(plaintext_hash_alg IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT_PLAINTEXT_HASH_ALG_NAME KCONFIG)

list(APPEND SUIT_ENCRYPT_ARGS --firmware ${BINARY_DIR}/zephyr/${BINARY_FILE})
list(APPEND SUIT_ENCRYPT_ARGS --key-name ${encrypt_key_name})
list(APPEND SUIT_ENCRYPT_ARGS --string-key-id ${encrypt_string_key_id})
list(APPEND SUIT_ENCRYPT_ARGS --hash-alg ${plaintext_hash_alg})
list(APPEND SUIT_ENCRYPT_ARGS --context ${SB_CONFIG_SUIT_ENVELOPE_KMS_SCRIPT_CONTEXT})
list(APPEND SUIT_ENCRYPT_ARGS --kms-script ${SB_CONFIG_SUIT_ENVELOPE_KMS_SCRIPT_PATH})

suit_encrypt_image("${SUIT_ENCRYPT_ARGS}" ${${image}_SUIT_ENCRYPT_DIR})

set(${image}_SUIT_PAYLOAD_BINARY ${${image}_SUIT_ENCRYPT_DIR}/encrypted_content.bin)
else()
set(${image}_SUIT_PAYLOAD_BINARY ${BINARY_DIR}/zephyr/${BINARY_FILE})
endif()

list(APPEND CORE_ARGS
--core ${image},${SUIT_ROOT_DIRECTORY}${image}.bin,${BINARY_DIR}/zephyr/edt.pickle,${BINARY_DIR}/zephyr/.config
)
Expand All @@ -262,11 +302,11 @@ function(suit_create_package)
--core ${target},${SUIT_ROOT_DIRECTORY}${image}.bin,${BINARY_DIR}/zephyr/edt.pickle,${BINARY_DIR}/zephyr/.config
)
endif()
suit_copy_artifact_to_output_directory(${image} ${BINARY_DIR}/zephyr/${BINARY_FILE})
suit_copy_artifact_to_output_directory(${image} ${${image}_SUIT_PAYLOAD_BINARY})

unset(CONFIG_SUIT_RECOVERY)
sysbuild_get(CONFIG_SUIT_RECOVERY IMAGE ${image} VAR CONFIG_SUIT_RECOVERY KCONFIG)
if(CONFIG_SUIT_RECOVERY)
unset(recovery)
sysbuild_get(recovery IMAGE ${image} VAR CONFIG_SUIT_RECOVERY KCONFIG)
if(recovery)
set_property(GLOBAL APPEND PROPERTY SUIT_RECOVERY_DFU_ARTIFACTS ${SUIT_ROOT_DIRECTORY}${image}.bin)
else()
set_property(GLOBAL APPEND PROPERTY SUIT_DFU_ARTIFACTS ${SUIT_ROOT_DIRECTORY}${image}.bin)
Expand Down Expand Up @@ -313,9 +353,9 @@ function(suit_create_package)
suit_render_template(${INPUT_ENVELOPE_JINJA_FILE} ${ENVELOPE_YAML_FILE} "${TEMPLATE_ARGS}")
suit_create_envelope(${ENVELOPE_YAML_FILE} ${ENVELOPE_SUIT_FILE} ${SB_CONFIG_SUIT_ENVELOPE_SIGN})

unset(CONFIG_SUIT_RECOVERY)
sysbuild_get(CONFIG_SUIT_RECOVERY IMAGE ${image} VAR CONFIG_SUIT_RECOVERY KCONFIG)
if(CONFIG_SUIT_RECOVERY)
unset(recovery)
sysbuild_get(recovery IMAGE ${image} VAR CONFIG_SUIT_RECOVERY KCONFIG)
if(recovery)
set_property(GLOBAL APPEND PROPERTY SUIT_RECOVERY_DFU_ARTIFACTS ${ENVELOPE_SUIT_FILE})
else()
set_property(GLOBAL APPEND PROPERTY SUIT_DFU_ARTIFACTS ${ENVELOPE_SUIT_FILE})
Expand All @@ -336,10 +376,10 @@ function(suit_create_package)
if(EXTRACT_TO_CACHE)
sysbuild_get(CACHE_PARTITION_NUM IMAGE ${image} VAR CONFIG_SUIT_DFU_CACHE_EXTRACT_IMAGE_PARTITION KCONFIG)

unset(CONFIG_SUIT_RECOVERY)
sysbuild_get(CONFIG_SUIT_RECOVERY IMAGE ${image} VAR CONFIG_SUIT_RECOVERY KCONFIG)
unset(recovery)
sysbuild_get(recovery IMAGE ${image} VAR CONFIG_SUIT_RECOVERY KCONFIG)

if(CONFIG_SUIT_RECOVERY)
if(recovery)
list(APPEND RECOVERY_DFU_CACHE_PARTITIONS_USED ${CACHE_PARTITION_NUM})
list(APPEND SUIT_RECOVERY_CACHE_PARTITION_${CACHE_PARTITION_NUM} ${image})
else()
Expand All @@ -356,11 +396,10 @@ function(suit_create_package)
foreach(CACHE_PARTITION_NUM ${DFU_CACHE_PARTITIONS_USED})
set(CACHE_CREATE_ARGS "")
foreach(image ${SUIT_CACHE_PARTITION_${CACHE_PARTITION_NUM}})
sysbuild_get(BINARY_DIR IMAGE ${image} VAR APPLICATION_BINARY_DIR CACHE)
sysbuild_get(BINARY_FILE IMAGE ${image} VAR CONFIG_KERNEL_BIN_NAME KCONFIG)
sysbuild_get(IMAGE_CACHE_URI IMAGE ${image} VAR CONFIG_SUIT_DFU_CACHE_EXTRACT_IMAGE_URI KCONFIG)

list(APPEND CACHE_CREATE_ARGS
"--input" "\"${IMAGE_CACHE_URI},${BINARY_DIR}/zephyr/${BINARY_FILE}.bin\""
"--input" "\"${IMAGE_CACHE_URI},${${image}_SUIT_PAYLOAD_BINARY}\""
)
endforeach()

Expand All @@ -382,11 +421,9 @@ function(suit_create_package)
foreach(CACHE_PARTITION_NUM ${RECOVERY_DFU_CACHE_PARTITIONS_USED})
set(CACHE_CREATE_ARGS "")
foreach(image ${SUIT_RECOVERY_CACHE_PARTITION_${CACHE_PARTITION_NUM}})
sysbuild_get(BINARY_DIR IMAGE ${image} VAR APPLICATION_BINARY_DIR CACHE)
sysbuild_get(BINARY_FILE IMAGE ${image} VAR CONFIG_KERNEL_BIN_NAME KCONFIG)
sysbuild_get(IMAGE_CACHE_URI IMAGE ${image} VAR CONFIG_SUIT_DFU_CACHE_EXTRACT_IMAGE_URI KCONFIG)
list(APPEND CACHE_CREATE_ARGS
"--input" "\"${IMAGE_CACHE_URI},${BINARY_DIR}/zephyr/${BINARY_FILE}.bin\""
"--input" "\"${IMAGE_CACHE_URI},${${image}_SUIT_PAYLOAD_BINARY}\""
)
endforeach()

Expand Down Expand Up @@ -544,9 +581,9 @@ function(suit_setup_merge)
foreach(image ${IMAGES})
set(ARTIFACTS_TO_MERGE)

unset(CONFIG_NRF_REGTOOL_GENERATE_UICR)
sysbuild_get(CONFIG_NRF_REGTOOL_GENERATE_UICR IMAGE ${image} VAR CONFIG_NRF_REGTOOL_GENERATE_UICR KCONFIG)
if(NOT DEFINED CONFIG_NRF_REGTOOL_GENERATE_UICR)
unset(regtool_generate_uicr)
sysbuild_get(regtool_generate_uicr IMAGE ${image} VAR CONFIG_NRF_REGTOOL_GENERATE_UICR KCONFIG)
if(NOT DEFINED regtool_generate_uicr)
continue()
endif()

Expand Down
48 changes: 47 additions & 1 deletion cmake/sysbuild/suit_utilities.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,17 @@ function(suit_create_envelope input_file output_file create_signature)
endif()
endfunction()

# Create a SUIT DFU cache partition file from a list of payloads.
#
# Usage:
# suit_create_cache_partition(<args> <output_file> <partition_num> <recovery>)
#
# Parameters:
# 'args' - list of arguments for the cache_create command
# 'output_file' - path to output cache partition file
# 'partition_num' - partition number
# 'recovery' - if set to true, the cache partition contains recovery firmware payloads
function(suit_create_cache_partition args output_file partition_num recovery)

list(APPEND args "--output-file" "${output_file}")

set_property(
Expand All @@ -110,6 +119,15 @@ function(suit_create_cache_partition args output_file partition_num recovery)
endif()
endfunction()

# Create a SUIT DFU cache partition with Nordic proprietary payloads
# extracted from the top-level SUIT envelope.
#
# Usage:
# suit_create_nordic_cache_partition(<args> <output_file>)
#
# Parameters:
# 'args' - list of arguments for the cache_create command
# 'output_file' - path to output cache partition file
function(suit_create_nordic_cache_partition args output_file)
list(APPEND args "--output-file" "${output_file}")
list(APPEND args "--omit-payload-regex" "'(?!.*secdom.*\.bin|.*sysctl_v.*\.bin).*'")
Expand Down Expand Up @@ -143,3 +161,31 @@ function(suit_add_merge_hex_file)
set_property(GLOBAL APPEND PROPERTY SUIT_MERGE_application_DEPENDENCIES ${arg_DEPENDENCIES})
endif()
endfunction()

# Create SUIT encryption artifacts for a given image.
#
# Usage:
# suit_encrypt_image(<args> <output_directory>)
#
# Parameters:
# 'args' - list of arguments for the encryption script
# 'output_directory' - path to a directory where the encryption artifacts will be stored
function(suit_encrypt_image args output_directory)
list(APPEND args "--output-dir" "${output_directory}")

if(NOT EXISTS ${SB_CONFIG_SUIT_ENVELOPE_ENCRYPT_SCRIPT_PATH})
message(SEND_ERROR "DFU: ${SB_CONFIG_SUIT_ENVELOPE_ENCRYPT_SCRIPT_PATH} does not exist. Corrupted configuration?")
return()
endif()

set_property(
GLOBAL APPEND PROPERTY SUIT_POST_BUILD_COMMANDS
COMMAND ${CMAKE_COMMAND} -E make_directory ${output_directory}
)
set_property(
GLOBAL APPEND PROPERTY SUIT_POST_BUILD_COMMANDS
COMMAND ${PYTHON_EXECUTABLE} ${SB_CONFIG_SUIT_ENVELOPE_ENCRYPT_SCRIPT_PATH}
encrypt-and-generate
${args}
)
endfunction()
33 changes: 33 additions & 0 deletions config/suit/templates/nrf54h20/default/v1/app_envelope.yaml.jinja2
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{%- set mpi_application_vendor_name = sysbuild['config']['SB_CONFIG_SUIT_MPI_APP_LOCAL_1_VENDOR_NAME']|default('nordicsemi.com') %}
{%- set mpi_application_class_name = sysbuild['config']['SB_CONFIG_SUIT_MPI_APP_LOCAL_1_CLASS_NAME']|default('nRF54H20_sample_app') %}
{%- set suit_artifacts_base_dir = ( application['binary'].split('/')[:-1] | join('/') ) %}
{%- if 'CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT' in application['config'] and application['config']['CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT'] != '' %}
{%- set encrypted = True %}
{%- set app_encryption_dir = ( suit_artifacts_base_dir ) + "/" + ( application['name'] ) + "_encryption_artifacts" %}
{%- else %}
{%- set encrypted = False %}
{%- endif %}
SUIT_Envelope_Tagged:
suit-authentication-wrapper:
SuitDigest:
Expand Down Expand Up @@ -33,9 +40,17 @@ SUIT_Envelope_Tagged:
suit-parameter-image-digest:
suit-digest-algorithm-id: cose-alg-sha-256
suit-digest-bytes:
{%- if encrypted %}
file_direct: {{ app_encryption_dir }}/plain_text_digest.bin
{%- else %}
file: {{ application['binary'] }}
{%- endif %}
suit-parameter-image-size:
{%- if encrypted %}
file_direct: {{ app_encryption_dir }}/plain_text_size.txt
{%- else %}
file: {{ application['binary'] }}
{%- endif %}
- suit-condition-vendor-identifier:
- suit-send-record-success
- suit-send-record-failure
Expand Down Expand Up @@ -102,6 +117,10 @@ SUIT_Envelope_Tagged:
- suit-directive-set-component-index: 0
- suit-directive-override-parameters:
suit-parameter-source-component: 1
{%- if encrypted %}
suit-parameter-encryption-info:
file: {{ app_encryption_dir }}/suit_encryption_info.bin
{%- endif %}
# When copying the data it is worth to retry the sequence of
# suit-directive-copy and suit-condition-image-match at least once.
# If a bit flip occurs, it might be due to a transport issue, not
Expand Down Expand Up @@ -138,8 +157,21 @@ SUIT_Envelope_Tagged:
suit-digest-algorithm-id: cose-alg-sha-256
suit-digest-bytes:
file: {{ application['binary'] }}
{%- if encrypted %}
# For the encrypted image this fetch directive is used to verify the tag and the AAD
# of the received encrypted image The target "CAND_IMG" behaves like a /dev/null device
# and all the data is discarded.
# This way even if the encrypted content is incorrect, the contents of the target memory
# will not be affected.
# Note that no digest checking is required on the encrypted content itself, as checking the tag
# and the AAD verifies the integrity of the content. In fact, suit-condition-image-match
# won't be able to work in this case, as the CAND_IMG won't contain any valid content.
suit-parameter-encryption-info:
file: {{ app_encryption_dir }}/suit_encryption_info.bin
{%- endif %}
- suit-directive-fetch:
- suit-send-record-failure
{%- if not encrypted %}
- suit-directive-try-each:
- - suit-condition-image-match:
- suit-send-record-success
Expand All @@ -151,6 +183,7 @@ SUIT_Envelope_Tagged:
- suit-send-record-failure
- suit-send-sysinfo-success
- suit-send-sysinfo-failure
{%- endif %}

suit-manifest-component-id:
- INSTLD_MFST
Expand Down
33 changes: 33 additions & 0 deletions config/suit/templates/nrf54h20/default/v1/rad_envelope.yaml.jinja2
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{%- set mpi_radio_vendor_name = sysbuild['config']['SB_CONFIG_SUIT_MPI_RAD_LOCAL_1_VENDOR_NAME']|default('nordicsemi.com') %}
{%- set mpi_radio_class_name = sysbuild['config']['SB_CONFIG_SUIT_MPI_RAD_LOCAL_1_CLASS_NAME']|default('nRF54H20_sample_rad') %}
{%- set suit_artifacts_base_dir = ( radio['binary'].split('/')[:-1] | join('/') ) %}
{%- if 'CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT' in radio['config'] and radio['config']['CONFIG_SUIT_ENVELOPE_TARGET_ENCRYPT'] != '' %}
{%- set encrypted = True %}
{%- set rad_encryption_dir = ( suit_artifacts_base_dir ) + "/" + ( radio['name'] ) + "_encryption_artifacts" %}
{%- else %}
{%- set encrypted = False %}
{%- endif %}
SUIT_Envelope_Tagged:
suit-authentication-wrapper:
SuitDigest:
Expand Down Expand Up @@ -33,9 +40,17 @@ SUIT_Envelope_Tagged:
suit-parameter-image-digest:
suit-digest-algorithm-id: cose-alg-sha-256
suit-digest-bytes:
{%- if encrypted %}
file_direct: {{ rad_encryption_dir }}/plain_text_digest.bin
{%- else %}
file: {{ radio['binary'] }}
{%- endif %}
suit-parameter-image-size:
{%- if encrypted %}
file_direct: {{ rad_encryption_dir }}/plain_text_size.txt
{%- else %}
file: {{ radio['binary'] }}
{%- endif %}
- suit-condition-vendor-identifier:
- suit-send-record-success
- suit-send-record-failure
Expand Down Expand Up @@ -102,6 +117,10 @@ SUIT_Envelope_Tagged:
- suit-directive-set-component-index: 0
- suit-directive-override-parameters:
suit-parameter-source-component: 1
{%- if encrypted %}
suit-parameter-encryption-info:
file: {{ rad_encryption_dir }}/suit_encryption_info.bin
{%- endif %}
# When copying the data it is worth to retry the sequence of
# suit-directive-copy and suit-condition-image-match at least once.
# If a bit flip occurs, it might be due to a transport issue, not
Expand Down Expand Up @@ -138,8 +157,21 @@ SUIT_Envelope_Tagged:
suit-digest-algorithm-id: cose-alg-sha-256
suit-digest-bytes:
file: {{ radio['binary'] }}
{%- if encrypted %}
# For the encrypted image this fetch directive is used to verify the tag and the AAD
# of the received encrypted image The target "CAND_IMG" behaves like a /dev/null device
# and all the data is discarded.
# This way even if the encrypted content is incorrect, the contents of the target memory
# will not be affected.
# Note that no digest checking is required on the encrypted content itself, as checking the tag
# and the AAD verifies the integrity of the content. In fact, suit-condition-image-match
# won't be able to work in this case, as the CAND_IMG won't contain any valid content.
suit-parameter-encryption-info:
file: {{ rad_encryption_dir }}/suit_encryption_info.bin
{%- endif %}
- suit-directive-fetch:
- suit-send-record-failure
{%- if not encrypted %}
- suit-directive-try-each:
- - suit-condition-image-match:
- suit-send-record-success
Expand All @@ -151,6 +183,7 @@ SUIT_Envelope_Tagged:
- suit-send-record-failure
- suit-send-sysinfo-success
- suit-send-sysinfo-failure
{%- endif %}

suit-manifest-component-id:
- INSTLD_MFST
Expand Down
Loading

0 comments on commit b40b0a3

Please sign in to comment.