From b40b0a3594eb0ae55668303969a78239988d8dd5 Mon Sep 17 00:00:00 2001 From: Artur Hadasz Date: Mon, 16 Dec 2024 10:03:48 +0100 Subject: [PATCH] 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 --- cmake/sysbuild/suit.cmake | 75 ++++++++++++++----- cmake/sysbuild/suit_utilities.cmake | 48 +++++++++++- .../default/v1/app_envelope.yaml.jinja2 | 33 ++++++++ .../default/v1/rad_envelope.yaml.jinja2 | 33 ++++++++ .../app_envelope_extflash.yaml.jinja2 | 33 ++++++++ .../rad_envelope_extflash.yaml.jinja2 | 35 ++++++++- sysbuild/Kconfig.suit | 63 +++++++++++++++- west.yml | 2 +- 8 files changed, 299 insertions(+), 23 deletions(-) diff --git a/cmake/sysbuild/suit.cmake b/cmake/sysbuild/suit.cmake index d7c2e92fbb38..5c1c8c4d7b57 100644 --- a/cmake/sysbuild/suit.cmake +++ b/cmake/sysbuild/suit.cmake @@ -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 ) @@ -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) @@ -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}) @@ -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() @@ -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() @@ -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() @@ -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() diff --git a/cmake/sysbuild/suit_utilities.cmake b/cmake/sysbuild/suit_utilities.cmake index 2d5fbd7eb253..9140f8d514d4 100644 --- a/cmake/sysbuild/suit_utilities.cmake +++ b/cmake/sysbuild/suit_utilities.cmake @@ -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( ) +# +# 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( @@ -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( ) +# +# 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).*'") @@ -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( ) +# +# 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() diff --git a/config/suit/templates/nrf54h20/default/v1/app_envelope.yaml.jinja2 b/config/suit/templates/nrf54h20/default/v1/app_envelope.yaml.jinja2 index f62c41f49672..0e447e040954 100644 --- a/config/suit/templates/nrf54h20/default/v1/app_envelope.yaml.jinja2 +++ b/config/suit/templates/nrf54h20/default/v1/app_envelope.yaml.jinja2 @@ -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: @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/config/suit/templates/nrf54h20/default/v1/rad_envelope.yaml.jinja2 b/config/suit/templates/nrf54h20/default/v1/rad_envelope.yaml.jinja2 index e9bfc83a8a9a..7b415196056e 100644 --- a/config/suit/templates/nrf54h20/default/v1/rad_envelope.yaml.jinja2 +++ b/config/suit/templates/nrf54h20/default/v1/rad_envelope.yaml.jinja2 @@ -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: @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/samples/suit/smp_transfer/suit/nrf54h20/app_envelope_extflash.yaml.jinja2 b/samples/suit/smp_transfer/suit/nrf54h20/app_envelope_extflash.yaml.jinja2 index c681c18a0675..868f6097e833 100644 --- a/samples/suit/smp_transfer/suit/nrf54h20/app_envelope_extflash.yaml.jinja2 +++ b/samples/suit/smp_transfer/suit/nrf54h20/app_envelope_extflash.yaml.jinja2 @@ -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: @@ -41,9 +48,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 @@ -169,6 +184,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 @@ -247,8 +266,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 @@ -260,6 +292,7 @@ SUIT_Envelope_Tagged: - suit-send-record-failure - suit-send-sysinfo-success - suit-send-sysinfo-failure +{%- endif %} - suit-directive-set-component-index: 0 # declare application image MRAM memory as IPUC - suit-directive-override-parameters: diff --git a/samples/suit/smp_transfer/suit/nrf54h20/rad_envelope_extflash.yaml.jinja2 b/samples/suit/smp_transfer/suit/nrf54h20/rad_envelope_extflash.yaml.jinja2 index e81c10f3a50c..883f24c6a93e 100644 --- a/samples/suit/smp_transfer/suit/nrf54h20/rad_envelope_extflash.yaml.jinja2 +++ b/samples/suit/smp_transfer/suit/nrf54h20/rad_envelope_extflash.yaml.jinja2 @@ -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: @@ -35,9 +42,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 @@ -80,7 +95,7 @@ SUIT_Envelope_Tagged: suit-payload-fetch: - suit-directive-set-component-index: 2 - suit-directive-override-parameters: - suit-parameter-uri: 'file://{{ radio['filename'] }}' + suit-parameter-uri: "file://{{ radio['filename'] }}" - suit-directive-fetch: - suit-send-record-failure {%- endif %} @@ -113,6 +128,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 @@ -149,8 +168,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 @@ -162,6 +194,7 @@ SUIT_Envelope_Tagged: - suit-send-record-failure - suit-send-sysinfo-success - suit-send-sysinfo-failure +{%- endif %} # declare radio image MRAM memory as IPUC - suit-directive-set-component-index: 0 - suit-directive-override-parameters: diff --git a/sysbuild/Kconfig.suit b/sysbuild/Kconfig.suit index 473f5df61d1f..34be76dc3773 100644 --- a/sysbuild/Kconfig.suit +++ b/sysbuild/Kconfig.suit @@ -31,6 +31,7 @@ config SUIT_ENVELOPE_ROOT_TEMPLATE_FILENAME config SUIT_ENVELOPE_SIGN_SCRIPT string "Location of SUIT sign script" depends on SUIT_ENVELOPE_SIGN + default "modules/lib/suit-generator/ncs/sign_script.py" help Python script called to sign SUIT envelope. You can use either absolute or relative path. @@ -38,7 +39,67 @@ config SUIT_ENVELOPE_SIGN_SCRIPT Script need to accept two arguments: - --input-file - location of unsigned envelope in the build system - --output-file - location of signed envelope to create by script - default "modules/lib/suit-generator/ncs/sign_script.py" + +choice SUIT_ENVELOPE_ENCRYPT_SCRIPT + prompt "Select the used SUIT encryption script" + default SUIT_ENVELOPE_ENCRYPT_SCRIPT_DEFAULT + help + The SUIT encryption script is used to generate encryption artifacts for images inside a SUIT envelope. + It is the "external" script that is called by the build system - it is responsible for creating + various needed SUIT structures, but passes the actual encryption of the payload to a separate KMS script. + +config SUIT_ENVELOPE_ENCRYPT_SCRIPT_DEFAULT + bool "Use the default SUIT encryption script" + help + Use the default encryption script to generate encryption artifacts for images inside a SUIT envelope. + +endchoice + +config SUIT_ENVELOPE_ENCRYPT_SCRIPT_PATH + string "Location of SUIT encrypt script" + default "${ZEPHYR_SUIT_GENERATOR_MODULE_DIR}/ncs/encrypt_script.py" if SUIT_ENVELOPE_ENCRYPT_SCRIPT_DEFAULT + help + Python script called to generate encryption artifacts for images inside a SUIT envelope. + See the help message for the default encryption script to see what arguments the script + must accept. + +choice SUIT_ENVELOPE_KMS_SCRIPT + prompt "Select the used SUIT KMS script to be used by the encryption script" + help + This is the "internal" python script that is called by the encryption script to perform the cryptographic operations, + such as encryption using an AES key. The script must contain a class implementing the interface defined by + the abstract class SuitKMSBase found in the suit_generator.suit_kms_base and a suit_kms_factory function + needed to get an object of the class. + +config SUIT_ENVELOPE_KMS_SCRIPT_BASIC + bool "Use the basic SUIT KMS script" + help + Use the basic KMS script to encrypt firmware. + This script provides a basic implementation of the SuitKMS interface, in which + the private/encryption keys are stored in the filesystem. + +endchoice + +config SUIT_ENVELOPE_KMS_SCRIPT_PATH + string "Location of SUIT KMS script" + default "${ZEPHYR_SUIT_GENERATOR_MODULE_DIR}/ncs/basic_kms.py" if SUIT_ENVELOPE_KMS_SCRIPT_BASIC + +if SUIT_ENVELOPE_KMS_SCRIPT_BASIC + +config SUIT_ENVELOPE_KMS_SCRIPT_BASIC_KEY_DIRECTORY + string "The directory in which the keys are stored" + default "${ZEPHYR_SUIT_GENERATOR_MODULE_DIR}/ncs" + help + Location of the key file used by the basic KMS script. + +endif + +config SUIT_ENVELOPE_KMS_SCRIPT_CONTEXT + string "Context for the SUIT KMS script" + default SUIT_ENVELOPE_KMS_SCRIPT_BASIC_KEY_DIRECTORY if SUIT_ENVELOPE_KMS_SCRIPT_BASIC + default "" + help + Context to pass to the SUIT KMS script. config SUIT_ENVELOPE_ROOT_ARTIFACT_NAME string "Name of the root SUIT artifact." diff --git a/west.yml b/west.yml index 2e17d8112053..fd01e9ef5866 100644 --- a/west.yml +++ b/west.yml @@ -242,7 +242,7 @@ manifest: upstream-sha: c6eaeda5a1c1c5dbb24dce7e027340cb8893a77b compare-by-default: false - name: suit-generator - revision: aa3da7d6c15960b3346cdaf3587ca666c21db953 + revision: pull/160/head path: modules/lib/suit-generator - name: suit-processor revision: a499bcadceff8877da63a0a140c6a91ff2f87b25