diff --git a/tests/subsys/suit/fetch/CMakeLists.txt b/tests/subsys/suit/fetch/CMakeLists.txt index a89f4f225a89..774c2027a99c 100644 --- a/tests/subsys/suit/fetch/CMakeLists.txt +++ b/tests/subsys/suit/fetch/CMakeLists.txt @@ -11,8 +11,14 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(integration_test_fetch) include(../cmake/test_template.cmake) +target_include_directories(app PRIVATE mocks) + zephyr_library_link_libraries(suit_memptr_storage_interface) zephyr_library_link_libraries(suit_platform_interface) zephyr_library_link_libraries(suit_ipuc) -zephyr_library_link_libraries(suit_stream_filters_interface) -zephyr_library_link_libraries(suit_decrypt_test_utils) + +zephyr_library_link_libraries_ifdef(CONFIG_TEST_SUIT_PLATFORM_FETCH_VARIANT_APP suit_memory_layout_interface) +zephyr_library_link_libraries_ifdef(CONFIG_TEST_SUIT_PLATFORM_FETCH_VARIANT_SDFW suit_decrypt_test_utils) +zephyr_library_link_libraries_ifdef(CONFIG_TEST_SUIT_PLATFORM_FETCH_VARIANT_SDFW suit_stream_filters_interface) + +zephyr_compile_definitions(CONFIG_SOC_NRF54H20_CPUAPP) diff --git a/tests/subsys/suit/fetch/Kconfig b/tests/subsys/suit/fetch/Kconfig index 8edc11bd7cde..2a0a29ea192e 100644 --- a/tests/subsys/suit/fetch/Kconfig +++ b/tests/subsys/suit/fetch/Kconfig @@ -8,4 +8,39 @@ rsource "../mocks/Kconfig" rsource "../tests/Kconfig" +choice TEST_SUIT_PLATFORM_FETCH_VARIANT + prompt "SUIT platform implementation variant to test" + default TEST_SUIT_PLATFORM_FETCH_VARIANT_SDFW + +config TEST_SUIT_PLATFORM_FETCH_VARIANT_APP + bool "Local or application" + depends on SUIT_PLATFORM_VARIANT_APP + select FLASH_IPUC + select SUIT_ENVELOPE_INFO + select SUIT_CACHE_RW + select SUIT_STREAM_SINK_CACHE + select SUIT_STREAM_FETCH_SOURCE_MGR + +config TEST_SUIT_PLATFORM_FETCH_VARIANT_SDFW + bool "Bootloader or SDFW" + depends on SUIT_PLATFORM_VARIANT_SDFW + select MOCK_SDFW_ARBITER + select SUIT_EXECUTION_MODE + select SUIT_MCI + select SUIT_STREAM_FILTER_DECRYPT + select SUIT_CRYPTO + select SUIT_STORAGE + +endchoice # TEST_SUIT_PLATFORM_FETCH_VARIANT + +if TEST_SUIT_PLATFORM_FETCH_VARIANT_APP + +config SUIT_CACHE_SDFW_IPUC_ID + default 254 + +config SUIT_CACHE_APP_IPUC_ID + default 255 + +endif # TEST_SUIT_PLATFORM_FETCH_VARIANT_APP + source "Kconfig.zephyr" diff --git a/tests/subsys/suit/fetch/boards/native_sim.overlay b/tests/subsys/suit/fetch/boards/native_sim.overlay index ac659f573154..369c537bd235 100644 --- a/tests/subsys/suit/fetch/boards/native_sim.overlay +++ b/tests/subsys/suit/fetch/boards/native_sim.overlay @@ -7,12 +7,30 @@ &flash0 { partitions { compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; + #address-cells = < 0x1 >; + #size-cells = < 0x1 >; - /* Use the last 48KB of NVM as suit storage. */ - suit_storage: partition@f4000 { - reg = <0xf4000 DT_SIZE_K(48)>; + suit_storage: partition@e9000 { + reg = <0xe9000 DT_SIZE_K(48)>; }; + + dfu_partition: partition@f5000 { + reg = < 0xf5000 DT_SIZE_K(4) >; + }; + + dfu_cache_partition_1: partition@f6000 { + reg = <0xf6000 DT_SIZE_K(4)>; + }; + + dfu_cache_partition_3: partition@f7000 { + reg = <0xf7000 DT_SIZE_K(4)>; + }; + }; +}; + +/ { + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(256)>; }; }; diff --git a/tests/subsys/suit/fetch/boards/native_sim_64.overlay b/tests/subsys/suit/fetch/boards/native_sim_64.overlay index ac659f573154..369c537bd235 100644 --- a/tests/subsys/suit/fetch/boards/native_sim_64.overlay +++ b/tests/subsys/suit/fetch/boards/native_sim_64.overlay @@ -7,12 +7,30 @@ &flash0 { partitions { compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; + #address-cells = < 0x1 >; + #size-cells = < 0x1 >; - /* Use the last 48KB of NVM as suit storage. */ - suit_storage: partition@f4000 { - reg = <0xf4000 DT_SIZE_K(48)>; + suit_storage: partition@e9000 { + reg = <0xe9000 DT_SIZE_K(48)>; }; + + dfu_partition: partition@f5000 { + reg = < 0xf5000 DT_SIZE_K(4) >; + }; + + dfu_cache_partition_1: partition@f6000 { + reg = <0xf6000 DT_SIZE_K(4)>; + }; + + dfu_cache_partition_3: partition@f7000 { + reg = <0xf7000 DT_SIZE_K(4)>; + }; + }; +}; + +/ { + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(256)>; }; }; diff --git a/tests/subsys/suit/fetch/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/tests/subsys/suit/fetch/boards/nrf54h20dk_nrf54h20_cpuapp.conf new file mode 100644 index 000000000000..002a70f0d47b --- /dev/null +++ b/tests/subsys/suit/fetch/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -0,0 +1,16 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +#Logging and printk is using standard UART. +CONFIG_LOG_MODE_DEFERRED=y +CONFIG_LOG_BACKEND_UART=y +CONFIG_LOG_PRINTK=y +CONFIG_LOG_BUFFER_SIZE=8192 diff --git a/tests/subsys/suit/fetch/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/subsys/suit/fetch/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 000000000000..54b69afdc5c4 --- /dev/null +++ b/tests/subsys/suit/fetch/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* Split DFU partition into a smaller one and DFU caches. */ +/delete-node/ &dfu_partition; + +&mram1x { + erase-block-size = < 0x10 >; + /* Hardcoded inside the soc_flash_nrf_mram.c (MRAM_WORD_SIZE) */ + write-block-size = < 0x10 >; + + cpuapp_rw_partitions: cpuapp-rw-partitions { + compatible = "nordic,owned-partitions", "fixed-partitions"; + status = "okay"; + nordic,access = ; + #address-cells = < 0x1 >; + #size-cells = < 0x1 >; + + dfu_partition: partition@19d000 { + reg = < 0x19d000 DT_SIZE_K(1) >; + }; + + dfu_cache_partition_1: partition@19d400 { + reg = <0x19d400 DT_SIZE_K(1)>; + }; + + dfu_cache_partition_3: partition@19d800 { + reg = <0x19d800 DT_SIZE_K(1)>; + }; + + __mpc_override_align: partition@19dc00 { + reg = <0x19dc00 DT_SIZE_K(1)>; + }; + }; +}; diff --git a/tests/subsys/suit/fetch/mocks/mock_suit_ipuc.h b/tests/subsys/suit/fetch/mocks/mock_suit_ipuc.h new file mode 100644 index 000000000000..2405f8139b53 --- /dev/null +++ b/tests/subsys/suit/fetch/mocks/mock_suit_ipuc.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef MOCK_SUIT_IPUC_H__ +#define MOCK_SUIT_IPUC_H__ + +#include +#include + +DEFINE_FFF_GLOBALS; + +FAKE_VALUE_FUNC(int, suit_ipuc_get_count, size_t *); +FAKE_VALUE_FUNC(int, suit_ipuc_get_info, size_t, struct zcbor_string *, suit_manifest_role_t *); +FAKE_VALUE_FUNC(int, suit_ipuc_write_setup, struct zcbor_string *, struct zcbor_string *, + struct zcbor_string *); +FAKE_VALUE_FUNC(int, suit_ipuc_write, struct zcbor_string *, size_t, uintptr_t, size_t, bool); + +static inline void mock_suit_ipuc_reset(void) +{ + RESET_FAKE(suit_ipuc_get_count); + RESET_FAKE(suit_ipuc_get_info); + RESET_FAKE(suit_ipuc_write_setup); + RESET_FAKE(suit_ipuc_write); +} + +#endif /* MOCK_SUIT_IPUC_H__ */ diff --git a/tests/subsys/suit/fetch/prj.conf b/tests/subsys/suit/fetch/prj.conf index 39dfd781706c..7b8b600e6ccd 100644 --- a/tests/subsys/suit/fetch/prj.conf +++ b/tests/subsys/suit/fetch/prj.conf @@ -22,6 +22,8 @@ CONFIG_SUIT_UTILS=y CONFIG_SUIT_CACHE=y CONFIG_SUIT_MEMPTR_STORAGE=y +CONFIG_SUIT_LOG_LEVEL_DBG=y + CONFIG_ZCBOR=y CONFIG_ZCBOR_CANONICAL=y @@ -29,10 +31,3 @@ CONFIG_FLASH=y CONFIG_FLASH_MAP=y CONFIG_SUIT_IPUC=y -CONFIG_MOCK_SDFW_ARBITER=y -CONFIG_SUIT_STORAGE=y - -CONFIG_SUIT_EXECUTION_MODE=y -CONFIG_SUIT_MCI=y -CONFIG_SUIT_STREAM_FILTER_DECRYPT=y -CONFIG_SUIT_CRYPTO=y diff --git a/tests/subsys/suit/fetch/src/main.c b/tests/subsys/suit/fetch/src/main.c index 547c080ae02a..1f491589db22 100644 --- a/tests/subsys/suit/fetch/src/main.c +++ b/tests/subsys/suit/fetch/src/main.c @@ -8,15 +8,7 @@ #include #include #include -#include #include -#include -#include -#include -#include - -#define TEST_DATA_SIZE 64 -#define WRITE_ADDR 0x1A00080000 static uint8_t test_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, @@ -91,58 +83,14 @@ static void setup_cache_with_sample_entries(void) dfu_caches.pools[1].size = (size_t)cache2_len; dfu_caches.pools_count = 2; + suit_dfu_cache_deinitialize(); + suit_plat_err_t rc = suit_dfu_cache_initialize(&dfu_caches); zassert_equal(rc, SUIT_PLAT_SUCCESS, "Failed to initialize cache: %i", rc); } -static void test_before(void *data) -{ - /* Reset mocks */ - mocks_sdfw_reset(); - - /* Reset common FFF internal structures */ - FFF_RESET_HISTORY(); -} - -ZTEST_SUITE(fetch_tests, NULL, NULL, test_before, NULL, NULL); - -ZTEST(fetch_tests, test_integrated_fetch_to_msink_OK) -{ - struct zcbor_string source = {.value = test_data, .len = sizeof(test_data)}; - /* Create handle that will be used as destination */ - suit_component_t dst_handle; - /* [h'MEM', h'02', h'1A00080000', h'191000'] */ - uint8_t valid_dst_value[] = {0x84, 0x44, 0x63, 'M', 'E', 'M', 0x41, 0x02, 0x45, - 0x1A, 0x00, 0x08, 0x00, 0x00, 0x43, 0x19, 0x10, 0x00}; - - struct zcbor_string valid_dst_component_id = { - .value = valid_dst_value, - .len = sizeof(valid_dst_value), - }; - - int ipc_client_id = 1234; - int ret = suit_plat_create_component_handle(&valid_dst_component_id, false, &dst_handle); - - zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); - ret = suit_ipuc_sdfw_write_setup(ipc_client_id, &valid_dst_component_id, NULL, NULL); - zassert_equal(ret, SUIT_PLAT_ERR_NOT_FOUND, "in-place updateable component found"); - - ret = suit_ipuc_sdfw_declare(dst_handle, SUIT_MANIFEST_UNKNOWN); - zassert_equal(ret, SUIT_PLAT_SUCCESS, "suit_ipuc_sdfw_declare failed - error %i", ret); - - ret = suit_ipuc_sdfw_write_setup(ipc_client_id, &valid_dst_component_id, NULL, NULL); - zassert_equal(ret, SUIT_PLAT_SUCCESS, "suit_ipuc_sdfw_write_setup failed - error %i", ret); - - ret = suit_plat_fetch_integrated(dst_handle, &source, &valid_dst_component_id, NULL); - zassert_equal(ret, SUIT_SUCCESS, "suit_plat_fetch failed - error %i", ret); - - ret = suit_ipuc_sdfw_write_setup(ipc_client_id, &valid_dst_component_id, NULL, NULL); - zassert_equal(ret, SUIT_PLAT_ERR_NOT_FOUND, "in-place updateable component found"); - - ret = suit_plat_release_component_handle(dst_handle); - zassert_equal(ret, SUIT_SUCCESS, "dst_handle release failed - error %i", ret); -} +ZTEST_SUITE(fetch_tests, NULL, NULL, NULL, NULL, NULL); ZTEST(fetch_tests, test_integrated_fetch_to_memptr_OK) { @@ -356,207 +304,3 @@ ZTEST(fetch_tests, test_integrated_fetch_to_memptr_NOK_handle_NULL) ret = suit_plat_release_component_handle(component_handle); zassert_equal(ret, SUIT_SUCCESS, "Handle release failed - error %i", ret); } - -ZTEST(fetch_tests, test_integrated_fetch_to_msink_encrypted_OK) -{ - suit_component_t component_handle; - memptr_storage_handle_t handle = NULL; - struct zcbor_string source = { - .value = decrypt_test_ciphertext_direct, - .len = sizeof(decrypt_test_ciphertext_direct) - }; - - /* [h'MEM', h'02', h'1A00080000', h'191000'] */ - uint8_t valid_value[] = {0x84, 0x44, 0x63, 'M', 'E', 'M', 0x41, 0x02, 0x45, - 0x1A, 0x00, 0x08, 0x00, 0x00, 0x43, 0x19, 0x10, 0x00}; - - struct zcbor_string valid_component_id = { - .value = valid_value, - .len = sizeof(valid_value), - }; - - psa_key_id_t cek_key_id; - uint8_t cek_key_id_cbor[] = { - 0x1A, 0x00, 0x00, 0x00, 0x00, - }; - - psa_status_t status = psa_crypto_init(); - - zassert_equal(status, PSA_SUCCESS, "Failed to init psa crypto"); - - status = decrypt_test_init_encryption_key(decrypt_test_key_data, - sizeof(decrypt_test_key_data), &cek_key_id, - PSA_ALG_GCM, cek_key_id_cbor); - zassert_equal(status, PSA_SUCCESS, "Failed to import key"); - - struct suit_encryption_info enc_info = - DECRYPT_TEST_ENC_INFO_DEFAULT_INIT(cek_key_id_cbor); - - int ret = suit_plat_create_component_handle(&valid_component_id, false, &component_handle); - - zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); - - ret = suit_plat_fetch_integrated(component_handle, &source, - &valid_manifest_component_id, &enc_info); - zassert_equal(ret, SUIT_SUCCESS, "suit_plat_fetch failed - error %i", ret); - - ret = suit_plat_component_impl_data_get(component_handle, &handle); - zassert_equal(ret, SUIT_SUCCESS, "suit_plat_component_impl_data_get failed - error %i", - ret); - - const uint8_t *payload; - size_t payload_size = 0; - - - ret = suit_memptr_storage_ptr_get(handle, &payload, &payload_size); - - zassert_equal(ret, SUIT_PLAT_SUCCESS, "storage.get failed - error %i", ret); - zassert_equal(memcmp(decrypt_test_plaintext, payload, - strlen(decrypt_test_plaintext)), 0, - "Retrieved decrypted payload doesn't mach decrypt_test_plaintext"); - zassert_equal(sizeof(decrypt_test_plaintext), payload_size, - "Retrieved payload_size doesn't mach size of decrypt_test_plaintext"); - - ret = suit_plat_release_component_handle(component_handle); - zassert_equal(ret, SUIT_SUCCESS, "Handle release failed - error %i", ret); - - psa_destroy_key(cek_key_id); -} - -ZTEST(fetch_tests, test_integrated_fetch_to_memptr_encrypted_NOK) -{ - suit_component_t component_handle; - memptr_storage_handle_t handle = NULL; - struct zcbor_string source = { - .value = decrypt_test_ciphertext_direct, - .len = sizeof(decrypt_test_ciphertext_direct) - }; - - /* [h'CAND_IMG', h'02'] */ - uint8_t valid_value[] = {0x82, 0x49, 0x68, 'C', 'A', 'N', 'D', - '_', 'I', 'M', 'G', 0x41, 0x02}; - - struct zcbor_string valid_component_id = { - .value = valid_value, - .len = sizeof(valid_value), - }; - - psa_key_id_t cek_key_id; - uint8_t cek_key_id_cbor[] = { - 0x1A, 0x00, 0x00, 0x00, 0x00, - }; - - psa_status_t status = psa_crypto_init(); - - zassert_equal(status, PSA_SUCCESS, "Failed to init psa crypto"); - - status = decrypt_test_init_encryption_key(decrypt_test_key_data, - sizeof(decrypt_test_key_data), &cek_key_id, - PSA_ALG_GCM, cek_key_id_cbor); - zassert_equal(status, PSA_SUCCESS, "Failed to import key"); - - struct suit_encryption_info enc_info = - DECRYPT_TEST_ENC_INFO_DEFAULT_INIT(cek_key_id_cbor); - - int ret = suit_plat_create_component_handle(&valid_component_id, false, &component_handle); - - zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); - - ret = suit_plat_fetch_integrated(component_handle, &source, - &valid_manifest_component_id, &enc_info); - zassert_equal(ret, SUIT_SUCCESS, "suit_plat_fetch failed - error %i", ret); - - ret = suit_plat_component_impl_data_get(component_handle, &handle); - zassert_equal(ret, SUIT_SUCCESS, "suit_plat_component_impl_data_get failed - error %i", - ret); - - const uint8_t *payload; - size_t payload_size = 0; - - - ret = suit_memptr_storage_ptr_get(handle, &payload, &payload_size); - - zassert_equal(ret, SUIT_PLAT_SUCCESS, "storage.get failed - error %i", ret); - zassert_not_equal(memcmp(decrypt_test_plaintext, payload, - strlen(decrypt_test_plaintext)), 0, - "Retrieved decrypted payload should not mach decrypt_test_plaintext"); - zassert_equal(sizeof(decrypt_test_plaintext), payload_size, - "Retrieved payload_size doesn't mach size of decrypt_test_plaintext"); - - ret = suit_plat_release_component_handle(component_handle); - zassert_equal(ret, SUIT_SUCCESS, "Handle release failed - error %i", ret); - - psa_destroy_key(cek_key_id); -} - -ZTEST(fetch_tests, test_integrated_fetch_to_msink_encrypted_wrong_key_NOK) -{ - suit_component_t component_handle; - memptr_storage_handle_t handle = NULL; - struct zcbor_string source = { - .value = decrypt_test_ciphertext_direct, - .len = sizeof(decrypt_test_ciphertext_direct) - }; - - /* [h'MEM', h'02', h'1A00080000', h'191000'] */ - uint8_t valid_value[] = {0x84, 0x44, 0x63, 'M', 'E', 'M', 0x41, 0x02, 0x45, - 0x1A, 0x00, 0x08, 0x00, 0x00, 0x43, 0x19, 0x10, 0x00}; - - struct zcbor_string valid_component_id = { - .value = valid_value, - .len = sizeof(valid_value), - }; - - psa_key_id_t cek_key_id; - uint8_t cek_key_id_cbor[] = { - 0x1A, 0x00, 0x00, 0x00, 0x00, - }; - - psa_status_t status = psa_crypto_init(); - - zassert_equal(status, PSA_SUCCESS, "Failed to init psa crypto"); - - uint8_t wrong_test_key_data[sizeof(decrypt_test_key_data)]; - - memcpy(wrong_test_key_data, decrypt_test_key_data, sizeof(wrong_test_key_data)); - /* Corrupt CEK that we store.*/ - wrong_test_key_data[10] = 0x00; - - status = decrypt_test_init_encryption_key(wrong_test_key_data, - sizeof(wrong_test_key_data), &cek_key_id, - PSA_ALG_GCM, cek_key_id_cbor); - zassert_equal(status, PSA_SUCCESS, "Failed to import key"); - - struct suit_encryption_info enc_info = - DECRYPT_TEST_ENC_INFO_DEFAULT_INIT(cek_key_id_cbor); - - int ret = suit_plat_create_component_handle(&valid_component_id, false, &component_handle); - - zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); - - ret = suit_plat_fetch_integrated(component_handle, &source, - &valid_manifest_component_id, &enc_info); - zassert_equal(ret, SUIT_ERR_AUTHENTICATION, - "suit_plat_fetch should have failed with SUIT_ERR_AUTHENTICATION"); - - ret = suit_plat_component_impl_data_get(component_handle, &handle); - zassert_equal(ret, SUIT_SUCCESS, "suit_plat_component_impl_data_get failed - error %i", - ret); - - const uint8_t *payload; - size_t payload_size = 0; - - ret = suit_memptr_storage_ptr_get(handle, &payload, &payload_size); - - zassert_equal(ret, SUIT_PLAT_SUCCESS, "storage.get failed - error %i", ret); - zassert_not_equal(memcmp(decrypt_test_plaintext, payload, - strlen(decrypt_test_plaintext)), 0, - "Retrieved decrypted payload should not mach decrypt_test_plaintext"); - zassert_equal(payload_size, 0, - "Retrieved payload_size is not 0"); - - ret = suit_plat_release_component_handle(component_handle); - zassert_equal(ret, SUIT_SUCCESS, "Handle release failed - error %i", ret); - - psa_destroy_key(cek_key_id); -} diff --git a/tests/subsys/suit/fetch/src/test_app_ipuc.c b/tests/subsys/suit/fetch/src/test_app_ipuc.c new file mode 100644 index 000000000000..a09b656d249b --- /dev/null +++ b/tests/subsys/suit/fetch/src/test_app_ipuc.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifdef CONFIG_TEST_SUIT_PLATFORM_FETCH_VARIANT_APP +#include +#include +#include +#include +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_FLASH) +#if (DT_NODE_EXISTS(DT_CHOSEN(zephyr_flash_controller))) +#define SUIT_PLAT_INTERNAL_NVM_DEV DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller)) +#else +#define SUIT_PLAT_INTERNAL_NVM_DEV DEVICE_DT_GET(DT_CHOSEN(zephyr_flash)) +#endif +#else +#define SUIT_PLAT_INTERNAL_NVM_DEV NULL +#endif + +static const uint8_t test_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; +static const uint8_t test_data_sdfw[] = {'S', 'D', 'F', 'W', '.', 'b', 'i', 'n'}; +static const uint8_t test_data_scfw[] = {'S', 'y', 's', 'C', 't', 'r', 'l', '.', 'b', 'i', 'n'}; + +/* clang-format off */ +static const uint8_t component_rad_0x80000_0x1000[] = { + 0x84, /* array(4) */ + 0x44, /* bstr(4) */ + 0x63, /* text(3) */ + 'M', 'E', 'M', + 0x41, /* bstr(1) */ + 0x20, /* Data */ + 0x45, /* bstr(5) */ + 0x1a, /* uint32 */ + 0x00, 0x08, 0x00, 0x00, + 0x43, /* bstr(3) */ + 0x19, /* uint16 */ + 0x10, 0x00, +}; +static const uint8_t component_app_0x90000_0x1000[] = { + 0x84, /* array(4) */ + 0x44, /* bstr(4) */ + 0x63, /* text(3) */ + 'M', 'E', 'M', + 0x41, /* bstr(1) */ + 0x20, /* Data */ + 0x45, /* bstr(5) */ + 0x1a, /* uint32 */ + 0x00, 0x09, 0x00, 0x00, + 0x43, /* bstr(3) */ + 0x19, /* uint16 */ + 0x10, 0x00, +}; +/* clang-format on */ + +static suit_plat_err_t suit_ipuc_get_count_single_fake_func(size_t *count) +{ + zassert_not_null(count, "Caller must provide non-Null pointer"); + + *count = 1; + + return SUIT_PLAT_SUCCESS; +} + +static suit_plat_err_t +suit_ipuc_get_info_0x80000_0x1000_fake_func(size_t idx, struct zcbor_string *component_id, + suit_manifest_role_t *role) +{ + zassert_not_null(component_id, "Caller must provide non-Null pointer to read component_id"); + zassert_not_null(role, "Caller must provide non-Null pointer to read role"); + zassert_equal(idx, 0, "Unexpected idx value"); + + component_id->value = component_rad_0x80000_0x1000; + component_id->len = sizeof(component_rad_0x80000_0x1000); + *role = SUIT_MANIFEST_RAD_LOCAL_1; + + return SUIT_PLAT_SUCCESS; +} + +static suit_plat_err_t suit_ipuc_write_rad_fake_func(struct zcbor_string *component_id, + size_t offset, uintptr_t buffer, + size_t chunk_size, bool last_chunk) +{ + zassert_not_null(component_id, "Caller must provide non-Null pointer to read component_id"); + zassert_equal(component_id->len, sizeof(component_rad_0x80000_0x1000), + "Invalid component ID length passed"); + zassert_equal(memcmp(component_id->value, component_rad_0x80000_0x1000, component_id->len), + 0, "Invalid component ID value passed"); + + return SUIT_PLAT_SUCCESS; +} + +static suit_plat_err_t suit_ipuc_get_count_fake_func(size_t *count) +{ + zassert_not_null(count, "Caller must provide non-Null pointer"); + + *count = 2; + + return SUIT_PLAT_SUCCESS; +} + +static suit_plat_err_t suit_ipuc_get_info_fake_func(size_t idx, struct zcbor_string *component_id, + suit_manifest_role_t *role) +{ + zassert_not_null(component_id, "Caller must provide non-Null pointer to read component_id"); + zassert_not_null(role, "Caller must provide non-Null pointer to read role"); + zassert_true(idx < 2, "Unexpected idx value"); + + if (idx == 0) { + component_id->value = component_rad_0x80000_0x1000; + component_id->len = sizeof(component_rad_0x80000_0x1000); + *role = SUIT_MANIFEST_RAD_LOCAL_1; + } else if (idx == 1) { + component_id->value = component_app_0x90000_0x1000; + component_id->len = sizeof(component_app_0x90000_0x1000); + *role = SUIT_MANIFEST_APP_LOCAL_1; + } + + return SUIT_PLAT_SUCCESS; +} + +static suit_plat_err_t suit_ipuc_write_fake_func(struct zcbor_string *component_id, size_t offset, + uintptr_t buffer, size_t chunk_size, + bool last_chunk) +{ + zassert_not_null(component_id, "Caller must provide non-Null pointer to read component_id"); + zassert_equal(component_id->len, sizeof(component_app_0x90000_0x1000), + "Invalid component ID length passed"); + zassert_equal(memcmp(component_id->value, component_app_0x90000_0x1000, component_id->len), + 0, "Invalid component ID value passed"); + + zassert_equal(flash_write(SUIT_PLAT_INTERNAL_NVM_DEV, 0x90000 + offset, (uint8_t *)buffer, + chunk_size), + 0, "Unable to modify NVM to match requested changes"); + + return SUIT_PLAT_SUCCESS; +} + +static int fetch_request_fn(const uint8_t *uri, size_t uri_length, uint32_t session_id) +{ + int rc = 0; + + if (((uri_length == sizeof("http://databucket.com")) && + memcmp(uri, "http://databucket.com", uri_length) == 0)) { + zassert_equal(uri_length, sizeof("http://databucket.com"), + "Unexpected URI length: %d", uri_length); + zassert_equal(memcmp(uri, "http://databucket.com", uri_length), 0, + "Unexpected URI value"); + rc = suit_dfu_fetch_source_write_fetched_data(session_id, test_data, + sizeof(test_data)); + } else if (((uri_length == sizeof("http://databucket.com/sdfw.bin")) && + memcmp(uri, "http://databucket.com/sdfw.bin", uri_length) == 0)) { + zassert_equal(uri_length, sizeof("http://databucket.com/sdfw.bin"), + "Unexpected URI length: %d", uri_length); + zassert_equal(memcmp(uri, "http://databucket.com/sdfw.bin", uri_length), 0, + "Unexpected URI value"); + rc = suit_dfu_fetch_source_write_fetched_data(session_id, test_data_sdfw, + sizeof(test_data_sdfw)); + } else if (((uri_length == sizeof("http://databucket.com/scfw.bin")) && + memcmp(uri, "http://databucket.com/scfw.bin", uri_length) == 0)) { + zassert_equal(uri_length, sizeof("http://databucket.com/scfw.bin"), + "Unexpected URI length: %d", uri_length); + zassert_equal(memcmp(uri, "http://databucket.com/scfw.bin", uri_length), 0, + "Unexpected URI value"); + rc = suit_dfu_fetch_source_write_fetched_data(session_id, test_data_scfw, + sizeof(test_data_scfw)); + } else { + zassert_true(false, "Unsupporte URI value"); + } + + if (rc != 0) { + return SUIT_PLAT_ERR_CRASH; + } + + return SUIT_PLAT_SUCCESS; +} + +static void test_before(void *data) +{ + /* Reset mocks */ + mock_suit_ipuc_reset(); + + /* Reset common FFF internal structures */ + FFF_RESET_HISTORY(); + + /* Erase NVM area */ + zassert_equal(flash_erase(SUIT_PLAT_INTERNAL_NVM_DEV, 0x90000, 0x1000), 0, + "Unable to erase NVM before test execution"); + + /* Load IPUCs as SUIT caches */ + suit_ipuc_get_count_fake.custom_fake = suit_ipuc_get_count_fake_func; + suit_ipuc_get_info_fake.custom_fake = suit_ipuc_get_info_fake_func; + + suit_dfu_cache_rw_init(); + zassert_equal(suit_dfu_cache_0_resize(), SUIT_PLAT_SUCCESS, + "Failed to initialize SUIT cache before test execution."); + zassert_equal(suit_ipuc_get_count_fake.call_count, 2, + "Incorrect number of suit_ipuc_get_count() calls (%d)", + suit_ipuc_get_count_fake.call_count); + /* 2x ((count: search for max) + (info of the max))*/ + zassert_equal(suit_ipuc_get_info_fake.call_count, 6, + "Incorrect number of suit_ipuc_get_info() calls (%d)", + suit_ipuc_get_info_fake.call_count); + + /* Reset mocks */ + mock_suit_ipuc_reset(); + + /* Reset common FFF internal structures */ + FFF_RESET_HISTORY(); +} + +static void test_after(void *data) +{ + uintptr_t cache_ipuc_address = (uintptr_t)suit_plat_mem_ptr_get(0x90000); + size_t cache_ipuc_size = 0x1000; + struct device *flash_ipuc = NULL; + uintptr_t ipuc_address = 0; + size_t ipuc_size = 0; + + /* SUIT cache IPUC is not released automatically as it is possible to populate cache + * with miltiple payloads. + * Relase them manually to preserve constant number of IPUCs for all test cases. + */ + flash_ipuc = + flash_ipuc_find(cache_ipuc_address, cache_ipuc_size, &ipuc_address, &ipuc_size); + if (flash_ipuc != NULL) { + flash_ipuc_release(flash_ipuc); + } +} + +ZTEST_SUITE(fetch_app_mem_tests, NULL, NULL, test_before, NULL, NULL); + +ZTEST(fetch_app_mem_tests, test_fetch_to_ipuc_mem_OK) +{ + struct zcbor_string uri = {.value = "http://databucket.com", + .len = sizeof("http://databucket.com")}; + /* Create handle that will be used as destination */ + suit_component_t dst_handle; + /* [h'MEM', h'20', h'1A00080000', h'191000'] */ + uint8_t valid_dst_value[] = {0x84, 0x44, 0x63, 'M', 'E', 'M', 0x41, 0x20, 0x45, + 0x1A, 0x00, 0x08, 0x00, 0x00, 0x43, 0x19, 0x10, 0x00}; + + struct zcbor_string valid_dst_component_id = { + .value = valid_dst_value, + .len = sizeof(valid_dst_value), + }; + + suit_ipuc_get_count_fake.custom_fake = suit_ipuc_get_count_single_fake_func; + suit_ipuc_get_info_fake.custom_fake = suit_ipuc_get_info_0x80000_0x1000_fake_func; + suit_ipuc_write_setup_fake.return_val = SUIT_PLAT_SUCCESS; + suit_ipuc_write_fake.custom_fake = suit_ipuc_write_rad_fake_func; + + zassert_equal(suit_dfu_fetch_source_register(fetch_request_fn), SUIT_PLAT_SUCCESS, + "Failed to register fetch source mock"); + + int ret = suit_plat_create_component_handle(&valid_dst_component_id, false, &dst_handle); + + zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); + + ret = suit_plat_fetch(dst_handle, &uri, &valid_dst_component_id, NULL); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_fetch failed - error %i", ret); + + zassert_equal(suit_ipuc_get_count_fake.call_count, 2, + "Incorrect number of suit_ipuc_get_count() calls (%d)", + suit_ipuc_get_count_fake.call_count); + zassert_equal(suit_ipuc_get_info_fake.call_count, 2, + "Incorrect number of suit_ipuc_get_info() calls (%d)", + suit_ipuc_get_info_fake.call_count); + zassert_equal(suit_ipuc_write_setup_fake.call_count, 1, + "Incorrect number of suit_ipuc_write_setup() calls (%d)", + suit_ipuc_write_setup_fake.call_count); + zassert_equal(suit_ipuc_write_fake.call_count, 2, + "Incorrect number of suit_ipuc_write() calls (%d)", + suit_ipuc_write_fake.call_count); + + zassert_equal(suit_ipuc_write_fake.arg1_history[0], 0, + "Unexpected offset in the first suit_ipuc_write() call (0x%x)", + suit_ipuc_write_fake.arg1_history[0]); + zassert_equal_ptr(suit_ipuc_write_fake.arg2_history[0], test_data, + "Unexpected data pointer in the first suit_ipuc_write() call (0x%x)", + suit_ipuc_write_fake.arg2_history[0]); + zassert_equal(suit_ipuc_write_fake.arg3_history[0], sizeof(test_data), + "Unexpected data size in the first suit_ipuc_write() call (0x%x)", + suit_ipuc_write_fake.arg3_history[0]); + zassert_equal(suit_ipuc_write_fake.arg4_history[0], false, + "Write closed on the first suit_ipuc_write() call"); + + zassert_equal(suit_ipuc_write_fake.arg1_history[1], sizeof(test_data), + "Unexpected offset in the second suit_ipuc_write() call (0x%x)", + suit_ipuc_write_fake.arg1_history[1]); + zassert_equal_ptr(suit_ipuc_write_fake.arg2_history[1], NULL, + "Unexpected data pointer in the second suit_ipuc_write() call (0x%x)", + suit_ipuc_write_fake.arg2_history[1]); + zassert_equal(suit_ipuc_write_fake.arg3_history[1], 0, + "Unexpected data size in the second suit_ipuc_write() call (0x%x)", + suit_ipuc_write_fake.arg3_history[1]); + zassert_equal(suit_ipuc_write_fake.arg4_history[1], true, + "Write was not closed on the second suit_ipuc_write() call"); + + ret = suit_plat_release_component_handle(dst_handle); + zassert_equal(ret, SUIT_SUCCESS, "dst_handle release failed - error %i", ret); +} + +ZTEST_SUITE(fetch_app_cache_tests, NULL, NULL, test_before, test_after, NULL); + +ZTEST(fetch_app_cache_tests, test_fetch_to_ipuc_cache_OK) +{ + struct zcbor_string uri = {.value = "http://databucket.com", + .len = sizeof("http://databucket.com")}; + /* Create handle that will be used as destination */ + suit_component_t dst_handle; + /* clang-format off */ + uint8_t valid_dst_value[] = { + 0x82, /* array(2) */ + 0x4B, /* bytes(11) */ + 0x6A, /* text(10) */ + 'C', 'A', 'C', 'H', 'E', '_', 'P', 'O', 'O', 'L', + 0x42, /* bytes(2) */ + 0x18, /* uint8_t */ + CONFIG_SUIT_CACHE_APP_IPUC_ID, + }; + /* clang-format on */ + struct zcbor_string valid_dst_component_id = { + .value = valid_dst_value, + .len = sizeof(valid_dst_value), + }; + size_t cached_size = 0; + const uint8_t *cached_payload = NULL; + + suit_ipuc_get_count_fake.custom_fake = suit_ipuc_get_count_fake_func; + suit_ipuc_get_info_fake.custom_fake = suit_ipuc_get_info_fake_func; + suit_ipuc_write_setup_fake.return_val = SUIT_PLAT_SUCCESS; + suit_ipuc_write_fake.custom_fake = suit_ipuc_write_fake_func; + + zassert_equal(suit_dfu_fetch_source_register(fetch_request_fn), SUIT_PLAT_SUCCESS, + "Failed to register fetch source mock"); + + int ret = suit_plat_create_component_handle(&valid_dst_component_id, false, &dst_handle); + + zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); + + ret = suit_plat_fetch(dst_handle, &uri, &valid_dst_component_id, NULL); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_fetch failed - error %i", ret); + + zassert_equal(suit_ipuc_write_setup_fake.call_count, 1, + "Incorrect number of suit_ipuc_write_setup() calls (%d)", + suit_ipuc_write_setup_fake.call_count); + zassert_equal(suit_ipuc_get_count_fake.call_count, 1, + "Incorrect number of suit_ipuc_get_count() calls (%d)", + suit_ipuc_get_count_fake.call_count); + zassert_equal(suit_ipuc_get_info_fake.call_count, 3, + "Incorrect number of suit_ipuc_get_info() calls (%d)", + suit_ipuc_get_info_fake.call_count); + + zassert_true(suit_ipuc_write_fake.call_count >= 4, + "Too small number of suit_ipuc_write() calls (%d)", + suit_ipuc_write_fake.call_count); + + size_t last_write = suit_ipuc_write_fake.call_count - 1; + + for (size_t i = 0; i < suit_ipuc_write_fake.call_count; i++) { + printk("\t%d\n", suit_ipuc_write_fake.arg3_history[i]); + zassert_equal(suit_ipuc_write_fake.arg4_history[i], false, + "Write closed too early in suit_ipuc_write() call"); + } + + /* partition header + slot header + URI + (data length) */ + /* data */ + + /* slot length */ + zassert_equal(suit_ipuc_write_fake.arg3_history[last_write - 1], 4, + "Unexpected data size in the third suit_ipuc_write() call (0x%x)", + suit_ipuc_write_fake.arg3_history[last_write - 1]); + + /* slot end marker */ + zassert_equal(suit_ipuc_write_fake.arg3_history[last_write], 1, + "Unexpected data size in the fourth suit_ipuc_write() call (0x%x)", + suit_ipuc_write_fake.arg3_history[last_write]); + + ret = suit_plat_release_component_handle(dst_handle); + zassert_equal(ret, SUIT_SUCCESS, "dst_handle release failed - error %i", ret); + + /* Verify the cache contents. */ + zassert_equal(suit_dfu_cache_search(uri.value, uri.len, &cached_payload, &cached_size), + SUIT_PLAT_SUCCESS, "Failed to find cached entry inside the SUIT cache"); + zassert_equal(cached_size, sizeof(test_data), "Invalid size of the cached data (%d)", + cached_size); + zassert_equal(memcmp(cached_payload, test_data, sizeof(test_data)), 0, + "Invalid cached payload"); +} + +ZTEST(fetch_app_cache_tests, test_fetch_to_ipuc_cache_sdfw_scfw_OK) +{ + struct zcbor_string uri_sdfw = {.value = "http://databucket.com/sdfw.bin", + .len = sizeof("http://databucket.com/sdfw.bin")}; + struct zcbor_string uri_scfw = {.value = "http://databucket.com/scfw.bin", + .len = sizeof("http://databucket.com/scfw.bin")}; + /* Create handle that will be used as destination */ + suit_component_t dst_handle; + /* clang-format off */ + uint8_t valid_dst_value[] = { + 0x82, /* array(2) */ + 0x4B, /* bytes(11) */ + 0x6A, /* text(10) */ + 'C', 'A', 'C', 'H', 'E', '_', 'P', 'O', 'O', 'L', + 0x42, /* bytes(2) */ + 0x18, /* uint8_t */ + CONFIG_SUIT_CACHE_SDFW_IPUC_ID, + }; + /* clang-format on */ + struct zcbor_string valid_dst_component_id = { + .value = valid_dst_value, + .len = sizeof(valid_dst_value), + }; + size_t cached_size = 0; + const uint8_t *cached_payload = NULL; + + suit_ipuc_get_count_fake.custom_fake = suit_ipuc_get_count_fake_func; + suit_ipuc_get_info_fake.custom_fake = suit_ipuc_get_info_fake_func; + suit_ipuc_write_setup_fake.return_val = SUIT_PLAT_SUCCESS; + suit_ipuc_write_fake.custom_fake = suit_ipuc_write_fake_func; + + zassert_equal(suit_dfu_fetch_source_register(fetch_request_fn), SUIT_PLAT_SUCCESS, + "Failed to register fetch source mock"); + + int ret = suit_plat_create_component_handle(&valid_dst_component_id, false, &dst_handle); + + zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); + + /* Fetch SDFW binary */ + ret = suit_plat_fetch(dst_handle, &uri_sdfw, &valid_dst_component_id, NULL); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_fetch failed - error %i", ret); + + zassert_equal(suit_ipuc_write_setup_fake.call_count, 1, + "Incorrect number of suit_ipuc_write_setup() calls (%d)", + suit_ipuc_write_setup_fake.call_count); + zassert_equal(suit_ipuc_get_count_fake.call_count, 1, + "Incorrect number of suit_ipuc_get_count() calls (%d)", + suit_ipuc_get_count_fake.call_count); + zassert_equal(suit_ipuc_get_info_fake.call_count, 3, + "Incorrect number of suit_ipuc_get_info() calls (%d)", + suit_ipuc_get_info_fake.call_count); + + /* Fetch SCFW binary using the same IPUC and component context */ + ret = suit_plat_fetch(dst_handle, &uri_scfw, &valid_dst_component_id, NULL); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_fetch failed - error %i", ret); + + /* The write_setup call count should remain the same - IPUC must not be erased at this + * point. + */ + zassert_equal(suit_ipuc_write_setup_fake.call_count, 1, + "Incorrect number of suit_ipuc_write_setup() calls (%d)", + suit_ipuc_write_setup_fake.call_count); + + ret = suit_plat_release_component_handle(dst_handle); + zassert_equal(ret, SUIT_SUCCESS, "dst_handle release failed - error %i", ret); + + /* Verify the cache contents. */ + zassert_equal( + suit_dfu_cache_search(uri_sdfw.value, uri_sdfw.len, &cached_payload, &cached_size), + SUIT_PLAT_SUCCESS, "Failed to find SDFW entry inside the SUIT cache"); + zassert_equal(cached_size, sizeof(test_data_sdfw), "Invalid SDFW size in cache (%d)", + cached_size); + zassert_equal(memcmp(cached_payload, test_data_sdfw, sizeof(test_data_sdfw)), 0, + "Invalid SDFW payload"); + + zassert_equal( + suit_dfu_cache_search(uri_scfw.value, uri_scfw.len, &cached_payload, &cached_size), + SUIT_PLAT_SUCCESS, "Failed to find SCFW entry inside the SUIT cache"); + zassert_equal(cached_size, sizeof(test_data_scfw), "Invalid SCFW size in cache (%d)", + cached_size); + zassert_equal(memcmp(cached_payload, test_data_scfw, sizeof(test_data_scfw)), 0, + "Invalid SCFW payload"); +} +#endif /* CONFIG_TEST_SUIT_PLATFORM_FETCH_VARIANT_APP */ diff --git a/tests/subsys/suit/fetch/src/test_sdfw_mem.c b/tests/subsys/suit/fetch/src/test_sdfw_mem.c new file mode 100644 index 000000000000..bb89723a0dd4 --- /dev/null +++ b/tests/subsys/suit/fetch/src/test_sdfw_mem.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifdef CONFIG_TEST_SUIT_PLATFORM_FETCH_VARIANT_SDFW +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static uint8_t test_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; + +/* clang-format off */ +static const uint8_t valid_manifest_component[] = { + 0x82, /* array: 2 elements */ + 0x4c, /* byte string: 12 bytes */ + 0x6b, /* string: 11 characters */ + 'I', 'N', 'S', 'T', 'L', 'D', '_', 'M', 'F', 'S', 'T', + 0x50, /* byte string: 16 bytes */ + 0x5b, 0x46, 0x9f, 0xd1, 0x90, 0xee, 0x53, 0x9c, + 0xa3, 0x18, 0x68, 0x1b, 0x03, 0x69, 0x5e, 0x36 +}; +/* clang-format on */ + +static struct zcbor_string valid_manifest_component_id = { + .value = valid_manifest_component, + .len = sizeof(valid_manifest_component), +}; + +static void test_before(void *data) +{ + /* Reset mocks */ + mocks_sdfw_reset(); + + /* Reset common FFF internal structures */ + FFF_RESET_HISTORY(); +} + +ZTEST_SUITE(fetch_sdfw_mem_tests, NULL, NULL, test_before, NULL, NULL); + +ZTEST(fetch_sdfw_mem_tests, test_integrated_fetch_to_msink_OK) +{ + struct zcbor_string source = {.value = test_data, .len = sizeof(test_data)}; + /* Create handle that will be used as destination */ + suit_component_t dst_handle; + /* [h'MEM', h'02', h'1A00080000', h'191000'] */ + uint8_t valid_dst_value[] = {0x84, 0x44, 0x63, 'M', 'E', 'M', 0x41, 0x02, 0x45, + 0x1A, 0x00, 0x08, 0x00, 0x00, 0x43, 0x19, 0x10, 0x00}; + + struct zcbor_string valid_dst_component_id = { + .value = valid_dst_value, + .len = sizeof(valid_dst_value), + }; + + int ipc_client_id = 1234; + int ret = suit_plat_create_component_handle(&valid_dst_component_id, false, &dst_handle); + + zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); + ret = suit_ipuc_sdfw_write_setup(ipc_client_id, &valid_dst_component_id, NULL, NULL); + zassert_equal(ret, SUIT_PLAT_ERR_NOT_FOUND, "in-place updateable component found"); + + ret = suit_ipuc_sdfw_declare(dst_handle, SUIT_MANIFEST_UNKNOWN); + zassert_equal(ret, SUIT_PLAT_SUCCESS, "suit_ipuc_sdfw_declare failed - error %i", ret); + + ret = suit_ipuc_sdfw_write_setup(ipc_client_id, &valid_dst_component_id, NULL, NULL); + zassert_equal(ret, SUIT_PLAT_SUCCESS, "suit_ipuc_sdfw_write_setup failed - error %i", ret); + + ret = suit_plat_fetch_integrated(dst_handle, &source, &valid_dst_component_id, NULL); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_fetch failed - error %i", ret); + + ret = suit_ipuc_sdfw_write_setup(ipc_client_id, &valid_dst_component_id, NULL, NULL); + zassert_equal(ret, SUIT_PLAT_ERR_NOT_FOUND, "in-place updateable component found"); + + ret = suit_plat_release_component_handle(dst_handle); + zassert_equal(ret, SUIT_SUCCESS, "dst_handle release failed - error %i", ret); +} + +ZTEST(fetch_tests, test_integrated_fetch_to_msink_encrypted_OK) +{ + suit_component_t component_handle; + memptr_storage_handle_t handle = NULL; + struct zcbor_string source = {.value = decrypt_test_ciphertext_direct, + .len = sizeof(decrypt_test_ciphertext_direct)}; + + /* [h'MEM', h'02', h'1A00080000', h'191000'] */ + uint8_t valid_value[] = {0x84, 0x44, 0x63, 'M', 'E', 'M', 0x41, 0x02, 0x45, + 0x1A, 0x00, 0x08, 0x00, 0x00, 0x43, 0x19, 0x10, 0x00}; + + struct zcbor_string valid_component_id = { + .value = valid_value, + .len = sizeof(valid_value), + }; + + psa_key_id_t cek_key_id; + uint8_t cek_key_id_cbor[] = { + 0x1A, 0x00, 0x00, 0x00, 0x00, + }; + + psa_status_t status = psa_crypto_init(); + + zassert_equal(status, PSA_SUCCESS, "Failed to init psa crypto"); + + status = decrypt_test_init_encryption_key(decrypt_test_key_data, + sizeof(decrypt_test_key_data), &cek_key_id, + PSA_ALG_GCM, cek_key_id_cbor); + zassert_equal(status, PSA_SUCCESS, "Failed to import key"); + + struct suit_encryption_info enc_info = DECRYPT_TEST_ENC_INFO_DEFAULT_INIT(cek_key_id_cbor); + + int ret = suit_plat_create_component_handle(&valid_component_id, false, &component_handle); + + zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); + + ret = suit_plat_fetch_integrated(component_handle, &source, &valid_manifest_component_id, + &enc_info); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_fetch failed - error %i", ret); + + ret = suit_plat_component_impl_data_get(component_handle, &handle); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_component_impl_data_get failed - error %i", + ret); + + const uint8_t *payload; + size_t payload_size = 0; + + ret = suit_memptr_storage_ptr_get(handle, &payload, &payload_size); + + zassert_equal(ret, SUIT_PLAT_SUCCESS, "storage.get failed - error %i", ret); + zassert_equal(memcmp(decrypt_test_plaintext, payload, strlen(decrypt_test_plaintext)), 0, + "Retrieved decrypted payload doesn't mach decrypt_test_plaintext"); + zassert_equal(sizeof(decrypt_test_plaintext), payload_size, + "Retrieved payload_size doesn't mach size of decrypt_test_plaintext"); + + ret = suit_plat_release_component_handle(component_handle); + zassert_equal(ret, SUIT_SUCCESS, "Handle release failed - error %i", ret); + + psa_destroy_key(cek_key_id); +} + +ZTEST(fetch_tests, test_integrated_fetch_to_memptr_encrypted_NOK) +{ + suit_component_t component_handle; + memptr_storage_handle_t handle = NULL; + struct zcbor_string source = {.value = decrypt_test_ciphertext_direct, + .len = sizeof(decrypt_test_ciphertext_direct)}; + + /* [h'CAND_IMG', h'02'] */ + uint8_t valid_value[] = {0x82, 0x49, 0x68, 'C', 'A', 'N', 'D', + '_', 'I', 'M', 'G', 0x41, 0x02}; + + struct zcbor_string valid_component_id = { + .value = valid_value, + .len = sizeof(valid_value), + }; + + psa_key_id_t cek_key_id; + uint8_t cek_key_id_cbor[] = { + 0x1A, 0x00, 0x00, 0x00, 0x00, + }; + + psa_status_t status = psa_crypto_init(); + + zassert_equal(status, PSA_SUCCESS, "Failed to init psa crypto"); + + status = decrypt_test_init_encryption_key(decrypt_test_key_data, + sizeof(decrypt_test_key_data), &cek_key_id, + PSA_ALG_GCM, cek_key_id_cbor); + zassert_equal(status, PSA_SUCCESS, "Failed to import key"); + + struct suit_encryption_info enc_info = DECRYPT_TEST_ENC_INFO_DEFAULT_INIT(cek_key_id_cbor); + + int ret = suit_plat_create_component_handle(&valid_component_id, false, &component_handle); + + zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); + + ret = suit_plat_fetch_integrated(component_handle, &source, &valid_manifest_component_id, + &enc_info); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_fetch failed - error %i", ret); + + ret = suit_plat_component_impl_data_get(component_handle, &handle); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_component_impl_data_get failed - error %i", + ret); + + const uint8_t *payload; + size_t payload_size = 0; + + ret = suit_memptr_storage_ptr_get(handle, &payload, &payload_size); + + zassert_equal(ret, SUIT_PLAT_SUCCESS, "storage.get failed - error %i", ret); + zassert_not_equal(memcmp(decrypt_test_plaintext, payload, strlen(decrypt_test_plaintext)), + 0, "Retrieved decrypted payload should not mach decrypt_test_plaintext"); + zassert_equal(sizeof(decrypt_test_plaintext), payload_size, + "Retrieved payload_size doesn't mach size of decrypt_test_plaintext"); + + ret = suit_plat_release_component_handle(component_handle); + zassert_equal(ret, SUIT_SUCCESS, "Handle release failed - error %i", ret); + + psa_destroy_key(cek_key_id); +} + +ZTEST(fetch_tests, test_integrated_fetch_to_msink_encrypted_wrong_key_NOK) +{ + suit_component_t component_handle; + memptr_storage_handle_t handle = NULL; + struct zcbor_string source = {.value = decrypt_test_ciphertext_direct, + .len = sizeof(decrypt_test_ciphertext_direct)}; + + /* [h'MEM', h'02', h'1A00080000', h'191000'] */ + uint8_t valid_value[] = {0x84, 0x44, 0x63, 'M', 'E', 'M', 0x41, 0x02, 0x45, + 0x1A, 0x00, 0x08, 0x00, 0x00, 0x43, 0x19, 0x10, 0x00}; + + struct zcbor_string valid_component_id = { + .value = valid_value, + .len = sizeof(valid_value), + }; + + psa_key_id_t cek_key_id; + uint8_t cek_key_id_cbor[] = { + 0x1A, 0x00, 0x00, 0x00, 0x00, + }; + + psa_status_t status = psa_crypto_init(); + + zassert_equal(status, PSA_SUCCESS, "Failed to init psa crypto"); + + uint8_t wrong_test_key_data[sizeof(decrypt_test_key_data)]; + + memcpy(wrong_test_key_data, decrypt_test_key_data, sizeof(wrong_test_key_data)); + /* Corrupt CEK that we store.*/ + wrong_test_key_data[10] = 0x00; + + status = decrypt_test_init_encryption_key(wrong_test_key_data, sizeof(wrong_test_key_data), + &cek_key_id, PSA_ALG_GCM, cek_key_id_cbor); + zassert_equal(status, PSA_SUCCESS, "Failed to import key"); + + struct suit_encryption_info enc_info = DECRYPT_TEST_ENC_INFO_DEFAULT_INIT(cek_key_id_cbor); + + int ret = suit_plat_create_component_handle(&valid_component_id, false, &component_handle); + + zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); + + ret = suit_plat_fetch_integrated(component_handle, &source, &valid_manifest_component_id, + &enc_info); + zassert_equal(ret, SUIT_ERR_AUTHENTICATION, + "suit_plat_fetch should have failed with SUIT_ERR_AUTHENTICATION"); + + ret = suit_plat_component_impl_data_get(component_handle, &handle); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_component_impl_data_get failed - error %i", + ret); + + const uint8_t *payload; + size_t payload_size = 0; + + ret = suit_memptr_storage_ptr_get(handle, &payload, &payload_size); + + zassert_equal(ret, SUIT_PLAT_SUCCESS, "storage.get failed - error %i", ret); + zassert_not_equal(memcmp(decrypt_test_plaintext, payload, strlen(decrypt_test_plaintext)), + 0, "Retrieved decrypted payload should not mach decrypt_test_plaintext"); + zassert_equal(payload_size, 0, "Retrieved payload_size is not 0"); + + ret = suit_plat_release_component_handle(component_handle); + zassert_equal(ret, SUIT_SUCCESS, "Handle release failed - error %i", ret); + + psa_destroy_key(cek_key_id); +} +#endif /* CONFIG_TEST_SUIT_PLATFORM_FETCH_VARIANT_SDFW */ diff --git a/tests/subsys/suit/fetch/testcase.yaml b/tests/subsys/suit/fetch/testcase.yaml index 3cea0c3522ae..293e472e1b92 100644 --- a/tests/subsys/suit/fetch/testcase.yaml +++ b/tests/subsys/suit/fetch/testcase.yaml @@ -13,3 +13,18 @@ tests: - nrf52840dk/nrf52840 - native_sim - native_sim/native/64 + + suit-platform.integration.fetch.app: + platform_allow: + - native_sim + - native_sim/native/64 + tags: + - suit-processor + - suit_platform + - suit + - ci_tests_subsys_suit + extra_configs: + - CONFIG_SUIT_PLATFORM_VARIANT_APP=y + integration_platforms: + - native_sim + - native_sim/native/64