From 83fecc438ed862edc3d4baab016769e4bbfb38ff Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Wed, 8 Jan 2025 14:32:13 +0100 Subject: [PATCH] tests: Extend SUIT tests for fetch, copy and write with decryption This commit extends integration tests for fetch, copy and write SUIT directives with test cases for payload decryption. Common test module decrypt_test_utils.c was added with default constants and utilities for decryption tests to use. Refactor of decrypt_filter/src/main.c was made because of this common module. Ref: NCSDK-31276 Signed-off-by: Michal Kozikowski --- tests/subsys/suit/common/CMakeLists.txt | 2 + .../suit/common/decrypt_utils/CMakeLists.txt | 11 + .../common/decrypt_utils/decrypt_test_utils.c | 132 ++++++++++ .../common/decrypt_utils/decrypt_test_utils.h | 90 +++++++ tests/subsys/suit/copy/CMakeLists.txt | 1 + tests/subsys/suit/copy/prj.conf | 2 + tests/subsys/suit/copy/src/main.c | 99 ++++++++ .../subsys/suit/decrypt_filter/CMakeLists.txt | 1 + tests/subsys/suit/decrypt_filter/src/main.c | 225 +++++------------- tests/subsys/suit/fetch/CMakeLists.txt | 2 + tests/subsys/suit/fetch/prj.conf | 5 + tests/subsys/suit/fetch/src/main.c | 223 ++++++++++++++++- tests/subsys/suit/write/CMakeLists.txt | 1 + tests/subsys/suit/write/prj.conf | 2 + tests/subsys/suit/write/src/main.c | 51 ++++ 15 files changed, 673 insertions(+), 174 deletions(-) create mode 100644 tests/subsys/suit/common/decrypt_utils/CMakeLists.txt create mode 100644 tests/subsys/suit/common/decrypt_utils/decrypt_test_utils.c create mode 100644 tests/subsys/suit/common/decrypt_utils/decrypt_test_utils.h diff --git a/tests/subsys/suit/common/CMakeLists.txt b/tests/subsys/suit/common/CMakeLists.txt index 2ed45207c82c..800247a93f2c 100644 --- a/tests/subsys/suit/common/CMakeLists.txt +++ b/tests/subsys/suit/common/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(mci_test) add_subdirectory(validator_test) +add_subdirectory(decrypt_utils) zephyr_include_directories(${CMAKE_CURRENT_LIST_DIR}/include) if (CONFIG_MBEDTLS) @@ -20,6 +21,7 @@ endif() if (CONFIG_SUIT_STREAM_FILTER_DECRYPT) target_link_libraries(suit_stream_filters_interface INTERFACE mbedTLS) +target_link_libraries(suit_decrypt_test_utils INTERFACE mbedTLS) endif() if (CONFIG_SUIT_STORAGE_LAYOUT_NRF54H20) diff --git a/tests/subsys/suit/common/decrypt_utils/CMakeLists.txt b/tests/subsys/suit/common/decrypt_utils/CMakeLists.txt new file mode 100644 index 000000000000..8a1b07065048 --- /dev/null +++ b/tests/subsys/suit/common/decrypt_utils/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +if(CONFIG_SUIT_STREAM_FILTER_DECRYPT) + zephyr_library_named(suit_decrypt_test_utils) + zephyr_include_directories(.) + zephyr_library_sources(decrypt_test_utils.c) + zephyr_library_link_libraries(suit_metadata) +endif() diff --git a/tests/subsys/suit/common/decrypt_utils/decrypt_test_utils.c b/tests/subsys/suit/common/decrypt_utils/decrypt_test_utils.c new file mode 100644 index 000000000000..dfcbb7d88399 --- /dev/null +++ b/tests/subsys/suit/common/decrypt_utils/decrypt_test_utils.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "decrypt_test_utils.h" + +/* This module holds common utilities for SUIT decrypt filter tests. + * It defines default encryption key data, plaintext and ciphertext along with other + * suit_encryption_info struct members that can be used while testing. + * + * WARNING: All of the const values defined in this module CAN be changed freely. + * This also means that any test depending on them should expect it. + */ + +/** + * The master key used by these tests can be imported into the local KMS backend by running: + * + * nrfkms import_keyvalue -k TEST_AES_KEY -t aes -v aHWJdIkl5hdXw4SS1nTdVYE/q7ycMOZm2mR6qx/KvKw= + * + * The KEK below is derived from context "test" + * To acquire it run: + * nrfkms export_derived -k TEST_AES_KEY -c test --format native + * hexdump -e '16/1 "0x%02x, " "\n"' kms_output/derived_key_native_test_from_TEST_AES_KEY.bin + */ +const uint8_t decrypt_test_key_data[] = { + 0xf8, 0xfa, 0x8e, 0x7b, 0xed, 0x32, 0xd0, 0xc7, 0x15, 0x1f, 0xd9, 0xab, 0x0d, + 0x8d, 0xed, 0x95, 0x26, 0xa8, 0x6a, 0x15, 0x34, 0x16, 0x01, 0xcf, 0x9c, 0x6b, + 0xba, 0x00, 0x6a, 0xab, 0xaa, 0x9a, +}; + +const uint8_t decrypt_test_plaintext[] = { + "This is a sample plaintext for testing the decryption filter", +}; + +const uint8_t decrypt_test_aad[] = { + "sample aad" +}; + +/** + * Encryption and using wrapped CEK achieved by running: + * + * echo "This is a sample plaintext for testing the decryption filter" > plaintext.txt + * nrfkms wrap -k TEST_AES_KEY -c test -f plaintext.txt --format native -t aes --aad "sample aad" + * + * Wrapped CEK stored in the resulting wrapped_aek-aes-... file + * + * Ciphertext and NONCE (IV) taken from the encrypted_asset-... file, which is in format + * |nonce (12 bytes)|ciphertext|tag (16 bytes)| + * + */ +const uint8_t decrypt_test_wrapped_cek[] = { + 0x7d, 0xd6, 0xf4, 0xd3, 0x52, 0x44, 0x5a, 0x3a, 0x67, 0xb8, 0xcc, + 0x74, 0x5b, 0x4b, 0x6f, 0x70, 0x62, 0xc3, 0xf2, 0x7b, 0x6b, 0x14, + 0xf1, 0x06, 0x57, 0xa3, 0x68, 0x32, 0x44, 0xc3, 0x85, 0x77, 0x86, + 0xe7, 0xda, 0x15, 0xbf, 0xf8, 0x9e, 0x63, +}; + +const uint8_t decrypt_test_ciphertext_aes_kw[] = { + /* tag (16 bytes) */ + 0xdc, 0xe6, 0x95, 0xac, 0x0f, 0x61, 0x87, 0x17, 0x51, 0x48, 0xb4, 0xa1, + 0x8e, 0x09, 0x89, 0xb4, + /* ciphertext */ + 0x8b, 0xfb, 0xd9, 0xe4, 0xcf, 0xde, 0xf8, 0xcf, 0xe5, 0x69, 0x9d, 0x6d, + 0x92, 0x8a, 0x04, 0xf8, 0x26, 0x22, 0xd5, 0xd8, 0xe8, 0x77, 0x18, 0x5a, + 0x01, 0x13, 0xba, 0xd5, 0x23, 0x72, 0xae, 0x80, 0x44, 0xed, 0xea, 0xdf, + 0x74, 0x79, 0x8a, 0x83, 0x52, 0x72, 0x2f, 0x43, 0x06, 0xe9, 0xd4, 0xbb, + 0x54, 0x8a, 0x0d, 0xea, 0x7f, 0xe6, 0x48, 0xf0, 0xfd, 0x0e, 0xbb, 0xaa, + 0xa3, +}; + +const uint8_t decrypt_test_iv_aes_kw[] = { + 0x61, 0xb4, 0x70, 0x53, 0xa5, 0xe2, 0x05, 0x68, 0xfe, 0x77, 0x12, 0x89, +}; + +/** + * Encryption without wrapping CEK achieved by running: + * + * echo "This is a sample plaintext for testing the decryption filter" > plaintext.txt + * nrfkms encrypt -k TEST_AES_KEY -c test -f plaintext.txt --aad "sample aad" --format native + * + * Ciphertext and NONCE (IV) taken from the encrypted_data_using_TEST_AES_KEY-test.bin file, + * which is in format |nonce (12 bytes)|tag (16 bytes)|ciphertext| + */ + +const uint8_t decrypt_test_ciphertext_direct[] = { + /* tag (16 bytes) */ + 0x4d, 0x21, 0x30, 0xb7, 0xce, 0x8a, 0xd6, 0x00, 0xe4, 0x04, 0xbb, 0x32, + 0x72, 0x7a, 0xbb, 0x7c, + /* ciphertext */ + 0xf0, 0x72, 0xdb, 0x63, 0x03, 0xdd, 0x24, 0x69, + 0xd4, 0xbf, 0xd7, 0xa0, 0xec, 0xfa, 0x66, 0x58, 0x95, 0x2b, 0xc1, 0xc2, + 0x9d, 0x82, 0x02, 0x1a, 0xd7, 0x5b, 0xc0, 0x01, 0xce, 0x0b, 0x79, 0x53, + 0xe7, 0xdb, 0x0d, 0x35, 0xab, 0xef, 0x81, 0xc8, 0x68, 0xc5, 0xa7, 0x22, + 0x90, 0xea, 0xd0, 0x7f, 0x36, 0xed, 0x14, 0xbe, 0x30, 0xf2, 0x81, 0x56, + 0x7e, 0x2e, 0x5f, 0xd8, 0x7c, +}; + +const uint8_t decrypt_test_iv_direct[] = { + 0x60, 0x90, 0x6d, 0xb2, 0xfe, 0xc3, 0xc8, 0x5a, 0xf0, 0x28, 0xb1, 0xb6, +}; + +const suit_manifest_class_id_t decrypt_test_sample_class_id = { + {0x5b, 0x46, 0x9f, 0xd1, 0x90, 0xee, 0x53, 0x9c, 0xa3, 0x18, 0x68, 0x1b, 0x03, 0x69, 0x5e, + 0x36}}; + +psa_status_t decrypt_test_init_encryption_key(const uint8_t *data, size_t size, + psa_key_id_t *key_id, psa_key_id_t alg, uint8_t *cbor_key_id) +{ + psa_status_t status; + + /* Configure the key attributes */ + psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; + + psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_algorithm(&key_attributes, alg); + psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&key_attributes, 256); + + status = psa_import_key(&key_attributes, data, size, key_id); + + /* Encode KEK key ID as CBOR unsigned int */ + cbor_key_id[0] = 0x1A; + cbor_key_id[1] = ((*key_id >> 24) & 0xFF); + cbor_key_id[2] = ((*key_id >> 16) & 0xFF); + cbor_key_id[3] = ((*key_id >> 8) & 0xFF); + cbor_key_id[4] = ((*key_id >> 0) & 0xFF); + + return status; +} diff --git a/tests/subsys/suit/common/decrypt_utils/decrypt_test_utils.h b/tests/subsys/suit/common/decrypt_utils/decrypt_test_utils.h new file mode 100644 index 000000000000..bb7a20ddee09 --- /dev/null +++ b/tests/subsys/suit/common/decrypt_utils/decrypt_test_utils.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef DECRYPT_TEST_UTILS_H_ +#define DECRYPT_TEST_UTILS_H_ + +#include +#include + +/* This module holds common utilities for SUIT decrypt filter tests. + * It defines default encryption key data, plaintext and ciphertext along with other + * suit_encryption_info struct members that can be used while testing. + * + * WARNING: All of the const values defined in this module CAN be changed freely. + * This also means that any test depending on them should expect it. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Default initalization for suit_encryption_info struct. + * 'cek_key_id_cbor' - should be taken from init_encryption_key() call. + */ +#define DECRYPT_TEST_ENC_INFO_DEFAULT_INIT(cek_key_id_cbor) \ + { \ + .enc_alg_id = suit_cose_aes256_gcm, \ + .IV = { \ + .value = decrypt_test_iv_direct, \ + .len = sizeof(decrypt_test_iv_direct), \ + }, \ + .aad = { \ + .value = decrypt_test_aad, \ + .len = strlen(decrypt_test_aad), \ + }, \ + .kw_alg_id = suit_cose_direct, \ + .kw_key.direct = {.key_id = {.value = (cek_key_id_cbor), \ + .len = sizeof((cek_key_id_cbor))},} \ + } + +#define DECRYPT_TEST_KEY_LENGTH 32 +extern const uint8_t decrypt_test_key_data[DECRYPT_TEST_KEY_LENGTH]; + +#define DECRYPT_TEST_PLAINTEXT_LENGTH 61 +extern const uint8_t decrypt_test_plaintext[DECRYPT_TEST_PLAINTEXT_LENGTH]; + +#define DECRYPT_TEST_AAD_LENGTH 11 +extern const uint8_t decrypt_test_aad[DECRYPT_TEST_AAD_LENGTH]; + +#define DECRYPT_TEST_WRAPPED_CEK_LENGTH 40 +extern const uint8_t decrypt_test_wrapped_cek[DECRYPT_TEST_WRAPPED_CEK_LENGTH]; + +#define DECRYPT_TEST_CIPHERTEXT_AES_KW_LENGTH (DECRYPT_TEST_PLAINTEXT_LENGTH + 16) +extern const uint8_t decrypt_test_ciphertext_aes_kw[DECRYPT_TEST_CIPHERTEXT_AES_KW_LENGTH]; + +#define DECRYPT_TEST_IV_AES_KW_LENGTH 12 +extern const uint8_t decrypt_test_iv_aes_kw[DECRYPT_TEST_IV_AES_KW_LENGTH]; + +#define DECRYPT_TEST_CIPHERTEXT_DIRECT_LENGTH (DECRYPT_TEST_PLAINTEXT_LENGTH + 16) +extern const uint8_t decrypt_test_ciphertext_direct[DECRYPT_TEST_CIPHERTEXT_DIRECT_LENGTH]; + +#define DECRYPT_TEST_IV_DIRECT_LENGTH 12 +extern const uint8_t decrypt_test_iv_direct[DECRYPT_TEST_IV_DIRECT_LENGTH]; + +extern const suit_manifest_class_id_t decrypt_test_sample_class_id; + +/** + * @brief Initialize encryption key with given binary data. + * The key is initialized as PSA_KEY_TYPE_AES. + * + * @param[in] data binary key data. + * @param[in] size size of @a data. + * @param[out] key_id key ID of imported key. + * @param[in] alg encryption algorithm. + * @param[out] cbor_key_id key ID of imported key in cbor format. + * + * @retval PSA_SUCCESS successfuly imported given key. + * @retval PSA_ERROR_* returned error from dependent PSA calls. + */ +psa_status_t decrypt_test_init_encryption_key(const uint8_t *data, size_t size, + psa_key_id_t *key_id, psa_key_id_t alg, uint8_t *cbor_key_id); + +#ifdef __cplusplus +} +#endif + +#endif /* DECRYPT_TEST_UTILS_H_ */ diff --git a/tests/subsys/suit/copy/CMakeLists.txt b/tests/subsys/suit/copy/CMakeLists.txt index 3959466e84f5..dcc256d5f107 100644 --- a/tests/subsys/suit/copy/CMakeLists.txt +++ b/tests/subsys/suit/copy/CMakeLists.txt @@ -18,3 +18,4 @@ zephyr_library_link_libraries(suit_sink_selector_interface) zephyr_library_link_libraries(suit_storage_interface) zephyr_library_link_libraries(suit_manifest_variables) zephyr_library_link_libraries(suit_ipuc) +zephyr_library_link_libraries(suit_decrypt_test_utils) diff --git a/tests/subsys/suit/copy/prj.conf b/tests/subsys/suit/copy/prj.conf index 45f6e12f289e..d6dc71a7d4cf 100644 --- a/tests/subsys/suit/copy/prj.conf +++ b/tests/subsys/suit/copy/prj.conf @@ -36,3 +36,5 @@ CONFIG_FLASH_MAP=y CONFIG_SUIT_IPUC=y CONFIG_MOCK_SDFW_ARBITER=y + +CONFIG_SUIT_STREAM_FILTER_DECRYPT=y diff --git a/tests/subsys/suit/copy/src/main.c b/tests/subsys/suit/copy/src/main.c index a0a528575d2c..39590a23b203 100644 --- a/tests/subsys/suit/copy/src/main.c +++ b/tests/subsys/suit/copy/src/main.c @@ -16,6 +16,7 @@ #include #include #include +#include #define WRITE_ADDR 0x1A00080000 #define TEST_MFST_VAR_NVM_ID 1 @@ -654,3 +655,101 @@ ZTEST(copy_tests, test_mfst_nvm_var_to_mram_NOK) zassert_equal(ret, SUIT_SUCCESS, "Failed to release destination component handle after the test: %d", ret); } + +ZTEST(copy_tests, test_integrated_fetch_and_copy_to_msink_encrypted_OK) +{ + memptr_storage_handle_t handle; + struct zcbor_string source = { + .value = decrypt_test_ciphertext_direct, + .len = sizeof(decrypt_test_ciphertext_direct) + }; + + suit_component_t src_handle; + /* [h'CAND_IMG', h'02'] */ + uint8_t valid_src_value[] = {0x82, 0x49, 0x68, 'C', 'A', 'N', 'D', + '_', 'I', 'M', 'G', 0x41, 0x02}; + + struct zcbor_string valid_src_component_id = { + .value = valid_src_value, + .len = sizeof(valid_src_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_src_component_id, false, &src_handle); + + zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); + + ret = suit_plat_fetch_integrated(src_handle, &source, &valid_manifest_component_id, NULL); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_fetch failed - error %i", ret); + + ret = suit_plat_component_impl_data_get(src_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_ptr(decrypt_test_ciphertext_direct, payload, + "Retrieved payload doesn't mach ciphertext_direct"); + zassert_equal(sizeof(decrypt_test_ciphertext_direct), payload_size, + "Retrieved payload_size doesn't mach size of ciphertext_direct"); + zassert_not_null(payload, "Retrieved payload is NULL"); + + /* 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), + }; + + 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_copy(dst_handle, src_handle, &valid_manifest_component_id, &enc_info); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_copy failed - error %i", ret); + + ret = suit_plat_component_impl_data_get(dst_handle, &handle); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_component_impl_data_get failed - error %i", + ret); + + 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(dst_handle); + zassert_equal(ret, SUIT_SUCCESS, "dst_handle release failed - error %i", ret); + + ret = suit_plat_release_component_handle(src_handle); + zassert_equal(ret, SUIT_SUCCESS, "src_handle release failed - error %i", ret); + + ret = suit_memptr_storage_release(handle); + zassert_equal(ret, SUIT_PLAT_SUCCESS, "memptr_storage handle release failed - error %i", + ret); + + psa_destroy_key(cek_key_id); +} diff --git a/tests/subsys/suit/decrypt_filter/CMakeLists.txt b/tests/subsys/suit/decrypt_filter/CMakeLists.txt index 9035df0f3090..43ddc6065698 100644 --- a/tests/subsys/suit/decrypt_filter/CMakeLists.txt +++ b/tests/subsys/suit/decrypt_filter/CMakeLists.txt @@ -18,3 +18,4 @@ target_include_directories(suit_mci INTERFACE ${ZEPHYR_NRF_MODULE_DIR}/subsys/su zephyr_library_link_libraries(suit_stream_filters_interface) zephyr_library_link_libraries(suit_stream_sources_interface) zephyr_library_link_libraries(suit_mci) +zephyr_library_link_libraries(suit_decrypt_test_utils) diff --git a/tests/subsys/suit/decrypt_filter/src/main.c b/tests/subsys/suit/decrypt_filter/src/main.c index f285d2712485..99af0cd8cc45 100644 --- a/tests/subsys/suit/decrypt_filter/src/main.c +++ b/tests/subsys/suit/decrypt_filter/src/main.c @@ -11,6 +11,7 @@ #include #include #include +#include /* Forward declaration of the internal, temporary AES key-unwrap implementation. */ psa_status_t suit_aes_key_unwrap_manual(psa_key_id_t kek_key_id, const uint8_t *wrapped_cek, @@ -22,22 +23,6 @@ DEFINE_FFF_GLOBALS; FAKE_VALUE_FUNC(int, suit_mci_fw_encryption_key_id_validate, const suit_manifest_class_id_t *, uint32_t); -/** - * The master key used by these tests can be imported into the local KMS backend by running: - * - * nrfkms import_keyvalue -k TEST_AES_KEY -t aes -v aHWJdIkl5hdXw4SS1nTdVYE/q7ycMOZm2mR6qx/KvKw= - * - * The KEK below is derived from context "test" - * To acquire ut run: - * nrfkms export_derived -k TEST_AES_KEY -c test --format native - * hexdump -e '16/1 "0x%02x, " "\n"' kms_output/derived_key_native_test_from_TEST_AES_KEY.bin - */ -static const uint8_t test_key_data[] = { - 0xf8, 0xfa, 0x8e, 0x7b, 0xed, 0x32, 0xd0, 0xc7, 0x15, 0x1f, 0xd9, 0xab, 0x0d, - 0x8d, 0xed, 0x95, 0x26, 0xa8, 0x6a, 0x15, 0x34, 0x16, 0x01, 0xcf, 0x9c, 0x6b, - 0xba, 0x00, 0x6a, 0xab, 0xaa, 0x9a, -}; - static uint8_t kek_key_id_cbor[] = { 0x1A, 0x00, 0x00, 0x00, 0x00, }; @@ -47,109 +32,8 @@ struct suit_decrypt_filter_tests_fixture { psa_key_id_t key_id; }; -static const uint8_t plaintext[] = { - "This is a sample plaintext for testing the decryption filter", -}; - -static const uint8_t aad[] = { - "sample aad" -}; - -/** - * Encryption and using wrapped CEK achieved by running: - * - * echo "This is a sample plaintext for testing the decryption filter" > plaintext.txt - * nrfkms wrap -k TEST_AES_KEY -c test -f plaintext.txt --format native -t aes --aad "sample aad" - * - * Wrapped CEK stored in the resulting wrapped_aek-aes-... file - * - * Ciphertext and NONCE (IV) taken from the encrypted_asset-... file, which is in format - * |nonce (12 bytes)|ciphertext|tag (16 bytes)| - * - */ -static const uint8_t wrapped_cek[] = { - 0x7d, 0xd6, 0xf4, 0xd3, 0x52, 0x44, 0x5a, 0x3a, 0x67, 0xb8, 0xcc, - 0x74, 0x5b, 0x4b, 0x6f, 0x70, 0x62, 0xc3, 0xf2, 0x7b, 0x6b, 0x14, - 0xf1, 0x06, 0x57, 0xa3, 0x68, 0x32, 0x44, 0xc3, 0x85, 0x77, 0x86, - 0xe7, 0xda, 0x15, 0xbf, 0xf8, 0x9e, 0x63 -}; - -static const uint8_t ciphertext_aes_kw[] = { - /* tag (16 bytes) */ - 0xdc, 0xe6, 0x95, 0xac, 0x0f, 0x61, 0x87, 0x17, 0x51, 0x48, 0xb4, 0xa1, - 0x8e, 0x09, 0x89, 0xb4, - /* ciphertext */ - 0x8b, 0xfb, 0xd9, 0xe4, 0xcf, 0xde, 0xf8, 0xcf, 0xe5, 0x69, 0x9d, 0x6d, - 0x92, 0x8a, 0x04, 0xf8, 0x26, 0x22, 0xd5, 0xd8, 0xe8, 0x77, 0x18, 0x5a, - 0x01, 0x13, 0xba, 0xd5, 0x23, 0x72, 0xae, 0x80, 0x44, 0xed, 0xea, 0xdf, - 0x74, 0x79, 0x8a, 0x83, 0x52, 0x72, 0x2f, 0x43, 0x06, 0xe9, 0xd4, 0xbb, - 0x54, 0x8a, 0x0d, 0xea, 0x7f, 0xe6, 0x48, 0xf0, 0xfd, 0x0e, 0xbb, 0xaa, - 0xa3, -}; - -static const uint8_t iv_aes_kw[] = { - 0x61, 0xb4, 0x70, 0x53, 0xa5, 0xe2, 0x05, 0x68, 0xfe, 0x77, 0x12, 0x89, -}; - -/** - * Encryption without wrapping CEK achieved by running: - * - * echo "This is a sample plaintext for testing the decryption filter" > plaintext.txt - * nrfkms encrypt -k TEST_AES_KEY -c test -f plaintext.txt --aad "sample aad" --format native - * - * Ciphertext and NONCE (IV) taken from the encrypted_data_using_TEST_AES_KEY-test.bin file, - * which is in format |nonce (12 bytes)|tag (16 bytes)|ciphertext| - */ - -static const uint8_t ciphertext_direct[] = { - /* tag (16 bytes) */ - 0x4d, 0x21, 0x30, 0xb7, 0xce, 0x8a, 0xd6, 0x00, 0xe4, 0x04, 0xbb, 0x32, - 0x72, 0x7a, 0xbb, 0x7c, - /* ciphertext */ - 0xf0, 0x72, 0xdb, 0x63, 0x03, 0xdd, 0x24, 0x69, - 0xd4, 0xbf, 0xd7, 0xa0, 0xec, 0xfa, 0x66, 0x58, 0x95, 0x2b, 0xc1, 0xc2, - 0x9d, 0x82, 0x02, 0x1a, 0xd7, 0x5b, 0xc0, 0x01, 0xce, 0x0b, 0x79, 0x53, - 0xe7, 0xdb, 0x0d, 0x35, 0xab, 0xef, 0x81, 0xc8, 0x68, 0xc5, 0xa7, 0x22, - 0x90, 0xea, 0xd0, 0x7f, 0x36, 0xed, 0x14, 0xbe, 0x30, 0xf2, 0x81, 0x56, - 0x7e, 0x2e, 0x5f, 0xd8, 0x7c, -}; - - -static const uint8_t iv_direct[] = { - 0x60, 0x90, 0x6d, 0xb2, 0xfe, 0xc3, 0xc8, 0x5a, 0xf0, 0x28, 0xb1, 0xb6, -}; - -static const suit_manifest_class_id_t sample_class_id = { - {0x5b, 0x46, 0x9f, 0xd1, 0x90, 0xee, 0x53, 0x9c, 0xa3, 0x18, 0x68, 0x1b, 0x03, 0x69, 0x5e, - 0x36}}; - static uint8_t output_buffer[128] = {0}; -static void init_encryption_key(const uint8_t *data, size_t size, psa_key_id_t *key_id, - psa_key_id_t alg, uint8_t *cbor_key_id) -{ - psa_status_t status; - - /* Configure the key attributes */ - psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; - - psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); - psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); - psa_set_key_algorithm(&key_attributes, alg); - psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&key_attributes, 256); - - status = psa_import_key(&key_attributes, data, size, key_id); - - zassert_equal(status, PSA_SUCCESS, "Failed to import key"); - - /* Encode KEK key ID as CBOR unsigned int */ - cbor_key_id[1] = ((*key_id >> 24) & 0xFF); - cbor_key_id[2] = ((*key_id >> 16) & 0xFF); - cbor_key_id[3] = ((*key_id >> 8) & 0xFF); - cbor_key_id[4] = ((*key_id >> 0) & 0xFF); -} - static void *test_suite_setup(void) { static struct suit_decrypt_filter_tests_fixture fixture = {0}; @@ -159,8 +43,11 @@ static void *test_suite_setup(void) zassert_equal(status, PSA_SUCCESS, "Failed to init psa crypto"); /* Init the KEK key */ - init_encryption_key(test_key_data, sizeof(test_key_data), &fixture.key_id, - PSA_ALG_ECB_NO_PADDING, kek_key_id_cbor); + status = decrypt_test_init_encryption_key(decrypt_test_key_data, + sizeof(decrypt_test_key_data), &fixture.key_id, + PSA_ALG_ECB_NO_PADDING, kek_key_id_cbor); + zassert_equal(status, PSA_SUCCESS, "Failed to import key"); + kek_key_id = fixture.key_id; return &fixture; @@ -192,8 +79,8 @@ ZTEST_F(suit_decrypt_filter_tests, test_aes_unwrap_smoke) mbedtls_svc_key_id_t unwrapped_cek_key_id; psa_status_t status = - suit_aes_key_unwrap_manual(fixture->key_id, wrapped_cek, 256, PSA_KEY_TYPE_AES, - PSA_ALG_GCM, &unwrapped_cek_key_id); + suit_aes_key_unwrap_manual(fixture->key_id, decrypt_test_wrapped_cek, + 256, PSA_KEY_TYPE_AES, PSA_ALG_GCM, &unwrapped_cek_key_id); zassert_equal(status, PSA_SUCCESS, "Failed to unwrap CEK"); } @@ -205,18 +92,18 @@ ZTEST_F(suit_decrypt_filter_tests, test_filter_smoke_aes_kw) struct suit_encryption_info enc_info = { .enc_alg_id = suit_cose_aes256_gcm, .IV = { - .value = iv_aes_kw, - .len = sizeof(iv_aes_kw), + .value = decrypt_test_iv_aes_kw, + .len = sizeof(decrypt_test_iv_aes_kw), }, .aad = { - .value = aad, - .len = strlen(aad), + .value = decrypt_test_aad, + .len = strlen(decrypt_test_aad), }, .kw_alg_id = suit_cose_aes256_kw, .kw_key.aes = {.key_id = {.value = kek_key_id_cbor, .len = sizeof(kek_key_id_cbor)}, .ciphertext = { - .value = wrapped_cek, - .len = sizeof(wrapped_cek), + .value = decrypt_test_wrapped_cek, + .len = sizeof(decrypt_test_wrapped_cek), }}, }; suit_mci_fw_encryption_key_id_validate_fake.return_val = SUIT_PLAT_SUCCESS; @@ -225,17 +112,20 @@ ZTEST_F(suit_decrypt_filter_tests, test_filter_smoke_aes_kw) zassert_equal(err, SUIT_PLAT_SUCCESS, "Unable to create RAM sink"); - err = suit_decrypt_filter_get(&dec_sink, &enc_info, &sample_class_id, &ram_sink); + err = suit_decrypt_filter_get(&dec_sink, &enc_info, + &decrypt_test_sample_class_id, &ram_sink); zassert_equal(err, SUIT_PLAT_SUCCESS, "Failed to create decrypt filter"); - zassert_equal_ptr(suit_mci_fw_encryption_key_id_validate_fake.call_count, 1, + zassert_equal(suit_mci_fw_encryption_key_id_validate_fake.call_count, 1, "Invalid number of calls to suit_mci_fw_encryption_key_id_validate"); - zassert_equal_ptr(suit_mci_fw_encryption_key_id_validate_fake.arg0_val, &sample_class_id, + zassert_equal_ptr(suit_mci_fw_encryption_key_id_validate_fake.arg0_val, + &decrypt_test_sample_class_id, "Invalid class ID passed to suit_mci_fw_encryption_key_id_validate"); zassert_equal(suit_mci_fw_encryption_key_id_validate_fake.arg1_val, kek_key_id, "Invalid key ID passed to suit_mci_fw_encryption_key_id_validate"); - err = suit_memptr_streamer_stream(ciphertext_aes_kw, sizeof(ciphertext_aes_kw), &dec_sink); + err = suit_memptr_streamer_stream(decrypt_test_ciphertext_aes_kw, + sizeof(decrypt_test_ciphertext_aes_kw), &dec_sink); zassert_equal(err, SUIT_PLAT_SUCCESS, "Failed to decrypt ciphertext"); @@ -247,7 +137,8 @@ ZTEST_F(suit_decrypt_filter_tests, test_filter_smoke_aes_kw) zassert_equal(err, SUIT_PLAT_SUCCESS, "Failed to release decrypt filter"); - zassert_equal(memcmp(output_buffer, plaintext, strlen(plaintext)), 0, + zassert_equal(memcmp(output_buffer, decrypt_test_plaintext, + strlen(decrypt_test_plaintext)), 0, "Decrypted plaintext does not match"); } @@ -261,23 +152,15 @@ ZTEST_F(suit_decrypt_filter_tests, test_filter_smoke_direct) psa_key_id_t cek_key_id; - init_encryption_key(test_key_data, sizeof(test_key_data), &cek_key_id, - PSA_ALG_GCM, cek_key_id_cbor); + psa_status_t const 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); - struct suit_encryption_info enc_info = { - .enc_alg_id = suit_cose_aes256_gcm, - .IV = { - .value = iv_direct, - .len = sizeof(iv_direct), - }, - .aad = { - .value = aad, - .len = strlen(aad), - }, - .kw_alg_id = suit_cose_direct, - .kw_key.aes = {.key_id = {.value = cek_key_id_cbor, - .len = sizeof(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); suit_mci_fw_encryption_key_id_validate_fake.return_val = SUIT_PLAT_SUCCESS; @@ -285,19 +168,22 @@ ZTEST_F(suit_decrypt_filter_tests, test_filter_smoke_direct) zassert_equal(err, SUIT_PLAT_SUCCESS, "Unable to create RAM sink"); - err = suit_decrypt_filter_get(&dec_sink, &enc_info, &sample_class_id, &ram_sink); + err = suit_decrypt_filter_get(&dec_sink, &enc_info, + &decrypt_test_sample_class_id, &ram_sink); zassert_equal(err, SUIT_PLAT_SUCCESS, "Failed to create decrypt filter"); - zassert_equal_ptr(suit_mci_fw_encryption_key_id_validate_fake.call_count, 1, + zassert_equal(suit_mci_fw_encryption_key_id_validate_fake.call_count, 1, "Invalid number of calls to suit_mci_fw_encryption_key_id_validate"); - zassert_equal_ptr(suit_mci_fw_encryption_key_id_validate_fake.arg0_val, &sample_class_id, + zassert_equal_ptr(suit_mci_fw_encryption_key_id_validate_fake.arg0_val, + &decrypt_test_sample_class_id, "Invalid class ID passed to suit_mci_fw_encryption_key_id_validate"); zassert_equal(suit_mci_fw_encryption_key_id_validate_fake.arg1_val, cek_key_id, "Invalid key ID passed to suit_mci_fw_encryption_key_id_validate"); - err = suit_memptr_streamer_stream(ciphertext_direct, sizeof(ciphertext_direct), &dec_sink); + err = suit_memptr_streamer_stream(decrypt_test_ciphertext_direct, + sizeof(decrypt_test_ciphertext_direct), &dec_sink); zassert_equal(err, SUIT_PLAT_SUCCESS, "Failed to decrypt ciphertext"); @@ -309,7 +195,8 @@ ZTEST_F(suit_decrypt_filter_tests, test_filter_smoke_direct) zassert_equal(err, SUIT_PLAT_SUCCESS, "Failed to release decrypt filter"); - zassert_equal(memcmp(output_buffer, plaintext, strlen(plaintext)), 0, + zassert_equal(memcmp(output_buffer, decrypt_test_plaintext, + strlen(decrypt_test_plaintext)), 0, "Decrypted plaintext does not match"); psa_destroy_key(cek_key_id); @@ -325,23 +212,15 @@ ZTEST_F(suit_decrypt_filter_tests, test_key_id_validation_fail) psa_key_id_t cek_key_id; - init_encryption_key(test_key_data, sizeof(test_key_data), &cek_key_id, - PSA_ALG_GCM, cek_key_id_cbor); + psa_status_t const 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); - struct suit_encryption_info enc_info = { - .enc_alg_id = suit_cose_aes256_gcm, - .IV = { - .value = iv_direct, - .len = sizeof(iv_direct), - }, - .aad = { - .value = aad, - .len = strlen(aad), - }, - .kw_alg_id = suit_cose_direct, - .kw_key.aes = {.key_id = {.value = cek_key_id_cbor, - .len = sizeof(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); suit_mci_fw_encryption_key_id_validate_fake.return_val = MCI_ERR_WRONGKEYID; @@ -349,13 +228,15 @@ ZTEST_F(suit_decrypt_filter_tests, test_key_id_validation_fail) zassert_equal(err, SUIT_PLAT_SUCCESS, "Unable to create RAM sink"); - err = suit_decrypt_filter_get(&dec_sink, &enc_info, &sample_class_id, &ram_sink); + err = suit_decrypt_filter_get(&dec_sink, &enc_info, + &decrypt_test_sample_class_id, &ram_sink); zassert_equal(err, SUIT_PLAT_ERR_AUTHENTICATION, "Incorrect error code when getting decrypt filter"); - zassert_equal_ptr(suit_mci_fw_encryption_key_id_validate_fake.call_count, 1, + zassert_equal(suit_mci_fw_encryption_key_id_validate_fake.call_count, 1, "Invalid number of calls to suit_mci_fw_encryption_key_id_validate"); - zassert_equal_ptr(suit_mci_fw_encryption_key_id_validate_fake.arg0_val, &sample_class_id, + zassert_equal_ptr(suit_mci_fw_encryption_key_id_validate_fake.arg0_val, + &decrypt_test_sample_class_id, "Invalid class ID passed to suit_mci_fw_encryption_key_id_validate"); zassert_equal(suit_mci_fw_encryption_key_id_validate_fake.arg1_val, cek_key_id, "Invalid key ID passed to suit_mci_fw_encryption_key_id_validate"); diff --git a/tests/subsys/suit/fetch/CMakeLists.txt b/tests/subsys/suit/fetch/CMakeLists.txt index 97ca8c37a211..a89f4f225a89 100644 --- a/tests/subsys/suit/fetch/CMakeLists.txt +++ b/tests/subsys/suit/fetch/CMakeLists.txt @@ -14,3 +14,5 @@ include(../cmake/test_template.cmake) 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) diff --git a/tests/subsys/suit/fetch/prj.conf b/tests/subsys/suit/fetch/prj.conf index 7d88f215895c..3424e6bebbab 100644 --- a/tests/subsys/suit/fetch/prj.conf +++ b/tests/subsys/suit/fetch/prj.conf @@ -30,3 +30,8 @@ CONFIG_FLASH_MAP=y CONFIG_SUIT_IPUC=y CONFIG_MOCK_SDFW_ARBITER=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 6e77fe14039f..547c080ae02a 100644 --- a/tests/subsys/suit/fetch/src/main.c +++ b/tests/subsys/suit/fetch/src/main.c @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include #define TEST_DATA_SIZE 64 #define WRITE_ADDR 0x1A00080000 @@ -57,9 +60,21 @@ static const uint8_t cache2[] = { 0x90, 0x70, 0x18, 0x92, 0x36, 0x51, 0x92, 0x83, 0x09, 0x86, 0x70, 0x19, 0x23}; static const size_t cache2_len = sizeof(cache2); +/* 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 = (const uint8_t *)0x1234, - .len = 123, + .value = valid_manifest_component, + .len = sizeof(valid_manifest_component), }; static void setup_cache_with_sample_entries(void) @@ -341,3 +356,207 @@ 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/write/CMakeLists.txt b/tests/subsys/suit/write/CMakeLists.txt index 5f320ea13772..111e74aac1df 100644 --- a/tests/subsys/suit/write/CMakeLists.txt +++ b/tests/subsys/suit/write/CMakeLists.txt @@ -19,3 +19,4 @@ zephyr_library_link_libraries(suit_memory_layout_interface) zephyr_library_link_libraries(suit_storage_interface) zephyr_library_link_libraries(suit_manifest_variables) zephyr_library_link_libraries(suit_ipuc) +zephyr_library_link_libraries(suit_decrypt_test_utils) diff --git a/tests/subsys/suit/write/prj.conf b/tests/subsys/suit/write/prj.conf index 79a0199ac1f9..4d7a3d1eb657 100644 --- a/tests/subsys/suit/write/prj.conf +++ b/tests/subsys/suit/write/prj.conf @@ -36,3 +36,5 @@ CONFIG_FLASH_MAP=y CONFIG_SUIT_IPUC=y CONFIG_MOCK_SDFW_ARBITER=y + +CONFIG_SUIT_STREAM_FILTER_DECRYPT=y diff --git a/tests/subsys/suit/write/src/main.c b/tests/subsys/suit/write/src/main.c index eeda24bccae7..083120b8e7c4 100644 --- a/tests/subsys/suit/write/src/main.c +++ b/tests/subsys/suit/write/src/main.c @@ -18,6 +18,7 @@ #include #include #include +#include #define DFU_PARTITION_OFFSET FIXED_PARTITION_OFFSET(dfu_partition) #define FLASH_WRITE_ADDR (suit_plat_mem_nvm_ptr_get(DFU_PARTITION_OFFSET)) @@ -112,6 +113,56 @@ ZTEST(write_tests, test_write_to_flash_sink_OK) "Data in destination is invalid"); } +ZTEST(write_tests, test_write_to_flash_sink_encrypted_OK) +{ + struct zcbor_string source = { + .value = decrypt_test_ciphertext_direct, + .len = sizeof(decrypt_test_ciphertext_direct) + }; + + /* Create handle that will be used as destination */ + suit_component_t dst_handle; + /* [h'MEM', h'02', h'1A000F0000', h'191000'] */ + uint8_t valid_dst_value[] = {0x84, 0x44, 0x63, 'M', 'E', 'M', 0x41, 0x02, 0x45, + 0x1A, 0x00, 0x0F, 0x00, 0x00, 0x43, 0x19, 0x10, 0x00}; + + struct zcbor_string valid_dst_component_id = { + .value = valid_dst_value, + .len = sizeof(valid_dst_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_dst_component_id, false, &dst_handle); + + zassert_equal(ret, SUIT_SUCCESS, "create_component_handle failed - error %i", ret); + + ret = suit_plat_write(dst_handle, &source, &valid_manifest_component_id, &enc_info); + zassert_equal(ret, SUIT_SUCCESS, "suit_plat_write failed - error %i", ret); + + ret = suit_plat_release_component_handle(dst_handle); + zassert_equal(ret, SUIT_SUCCESS, "dst_handle release failed - error %i", ret); + zassert_mem_equal(FLASH_WRITE_ADDR, decrypt_test_plaintext, strlen(decrypt_test_plaintext), + "Data in destination is invalid"); + + psa_destroy_key(cek_key_id); +} + ZTEST(write_tests, test_write_to_ram_sink_OK) { struct zcbor_string source = {.value = test_data, .len = sizeof(test_data)};